第11讲 梯度下降到底在做什么很多人第一次学到“梯度下降”时都会有一种很强的不安。名字听起来很数学公式看起来也很复杂梯度求导学习率参数更新这些词单独看都不陌生但连在一起时初学者最容易陷入一种状态公式会抄过程会背但并不知道它到底在做什么。更具体一点很多困惑都集中在下面几个问题上梯度到底是对谁求的为什么要对它求导输入 (x) 也在公式里为什么不去改输入模型训练时到底什么在变什么不变如果这些问题没有想清楚那后面即使继续学反向传播、神经网络训练也很容易一直停留在“会写不会懂”的层面。所以这一讲我们不急着上来就堆公式而是先把最核心的一件事讲清楚梯度下降本质上是在根据损失函数的变化趋势去调整模型参数让模型犯的错越来越小。而训练之所以要这样做是因为机器一开始并不会分类它是通过大量样本不断调整内部参数慢慢把判断规则学出来的 。一、梯度下降到底在解决什么问题前面我们已经知道机器学习不是一个抽象的“让机器变聪明”的过程而是在学习一种从输入到输出的映射关系。对于分类模型来说过程通常是这样的输入数据进入模型模型给出预测结果预测结果和真实答案之间会有差距我们需要根据这个差距去调整模型参数其中模型一开始并不会分类它只是带着一组初始参数去做计算之所以后来能识别数字是因为它在大量样本中不断试错、不断修正最后学会了一套更好的分类规则 。于是问题就来了既然已经知道模型当前错了多少那参数到底该怎么改这正是梯度下降要解决的问题。换句话说梯度下降真正关心的不是“模型会不会分类”而是怎样调整参数才能让损失函数变小二、先把最关键的一点讲清楚我们到底在对谁求导这是初学者最容易卡住的地方。假设我们现在有一个训练样本输入(x)标签(y)模型根据当前参数做出预测[\hat{y} f(x; w, b)]然后我们用损失函数来衡量预测和真实答案之间的差距[L L(y, \hat{y}) L(y, f(x; w,b))]看到这里很多人会疑惑损失函数里面明明有 (x)、(y)、(w)、(b)那我们到底在对谁求导答案一定要非常明确我们是在对参数求导。也就是[\frac{\partial L}{\partial w}, \quad \frac{\partial L}{\partial b}]而不是去求输入怎么变标签怎么变因为训练模型时当前这一步里输入 (x) 是给定的数据视为常量标签 (y) 是标准答案视为常量真正需要学习、需要调整的是参数 (w,b)所以从训练的角度看当前真正的未知数不是输入而是参数。这一点必须想清楚因为后面所有“求梯度”“更新参数”的操作都是建立在这个前提上的我们关心的是参数稍微变一点损失会怎么变。三、为什么输入看成常量参数看成变量因为训练的目标不是改数据而是改模型。机器学习的基本框架里数据提供输入标签提供标准答案任务定义了我们到底要学什么。这些东西一旦确定在当前训练步骤里就已经是已知的了。比如一张手写数字图片它的像素值就是当前输入它对应的标签“这是数字 3”也是已知答案。训练时我们不会做的事情是把这张图片偷偷改一改把标签临时换一个让数据去适应模型我们真正做的是反过来让模型的参数去适应数据。而前面也已经讲过分类模型的判断能力本质上就是由参数塑造出来的学习这件事说到底就是在调参数 。所以在求导时(x, y) 看成常量(w, b) 看成变量这是训练过程最自然、也是最核心的视角。四、为什么我们优化的是损失函数这也是很容易被忽略的一点。很多人会说“训练模型不就是为了提高准确率吗为什么不直接优化准确率”因为训练时我们需要一个可以计算、可以比较、可以优化的目标而损失函数正是为此存在的 。损失函数的作用不是简单判断“对”还是“错”而是把预测结果和真实答案之间的差距变成一个可以优化的数值 。这意味着什么意味着预测错了损失通常会比较大预测对了也不代表损失一定很小同样都是预测对0.51 和 0.99 的把握程度不一样损失也可能不一样所以训练不是只关心“最后类别对没对”而是关心当前预测离真实答案到底还有多远。这就是为什么梯度下降优化的对象不是“准确率”本身而是损失函数 。五、梯度到底是什么把前面的铺垫都放好以后现在就可以谈“梯度”了。如果先只考虑一个参数 (w)那么梯度你可以先理解成损失函数对参数 (w) 的导数。写成公式就是[\frac{dL}{dw}]它表示的是如果参数 (w) 变动一点点损失 (L) 会怎样变化。注意这里的主语一定是“损失函数”。也就是说梯度不是一个脱离上下文的抽象概念它在训练里说的其实是损失函数关于参数的变化趋势。比如梯度是正的说明参数往增大的方向走时损失倾向于变大梯度是负的说明参数往增大的方向走时损失倾向于变小梯度接近 0说明当前位置可能已经比较平缓了所以梯度并不是“模型理解了答案”它只是告诉我们在当前位置参数往哪边改更可能让损失下降。六、为什么叫“梯度下降”这个名字其实非常形象。你可以把损失函数想象成一片地形地势高的地方表示损失大说明模型错得多地势低的地方表示损失小说明模型错得少而模型当前的参数位置就相当于你站在这片地形中的某个点。现在我们的目标很简单从高处往低处走。那该怎么走最自然的办法是先看当前位置朝哪个方向上升最快然后不要顺着这个方向走而是朝着相反方向走一步这就是“梯度下降”的含义梯度告诉你上升最快的方向下降我们偏偏朝相反方向走让损失变小所以它本质上并不神秘只是一个非常朴素的优化思路根据当前位置的局部变化趋势沿着让损失减小的方向去更新参数。七、梯度下降的更新公式到底在说什么最经典的参数更新公式是[w \leftarrow w - \eta \frac{\partial L}{\partial w}]如果模型里还有偏置 (b)那它也会更新[b \leftarrow b - \eta \frac{\partial L}{\partial b}]这个公式第一次看很吓人但拆开以后其实只有三层意思。1(\frac{\partial L}{\partial w}) 是什么它表示的是损失函数对参数 (w) 的导数。也就是如果 (w) 发生一点变化损失会怎样变化。这一项一定不能含糊。因为训练时我们不是在对模型随便求导而是在对损失函数关于参数求导。2(\eta) 是什么(\eta) 是学习率。它决定每次更新时参数走多大一步。你可以把它理解成方向由梯度决定步子大小由学习率决定3为什么前面是减号因为梯度指向的是“损失上升更快”的方向。但训练目标是让损失下降所以我们要朝相反方向走。因此更新公式里的核心逻辑就是参数的新值 参数的旧值 - 学习率 × 损失对参数的梯度八、先用一个最简单的损失函数理解“对损失求导”到底是什么意思一上来就讲神经网络很容易把问题搞复杂。所以我们先看一个最简单的例子[L(w) w^2]这里故意把它写成 (L(w))就是为了强调现在我们正在优化的就是一个损失函数。问题很直接怎样调整参数 (w)让损失 (L(w)) 变小第一步先对损失函数求导[\frac{dL}{dw} 2w]这个导数告诉我们当 (w 0) 时梯度是正的当 (w 0) 时梯度是负的当 (w 0) 时梯度是 0第二步按梯度下降公式更新假设学习率 (\eta 0.2)那么更新公式就是[w \leftarrow w - 0.2 \cdot 2w]如果一开始[w 4]那么当前损失是 (L(4)16)当前梯度是 (\frac{dL}{dw}8)更新后[w \leftarrow 4 - 0.2 \times 8 2.4]再来一步当前损失变成 (L(2.4)5.76)当前梯度变成 (4.8)于是继续更新[w \leftarrow 2.4 - 0.2 \times 4.8 1.44]你会发现(w) 在逐渐接近 0损失也在不断下降。这个例子虽然简单但它已经完整说明了梯度下降的本质先对损失函数关于参数求导再根据这个导数去调整参数。九、把“输入是常量参数是变量”放进模型里看一遍上面的例子太简单了没有输入数据。现在我们看一个更接近机器学习训练的形式。假设模型非常简单[\hat{y} wx b]然后定义损失函数[L (y - \hat{y})^2 (y - (wxb))^2]注意这个式子里一共有四类量(x)输入(y)真实标签(w)权重(b)偏置在当前这一步训练时(x) 是给定样本视为常量(y) 是标准答案视为常量(w,b) 是模型参数视为变量所以我们真正关心的是[\frac{\partial L}{\partial w}, \quad \frac{\partial L}{\partial b}]而不是去改 (x) 或 (y)。这一点一旦想通后面哪怕模型从线性模型变成神经网络本质也没有变。只不过函数形式更复杂了但核心仍然是研究损失函数随着参数变化会怎样变化。十、用代码看一遍梯度下降到底做了什么下面用一个最小可运行例子把刚才的过程写成代码。这里还是用最简单的损失函数[L(w)w^2]对应代码如下w4.0lr0.2defloss(w):returnw**2defgrad(w):return2*wforstepinrange(10):current_lossloss(w)current_gradgrad(w)print(fstep{step}, w{w:.6f}, loss{current_loss:.6f}, grad{current_grad:.6f})ww-lr*current_grad输出step0,w4.000000,loss16.000000,grad8.000000step1,w2.400000,loss5.760000,grad4.800000step2,w1.440000,loss2.073600,grad2.880000step3,w0.864000,loss0.746496,grad1.728000step4,w0.518400,loss0.268739,grad1.036800step5,w0.311040,loss0.096746,grad0.622080step6,w0.186624,loss0.034829,grad0.373248step7,w0.111974,loss0.012538,grad0.223949step8,w0.067185,loss0.004514,grad0.134369step9,w0.040311,loss0.001625,grad0.080622...这段代码特别适合初学者因为它把整个过程压缩成了三件事计算当前损失计算损失函数对参数的梯度根据梯度下降公式更新参数而且你能非常清楚地看到我们求的是损失对参数的导数不是别的量。十一、放回机器学习里梯度下降到底在更新什么现在把视角重新放回真正的模型训练。训练过程通常可以理解成这样一条线输入数据 x → 模型根据当前参数做计算 → 得到预测结果 → 损失函数衡量预测与真实答案的差距 → 对损失函数关于参数求导 → 更新参数这里面损失函数的作用非常关键它把“模型到底错了多少”变成了一个可以计算、可以优化的数值 。如果没有这一步参数更新就没有依据训练过程也无从谈起 。而前面也讲过机器并不是突然“懂了”图片而是在大量数据中不断调整内部参数慢慢学会了更好的分类规则 。所以梯度下降真正更新的就是模型内部这些参数权重偏置而不是输入样本本身。从这个角度看训练的本质其实很朴素模型先犯错损失函数衡量它错了多少再通过梯度下降把参数往更合适的方向推。十二、为什么梯度下降不是“模型突然知道答案了”这是一个很常见的误解。很多人看到“求梯度、更新参数”容易产生一种感觉好像模型一算导数就突然开窍了。其实不是。梯度并不代表模型“理解了问题”它只是提供了一个非常局部的信息在当前参数位置上往哪个方向改更可能让损失下降。所以梯度下降本质上不是“顿悟”而是一个反复试错和修正的过程。这和前面讲机器为什么能识别数字时的逻辑是一致的机器不是天生会分类而是在大量数据中不断调整参数慢慢把判断规则学出来的 。十三、学习率为什么也必须一起理解更新公式里除了梯度还有一个非常重要的量[\eta]它就是学习率。很多初学者只盯着“梯度”却忽略了学习率。但实际上梯度决定的是方向学习率决定的是步子大小。如果学习率太小每次改动都很保守损失虽然可能持续下降但训练速度会很慢如果学习率太大参数一步跨太远可能直接越过较优位置甚至来回震荡训练不稳定所以一个完整的理解应该是梯度告诉你该往哪边走学习率告诉你这一步走多大十四、这一讲最容易混淆的几个点1. 梯度是对输入求的不是。在这一步训练里输入和标签都是已知量通常看成常量我们真正关心的是损失函数对参数的导数。2. 损失函数只是判断对错不完全是。损失函数不是简单判断预测是否正确而是在衡量预测和真实答案之间的差距到底有多大 。3. 分类对了损失就一定很小不一定。即使最后分类结果一样不同置信程度对应的损失也可能不同 。4. 梯度下降是在更新模型结构不是。梯度下降通常更新的是模型参数而不是任务定义、输入数据或模型结构本身。5. 梯度下降就是随便调参数不是。它不是盲目乱试而是根据损失函数对参数的变化趋势有方向地更新参数。十五、总结现在回到最开始的问题梯度下降到底在做什么如果把这一讲压缩成一句话那么最核心的答案就是梯度下降是在对损失函数关于模型参数求导。训练时把输入和标签看成已知常量把参数看成待学习的变量然后根据导数给出的变化趋势沿着让损失减小的方向一步步更新参数。再说得更直白一点就是数据先进入模型模型给出预测结果损失函数衡量预测和真实答案之间差了多少我们关心“损失对参数的导数”然后按照让损失变小的方向更新参数参数不断被修正后模型的判断能力也就慢慢形成了所以梯度下降并不神秘。它做的事情其实非常朴素看当前哪里错了再朝着“错得更少”的方向改一点。