4. 深度学习基础:感知机与神经网络、激活函数、损失函数与梯度下降、反向传播算法
说实话,很多做自动驾驶的朋友一上来就啃Transformer、BEV感知这些高大上的东西,结果调参调到怀疑人生。我个人的经验是,先把深度学习最底层的这几块砖头码结实了,后面盖楼才稳当。今天咱们就从最朴素的感知机开始,一步步把神经网络、激活函数、损失函数、梯度下降和反向传播这五兄弟捋清楚。
4.1 感知机:神经网络的老祖宗
感知机(Perceptron)是1957年由Frank Rosenblatt提出的。说白了,它就是模仿人脑神经元工作的一个数学模型。你想想看,一个神经元接收多个输入信号,经过加权求和,再决定是否激活输出——感知机干的就是这事。
数学上长这样:
y = f(w₁x₁ + w₂x₂ + ... + wₙxₙ + b)
其中w是权重,b是偏置,f是激活函数(早期用的是阶跃函数)。
核心要点:感知机只能解决线性可分问题。比如AND、OR这类逻辑门它能搞定,但XOR(异或)它就抓瞎了。我在做早期车道线检测时,就遇到过类似的问题——简单的线性分类器根本搞不定弯道场景。
4.2 多层感知机与神经网络
既然单层感知机搞不定非线性问题,那就堆层呗。把多个感知机叠起来,中间加一层或多层“隐藏层”,就成了多层感知机(MLP),也就是我们常说的神经网络。
一个典型的全连接神经网络结构:
- 输入层:接收原始特征,比如图像像素值、点云坐标
- 隐藏层:负责特征提取和变换,层数越多,表达能力越强
- 输出层:输出最终结果,比如分类概率、回归数值
我记得刚入行时,导师跟我说过一句话:“神经网络本质上就是一个万能函数逼近器。” 你给它足够多的神经元和层数,理论上它能拟合任何复杂的函数关系。自动驾驶中的感知、预测、规划,本质上都是在学这种映射关系。
我的经验:别一上来就搞几十层的深度网络。从2-3层开始,先验证数据流和梯度是否正常,再逐步加深。我在做端到端驾驶模型时,初期用3层MLP跑通了一个简化版的转向角预测,虽然精度不高,但整个pipeline跑通了,后面迭代起来心里就有底了。
4.3 激活函数:给网络注入非线性
如果没有激活函数,多层线性变换叠在一起,本质上还是一层线性变换。那跟单层感知机有啥区别?所以激活函数的核心作用就是——引入非线性。
常用的三种激活函数:
| 函数 | 公式 | 取值范围 | 优点 | 缺点 |
|---|---|---|---|---|
| Sigmoid | σ(x) = 1/(1+e⁻ˣ) | (0, 1) | 输出可解释为概率 | 梯度饱和、非零中心 |
| Tanh | tanh(x) = (eˣ-e⁻ˣ)/(eˣ+e⁻ˣ) | (-1, 1) | 零中心、比Sigmoid梯度更强 | 仍有梯度饱和问题 |
| ReLU | f(x) = max(0, x) | [0, +∞) | 计算快、缓解梯度消失 | 神经元死亡(Dead ReLU) |
我个人习惯在隐藏层优先用ReLU,输出层根据任务选:二分类用Sigmoid,回归用线性激活。不过要注意,ReLU有个坑——当输入为负时,梯度为0,神经元就“死”了。我曾经在训练一个深度模型时,发现loss死活降不下去,查了半天,原来是学习率设太大,导致大量ReLU神经元挂了。换成Leaky ReLU后问题就解决了。
避坑指南:我曾经在自动驾驶的感知模型里,输出层用了Sigmoid做回归,结果模型预测值始终在0-1之间,而实际车速是0-120km/h。嗯,这个错误让我白调了一周参数。回归任务千万别用Sigmoid或Tanh做输出激活!
4.4 损失函数:衡量模型好坏的标准
损失函数(Loss Function)量化了模型预测值与真实值之间的差距。训练神经网络,本质上就是最小化这个损失函数。
常见损失函数:
- 均方误差(MSE):L = (ŷ - y)²,适合回归任务,比如预测车速、转向角
- 交叉熵损失(Cross-Entropy):L = -[y·log(ŷ) + (1-y)·log(1-ŷ)],适合分类任务,比如识别交通标志
- Huber损失:结合了MSE和MAE的优点,对异常值更鲁棒
在端到端自动驾驶中,我们经常需要同时优化多个目标。比如既要预测方向盘转角(回归),又要检测行人(分类)。这时候就得用多任务损失,给每个任务分配一个权重。我一般先用等权重跑一轮,观察各任务的loss量级,再手动调整权重。
4.5 梯度下降:下山的最优路径
有了损失函数,怎么找到让损失最小的参数呢?梯度下降(Gradient Descent)就是干这个的。它的思想很简单:沿着损失函数下降最快的方向(即负梯度方向)更新参数。
参数更新公式:
w_new = w_old - η · ∂L/∂w
其中η是学习率,控制每一步迈多大。
三种常见变体:
- 批量梯度下降(BGD):用全部数据计算梯度,准确但慢
- 随机梯度下降(SGD):每次用一个样本,快但不稳定
- 小批量梯度下降(Mini-batch GD):折中方案,每次用一小批样本,实践中用得最多
我的建议:学习率是梯度下降里最敏感的超参数。设太大,loss会震荡甚至发散;设太小,训练慢得像蜗牛。我一般从0.01开始试,观察loss曲线:如果震荡剧烈就减小,如果下降太慢就增大。另外,配合学习率衰减策略(如Cosine Annealing)效果更好。
4.6 反向传播算法:让梯度流起来
反向传播(Backpropagation)是训练神经网络的灵魂算法。它的核心思想是:利用链式法则,从输出层向输入层逐层计算梯度。
简单来说,分三步:
- 前向传播:输入数据经过各层计算,得到预测值
- 计算损失:比较预测值和真实值,得到损失
- 反向传播:从输出层开始,逐层计算损失对每个参数的梯度
你想想看,一个100层的网络,如果不用反向传播,直接对每个参数求偏导,计算量是天文数字。而反向传播通过复用中间结果,把复杂度从O(n²)降到了O(n)。
下面我用一个简单的计算图来展示反向传播的流程:
上图展示了一个最简单的计算图。前向传播时,数据从左往右流:输入x和权重w相乘得到z,经过激活函数得到ŷ,再与真实值y计算损失L。反向传播时,梯度从右往左流:先算∂L/∂ŷ,再通过链式法则算出∂L/∂z,最后算出∂L/∂w。这个∂L/∂w就是我们要用来更新权重的梯度。
关键理解:反向传播的核心就是链式法则的工程实现。它让梯度能够高效地从输出层“流”回输入层,每一层只需要关注自己局部的梯度计算,然后乘以上游传下来的梯度即可。这种模块化的设计,使得我们可以像搭积木一样构建任意复杂的网络。
4.7 实践中的常见问题与调试技巧
说了这么多理论,来点实战经验。我在训练端到端驾驶模型时,经常遇到这几个问题:
- 梯度消失:深层网络的前几层梯度趋近于0,导致参数几乎不更新。解决方案:用ReLU替代Sigmoid/Tanh,或者加Batch Normalization
- 梯度爆炸:梯度值过大,导致参数更新步长太大,loss直接飞上天。解决方案:梯度裁剪(Gradient Clipping),把梯度限制在[-1, 1]范围内
- 过拟合:模型在训练集上表现很好,但在验证集上一塌糊涂。解决方案:加Dropout、L2正则化、数据增强
调试小技巧:当你怀疑梯度有问题时,可以打印出每一层的梯度均值和方差。如果某一层的梯度均值接近0,那大概率是梯度消失了。我曾经在调试一个8层网络时,发现第5层之后的梯度全是0,排查后发现是激活函数选错了——在深层网络里用了Sigmoid,梯度在反向传播过程中被“吃”掉了。
好了,这一章的内容就到这里。感知机、神经网络、激活函数、损失函数、梯度下降、反向传播——这六个概念是深度学习的基石。你想想看,后面要学的CNN、RNN、Transformer,本质上都是在这些基础组件上做的扩展和优化。把这一章吃透了,后面的路就好走了。