深度学习基础回顾(上):神经网络核心概念、卷积神经网络(CNN)基础、激活函数与损失函数、优化器(SGD、Adam)

各位同学,欢迎来到《基于深度学习的视觉定位方法》课程。我是你们的讲师,一个在计算机视觉和SLAM领域摸爬滚打多年的工程师。

今天咱们开始第一讲,深度学习基础回顾的上半部分。别觉得基础就简单,我这些年踩过的坑,十有八九都是基础不牢导致的。咱们把地基打扎实了,后面讲视觉定位、位姿回归这些硬骨头,你才能啃得动。

核心观点:深度学习不是黑魔法,它本质上是一个巨大的函数逼近器。我们做的所有工作——设计网络、选损失函数、调优化器——都是在教这个函数逼近器,如何从图像像素映射到我们想要的空间位置或姿态。

一、神经网络核心概念:从感知机到多层网络

先聊聊最基础的东西。神经网络,说白了就是一堆“神经元”串起来的计算图。

我记得刚入行时,导师跟我说:“你把它想象成一个流水线,数据从一头进去,经过一道道工序,从另一头出来一个结果。” 这个比喻我一直用到现在。

一个神经元做的事其实很简单:

  • 接收多个输入(比如图像的像素值)
  • 每个输入乘以一个权重(重要程度)
  • 加上一个偏置(阈值)
  • 扔进一个激活函数(决定是否“兴奋”)

数学上就是:output = activation(w·x + b)

单个神经元能力有限,只能解决线性可分问题。但当我们把大量神经元堆叠成多层结构,事情就变得有趣了。

为什么需要多层? 我举个实际例子。在视觉定位里,我们要从一张图片里估计相机位姿。单层网络只能看到像素级的特征,比如“这个点亮不亮”。但多层网络就不一样了:

  • 第一层:检测边缘、角点
  • 第二层:组合成纹理、图案
  • 第三层:识别出物体部件(门、窗、桌子)
  • 更高层:理解整个场景的几何结构

这就是“层次化特征学习”。你想想看,这不就跟人眼看东西一样吗?先看轮廓,再看细节。

我的经验:在视觉定位任务中,网络深度不是越深越好。我曾经在一个室内定位项目里,把ResNet从50层加到101层,结果精度反而下降了。为什么?因为梯度消失和过拟合同时找上门了。所以,深度要跟数据量和任务复杂度匹配。

二、卷积神经网络(CNN)基础

说到视觉,就绕不开CNN。CNN为什么适合图像?因为它天生就利用了图像的“局部性”和“平移不变性”。

咱们拆开来看:

2.1 卷积层

卷积操作,说白了就是一个滑动窗口。一个小的卷积核(比如3x3)在图像上滑过,每次计算窗口内像素和卷积核权重的点积。

这样做的好处是什么?

  • 参数共享:同一个卷积核在整个图像上复用,参数量大大减少。全连接层处理224x224的图像,光第一层就要上百万参数;卷积层只需要几百个。
  • 局部连接:每个神经元只关注局部区域,符合视觉皮层的特性。

我习惯用这个公式计算输出特征图尺寸:

输出尺寸 = (输入尺寸 - 卷积核尺寸 + 2 * padding) / stride + 1

举个例子,输入是32x32,用3x3卷积核,padding=1,stride=1:

输出 = (32 - 3 + 2*1) / 1 + 1 = 32

嗯,尺寸不变,这叫“same卷积”。

2.2 池化层

池化层的作用是降采样,说白了就是“压缩”。最大池化取窗口内最大值,平均池化取平均值。

为什么要池化?

  • 减少计算量
  • 增强平移不变性——物体稍微移动一点,池化后的特征变化不大
  • 防止过拟合

注意:在视觉定位任务中,过度池化会丢失空间信息。我曾经在一个项目中用了4次2x2最大池化,结果网络完全分不清“左边”和“右边”的特征。后来我改用空洞卷积(Dilated Convolution)来保持分辨率,效果好了很多。

2.3 全连接层

全连接层通常放在网络尾部,把前面提取的特征“整合”起来,输出最终的预测结果。在视觉定位里,全连接层的输出就是6维位姿向量(3维位置 + 3维姿态)。

下面我用一张SVG图来展示CNN的典型结构:

输入 224x224x3 Conv1 3x3, 64 ReLU Pool1 2x2 max Conv2 3x3, 128 ReLU Pool2 2x2 max FC 1024 输出 6维位姿 输入层 卷积层 池化层 全连接层 输出层

三、激活函数与损失函数

3.1 激活函数

激活函数的作用是引入非线性。没有它,再多层网络也只是线性变换的堆叠,表达能力有限。

Sigmoid: 输出范围(0,1),早期常用。但有两个问题:

  • 梯度饱和——输入很大或很小时,梯度接近0,网络几乎不学习
  • 输出不是零中心的——影响梯度下降效率

Tanh: 输出范围(-1,1),零中心,但梯度饱和问题依然存在。

ReLU: 现在的主流选择。f(x) = max(0, x)。优点很明显:

  • 计算简单
  • 缓解梯度消失
  • 稀疏激活——很多神经元输出0,相当于被“关闭”了

避坑指南:ReLU有个问题叫“神经元死亡”。如果某个神经元的所有输入都是负的,它的输出永远是0,梯度也是0,这个神经元就再也学不动了。我曾经在一个深层网络里遇到这个问题,后来改用Leaky ReLU(给负数部分一个很小的斜率,比如0.01),问题就解决了。

3.2 损失函数

损失函数衡量的是“预测值”和“真实值”之间的差距。我们训练网络,本质上就是在最小化这个损失。

在视觉定位任务中,最常用的是:

损失函数 公式 适用场景
均方误差 (MSE) L = (y_pred - y_true)² 位置回归(x, y, z)
平均绝对误差 (MAE) L = |y_pred - y_true| 对异常值更鲁棒
Huber损失 MSE当误差小,MAE当误差大 兼顾两者优点,我常用这个
交叉熵损失 L = -Σ y_true * log(y_pred) 分类任务(如场景识别)

我个人的习惯是:对于位姿回归,位置用MSE,姿态用Huber损失。为什么?因为姿态的角度误差有时会出现离群值,Huber损失对离群值不那么敏感。

四、优化器:SGD与Adam

有了损失函数,接下来就是怎么优化它。优化器就是干这个的。

4.1 SGD(随机梯度下降)

SGD是最基础的优化器。每次迭代,用当前batch的梯度更新参数:

θ = θ - lr * ∇L(θ)

其中lr是学习率,∇L是梯度。

SGD的问题:

  • 学习率难调——太大不收敛,太小收敛慢
  • 容易陷入局部最优或鞍点
  • 对不同参数用相同学习率,不合理

我刚开始做深度学习时,调SGD的学习率调得想砸电脑。后来发现加上动量(Momentum)会好很多:

v = β * v + (1-β) * ∇L
θ = θ - lr * v

动量相当于给梯度更新加了“惯性”,能加速收敛,也能帮助跳出局部最优。

4.2 Adam

Adam是目前最流行的优化器。它结合了动量和自适应学习率的思想。

核心思路:

  • 对每个参数维护一个“动量”项(一阶矩估计)
  • 对每个参数维护一个“梯度平方”的指数移动平均(二阶矩估计)
  • 用这两个值动态调整每个参数的学习率

Adam的默认参数(lr=0.001, β1=0.9, β2=0.999)在大多数任务上表现都不错。我90%的项目直接用默认参数就能跑出不错的结果。

我的建议:如果你刚开始一个新任务,先用Adam快速验证模型能不能收敛。等模型结构确定后,再尝试换成SGD + 动量 + 学习率衰减,有时能获得更好的泛化性能。我在一个视觉定位竞赛里就是这么干的——先用Adam跑50个epoch找到好参数,再用SGD精调20个epoch,最后拿了第二名。

下面做个对比:

特性 SGD + Momentum Adam
收敛速度 较慢
超参数敏感度 高(学习率要仔细调) 低(默认参数通常可用)
泛化性能 通常更好 有时会过拟合
适用场景 数据量大、需要精细调优 快速原型、新手友好

好了,这一讲的内容就到这里。咱们把神经网络的核心概念、CNN的基础结构、激活函数和损失函数、以及两个主流优化器都过了一遍。这些东西看着简单,但每个点都值得你花时间去琢磨。下一讲我们会继续深入,聊聊训练技巧、正则化、以及更高级的网络结构。

记住我开头说的:基础不牢,地动山摇。把这些吃透了,后面的视觉定位内容你会学得轻松很多。


专注资料整理