news 2026/10/21 1:01:02

用纯数字理解大模型训练:前向传播、损失计算与反向传播

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用纯数字理解大模型训练:前向传播、损失计算与反向传播

1. 为什么“纯数字”才是理解大模型训练的最佳入口

很多人第一次接触大语言模型训练,脑子里冒出来的全是“Transformer”“注意力机制”“梯度下降”这些术语,结果看了三天文档,连模型到底在干什么都说不清楚。我自己刚开始也是这样,后来发现一个特别有效的办法:把整个训练过程翻译成纯数字的运算,用最朴素的加减乘除去理解,反而一下子就通了。

这篇文章是“从零训练一个大语言模型”连载的第二篇,第一篇我们聊了整体流程和准备工作,这一篇专门解决一个问题:大语言模型训练到底在算什么?我会用纯数字的方式,把前向传播、损失计算、反向传播、参数更新这四个核心环节拆开讲,不涉及任何复杂公式推导,只要你会加减乘除和一点点指数运算,就能看懂。

适合谁来读?如果你是对大模型感兴趣但数学基础一般的人,或者你已经看过一些教程但总觉得隔着一层纱,那这篇就是写给你的。我会用具体的数字例子,一步一步算给你看,让你真正理解模型内部发生了什么。读完这一篇,你再去看那些专业论文,会发现很多概念其实没那么吓人。

先打个预防针:真实的大模型训练当然比这里讲的复杂得多,参数量动辄几十亿上百亿,但核心原理和用几个数字演示的版本是完全一致的。就像你学开车,教练车和F1赛车的操作逻辑本质上是一样的,只是规模和精度不同。我们先把教练车开明白,再去想F1的事。

2. 用一组具体数字走完一次完整的前向传播

2.1 把一句话变成数字:词嵌入的直观理解

假设我们有一个极简的模型,词表里只有四个词:“我”“爱”“学”“习”。我们要让模型学会“我爱学习”这句话。第一步是把词变成数字,这个过程叫词嵌入。

假设每个词用两个数字表示(真实模型可能是几千维,这里为了好算只用两维):

词向量表示
我[1, 0]
爱[0, 1]
学[1, 1]
习[0.5, 0.5]

这些数字一开始是随机生成的,模型训练的目的就是把这些数字调整到“合适”的值。什么叫合适?就是让“我”和“爱”组合起来能预测出“学”,让“爱”和“学”组合起来能预测出“习”。

现在输入“我爱”,模型要预测下一个词是“学”。我们把“我”的向量[1, 0]和“爱”的向量[0, 1]拿出来,准备送进网络。

2.2 注意力机制的纯数字版:谁跟谁更相关

注意力机制听起来很玄,其实核心就一句话:当前词应该关注前面哪些词。我们用数字来算一遍。

假设现在要处理“学”这个词,它需要回头看“我”和“爱”。怎么决定看谁更多?用点积算相似度:

  • “学”和“我”的相似度:1×1 + 1×0 = 1
  • “学”和“爱”的相似度:1×0 + 1×1 = 1

两个都是1,说明“学”觉得“我”和“爱”一样重要。但实际语言中,“爱”对“学”的影响通常更大。这个“应该更大”的判断,就是模型要通过训练学出来的。训练之前,模型不知道谁更重要,训练之后,它会调整参数让“爱”的权重变大。

假设经过softmax归一化(一种把数字变成概率的方法),我们得到“我”的权重是0.4,“爱”的权重是0.6。那么“学”这个位置的输出就是:

0.4 × [1, 0] + 0.6 × [0, 1] = [0.4, 0.6]

这个[0.4, 0.6]就是注意力层的输出,它融合了前面两个词的信息,而且“爱”的贡献更大。

2.3 前馈网络:把融合后的信息再做一次变换

注意力层的输出[0.4, 0.6]会送进一个前馈网络。假设这个网络只有一层,权重矩阵是:

W = [[0.5, 0.2], [0.3, 0.8]]

偏置是[0.1, 0.1]。计算过程:

  • 第一维:0.4×0.5 + 0.6×0.3 + 0.1 = 0.2 + 0.18 + 0.1 = 0.48
  • 第二维:0.4×0.2 + 0.6×0.8 + 0.1 = 0.08 + 0.48 + 0.1 = 0.66

输出是[0.48, 0.66]。然后经过一个激活函数(比如ReLU,就是把负数变成0,正数不变),这里两个都是正数,所以不变。

2.4 输出层:从数字变回词的概率

最后一步是把[0.48, 0.66]变成四个词的概率。假设输出层的权重矩阵是:

W_out = [[0.2, 0.1], [0.3, 0.4], [0.5, 0.2], [0.1, 0.3]]

计算每个词的得分:

  • “我”:0.48×0.2 + 0.66×0.1 = 0.096 + 0.066 = 0.162
  • “爱”:0.48×0.3 + 0.66×0.4 = 0.144 + 0.264 = 0.408
  • “学”:0.48×0.5 + 0.66×0.2 = 0.24 + 0.132 = 0.372
  • “习”:0.48×0.1 + 0.66×0.3 = 0.048 + 0.198 = 0.246

然后用softmax把这些得分变成概率。softmax的算法是:先对每个数求e的指数,再除以所有指数之和。

  • e^0.162 ≈ 1.176
  • e^0.408 ≈ 1.504
  • e^0.372 ≈ 1.451
  • e^0.246 ≈ 1.279

总和 = 1.176 + 1.504 + 1.451 + 1.279 = 5.410

概率:

  • “我”:1.176 / 5.410 ≈ 0.217
  • “爱”:1.504 / 5.410 ≈ 0.278
  • “学”:1.451 / 5.410 ≈ 0.268
  • “习”:1.279 / 5.410 ≈ 0.236

模型预测下一个词是“爱”的概率最高(0.278),但正确答案是“学”。这说明模型现在预测错了,需要调整参数。怎么调?这就是下一节要讲的损失计算和反向传播。

注意:这里的所有数字都是随机设定的,真实训练中这些数字会通过不断迭代自动调整。你不需要记住具体数值,而是要理解这个“输入→变换→输出→比较→调整”的循环。

3. 损失函数:用一个数字衡量模型有多“错”

3.1 交叉熵损失:把错误程度量化

模型预测“学”的概率是0.268,但正确答案就是“学”。我们希望这个概率越接近1越好。交叉熵损失就是用来衡量这个差距的,公式很简单:

损失 = -log(正确答案的概率)

这里正确答案是“学”,概率是0.268,所以:

损失 = -log(0.268) ≈ 1.317

这个1.317就是当前样本的损失值。损失越大,说明模型错得越离谱。如果模型预测“学”的概率是0.9,损失就是-log(0.9)≈0.105,小很多。如果概率是0.99,损失≈0.01,几乎为零。

所以训练的目标就是让这个损失值越来越小。怎么让它变小?调整模型里的所有参数(就是前面那些权重矩阵和词向量)。调整的方法叫梯度下降。

3.2 为什么用-log而不是直接用1减去概率

你可能会想,直接用1减去正确答案的概率不就行了吗?比如1-0.268=0.732,也能衡量错误程度啊。为什么非要用log?

原因有两个。第一,log函数在概率接近0时会给一个非常大的惩罚。比如概率是0.01,-log(0.01)≈4.6,而1-0.01=0.99,差别不大。但概率是0.001时,-log(0.001)≈6.9,而1-0.001=0.999,几乎没变。log能放大“严重错误”的惩罚,让模型更快地纠正大错。

第二,log函数和softmax搭配使用时,求导特别简洁,计算效率高。这在参数量巨大的大模型里非常重要。所以交叉熵损失是行业标准做法,不是随便选的。

3.3 一个批次的总损失:把多个样本平均起来

实际训练不会一次只处理一个样本,而是一次处理一批(batch)。假设一个批次有32个样本,每个样本都有一个损失值,我们把它们平均一下,就得到这个批次的平均损失。

比如32个样本的损失分别是1.317、0.892、1.045……加起来除以32,得到平均损失1.102。这个1.102就是当前批次的整体表现。训练过程中,我们会看到这个数字逐渐下降,从1.1降到0.8,再降到0.5,最后可能降到0.1以下。损失曲线是判断训练是否正常的最重要指标。

实操心得:如果你看到损失突然变成NaN(不是数字),通常是学习率太大导致数值爆炸。解决办法是把学习率调小,比如从0.001降到0.0001。如果损失一直不下降,可能是数据有问题或者模型结构设计不合理。

4. 反向传播:从错误反推每个参数该怎么调

4.1 梯度是什么:用生活例子理解

反向传播的核心是计算梯度。梯度这个词听起来很数学,其实就是一个意思:如果我把某个参数稍微调大一点点,损失会变大还是变小?变大多少?

举个例子。假设你在山上,想走到山谷最低点。你环顾四周,发现往东走一步,高度下降0.5米;往西走一步,高度上升0.3米。那么“往东”就是你应该走的方向,0.5就是那个方向的梯度(下降的梯度)。反向传播就是在算每个参数的“方向”和“大小”。

具体到我们的例子,损失是1.317。我们想知道:如果把输出层权重W_out里第一个数字0.2调大一点,损失会变成多少?这个“变化率”就是梯度。如果梯度是正的,说明调大0.2会让损失增加,那我们就应该调小它。如果梯度是负的,说明调大0.2会让损失减小,那我们就应该调大它。

4.2 链式法则:一层一层往回算

反向传播的名字就来自于这个过程:从损失出发,一层一层往回传,算出每个参数的梯度。

先算输出层的梯度。损失对“学”的得分0.372的梯度是:预测概率0.268减去真实概率1,等于-0.732。这个-0.732的意思是:如果“学”的得分增加1,损失会减少0.732。所以我们应该增加“学”的得分。

然后算“学”的得分对输出层权重的梯度。得分 = 0.48×0.5 + 0.66×0.2,所以对0.5的梯度是0.48,对0.2的梯度是0.66。结合前面的-0.732,最终对0.5的梯度是-0.732×0.48≈-0.351,对0.2的梯度是-0.732×0.66≈-0.483。

这两个梯度都是负数,说明增加这两个权重会减少损失。所以下一步更新参数时,我们会把它们稍微调大一点。

同样的过程会一直往回传,传到前馈网络、注意力层、词嵌入层,算出每一个参数的梯度。这就是反向传播的完整链路。

4.3 梯度消失和梯度爆炸:为什么深层网络难训练

当网络层数很多时,梯度在往回传的过程中会不断乘以权重矩阵里的数字。如果这些数字都小于1,比如0.5,乘上十次就变成0.5^10≈0.001,梯度几乎消失了。参数几乎不更新,模型学不动。这就是梯度消失。

反过来,如果数字都大于1,比如1.5,乘上十次就变成1.5^10≈57.7,梯度变得巨大。参数更新时一下子跳太远,损失反而爆炸。这就是梯度爆炸。

大模型通常有几十层甚至上百层,所以这个问题特别突出。解决办法包括:使用残差连接(让梯度可以走“捷径”)、层归一化(把每层的输出标准化)、使用ReLU等不容易饱和的激活函数。这些技术细节我们会在后续连载里展开,这里你只需要知道:反向传播不是简单地把梯度乘回去,而是需要很多工程技巧来保持数值稳定。

注意:如果你自己动手训练一个小模型,发现损失降到一定程度就不动了,很可能是梯度消失。可以试试减小网络深度,或者加入残差连接。

5. 参数更新:让模型一点点变聪明

5.1 学习率:每次调多少才合适

算出梯度之后,下一步就是更新参数。更新公式很简单:

新参数 = 旧参数 - 学习率 × 梯度

学习率是一个很小的数字,比如0.001。它决定了每次调整的幅度。如果学习率太大,参数会跳来跳去,损失震荡不下降;如果太小,训练速度会慢得让人抓狂。

拿前面的例子来说,输出层权重0.5的梯度是-0.351,学习率是0.001,那么新值就是:

0.5 - 0.001 × (-0.351) = 0.5 + 0.000351 = 0.500351

你看,只增加了0.000351,非常微小。但经过成千上万次迭代,这些微小的调整累积起来,就能让模型从随机猜测变成准确预测。

5.2 批量大小和学习率的关系

批量大小(batch size)是指一次更新参数时用了多少个样本。批量越大,梯度越稳定(因为平均了更多样本的噪声),但计算越慢。批量越小,梯度噪声越大,但更新越频繁。

经验法则是:批量大小翻倍,学习率也可以适当调大。比如批量从32增加到64,学习率可以从0.001调到0.002左右。但这不是绝对的,需要根据实际训练情况微调。

批量大小学习率建议特点
160.0005噪声大,适合小数据集
320.001常用起点
640.002训练稳定,需要更多显存
1280.003适合大规模训练

5.3 优化器:比朴素梯度下降更聪明的办法

上面讲的“新参数 = 旧参数 - 学习率 × 梯度”叫随机梯度下降(SGD)。实际训练大模型时,几乎没人直接用SGD,而是用Adam或AdamW这类优化器。

Adam的核心思想是:为每个参数单独调整学习率。有些参数梯度一直很大,就给它小一点的学习率;有些参数梯度一直很小,就给它大一点的学习率。这样每个参数都能以合适的步伐更新,训练更快更稳。

Adam还引入了“动量”的概念。就像下山时不仅看当前坡度,还看之前的速度。如果一直往同一个方向走,就加速;如果方向变了,就减速。这样能避免在局部最小值附近震荡。

实操心得:如果你刚开始训练一个小模型,直接用Adam,学习率设0.001,通常都能跑起来。如果损失不下降,试试0.0001。如果下降太慢,试试0.003。Adam对学习率不那么敏感,容错率高,适合新手。

6. 把整个循环串起来:一次迭代的完整时间线

6.1 从输入到更新的十二个步骤

现在我们把前面所有内容串起来,看看一次完整的训练迭代到底发生了什么:

  1. 从数据集中取一个批次的数据,比如32个句子。
  2. 把每个句子里的词转换成词向量(查表)。
  3. 把词向量送进注意力层,计算每个词应该关注哪些词。
  4. 注意力层的输出送进前馈网络,做非线性变换。
  5. 前馈网络的输出送进输出层,得到每个词的概率分布。
  6. 用交叉熵损失计算预测和真实答案的差距。
  7. 把32个样本的损失平均,得到批次损失。
  8. 从批次损失出发,反向传播计算每个参数的梯度。
  9. 用优化器(如Adam)根据梯度更新所有参数。
  10. 清空梯度,准备下一次迭代。
  11. 重复步骤1到10,直到损失降到满意水平。
  12. 保存模型参数,训练结束。

这个过程看起来简单,但实际训练中每一步都有很多细节。比如数据怎么分批、梯度怎么累积、学习率怎么衰减、什么时候保存检查点,这些工程细节决定了训练能不能成功。

6.2 一个数字的旅程:跟踪“学”的概率变化

让我们跟踪一个具体数字的变化。初始时,模型预测“学”的概率是0.268。经过一次参数更新后,假设概率变成了0.271。变化很小,对吧?但经过100次迭代,可能变成0.35;经过1000次,可能变成0.62;经过10000次,可能变成0.89。

这个从0.268到0.89的过程,就是模型“学会”预测“学”的过程。训练的本质就是让正确的概率一点点上升,让错误的概率一点点下降。没有魔法,就是无数次微小的数字调整。

你可以自己写一个简单的脚本,记录每次迭代后“学”的概率,然后画成曲线。你会看到一条波动上升的曲线,中间可能有平台期,也可能有短暂下降,但总体趋势是向上的。这条曲线就是模型学习的轨迹。

6.3 训练多久才算够:早停和验证集

训练不是越久越好。训练太久,模型会“死记硬背”训练数据,在新数据上表现反而变差,这叫过拟合。判断过拟合的方法是:把数据分成训练集和验证集,训练集用来更新参数,验证集用来评估效果。

如果训练集损失还在下降,但验证集损失开始上升,说明模型开始过拟合了,应该停止训练。这个策略叫早停。通常我们会每隔一段时间(比如每1000次迭代)在验证集上评估一次,记录最好的模型参数。

训练集损失验证集损失判断
下降下降正常训练,继续
下降持平接近最优,可以准备停止
下降上升过拟合,立即停止
不下降不下降学习率太小或模型有问题

注意:验证集不能用来更新参数,只能用来评估。如果用验证集调参数,它就变成了训练集的一部分,评估结果就不可信了。正确做法是再分出一个测试集,只在最终评估时用一次。

7. 常见困惑与实操中的坑

7.1 为什么损失降不下去:排查清单

很多人第一次训练模型时,会遇到损失不下降的情况。根据我的经验,按以下顺序排查:

  • 学习率太大:损失震荡或变成NaN。调小10倍试试。
  • 学习率太小:损失下降极慢。调大10倍试试。
  • 数据有问题:标签错了,或者输入输出没对齐。随机抽查几条数据看看。
  • 模型太小:参数量不够,学不会复杂模式。增加层数或隐藏维度。
  • 初始化太差:所有参数初始化为0,导致对称性无法打破。用随机初始化。
  • 激活函数不合适:用了sigmoid导致梯度消失。换成ReLU或GELU。

这个清单我打印出来贴在显示器旁边,每次训练不顺利就对照着查,能解决80%的问题。

7.2 为什么训练损失很低但生成效果很差

这是另一个常见困惑。训练损失很低,说明模型在训练数据上预测得很准。但生成文本时,你发现它说的全是训练集里的原话,稍微换个开头就胡言乱语。这是典型的过拟合。

解决办法:增加数据量、增加Dropout(随机丢弃一些神经元)、减小模型规模、加入权重衰减(让参数不要太大)。其中增加数据量是最有效的,但也是最贵的。如果数据有限,Dropout和权重衰减是性价比最高的选择。

7.3 数值精度:float32和float16的取舍

大模型训练通常用float16(半精度)来节省显存和加速计算。但float16的数值范围小,容易溢出。所以实践中常用混合精度训练:前向传播和反向传播用float16,参数更新用float32。

这样既能享受float16的速度,又能保持float32的稳定性。PyTorch和TensorFlow都提供了自动混合精度的工具,几行代码就能开启。如果你自己写训练循环,记得在损失缩放(loss scaling)上花点心思,防止梯度下溢。

实操心得:混合精度训练能让显存占用减少约40%,训练速度提升20%到30%。但如果你发现损失不稳定,先关掉混合精度,用纯float32跑一遍,确认模型本身没问题,再开启混合精度调优。

8. 从数字到直觉:训练大模型的思维模型

8.1 把模型想象成一个巨大的调音台

经过上面的数字拆解,你现在应该对训练过程有了具体的感知。我想再给你一个思维模型:把模型想象成一个有几十亿个旋钮的调音台。每个旋钮就是一个参数。训练就是不断微调这些旋钮,让输出的音乐(预测结果)越来越接近目标。

反向传播告诉你每个旋钮应该往哪个方向拧、拧多少。学习率决定你每次拧的幅度。优化器决定你是匀速拧还是根据情况加速减速。损失函数就是你的耳朵,告诉你当前音乐和目标差多远。

这个比喻的好处是:你不需要理解每个旋钮的具体作用,只需要知道整个系统在协同工作。大模型之所以强大,不是因为某个旋钮特别关键,而是因为几十亿个旋钮一起微调,能表达出极其复杂的模式。

8.2 规模带来的质变:为什么大模型“涌现”出能力

你可能会问:既然原理这么简单,为什么小模型做不到大模型的事?答案是规模带来质变。当参数量从百万级增加到百亿级,模型能记住的模式从几千个增加到几十亿个。一些在小模型上完全学不会的任务(比如多步推理、代码生成),在大模型上突然就“会”了。

这种现象叫涌现。它不是魔法,而是量变引起质变。就像水分子在0度以下突然结冰,不是单个水分子变了,而是大量水分子集体行为的结果。大模型的涌现能力也是大量参数协同作用的结果。

理解这一点很重要:你不需要为每个任务设计特殊结构,只需要把模型做大、数据做多、训练做久,很多能力会自动出现。这也是为什么现在的大模型都走“大力出奇迹”的路线。

8.3 下一步:从理解原理到动手实践

这一篇我们用纯数字走完了大模型训练的核心循环。你现在应该能回答这些问题:前向传播在算什么?损失函数为什么用交叉熵?反向传播怎么算梯度?参数怎么更新?学习率和批量大小怎么配合?

下一篇连载,我们会从数字回到代码,用一个极简的Python实现,把今天讲的每一步变成可运行的代码。你会看到几十行代码就能训练一个迷你语言模型,虽然它只会说“我爱学习”这一句话,但所有核心机制都在里面。

如果你等不及,可以自己先试试:用NumPy实现一个两层的神经网络,输入是[1,0]和[0,1],输出是四个词的概率,用交叉熵损失和梯度下降训练它预测“学”。你会发现,即使这么简单的模型,也需要仔细调整学习率和初始化才能收敛。这个过程会让你对今天讲的数字有更深的体会。

我在实际动手过程中最大的感受是:看懂原理和跑通代码之间有一条鸿沟。原理告诉你“应该这样做”,但代码会告诉你“实际上会遇到什么”。比如数值精度问题、梯度消失问题、内存不够问题,这些只有亲手跑过才会真正理解。所以下一篇的代码实践,建议你一定要跟着敲一遍,不要只是复制粘贴。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 0:57:49

Django视频点播网站系统:架构设计、核心实现与答辩指南

简介:基于Python与Django框架实现的视频点播网站系统,是一套面向毕业设计或课程实践的完整可运行项目,覆盖在线教育、视频分享等常见应用场景。项目前后端功能齐备:前端支持视频列表展示、播放详情、用户评论与个人中心&#xff0…

作者头像 李华
网站建设 2026/10/21 0:56:29

图书馆管理系统数据库设计:六张表撑起借还业务闭环

1. 需求与范围:先把"图书馆管理系统"到底要管理什么盘明白做这个数据库版的图书馆管理系统之前,我建议你先别急着建表。很多新手拿到题目就直接开库建表,做着做着发现漏了功能,回头改表结构,改到后面数据乱成…

作者头像 李华
网站建设 2026/10/21 0:56:25

Suno Studio时间对齐与片段拉伸:AI音乐从抽卡到手术刀式精修

做 AI 音乐这行的人,大概率都经历过这种尴尬:Suno 生成了一段旋律和歌词都挺对味的东西,但副歌总是比伴奏慢半拍,或者说唱部分有一句明显抢拍,你恨不得冲进屏幕里把波形拽回来。结果只能一次次重新生成、抽卡、碰运气。…

作者头像 李华
网站建设 2026/10/21 0:55:51

多Agent集群实战:构建24小时自主运转的调度、执行与监督系统

1. 从单兵作战到集群协作:我为什么要折腾多 Agent 系统最开始接触 Agent 这个概念的时候,我和大多数人一样,停留在"写个提示词,让模型帮我干一件事"的阶段。比如让它帮我总结一篇文章、生成一段代码、翻译一份文档。这种…

作者头像 李华
网站建设 2026/10/21 0:52:48

ChaosToolbox:轻量级混沌工程框架实战指南

简介:本资源是陆振波老师开发的「混沌工具箱」MATLAB实现包,面向混沌理论初学者、高校理工科师生及科研人员,提供李雅普诺夫指数计算、经典混沌系统建模与混沌序列生成等核心分析能力,有效降低混沌动力学实验门槛。压缩包共136个文…

作者头像 李华
网站建设 2026/10/21 0:49:56

AI逆向工程火了:31.2K Star开源项目用大模型读懂反编译代码

“GitHub 31.2K Star!AI开始搞逆向工程了?这个开源项目火了”如果说前两年AI写代码、AI做漏洞挖掘已经不算新闻,那最近这个飙到31.2K Star的开源项目,算是把AI正式推进了逆向工程这个“老派手艺活”的深水区。我一开始看到这个标题…

作者头像 李华