NYU-DLSP20 第五周全解析:从梯度下降、动量到自适应优化、归一化层与 PyTorch 卷积/自动微分实战

📅 发布时间:2026/10/10 18:09:29
NYU-DLSP20 第五周全解析:从梯度下降、动量到自适应优化、归一化层与 PyTorch 卷积/自动微分实战
示例工程【免费下载链接】NYU-DLSP20NYU Deep Learning Spring 2020项目地址https://gitcode.com/gh_mirrors/pyt/pytorch-Deep-Learning点击查看免费下载本周课程是 NYU-DLSP20NYU Deep Learning Spring 2020对应本仓库优化与卷积主题的核心章节横跨三大部分Lecture A讲解梯度下降GD、随机梯度下降SGD与动量Momentum三类基础优化技术Lecture B讲解 RMSprop、ADAM 等自适应方法、归一化层Normalization Layers以及深度学习加速 MRI 重建的工业级案例Practicum则回到动手环节手推 1D 卷积、用 PyTorch 验证 kernel 与输出维度、理解自动微分引擎并编写自定义梯度模块。读完本文你将掌握优化器的数学原理、调参经验、归一化层的选型依据并能用 PyTorch 独立复现卷积尺寸计算与autograd自定义梯度。一、Lecture A从梯度下降到带动量的 SGD1.1 梯度下降Gradient Descent最基础也最差的方法我们研究优化方法通常从最基础也最朴素的方法开始——梯度下降。其目标是最小化一个连续可微函数问题$$ \min_w f(w) $$迭代解法$$ w_{k1} w_k - \gamma_k \nabla f(w_k) $$其中各符号含义为$w_{k1}$第 $k$ 次迭代后更新得到的值$w_k$第 $k$ 次迭代前的初始值$\gamma_k$步长step size即学习率$\nabla f(w_k)$函数 $f$ 在 $w_k$ 处的梯度。这里的基本假设是函数 $f$ 连续且可微。我们的目标是找到优化函数的谷底但通往谷底的真实方向未知只能做局部观察——因此负梯度方向是我们掌握的最好信息。沿该方向迈出一小步就能更接近最小值走完一步后重新计算梯度再沿新方向移动如此反复直至抵达谷底。本质上梯度下降就是在沿着**最陡下降方向负梯度方向**前进。$\gamma$ 被称为步长学习率。通常我们并不知道最优步长的取值因此必须尝试不同数值标准做法是在对数尺度log-scale上试一批值再选用效果最好的一个。以 1D 二次函数为例存在几种典型场景见下图学习率过低向最小值稳步前进但耗时远超理想情况学习率略高于最优实际上收敛最快是最理想的选择学习率过大迭代点离最小值越来越远导致发散。实践中我们通常希望学习率比发散阈值略小一点。图片出处本仓库 docs/images/week05/05-1/step-size.png对应英文原笔记 docs/en/week05/05-1.md。1.2 随机梯度下降SGD无偏、带噪、更便宜在随机梯度下降中我们用梯度的随机估计替代真实梯度向量。对神经网络而言随机估计即单个数据点单个样本损失的梯度。设 $f_i$ 为网络在第 $i$ 个样本上的损失$$ f_i l(x_i, y_i, w) $$我们希望最小化的是所有样本的总损失 $f$$$ f \frac{1}{n}\sum_i^n f_i $$SGD 按 $f_i$ 的梯度而非总损失 $f$ 的梯度更新权重$$ \begin{aligned} w_{k1} w_k - \gamma_k \nabla f_i(w_k) \quad\text{i 均匀随机选取} \end{aligned} $$若 $i$ 随机选取则 $f_i$ 是 $f$ 的一个带噪声但无偏的估计数学上写作$$ \mathbb{E}[\nabla f_i(w_k)] \nabla f(w_k) $$因此 SGD 第 $k$ 步的期望与全批量梯度下降第 $k$ 步相同$$ \mathbb{E}[w_{k1}] w_k - \gamma_k \mathbb{E}[\nabla f_i(w_k)] w_k - \gamma_k \nabla f(w_k) $$也就是说任何一次 SGD 更新在期望意义下都等价于全批量更新。但 SGD 并不仅仅是更快的带噪梯度下降——它还能带来更好的结果SGD 的噪声可以帮助我们跳过较浅的局部最小值找到更深的、更优的最小值。这一现象称为退火annealing。总结 SGD 的优势各样本之间存在大量冗余信息SGD 避免了大量冗余计算训练初期噪声相对梯度中的信息量很小因此一步 SGD几乎与一步 GD 同样有效退火效应——SGD 更新中的噪声可以避免收敛到糟糕浅层的局部最小值SGD 的计算成本大幅降低无需遍历所有数据点。1.3 Mini-batching小批量Mini-batching 不是在单个样本上计算损失而是在多个随机选取的样本上计算损失从而降低每一步更新的噪声$$ w_{k1} w_k - \gamma_k \frac{1}{|B_i|} \sum_{j \in B_i}\nabla f_j(w_k) $$使用 mini-batch 而非单样本往往能更充分地利用硬件例如单样本训练时 GPU 利用率很差。分布式训练技术会把一个大的 mini-batch 拆分到集群的各台机器上再聚合各自算出的梯度英文原笔记中提到 Facebook 曾用分布式训练在一小时内完成 ImageNet 上的网络训练此为课程讲述的行业案例非本仓库实测数据。一个重要的实操提醒梯度下降不应配合全量大小的 batch 使用。如果确实想在全量 batch 上训练应使用 LBFGS 这类优化技术——PyTorch 与 SciPy 都提供了 LBFGS 的实现。1.4 动量Momentum两种更新规则动量方法维护两个迭代量$p$ 和 $w$而不是只维护一个$$ \begin{aligned} p_{k1} \hat{\beta_k}p_k \nabla f_i(w_k) \ w_{k1} w_k - \gamma_kp_{k1} \ \end{aligned} $$其中 $p$ 被称为SGD 动量。每一步更新时先把旧动量按因子 $\beta$取值在 0 到 1 之间衰减再加上当前随机梯度因此 $p$ 可以理解为梯度的运行平均running average。最后让 $w$ 沿新动量 $p$ 的方向移动。等价形式随机重球法Stochastic Heavy Ball Method$$ \begin{aligned} w_{k1} w_k - \gamma_k\nabla f_i(w_k) \beta_k(w_k - w_{k-1}) 0 \leq \beta 1 \end{aligned} $$该形式与上一形式数学等价下一步 上一步的方向$w_k - w_{k-1}$与新的负梯度的组合。直觉物理中的动量SGD 动量与物理学中的动量概念类似优化过程就像一颗重球滚下坡动量让球保持原有的运动方向而梯度可以看作把球推向其他方向的力。与剧烈改变行进方向相比动量只做温和的修正能有效抑制纯 SGD 中常见的来回震荡。$\beta$ 参数被称为阻尼因子Dampening Factor$\beta$ 必须大于 0——若等于 0就退化为普通梯度下降$\beta$ 必须小于 1——否则一切都会爆炸$\beta$ 越小转向越快$\beta$ 越大转向越慢。实践指南动量几乎总是应与 SGD 配合使用$\beta 0.9$ 或 $0.99$ 几乎总是表现良好增大动量参数时通常需要减小步长以维持收敛当 $\beta$ 从 0.9 变为 0.99 时学习率大约需要缩小 10 倍。为什么动量有效1加速AccelerationNesterov 动量的更新规则如下$$ p_{k1} \hat{\beta_k}p_k \nabla f_i(w_k) \ w_{k1} w_k - \gamma_k(\nabla f_i(w_k) \hat{\beta_k}p_{k1}) $$只要常数选取得当Nesterov 动量可以获得加速收敛。但这只适用于凸问题不适用于神经网络。很多人声称普通动量也是加速方法但事实上它只对二次函数加速而且加速与噪声不兼容SGD 本身带噪因此加速并不能很好解释 Momentum SGD 的高性能。2噪声平滑Noise Smoothing更实际、更可能的解释是噪声平滑动量对梯度取平均每次步进使用的是梯度的运行平均。理论上 SGD 要正常工作应当对所有步进取平均$$ \bar w_k \frac{1}{K} \sum_{k1}^K w_k $$SGD 加动量的好处在于不再需要这种显式平均动量给优化过程引入了平滑使每一步更新都成为对解的良好近似。纯 SGD 则往往需要平均一大批更新之后才朝该方向迈步。加速与噪声平滑共同贡献了动量的高性能。从 docs/images/week05/05-1/sgd-vs-momentum.png 可以看出纯 SGD 初期朝解的方向进展良好但到达谷底碗底后会在底部来回弹跳调整学习率只是让弹跳变慢而加上动量后步长被平滑几乎不再弹跳。二、Lecture B自适应优化、归一化层与优化的终结2.1 为什么需要自适应方法Adaptive Methods带动量的 SGD 目前仍是许多机器学习问题的先进优化方法但还有一类自适应方法对**病态条件poorly conditioned**的问题尤其有用即 SGD 失效的场景。在 SGD 公式中网络中每一个权重都用同一个全局学习率 $\gamma$ 更新。自适应方法则为每个权重单独适配学习率依据是每个权重各自的梯度信息。实际使用的网络在不同部分结构差异很大例如 CNN 早期可能是在大图上做很浅的卷积后期则是在小图上做大量通道的卷积两者性质迥异适合网络前期的学习率未必适合后期——这说明按层自适应的学习率是有价值的。网络后部的权重例如 VGG16 中 4096 维的全连接层见 docs/images/week05/05-2/5_2_vgg.png直接决定输出对输出影响极强需要更小的学习率而前期权重尤其随机初始化时对输出的个体影响更小。2.2 RMSprop用梯度均方根做归一化Root Mean Square Propagation均方根传播的核心思想是用梯度的均方根对梯度做归一化。下式中梯度平方表示对向量每个元素分别平方$$ \begin{aligned} v_{t1} {\alpha}v_t (1 - \alpha) \nabla f_i(w_t)^2 \ w_{t1} w_t - \gamma \frac {\nabla f_i(w_t)}{ \sqrt{v_{t1}} \epsilon} \end{aligned} $$其中$\gamma$ 是全局学习率$\epsilon$ 是接近机器精度 $\epsilon$ 的小量量级为 $10^{-7}$ 或 $10^{-8}$用于避免除零错误$v_{t1}$ 是二阶矩second moment估计。我们用指数移动平均exponential moving average更新 $v$ 来估计这个带噪量——这是维护可能随时间变化之量的平均的标准方式新值携带更多信息应给予更大权重于是用常数 $\alpha$0 到 1 之间对旧值逐级指数降权直到旧值不再重要。原始 RMSprop 维护的是非中心二阶矩的指数移动平均因此这里不减均值二阶矩被用来逐元素归一化梯度即每个梯度元素除以二阶矩估计的平方根。当梯度期望值很小时这个过程近似于用标准差去除梯度。分母使用很小的 $\epsilon$ 并不会导致发散因为当 $v$ 很小时动量梯度本身也很小。2.3 ADAMRMSprop 动量ADAMAdaptive Moment Estimation自适应矩估计可以理解为 RMSprop 加上动量是目前更常用的方法。动量更新被改造成指数移动平均且处理 $\beta$ 时无需改变学习率与 RMSprop 一样这里也对梯度平方取指数移动平均$$ \begin{aligned} m_{t1} {\beta}m_t (1 - \beta) \nabla f_i(w_t) \ v_{t1} {\alpha}v_t (1 - \alpha) \nabla f_i(w_t)^2 \ w_{t1} w_t - \gamma \frac {m_{t}}{ \sqrt{v_{t1}} \epsilon} \end{aligned} $$其中 $m_{t1}$ 是动量的指数移动平均。上式中省略了偏差修正bias correction——该修正用于在早期迭代中保持移动平均无偏。实践对比训练神经网络时SGD 在训练初期常常朝错误方向走而 RMSprop 能较快瞄准正确方向但 RMSprop 与普通 SGD 一样受噪声困扰接近局部最小值后会在最优点附近显著弹跳。就像给 SGD 加动量一样ADAM 带来了同样的改进它是解的一个良好、无噪的估计因此通常推荐使用 ADAM 而非 RMSprop对比图见 docs/images/week05/05-2/5_2_comparison.png。ADAM 对训练某些语言模型网络是必需的优化神经网络时一般优先选择带动量的 SGD 或 ADAM。但 ADAM 的论文理论尚不完善且存在若干缺点可以在非常简单的测试问题上证明该方法不收敛已知会带来泛化误差网络在训练数据上损失为零未必能在未见数据上保持零损失尤其在图像问题上其泛化误差往往比 SGD 更差可能因素包括找到的是最近的局部最小值、ADAM 噪声更小、或其自身结构等ADAM 需要维护3 个缓冲区而 SGD 只需 2 个。除非模型大到数 GB 量级、可能放不进内存否则这影响不大需要调2 个动量参数而不是 1 个。2.4 归一化层Normalization Layers与前文改进优化算法不同归一化层改进的是网络结构本身它们作为额外层插入已有层之间目标是提升优化与泛化性能。神经网络通常在线性运算与非线性运算激活函数如 ReLU之间交替归一化层可以放在线性层之前或激活函数之后最常见的做法是放在线性层与激活函数之间在 CNN 中典型形态为卷积 → 批量归一化 → ReLU见图 docs/images/week05/05-2/5_2_norm_layer_c.png。需要注意归一化层改变流经网络的数据但并不改变网络的表达能力——只要权重配置得当未归一化的网络仍可产生与归一化网络相同的输出。归一化的通用记号$$ y \frac{a}{\sigma}(x - \mu) b $$其中$x$ 为输入向量$y$ 为输出向量$\mu$ 为 $x$ 均值的估计$\sigma$ 为 $x$ 标准差std的估计$a$ 为可学习的缩放因子$b$ 为可学习的偏置项。如果没有可学习参数 $a$ 和 $b$输出向量 $y$ 的分布将固定为均值 0、标准差 1。$a$ 与 $b$ 的作用是保持网络的表示能力——输出值仍可落在任意特定范围。注意 $a$、$b$ 并不会抵消归一化因为它们是可学习参数比 $\mu$、$\sigma$ 稳定得多。四种归一化方式对于包含 $N$ 张高 $H$ 宽 $W$、共 $C$ 个通道的 mini-batch 图像示意图见 docs/images/week05/05-2/5_2_norm_operations.png按选取的归一化样本范围不同有 4 种典型做法方法归一化范围适用场景Batch Norm批量归一化只对输入的一个通道做归一化首个被提出、最广为人知的方法视觉任务效果好Layer Norm层归一化单张图像内跨全部通道语言任务中大量使用Instance Norm实例归一化单张图像、单个通道语言/风格类任务中大量使用Group Norm分组归一化单张图像、跨部分通道如 0~9 一组、10~19 一组视觉任务效果好且与 SGD 不冲突关于 Group Norm 的补充实践中分组大小几乎总是32这也是课程讲师 Aaron Defazio 推荐的做法——实际性能好且不与 SGD 冲突。为什么归一化有帮助虽然归一化在实践中效果很好但其有效的原因仍有争议。最初它被提出用于减小内部协变量偏移internal covariate shift但已有学者通过实验证伪了这一解释。可以确认的是归一化带来了以下多种因素的综合效果优化效果带归一化层的网络更易优化允许使用更大的学习率从而加速训练正则化效果由于批次内样本随机均值/标准差估计带有噪声这种额外噪声在某些情况下带来更好的泛化降低对权重初始化的敏感性。因此归一化让你可以更随意几乎可以把任意网络构件组合在一起而无需过多担心网络病态程度仍有机会成功训练。实践注意事项与 PyTorch 用法反向传播必须经过均值/标准差的计算以及归一化的应用否则网络训练会发散。这一反向传播计算相当繁琐且易错而 PyTorch 能自动完成非常省力。PyTorch 中对应的两个归一化层类torch.nn.BatchNorm2d(num_features, ...) torch.nn.GroupNorm(num_groups, num_channels, ...)Batch Norm 是最早提出、最广为人知的方法但Aaron Defazio 推荐改用 Group Norm它更稳定、理论上更简单通常效果更好分组大小 32 是不错的默认值。另外注意Batch Norm 与 Instance Norm 在训练结束后使用固定的均值/标准差不再每次评估时重算因为归一化需要多个训练样本而 Group Norm 与 Layer Norm 只需单个训练样本即可归一化因此无此问题。2.5 优化的终结深度学习加速 MRI 重建有时外行闯入一个陌生领域反而能改善现状深度学习用于 MRI 图像重建加速便是典型例子。传统 MRI 重建传统 MRI 重建中原始数据来自 MRI 机器用简单管线/算法重建图像。MRI 机器在二维傅里叶域逐行或逐列每几毫秒一次采集数据原始输入由频率与相位两个通道组成数值代表特定频率和相位的正弦波幅度——可简单理解为一张含实部、虚部通道的复值图像。对其做逆傅里叶变换把这些正弦波按数值加权求和即可得到原始解剖图像见 docs/images/week05/05-2/5_2_mri.png。目前从傅里叶域到图像域存在一个非常高效的线性映射无论图像多大都只需毫秒级完成。问题在于能不能更快加速 MRIAccelerated MRI加速的关键思路迄今最成功是不全采所有列可以随机跳过部分列但实践中最好保留中间列它们横跨整幅图像、信息量大外围则随机采样。问题随之而来——此时线性映射不再适用对下采样后的傅里叶空间直接做线性映射得到的结果毫无用处见 docs/images/week05/05-2/5_2_acc_mri.png显然需要更聪明的做法。压缩感知Compressed Sensing压缩感知是理论数学的重大突破之一Candes 等人的论文证明从下采样的傅里叶域图像出发在理论上可以获得完美重建——当目标信号稀疏或具有稀疏结构时用更少的测量即可完美重建。但实际应用有若干前提不需要随机采样而需要非相干采样incoherent sampling——不过实践中人们通常就是随机采样采一列或半列耗时相同因此实践中整列采样图像需要具备稀疏性大量零值/黑色像素。原始输入经波长分解后可稀疏表示但只是近似稀疏而非严格稀疏所以压缩感知能得到相当好但不完美的重建见 docs/images/week05/05-2/5_2_comp_sensing.png若输入在波长域非常稀疏则能获得完美图像。压缩感知基于优化理论其重建方式是求解一个带额外正则项的小型优化问题$$ \hat{x} \arg\min_x \frac{1}{2} \Vert M (\mathcal{F}(x)) - y \Vert^2 \lambda TV(x) $$其中 $M$ 是掩码函数把未采样位置置零$\mathcal{F}$ 是傅里叶变换$y$ 是观测到的傅里叶域数据$\lambda$ 是正则化惩罚强度$V$ 是正则化函数。这个优化问题必须对 MRI 扫描的每个时间步/每个切片求解一次耗时常常超过扫描本身——这让我们有理由寻找更好的方案。谁还需要优化——用深度网络一步求解与其每个时间步都解一个小优化问题不如用一个大型神经网络直接产出所需解。希望在于训练一个足够复杂的网络让它一步基本解决优化问题输出质量堪比逐时间步求解优化问题的结果$$ \hat{x} B(y) $$其中 $B$ 是深度学习模型$y$ 是观测到的傅里叶域数据。15 年前这条路很难走如今实现起来容易得多结果对比见 docs/images/week05/05-2/5_2_dl_approach.png。课程指出用于生成该重建的模型采用ADAM 优化器 Group Norm 归一化层 基于 U-Net 的卷积神经网络这一方案已非常接近实际应用。三、Practicum手推卷积、PyTorch 尺寸验证与自动微分3.1 理解 1D 卷积堆叠与平移 kernel这一部分探讨卷积是因为我们希望利用数据的稀疏性sparsity、平稳性stationarity与组合性compositionality。与上一周使用的矩阵 $A$见 上一周笔记不同这里把矩阵宽度改为 kernel 大小 $k$于是矩阵的每一行就是一个 kernel。通过堆叠stacking与平移shiftingkernel见 docs/images/week05/05-3/Illustration_1D_Conv.png可以得到 $m$ 层高度为 $n-k1$ 的输出即 $m$厚度个大小为 $n-k1$ 的向量见 docs/images/week05/05-3/Result_1D_Conv.png。单个输入向量可以看作单声道monophonic信号见 docs/images/week05/05-3/Monophonic_Signal.png。此时输入 $x$ 是一个映射$$ x:\Omega\rightarrow\mathbb{R}^{c} $$其中 $\Omega \lbrace 1, 2, 3, \cdots \rbrace \subset \mathbb{N}^1$因为这是 1 维信号/拥有 1 维定义域此时通道数 $c1$当 $c2$ 时即为立体声stereophonic信号。对 1D 卷积只需逐 kernel 计算标量积见 docs/images/week05/05-3/Layer_by_layer_scalar_product.png。3.2 PyTorch 中 kernel 与输出宽度的维度验证技巧在 IPython 中可以使用问号查看函数文档例如输入nn.Conv1d?得到签名Init signature: nn.Conv1d( in_channels, # 输入图像中的通道数 out_channels, # 卷积产生的通道数 kernel_size, # 卷积核的大小 stride1, # 卷积的步幅 padding0, # 在输入两侧添加的零填充 dilation1, # 卷积核元素之间的间距 groups1, # 从输入到输出的阻塞连接数 biasTrue, # 若为 True则为输出添加可学习的偏置 padding_modezeros, # 填充模式接受 zeros 与 circular )1D 卷积示例假设做 1 维卷积从 2 个通道立体声信号到 16 个通道16 个 kernelkernel 大小为 3、stride 为 1。于是共有 16 个厚度 2、长度 3 的 kernel。设输入信号 batch 大小为 1一个信号、2 个通道、64 个采样点。输出层为 1 个信号、16 个通道信号长度 $62 64-31$。每个输出通道一个偏置因此 bias 大小为 16。conv nn.Conv1d(2, 16, 3) # 2 通道立体声16 个大小为 3 的 kernel conv.weight.size() # 输出: torch.Size([16, 2, 3]) conv.bias.size() # 输出: torch.Size([16]) x torch.rand(1, 2, 64) # batch 为 12 通道64 个采样点 conv(x).size() # 输出: torch.Size([1, 16, 62]) conv nn.Conv1d(2, 16, 5) # 2 通道16 个大小为 5 的 kernel conv(x).size() # 输出: torch.Size([1, 16, 60])2D 卷积示例输入为 1 个样本、20 个通道例如高光谱图像高 64、宽 128。2D 卷积输入 20 通道、16 个大小为 $3\times5$ 的 kernel。卷积后输出为 1 个样本、16 个通道高 $6264-31$宽 $124128-51$。执行 2D 卷积所需存储的 kernel 张量是4 维的。x torch.rand(1, 20, 64, 128) # 1 个样本20 通道高 64宽 128 conv nn.Conv2d(20, 16, (3, 5)) # 20 通道16 个 kernelkernel 大小为 3 x 5 conv.weight.size() # 输出: torch.Size([16, 20, 3, 5]) conv(x).size() # 输出: torch.Size([1, 16, 62, 124])若想保持输入输出维度一致可以加 padding。延续上面代码设置stride1、padding(1, 2)即在 $y$ 方向填充 1顶部、底部各 1在 $x$ 方向填充 2。此时输出与输入尺寸相同# 20 通道16 个大小为 3 x 5 的 kernelstride 为 1padding 为 (1, 2) conv nn.Conv2d(20, 16, (3, 5), 1, (1, 2)) conv(x).size() # 输出: torch.Size([1, 16, 64, 128])3.3 自动梯度Autograd是如何工作的本节让 torch 追踪张量上的所有计算从而计算偏导数创建带梯度累积能力的 $2\times2$ 张量 $\boldsymbol{x}$对 $\boldsymbol{x}$ 的所有元素减 2 得到 $\boldsymbol{y}$。打印y.grad_fn会得到SubBackward0 object ...说明 $y$ 由减法模块$\boldsymbol{x}-2$生成也可用y.grad_fn.next_functions[0][0].variable反推原始张量继续运算$\boldsymbol{z} 3\boldsymbol{y}^2$计算 $\boldsymbol{z}$ 的均值。反向传播用于计算梯度。在本例中反向传播过程可看作计算 $\frac{d\boldsymbol{a}}{d\boldsymbol{x}}$。手工验证 $\frac{d\boldsymbol{a}}{d\boldsymbol{x}}$ 后可以发现执行a.backward()得到的x.grad与我们手算结果一致。手算过程如下$$ \begin{aligned} a \frac{1}{4} (z_1 z_2 z_3 z_4) \ z_i 3y_i^2 3(x_i-2)^2 \ \frac{da}{dx_i} \frac{1}{4}\times3\times2(x_i-2) \frac{3}{2}x_i-3 \ x \begin{pmatrix} 12\34\end{pmatrix} \ \left(\frac{da}{dx_i}\right)^\top \begin{pmatrix} 1.5-33-3\[2mm]4.5-36-3\end{pmatrix}\begin{pmatrix} -1.50\[2mm]1.53\end{pmatrix} \end{aligned} $$在 PyTorch 中使用偏导时得到的梯度与原始数据形状相同但从严格的 Jacobian 角度看正确形式应是转置。从基础到更疯狂循环中的梯度设 $x$ 为 $1\times3$ 向量令 $y$ 为 $x$ 的两倍并不断把 $y$ 翻倍直到其范数小于 1000。由于 $x$ 是随机的无法直接预知循环终止的迭代次数x torch.randn(3, requires_gradTrue) y x * 2 i 0 while y.data.norm() 1000: y y * 2 i 1但借助梯度可以轻易推断gradients torch.FloatTensor([0.1, 1.0, 0.0001]) y.backward(gradients) print(x.grad) tensor([1.0240e02, 1.0240e03, 1.0240e-01]) print(i) 9requires_grad 与 no_grad 的边界用requires_gradTrue标记希望追踪梯度累积。若在 $x$ 或 $w$ 的声明中省略requires_gradTrue再对 $z$ 调用backward()将因缺少梯度累积而报运行时错误# x 与 w 都允许梯度累积 x torch.arange(1., n 1, requires_gradTrue) w torch.ones(n, requires_gradTrue) z w x z.backward() print(x.grad, w.grad, sep\n)反向地可用with torch.no_grad()关闭梯度累积x torch.arange(1., n 1) w torch.ones(n, requires_gradTrue) # 其中的所有 torch 张量都不会累积梯度 with torch.no_grad(): z w x try: z.backward() # PyTorch 会在此抛错因为 z 没有梯度累积 except RuntimeError as e: print(RuntimeError!!! :[) print(e)3.4 自定义梯度Custom Gradients除了基础数值运算我们还可以生成自定义模块/函数并将其插入神经网络计算图。配套 Jupyter Notebook 位于仓库 extra/b-custom_grads.ipynb。做法是继承torch.autograd.Function并重写forward()与backward()。例如训练网络时需要前向传播、并知道输入对输出的偏导数才能把该模块用在代码的任何位置只要掌握了输入对输出的偏导数就可以通过反向传播链式法则把它插入运算链的任意位置。Notebook 中有三个自定义模块示例add、split与max。例如自定义加法模块# 自定义加法模块 class MyAdd(torch.autograd.Function): staticmethod def forward(ctx, x1, x2): # ctx 是一个上下文可以在其中保存 # backward 所需的中间计算。 ctx.save_for_backward(x1, x2) return x1 x2 staticmethod def backward(ctx, grad_output): x1, x2 ctx.saved_tensors grad_x1 grad_output * torch.ones_like(x1) grad_x2 grad_output * torch.ones_like(x2) # 需要按 forward 输入顺序返回梯度不含 ctx return grad_x1, grad_x2两个输入相加得到输出前向按上式重写反向传播时梯度会复制到两侧所以 backward 用复制实现。对于split若多个分支来自同一张量反向传播时应当把这些梯度相加/求和对于argmax它选出最大值的索引因此最大值索引处梯度为 1、其余为 0。需要牢记不同自定义模块要各自重写自己的 forward 与 backward 梯度逻辑。四、在仓库中继续深入配套代码与资源本仓库为 NYU-DLSP20 课程的配套开源实现围绕第五周主题提供了大量可直接运行的资源优化器可视化实验extra/utils/optim.py 定义了一个继承torch.optim.Optimizer的Optim基类其中step()遍历param_groups并在每个参数上调用my_step()子类只需实现my_step即可定制更新规则。文件底部还包含一个病态二次目标 $f(x,y)\frac{1}{2}xy^\top A xy b^\top xy$$A\mathrm{diag}(1,5)$条件数高达 5的等高线图绘制函数output(opt, nsteps, noise, fname)可用于直观对比不同优化器在病态问题上的收敛轨迹并支持通过noise参数模拟随机梯度噪声详见extra/optimization.ipynb。优化实验 Notebookextra/optimization.ipynb 基于上述工具演示 GD/SGD/Momentum 等的收敛行为。自定义梯度 Notebookextra/b-custom_grads.ipynb 完整实现add、split、max等自定义 autograd 模块对应上文 3.4 节。英文原版笔记docs/en/week05/05-1.mdOptimisation Techniques I、docs/en/week05/05-2.mdOptimisation Techniques II、docs/en/week05/05-3.mdConvolutions 与自动微分中文读者可对照阅读 docs/pt/week05/05-1.md、docs/pt/week05/05-2.md、docs/pt/week05/05-3.md。本讲幻灯slides/01 - Spiral classification.pdf、slides/04 - RNN.pdf 之外仓库根目录的 04-spiral_classification.ipynb、05-regression.ipynb、06-convnet.ipynb、07-listening_to_kernels.ipynb 等 Notebook 均会实际用到本章的优化器与卷积知识。小结第五周的内容构成了深度学习优化与卷积原理的完整闭环GD → SGD → Momentum → RMSprop/ADAM的进化脉络清晰呈现了如何让更新更稳、更快、更自适应归一化层从结构上改善优化与泛化加速 MRI案例则展示了用深度网络一步替代逐时间步优化的工程范式最后的1D/2D 卷积手推与 PyTorch 尺寸验证、autograd 与自定义梯度把理论落到可复现的代码上。若要在实际项目中应用可遵循课程给出的经验法则默认使用带动量 SGD$\beta0.9/0.99$或 ADAM归一化层优先考虑 Group Norm分组 32卷积输出尺寸按 $n-k1$加 padding 后相应调整快速心算校验。赞分享示例工程【免费下载链接】NYU-DLSP20NYU Deep Learning Spring 2020项目地址https://gitcode.com/gh_mirrors/pyt/pytorch-Deep-Learning点击查看免费下载相关推荐5 分钟让普通鼠标在 macOS 上比触控板好用Mac Mouse Fix 上手指南5 分钟让普通鼠标在 macOS 上比触控板好用Mac Mouse Fix 上手指南 第一次按下侧键、光标毫无反应的那一刻我就知道这只十几块的鼠标在 mac示例工程NYU-DLSP20 第五周精读梯度下降、Momentum 与自适应优化、归一化层以及卷积与自动微分实战NYU DLSP20 第五周精读梯度下降、Momentum 与自适应优化、归一化层以及卷积与自动微分实战 本文基于开源课程仓库 pytorch Deep L示例工程NYU-DLSP20 第 5 周深度笔记梯度下降、SGD 与动量、自适应优化、归一化层与 PyTorch 卷积/自动微分NYU DLSP20 第 5 周深度笔记梯度下降、SGD 与动量、自适应优化、归一化层与 PyTorch 卷积/自动微分 本文是 NYU Deep Learn示例工程上一篇Bokeh 自定义 TickFormatter 实战为坐标轴实现“偏移量刻度”显示下一篇RSS-Bridge 主机部署指南坚持不用私有 API的设计哲学与实例配置实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考