
深度学习这个领域我前前后后啃了将近两年笔记攒了几百页回头翻看时发现最值钱的不是那些抄来的公式而是自己踩坑之后补上的批注。这篇深度学习学习笔记就是从我的实际学习经历里整理出来的覆盖学习路径、核心概念、代码实操和训练调参适合正在入门或学了一半卡住的人。不吹不黑我尽量讲人话把当初让我困惑的东西拆开揉碎讲清楚。1. 学习路径怎么搭先学什么后学什么1.1 先建立直觉再啃公式很多人学深度学习一上来就抱着大部头啃矩阵求导、概率图模型结果没到两周就放弃了。我的经验和大多数人相反先跑通一个最简单的例子建立神经网络到底在干什么的直觉再回头补数学效率会高很多。打个比方学开车不需要你先学完发动机构造再摸方向盘而是先学会踩油门、打方向盘在开的过程中再逐步弄明白原理。深度学习也一样你完全可以在不理解反向传播所有数学推导的情况下先调用框架训练一个模型看它如何从乱猜到准确预测。这个从乱猜到准确的过程会让你对整个领域产生极其直观的认知。我推荐的顺序是Python基础列表、字典、函数、类→ 简单的线性回归/逻辑回归 → 用框架实现一个三层神经网络 → 手推一遍反向传播 → 再回头补线性代数和概率论。手推反向传播确实痛苦但这一步跳过的话后面调参遇到问题你根本没有排查方向。1.2 从线性模型到神经网络的过渡很多初学者困惑线性回归我都懂了但神经网络和它到底什么关系其实神经网络就是一堆线性变换堆叠起来中间插入非线性激活函数。线性模型的问题在于无论你怎么组合输出永远是输入的线性组合拟合不了曲线。而加入激活函数之后每一层都在对输入做非线性变换网络的表达能力就有了本质提升。这是神经网络最核心的跨越。我当时为了验证这一点写了一个只含一个隐藏层的网络分别用线性激活和ReLU激活去拟合一个二次函数曲线。结果非常直观线性激活的函数无论怎么训练都拟合不了弯曲的曲线ReLU版本很快就把曲线形状学出来了。这个实验花不了10分钟但对理解为什么需要激活函数帮助巨大。2. 核心概念拆解这些词到底在说什么2.1 损失函数——模型学习的方向盘损失函数是深度学习里最容易被低估的概念。很多初学者把它当成一个可有可无的评分标准实际上它直接决定了模型学习的方向。我在学习时把损失函数理解成方向盘模型训练就是一个不断调整方向盘让汽车从起点开向目标的过程。损失函数告诉你现在偏离目标有多远梯度则告诉你往哪个方向打方向能缩小这个偏离。常用的损失函数各有适配场景。回归问题常用均方误差MSE它对大误差的惩罚较重所以如果数据里有离群点模型会被带偏分类问题常用交叉熵它配合Softmax输出层能有效放大梯度让模型更快学习。我踩过的坑是分类问题用了MSE结果模型训练速度极慢准确率卡在低位。原因在于MSE配合Sigmoid输出层在分类场景下梯度容易饱和几乎学不动。选择损失函数前先问自己三个问题我的任务是回归还是分类输出层应该用哪种激活函数数据的噪声水平如何想清楚这三个问题损失函数基本不会选错。2.2 反向传播——误差怎么传回去反向传播是深度学习新手最畏惧的概念但它的核心思想其实一句话就能概括利用链式法则计算损失函数对每个参数的梯度然后用梯度下降法更新参数。我第一次手推反向传播时用的是一个非常简单的网络输入层2个节点隐藏层2个节点输出层1个节点。每一步计算我都写出来然后用数值梯度对参数做微小扰动看损失变化去验证我的推导结果。这是非常重要的自查方法——如果你手推的梯度和数值梯度对不上说明推导过程中某一步出了问题。我当时发现最容易被忽略的是局部梯度的概念。节点的输出对输入的梯度与路径上游传回来的梯度相乘才是该节点参数的完整梯度。很多人把矩阵形状搞混就是因为在写反向传播时没有盯住每个张量的维度变化。我的经验是每一步都标注好张量形状比如 (batch, feature) 经过某个权重矩阵 (in, out) 变成 (batch, out)再反向时确认梯度形状能对上。2.3 优化器与学习率——步子大了容易扯着蛋优化器是训练过程中最需要手动干预的部分。SGD、动量、Adam、AdamW名字很多但本质都是梯度下降的变体区别在于怎么更新方向和步长。我一开始无脑用Adam因为大家都说它收敛快、不用调学习率。实际用下来确实方便但最后精度往往比精细调过的SGD或AdamW要差一些。后来我理解了原因Adam会对每个参数自适应调整学习率这在前期能快速下降但在后期接近最优点时容易震荡难以收敛到更优解。学习率的设置我的经验是先用一个较大的值比如 0.01 或 0.001跑几十个step观察损失曲线。如果损失震荡特别剧烈就降低学习率如果下降非常缓慢就调高。更稳妥的方式是配合学习率调度器比如余弦退火、StepLR在训练过程中逐步降低学习率让模型在最后阶段缓慢收敛。表格对比一下我常用的三个优化器在实际使用中的感受优化器优点缺点适用场景SGD带动量泛化性好收敛结果稳定对学习率敏感前期收敛慢数据量较大、已有成熟训练pipelineAdam参数自适应上手快后期可能在最优点附近震荡快速原型验证、新模型初次尝试AdamWAdam的改进版权重衰减更规范需要额外设置权重衰减系数主流Transformer类模型、图像分类3. 实操笔记一个图像分类项目从零开始3.1 数据准备与预处理理论知识说再多不如跑一个完整的项目。我选择一个经典的图像分类数据集做例子手写数字识别MNIST。虽然这个数据集已经有点老掉牙了但用来理解整个pipeline依然是最佳选择因为数据干净、类别均衡、训练速度快。数据预处理这一步我一开始犯过严重错误直接用原始像素值0到255喂给模型。结果是训练非常慢损失下降得极其艰难。后来才意识到把像素值缩放到 0 到 1 之间除以255可以让梯度计算更稳定、收敛更快。另一个常见操作是标准化减均值、除标准差对于图像数据来说一般做归一化即可。还要留出验证集。很多新手把全部数据都用来训练结果模型在训练集上表现很好一到新数据上就垮。我当时按照 8:1:1 的比例划分训练集、验证集、测试集。验证集用来模拟测试环境观察模型是否过拟合、决定什么时候早停测试集只允许在最终评估时用一次避免对测试集反复调参造成信息泄漏。3.2 模型搭建与参数量计算对于 MNIST 这个任务一个简单的卷积神经网络就足够。我用的结构是卷积层8个3x3卷积核→ ReLU → 池化 → 卷积层16个3x3卷积核→ ReLU → 池化 → 展平 → 全连接层 → 输出层10类。参数量如何计算这是很多面试也会问的问题。以第一个卷积层为例输入是单通道灰度图卷积核大小 3x3输出8个通道那么权重参数量是输入通道数1 × 卷积核大小3×3 × 输出通道数8 72再加上8个偏置共80个参数。第二个卷积层输入8通道、输出16通道参数量为 8 × 3×3 × 16 16 1168。全连接层的参数量更直观上一层展平后的维度乘以本层节点数再加偏置。我特意算了整个模型的参数量发现不到1万。这告诉我们一个道理解决简单任务根本不需要动辄上亿参数的大模型。很多人上来就套用超大规模的网络训练慢、还容易过拟合。模型容量要和任务复杂度匹配这是深度学习实操中非常重要但常被忽视的原则。3.3 训练循环与评估指标训练循环的核心就四步前向传播、计算损失、反向传播、更新参数。用代码写出来非常简洁。我在训练时特别关注的是损失曲线的形态。我第一次训练时损失曲线一路下降到0.02左右看起来非常漂亮但我在验证集上的准确率却只有96%。后来才发现训练轮数太多模型已经开始背训练数据了这就是过拟合的典型表现。解决办法是加早停每个epoch结束后计算验证集损失如果连续几个epoch不再下降就停止训练。评估指标方面分类任务最常用的是准确率但准确率在某些场景下会骗人。比如类别严重不平衡的数据集模型把所有样本都预测为多数的类准确率依然很高。因此我在项目里额外看了每个类别的精确率、召回率以及F1分数。记住评估指标要和你关心的实际目标一致。4. 训练踩坑记录这些问题我都被坑过4.1 Loss不下降、NaN、显存爆掉Loss完全不下降我遇到的第一反应是检查学习率。如果学习率过大损失可能在震荡不降如果过小又会原地踏步。实操中我习惯先把学习率调到 0.001 左右如果几个step后损失纹丝不动再考虑是不是数据或模型结构的问题。NaN是最让人头大的问题之一。常见原因包括学习率过大导致梯度爆炸、数据里有NaN值、或者是某些层的输出除以了0。排查方法是从 loss 变 NaN 的前一个 step 开始逐个检查输入数据、网络中间输出、梯度值是否出现异常。我曾经排查过一个问题最后发现是数据标准化时某些像素标准差为0产生了除零操作。显存爆掉Out of Memory在训练图像模型时很常见。最直接的解决办法是减小 batch size或者把图片resize到更小的尺寸。还有一个操作是开启梯度累积每跑几个小batch攒够一次更新所需的梯度再统一更新参数。另外要确保模型和数据都在GPU上而不是CPU和GPU之间的反复搬运。4.2 过拟合、欠拟合、数据集划分判断模型是欠拟合还是过拟合有一个非常实用的观察方法看训练集损失和验证集损失的差距。如果两者都高说明欠拟合模型容量不够或者训练不充分如果训练损失很低但验证损失高说明过拟合模型把训练数据背下来了。解决过拟合我按优先级排序1增加数据量或做数据增强2加入 dropout 或权重衰减3降低模型容量。很多人一开始就上 dropout其实数据增强在图像任务里往往更有效。随机旋转、裁剪、翻转能让模型在同样标注数据下看到更多变化泛化能力显著提升。欠拟合则相对好办增加网络层数或每层宽度、延长训练时间、适当调大学习率。但要注意盲目加大模型容量会导致训练变慢而且更容易过拟合需要配合正则化一起调整。数据集划分的细节往往被人忽略。划分数据时要确保没有泄漏也就是训练集的信息不能流入验证集或测试集。比如做时间序列预测时不能随机打乱数据再划分而要按时间顺序切分否则模型会隐式地看到未来。4.3 可复现性与随机种子训练深度学习模型涉及大量随机性数据加载顺序、权重初始化、dropout 等。如果你不固定随机种子同样的代码每次跑出来的结果都会不一样。可复现性在调参和科研场景中非常重要。我在代码开头通常会统一设置随机种子Python的random、numpy.random、以及深度学习框架的随机数生成器三者都要设置。同时也需要把 cuDNN 的确定性开关打开确保GPU计算时也尽量可复现。不过要注意开启确定性后训练速度可能略微下降这是一个权衡。我还养成了一个习惯每次跑完实验把模型配置、随机种子、数据版本、关键指标记录到实验日志里。这样过了几天再回来看还能完全复现当时的结果。这个习惯在后期写总结、换方向调试时帮了我大忙。5. 笔记方法论怎样整理学习笔记才不白记5.1 笔记结构概念卡、公式卡、代码卡学习笔记如果只是抄课件、抄文档那整理的收益很低。我把自己的笔记分成三类概念卡、公式卡、代码卡。概念卡记录核心术语的直觉解释和类比比如损失函数就是方向盘一句话就让我在需要时快速回忆起来。公式卡会写关键推导但并不追求每一步都展开而是在推导的关键跳点处补充注释解释这一步为什么能这么变形。代码卡则是一个个可以运行的最小示例每段代码都配了注释解释每一行在做什么、为什么这样写。这三类卡片用标签互相连接。比如反向传播这个概念卡链接到链式法则的公式卡又链接到手推反向传播的代码卡。这样每次复习都是走一遍知识网络而不是单一的知识点。5.2 复盘节奏什么时候复习、怎么迭代遗忘曲线告诉我们新学的知识如果不复习几天后就忘掉大半。我的复习节奏是学完当天快速过一遍笔记第3天做一个小练习第7天把笔记里的代码重新不看答案敲一遍第30天尝试在没有参考的情况下复述整个知识框架。最关键的复盘动作是重写代码。看代码和写代码是完全不同的两件事前者让你觉得我懂了后者才会暴露你真正卡住的地方。我每次重写时都会发现一些细节不理解——比如某个维度的transpose为什么是这样的、某个损失函数为什么接收这个形状的输入。这些疑问恰恰是深化理解的机会。笔记的迭代也很重要。不要害怕在旧笔记上划掉、涂改。我经常在一周之后发现之前写的某个类比其实不够准确就会在旁边补充修订。好的学习笔记应该是活的你每一次翻看都能发现之前没有注意到的细节然后补上新的理解。最后再分享一个小技巧每学完一个模块尝试用大白话向朋友解释一遍。如果你解释的过程中卡壳了那个卡壳的地方就是你理解最薄弱的地方马上回笔记里补好。这也是我整理这份深度学习学习笔记最深的一个体会——真正的学会是能用简单的语言把复杂的东西讲清楚。