Minimind源码的详细解析(个人学习记录)(RMSNorm)
最近在学习LLM的相关知识,了解到Minimind这个轻量化的可以从0构建的语言模型,但是感觉边学边忘,所以选择做一个源码解析的博客,从而帮助自己巩固知识。
Minimind项目介绍
MiniMind 是一个开源的超小型语言模型项目,由开发者 jingyaogong 创建并维护,旨在以极低成本帮助个人开发者和AI爱好者从零开始训练自己的语言模型。项目秉承 "大道至简" 的理念,让最普通的个人GPU也能快速完成完整的大模型训练流程。
MiniMind的最小版本仅需 25.8M(0.02B)参数,体积约为GPT-3的七千分之一,却能够实现流畅的对话功能(基于NVIDIA 3090显卡测试,从零开始完整训练仅需2小时,GPU服务器租用成本约3元人民币。
截至2025年10月,该项目在GitHub上已斩获27.4k Star,成为轻量级语言模型训练领域的标杆性开源项
项目结构分析
我们常用的文件夹是model文件夹和trainer文件夹,其中model文件夹中的model_minimind是整个模型的架构,我将主要分析这个代码,后续也会对训练进行更详细的了解。
模块(1)RMSNORM
首先我们要先考虑一个问题,为什么要进行归一化呢?
我们知道,LLM的模型一般比较深的,那么模型的输出在没有归一化的情况下可能会呈现指数状的变化,比如一个输出原本为1.5,经过100层的变化,可能就会变得非常大,这会造成我们大模型训练过程中不稳定。可以规避以下几个问题:
1.数值爆炸,梯度消失
原因前文已经提到
2.优化注意力机制
在QKV机制中,若数值过大,那么在后续的softmax函数会对此非常敏感,那么就会出现多位置为0或近乎0的情况,出现梯度消失,模型也就无法继续更新了,而通过归一化的机制,我们可以对输出的内容进行限制,从而拯救注意力机制
3.缓解内部协变量偏移 (Internal Covariate Shift)
在训练过程中,随着前一层参数的更新,输入到后一层的特征数据分布会不断发生变化。后一层被迫不断去适应新的分布,这被称为内部协变量偏移。
归一化通过固定特征的均值和方差,为下一层提供了一个相对稳定的输入分布,使得每一层可以更加独立、高效地学习特征。
class RMSNorm(torch.nn.Module):
def __init__(self, dim: int, eps: float = 1e-5):
super().__init__()
self.eps = eps#极小值
self.weight = nn.Parameter(torch.ones(dim))
#我们进入norm模块的输入的尺寸是[batch_size,seqlen,dim]
def _norm(self, x):
return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
#rsqrt是平方根的倒数,即1/sqrt(x),torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps也就是RMS,在这里实现了x/rms(x)
def forward(self, x):
return self.weight * self._norm(x.float()).type_as(x)
#self.weight 就是公式里的gama。这里和上面的式子都采用了广播的机制。
相关知识点
LayerNorm,BatchNorm,RmsNorm
在NLP领域中,我们基本上会选择采用LayerNorm和RmsNorm
其中目前主流的是RMSNorm
其中的是均值,是方差,是极小值,防止除0
那么为什么要采用RMSNorm而不是LayerNorm呢?研究人员发现,LayerNorm真正的价值是尺度不变性,而不是偏移不变性,使用RMSNorm能够提高计算效率,减少计算消耗。