尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

周六我把计算图画了三遍,周一反向传播还是炸出了NaN

周六我把计算图画了三遍,周一反向传播还是炸出了NaN 周六我把计算图画了三遍,周一反向传播还是炸出了NaN去年我决定从后端转 AI,第一件事就是把吴恩达的课刷了一遍。当时觉得自己「懂了机器学习」,直到开始手写反向传播--链式法则在那张歪歪扭扭的计算图上绕了三圈,梯度值直接飙成了 NaN,训练 loss 曲线像坐过山车。那七天里,我至少重启了 20 次 notebook,有两天晚上合上电脑时连张量的 .grad 都不想看见。后来我才明白,我差的不是数学,是能把机器学习的计算图、梯度流动和 debug 路径串成一条线的学习材料。AWS 的深度学习入门课就是在这个时候救了我--它把一个两层网络的计算图拆成可交互的步骤,每步梯度都标了值,我终于不用盯着公式发呆。如果你也在反向传播上反复放弃,这门课里的可视化方法可能会让你第一次感到「终于通了」。为什么反向传播让我卡了一整个周末我那个周末的计划很简单:用 numpy 实现一个两层全连接,跑通 XOR 分类。正向传播半天就写完了,到了反向传播,链式法则一展开就开始头大。我对机器学习基础里的梯度下降流程其实是半生不熟的,知道要更新权重,但 ∂Loss/∂W 怎么流过去,全靠背公式当时我在纸上画了三遍计算图,每次到 Sigmoid 导数那一步,边上的标注就开始打架更糟的是,我直接拿 CS231n 的讲义硬啃,上面全是矩阵形式,我的小批量版本一对维度就报错我当时以为,只要把导数乘起来就行,结果发现跨层梯度不但乘,还要求和,还要 broadcast--计算图上的每条线到底对应哪个乘法,我根本说不清。连续两天调试同一个 nan,我开始怀疑是不是自己不适合做机器学习。但现在回过头看,那个困境本质上是:我缺一个能逐步骤显示梯度流动的「解释性环境」,而不是更多的公式推导。动手实现,踩进梯度爆炸的泥潭为了逼自己搞懂,我硬着头皮写了一个极简的两层网络:# 正向传播(出错版,X.shape (4,2)) h X W1 b1 h_act 1 / (1 np.exp(-h)) # sigmoid y_pred h_act W2 b2 loss np.mean((y_pred - y) ** 2)反向传播我照着公式扒了一段,结果 gradient 直接炸了--W1 的梯度里出现了 np.nan,loss 在第二个 epoch 就变成 inf。# 我最初的反向传播(简化但问题版) grad_y_pred 2 * (y_pred - y) / y.shape[0] grad_W2 h_act.T grad_y_pred grad_b2 np.sum(grad_y_pred, axis0) grad_h_act grad_y_pred W2.T grad_h grad_h_act * h_act * (1 - h_act) # sigmoid derivative grad_W1 X.T grad_h grad_b1 np.sum(grad_h, axis0)我检查了维度、求和方向,甚至把每个梯度都 print 出来,发现 grad_h 的绝对值在第二层已经涨到了 60 多,再往前传一层直接溢出。这是典型的梯度爆炸,但我当时只知道「梯度消失」和「梯度爆炸」两个词,完全没有诊断的能力。一个做过深度学习的朋友提醒我:「你试试把学习率降一个数量级」--降完后 nan 消失了,但 loss 几乎不动,训练变成了死循环。这个阶段我翻遍了博客和论文,也试了 AWS 的机器学习入门资料里关于损失函数和优化器的章节,但里面主要讲的是 sklearn 级别的接口,离我手写的那个梯度地狱还有点远。我当时真正需要的,是能告诉我「每一步梯度到底应该长什么样」的东西。AWS 深度学习入门课:用可交互计算图重新学一遍连崩三天之后,我翻到了 AWS 的深度学习入门课程。它和我之前看的资料完全不同--不是从数学讲起,而是从一张张已经标好数值的计算图切入,每张图里都把前向传播的值、局部导数、回来的梯度全部列在边上。课程的第一单元就拿一个只有两个神经元的极简网络拆解反向传播:每一根乘法、加法、激活的连线,都被拆成一个独立的节点每个节点上同时显示局部梯度(∂输出/∂输入)和上游回传的梯度最关键的是,它把「链式法则就是连乘」这个抽象概念,变成了三四个箭头依次相乘的可视化流程我照着那个思路把自己先前画的三张计算图重画了一遍,并且给每条边都写上数值--这次我终于看到,我之前在 Sigmoid 那一层漏乘了一个激活函数的偏导,而那个偏导因为输入值过大已经趋近于 0,才导致梯度爆炸的对立面其实是梯度消失。深度学习入门课程里的这种数值化拆解,让我一下子明白了之前那堆 nan 的来龙去脉。# 用课程里的梯度检查方法修正后的关键部分 grad_h grad_h_act * h_act * (1 - h_act) # 手动计算一小部分梯度,与数值梯度比对 epsilon 1e-5 approx_grad (loss_fn(W1 epsilon) - loss_fn(W1 - epsilon)) / (2 * epsilon) print(fAnalytic: {grad_W1[0,0]:.6f}, Approx: {approx_grad:.6f})这个 debug 技巧也是课程里教的--每步计算后拉一个数值梯度对照,误差超过 1e-5 就说明链式法则里肯定有错。我之前不知道还能这样查,全靠肉眼一行行比对矩阵乘法。课程还花了很大篇幅讲机器学习管道中数据预处理对梯度的影响:输入值没有归一化时,Sigmoid 在饱和区梯度几乎为零,整个网络学不动。我回头检查了自己的 XOR 数据,发现特征范围还是 [0,1],虽然不严重,但组合后隐藏层输出已经落到 0.9 以上,梯度确实在衰减。这些细节,以前我没在任何一篇公众号文章里看到过,但 AWS 的深度学习入门课把每一环都串起来了。可视化让我从背公式变成真理解突破发生在我把课程里的计算图可视化方法移植到自己的 notebook 里之后。我在每个 epoch 结束后都画一张简图,把当前权重、激活值、回传梯度标上去,同时运行一个简版的梯度范数监控:# 每个 epoch 记录梯度范数 grad_norm np.sqrt(sum(np.sum(g ** 2) for g in [grad_W1, grad_b1, grad_W2, grad_b2])) print(fEpoch {epoch1:3d}, Loss: {loss:.4f}, Grad Norm: {grad_norm:.4f})以前我只盯着 loss 曲线看,loss 不动就以为是学习率的问题,现在多了「梯度范数」这个仪表盘,我能立刻判断是梯度太大还是太小。这套监控方法是深度学习入门课程里专门强调的--它把训练过程拆成「前向传激活 → 计算 loss → 反向传梯度 → 更新权重」四个步骤,每一步都给出可量化的观测点。诊断项以前我的做法学完课程后的做法梯度异常看 loss 曲线,瞎猜每层打印梯度均值和范数,对比数值梯度激活饱和不知道要看,只管调结构每层输出直方图,检查是否进入饱和区权重初始化Xavier / He 随便选根据激活函数类型选,并结合输入尺度做测试更让我惊讶的是,深度学习入门里居然还提到了「混淆矩阵」和「过拟合」的早期信号。课程后半部分在一个图像分类案例里展示了训练集准确率走高但验证集不动的情况,直接带出 dropout 和 early stopping 的引入逻辑。我这才意识到,我之前以为「机器学习就是调参」,其实是因为根本没接触过一套完整的训练-评估管线--而这门课正好把管道上的每个节点都教到了。学完后的变化:从 numpy 手写到一个能跑的项目搞定反向传播之后,我趁热把课程提供的 PyTorch 版本也跑了一遍。AWS 的深度学习课程在代码仓库里直接给了一个可对比的 PyTorch 实现,我把自己的 numpy 成果和它对照,发现除了框架自动求导那部分,其余逻辑完全对上了。那个周末我终于完成了一个小猫识别器:从 Kaggle 上扒了 800 张猫狗图片,用 ResNet-18(当然只是调参)但这次我连每个卷积层的梯度分布都看了,还加了数据增强来抑制过拟合。最后验证准确率稳在 91% 以上,虽然不算多高,但对我这种转过一次放弃的人,已经是里程碑。更实际的变化是,后来面试一家公司时,被问到「你是怎么 debug 梯度问题的」,我直接把计算图拆解 数值梯度检查 激活直方图这三板斧讲了一遍,面试官当场说这是最近面试里听到最踏实的回答。我之所以从放弃又捡回来,不是因为意志力,而是因为找到了对的学习资料。AWS深度学习课程那种「先给你看数值,再讲为什么」的方式,对我这种习惯从代码反推理论的人尤其友好。如果你也跟我一样,公式看到第三行就跑神,那可能不是你的问题,是材料的顺序没选对。给同样卡住的人几个可执行建议不要在纯数学环境里学反向传播:找一张计算图(最好带数值),先看懂梯度怎么沿图流动,再回头看链式法则公式。深度学习入门课程里的可视化模块可以直接当这种「数值版图解」用。代码里每层都要留一个「梯度仪表盘」:至少打印出每层梯度均值和范数,配合数值梯度做对照。这个习惯能省掉至少一半的盲猜时间。先从极简网络开始 debug:2 个输入、2 个隐藏、1 个输出,人工构造一个超小的回归任务,在这种规模下梯度异常一目了然。AWS机器学习入门里也强调过「从小模型开始验证逻辑」的工程原则。把数据预处理放到排查清单第一位:输入没有归一化、标签没有 one-hot、特征量纲差太大都会直接让梯度失稳。这些在机器学习基础课程的数据预处理章节都讲得很细,值得花半天时间系统过一遍。遇到 nan 或 inf 马上查三件事:学习率是否太大、激活函数是否饱和、梯度计算链里是否有除零或 log(0)。如果能同时跑一次数值梯度检查,定位速度会快得多。不要一上来就上大模型:先把手写反向传播这个坑踩实,以后无论是调 Transformer 还是理解 attention 的梯度流,你都会比直接套框架的人快一步。深度学习入门帮你打的地基,就是让你在面对更大的网络时,不会因为一个 nan 就直接崩溃。如果时间有限,至少完成课程里的那个梯度可视化实验:花两个小时把计算图上的数字跑一遍,你会发现自己对机器学习的理解会从「我觉得我懂了」变成「我能给别人讲明白了」--这两者之间的差距,就是能否真正落地项目的关键。
返回列表