Day03|深度学习基础(1):从神经元到反向传播的数学直觉
苦猿的大模型日记 · Day03 · 从神经元到反向传播的数学直觉-帮普通人把AI学进简历系列
前言:把神经元想象成一个"小委员"
先做个思维实验。
把一个神经元想象成你公司里一个小委员。
每天他要做一道二选一的决策——批准 or 驳回一份提案。
提案送进来,带着一堆"特征":预算、紧急度、风险评分、老板脸色……
每一项都是一票,但票的权重不一样:
- "老板脸色"是老员工,说话重,权重 0.8
- "紧急度"是实习生,说话轻,权重 0.2
- "预算"中等,权重 0.5
委员把所有票加权求和,再叠一个个人偏好(偏置 b)。
总分过阈值?点火!批准! 没过?按住,驳回。
这就是一个神经元——神经网络里最小的决策单元。
但一提到"神经网络",大部分人的第一反应是:黑盒、高深、看不懂。更别提反向传播那串 ∂L/∂w 的偏导公式,劝退率 90%。
但我想告诉你一个反常识的事实:神经网络根本不是黑盒。剥到最底层,它就是初中数学——加权求和、激活函数、链式法则。
这一篇,我把"深度学习"四个字拆到你能讲给小学生听。不堆公式,只讲直觉。读完你能:
- 一句话讲清神经元在干啥
- 知道为啥激活函数不能省
- 看懂前向传播就是一连串矩阵乘
- 明白反向传播就是链式法则的工业化
- 知道 Adam 优化器为啥是默认
- 搞懂 Dropout、BatchNorm、LayerNorm 在干啥
我们开始。
PART 01:神经元——一个最小的决策单元
先给上面那位"小委员"起个学名:MP 神经元(McCulloch-Pitts,1943 年提出,比深度学习这个词早了 70 年)。
它的数学公式长这样:
y = f(w · x + b)
拆开看四个角色:
- x 是输入向量(那堆特征)
- w 是权重向量(每张票的权重)
- b 是偏置(委员的个人偏好)
- f 是激活函数(点火规则)
用一个具体数字算一遍,你就懂了。
委员要决策"今天要不要跑 AI 模型",三个输入:
- x1 = GPU 利用率(0~1)
- x2 = 紧急程度(0~1)
- x3 = 老板催没催(0 或 1)
权重 w = [0.5, 0.3, 0.8],偏置 b = -0.4。
来一组真实数据 x = [0.2, 0.9, 1](GPU 闲、事急、老板催)。
加权求和:
z = 0.5×0.2 + 0.3×0.9 + 0.8×1 + (-0.4)
= 0.1 + 0.27 + 0.8 - 0.4
= 0.77
激活函数 f 暂时设为"z > 0 就点火"。
0.77 > 0,点火!结论:跑模型。
这就是一个神经元做的事。一句话:加权求和 + 一个判定。
一个神经元能做的事有限。但当你把成千上万个这样的小委员叠成网络——奇迹就出现了。

但在叠网络之前,有个关键问题:那个激活函数 f,凭啥不能直接用 z 本身?
PART 02:激活函数——为啥不能线性到底
最直觉的想法:激活函数省了好不好?直接把 z 输出,多简单?
不行。这是新手最容易踩的坑。
原因一句话:线性叠线性,叠完还是线性。
假设有一个 3 层网络,每层都是 y = w·x + b,没有激活函数:
第1层: y1 = w1·x + b1
第2层: y2 = w2·y1 + b2
= w2·(w1·x + b1) + b2
= (w2·w1)·x + (w2·b1 + b2)
第3层: y3 = ... 还是 x 的线性组合
三层叠完,等价于一层。叠多少层都没用,网络能学的东西和一层没区别。
激活函数的存在,就是把线性掰成非线性,让网络能学"弯弯绕"的复杂模式。
三大主流激活函数:
Sigmoid:把任意数压到 (0, 1)
σ(x) = 1 / (1 + e^(-x))
输入越大越接近 1,越小越接近 0。早期神经网络主力,现在主要用在二分类输出层(预测概率)。
缺点:两端梯度几乎为 0(饱和),深网络反向传播传不动——这就是著名的"梯度消失"。
Tanh:把任意数压到 (-1, 1)
形状和 Sigmoid 像,但有正有负,收敛比 Sigmoid 快。早期 RNN 常用。
ReLU:最简单粗暴,但赢了
ReLU(x) = max(0, x)
负数全部砍成 0,正数原样输出。一个 max 操作,几乎不耗算力。
为啥 ReLU 赢了?
- 算得快:一个 max,比 Sigmoid 的 exp 快几十倍
- 不饱和:正数区域梯度恒为 1,深网络不会梯度消失
- 稀疏:负数全变 0,网络天然稀疏,自带正则化效果
现代深度学习,隐藏层 90% 用 ReLU,Transformer 里会用它的升级版 GELU。
一句话:隐藏层默认 ReLU,二分类输出层用 Sigmoid。

PART 03:前向传播——一层一层往上传
把单个神经元讲清楚了,现在把它们串起来。
最经典的结构——两层 MLP(多层感知机):
输入层(784 维) → 隐藏层(128 个神经元) → 输出层(10 维)
这是 MNIST 手写数字识别的标准结构:输入是 28×28=784 个像素,输出是 0~9 十个数字的得分。
前向传播(Forward)就是:输入信号一层一层往前传,直到输出预测。
关键操作就是——矩阵乘法。
一个神经元要做 w·x + b。128 个神经元呢? 就是 128 套权重,堆起来变成一个矩阵 W。
隐藏层输出 = W1 · x + b1
形状对一下:
- x 是 [784]
- W1 是 [128, 784](128 个神经元,每个 784 个权重)
- b1 是 [128]
- 输出是 [128]
一句话:矩阵乘 = 一层神经元并行算。这就是 GPU 加速的甜点——矩阵乘 GPU 最在行。
PyTorch 代码长这样:
import torch
import torch.nn as nn
x = torch.randn(1, 784) # 输入:1 张图,784 个像素
W1 = nn.Linear(784, 128) # 第一层:784 → 128
h = torch.relu(W1(x)) # 矩阵乘 + 激活
W2 = nn.Linear(128, 10) # 第二层:128 → 10
y = W2(h) # 矩阵乘
print(y.shape) # torch.Size([1, 10]) ← 10 个数字的得分
这就是前向传播的全部。一堆矩阵乘法串起来,中间夹几个激活函数。
输出 y 就是模型的"预测"——10 个数字里得分最高的那个,就是模型认为这张图是几。

但问题来了:这个预测一开始是错的。随机初始化的 W1、W2,准确率 10%(瞎猜)。
怎么让它变对?这就是反向传播的事。
PART 04:反向传播——链式法则的工业化
反向传播(backpropagation)是整个深度学习的灵魂。它解决一个问题:
网络预测错了,怎么调权重才能让它下次别错?
分三步。
第一步:算"错多少"——损失函数
预测 [0.1, 0.7, 0.05, ...] vs 真实标签 [0, 1, 0, ...](这张图是数字 1)。
差距多大?用一个数表示。最常用交叉熵,简化版:
L = -log(预测[正确类别])
预测越准,L 越小。L = 0 就是完美。
第二步:算"该往哪调"——梯度
我现在的 loss 是 0.8,我想知道每个权重 w 对这个 0.8 贡献了多少。贡献大的多调,贡献小的少调。
这就是导数——loss 对每个 w 的偏导数 ∂L/∂w。
但 w 在网络最前面,loss 在最后面,中间隔了一堆层。怎么算?链式法则。
举个例子:三层网络 y = f3(f2(f1(x))),要算 ∂L/∂w1,链式法则告诉你:
∂L/∂w1 = ∂L/∂y · ∂y/∂f2 · ∂f2/∂f1 · ∂f1/∂w1
一连串导数相乘,从输出层一路传到输入层。这就是"反向传播"——前向往前传信号,反向往回传梯度。
PyTorch 的 autograd 就是把这玩意儿自动化:loss.backward() 一行搞定。
第三步:更新权重——梯度下降
拿到梯度了,怎么调?往梯度的反方向走一小步:
w = w - lr · ∂L/∂w
lr 是学习率(learning rate),通常 0.001 ~ 0.01。
为啥反方向?梯度指向 loss 增大的方向,你想要 loss 减小,自然反向走。
这三步合起来,就是训练一个 batch 的完整流程:
pred = model(x) # 1. 前向传播
loss = loss_fn(pred, y) # 2. 算 loss
optimizer.zero_grad() # 3. 清空旧梯度(必加)
loss.backward() # 4. 反向传播算新梯度
optimizer.step() # 5. 优化器更新权重
注意第 5 步写的是 optimizer.step(),不是手动 w -= lr * grad。为什么?因为现实中没人用裸的梯度下降——大家用的都是"优化器"。

PART 05:优化器——从 SGD 到 Adam,谁才是默认
裸梯度下降(也叫 SGD)有个致命问题:它在山谷里疯狂震荡。
想象 loss 是一个二维地形,你想走到最低点。如果地形是个狭长的山谷:
- 横向陡,梯度大 → 步子大
- 纵向缓,梯度小 → 步子小
结果就是你在山谷两侧来回横跳,纵向却走得慢。这就是 SGD 的震荡问题。
怎么解决?三代优化器迭代:
第一代:SGD + Momentum(加惯性)
v = 0.9 · v + ∂L/∂w # 累积历史梯度
w = w - lr · v # 用累积梯度更新
直觉:给优化器一个"惯性",让它冲过震荡方向,持续往纵向走。就像滚下山的石头,有惯性就不会被小沟卡住。
第二代:RMSProp(自适应学习率)
每个参数单独有自己的学习率
梯度大的参数 → 学习率自动调小
梯度小的参数 → 学习率自动调大
直觉:不同参数用不同步长,狭长山谷里横向步子自动变小,纵向步子自动变大。震荡消失。
第三代:Adam = Momentum + RMSProp
Adam 同时用了两个机制:
- 动量(Momentum):看历史梯度的累积方向
- 自适应(RMSProp):每个参数自己调学习率
一句话:Adam 是当前深度学习的默认选项。LLM、CV、推荐系统,90% 的任务直接上 Adam。
为啥 Adam 这么强?
- 默认超参就能跑(lr=1e-3, β1=0.9, β2=0.999),新手友好
- 收敛快,对学习率不敏感
- 自适应,不用手动给不同层调不同 lr
PyTorch 里用 Adam 就一行:
from torch import optim
optimizer = optim.Adam(model.parameters(), lr=1e-3)
新手建议:永远从 Adam + lr=1e-3 开始。不收敛再换 SGD,别反过来。

PART 06:正则化与归一化——让训练别"飘"
到这里你已经能训出一个网络了。但真训起来,你会遇到两个新问题:
- 训练集上神勇,测试集上一塌糊涂 → 过拟合
- 训练 loss 直接 NaN,模型炸了 → 数值不稳定
这两类问题,深度学习准备了两个标准解法:正则化和归一化。
正则化:治过拟合
过拟合的本质是网络死记硬背训练数据,没学到通用规律。两个主流解法:
Dropout(随机失活)
每次前向传播,随机让一部分神经元"罢工"——输出强制变 0。
nn.Dropout(p=0.5) # 每次训练时 50% 神经元随机失活
直觉:网络不敢依赖任何单个神经元(因为它可能被随机关掉),被迫让所有神经元都学会做事。就像公司不能让一个核心员工独占知识,否则他请假就崩盘——Dropout 强制"知识分散"。
注意:Dropout 只在训练时生效,推理时全部神经元都开。model.train() / model.eval() 切换。

L2 正则(权重衰减)
在 loss 里加一项,惩罚权重过大:
L_total = L_original + λ · Σw²
直觉:让权重保持小一点,网络就不会过度拟合训练集里的噪声。PyTorch 里一句话启用:optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)。
归一化:治数值不稳
深层网络训练时,每一层的输入分布会随着前面层的权重变化而变化——这叫 Internal Covariate Shift。后果是:梯度爆炸或消失,训练直接崩。
两个主流解法:
BatchNorm(批归一化) —— CV 经典
把每个 batch 的数据强制拉回均值 0、方差 1。
nn.BatchNorm1d(128) # 全连接层用
nn.BatchNorm2d(64) # 卷积层用
直觉:每一层都对到达的数据做一次"标准化",让数值始终落在温和的区间,梯度就能稳定传。
BatchNorm 有个坑:batch 太小(比如 1 或 2)效果会很差,因为统计量不准。这就是为啥推理时要切 model.eval()——切换成用训练时累计的全局统计量,而不是当前 batch 的。
LayerNorm(层归一化) —— NLP / Transformer 标配
不看 batch 维,对单个样本自己的特征维做归一化。
nn.LayerNorm(768) # Transformer 每个 token 都过一遍
直觉:BatchNorm 是"横向归一化"(看 batch 内不同样本),LayerNorm 是"纵向归一化"(看一个样本自己的特征)。
为啥 NLP/LLM 都用 LayerNorm 不用 BatchNorm?
- NLP 里序列长度不一,batch 内对不同样本做统计会乱
- 推理时 batch_size 经常是 1,BatchNorm 直接失效
- LayerNorm 不依赖 batch,推理时和训练时行为一致
所以你看 Transformer、BERT、GPT、Llama 全都用 LayerNorm。这是从 CV 跨到 NLP 时最容易踩的"反直觉"点。

一句话记住:CV 用 BatchNorm,NLP 用 LayerNorm。
结尾:把"训练"两个字完整拆开
回头看,深度学习的全部数学,其实就是这几样东西:
- 神经元 = 加权求和 + 激活
- 激活函数 = 把线性掰成非线性,ReLU 是默认
- 前向传播 = 矩阵乘法一层层串起来
- 反向传播 = 链式法则算每个权重的梯度
- 优化器 = Adam 默认,带惯性 + 自适应学习率
- 正则化 = Dropout 防过拟合,L2 控权重
- 归一化 = CV 用 BatchNorm,NLP/LLM 用 LayerNorm
完整训练循环:
model.train() # 切训练模式(启用 Dropout/BatchNorm)
for x, y in dataloader:
pred = model(x) # 1. 前向
loss = loss_fn(pred, y) # 2. 算 loss
optimizer.zero_grad() # 3. 清梯度
loss.backward() # 4. 反向传播
optimizer.step() # 5. 优化器更新
就这 5 行,反复跑几万次,网络就学会了。
没有黑盒,没有玄学。
很多人卡在"深度学习"这四个字上,是因为被那一串偏导公式吓到了。但你拆开看,它就是中学数学的链式法则,加了个"反向遍历"的工业化流程,再配几个让训练别"飘"的小技巧。
下一篇 Day04,我们用 PyTorch 把这套理论落地——从 0 手写一个真实能跑的训练循环,在 MNIST 上训练一个能认数字的网络。
到那时候,你回头看这篇文章,会发现"深度学习"这四个字,其实就 5 行代码。
最后送你一句话:
所有"深度学习"的玄学,拆开都是中学数学。区别只在于——你有没有把它拆开看过。
互动时间:看完这篇,你觉得最难懂的是哪一块?是反向传播的链式法则,还是 Adam 优化器的自适应学习率,还是 BatchNorm 和 LayerNorm 怎么选?评论区告诉我,下一篇我挑高频问题专门补图补例子讲透。
下一篇预告:Day04 | 深度学习基础(2):用 PyTorch 从 0 训练 MNIST 数字识别
关注「苦猿」,和我一起从 0 走到大模型。
— END —
苦猿 · 帮普通人把 AI 学进简历
更多推荐
所有评论(0)