4. 深度学习基础回顾
各位同学,欢迎来到第四章。这一章我们得把深度学习的基础夯一夯。你可能会问:“我是做ISP的,为什么要学CNN?” 说白了,AI ISP的核心就是用神经网络替代传统的图像处理流水线。不懂CNN,后面讲AI去噪、超分、HDR融合,你根本听不懂。
我个人习惯,讲理论之前先画一张图,把本章的知识脉络理清楚。这样你学起来心里有数。
4.1 CNN核心概念:卷积、池化、感受野
卷积神经网络,说白了就是“用卷积核在图像上滑动”。每个卷积核就是一个特征提取器。边缘、纹理、颜色,一层层往上抽象。
卷积操作:输入一张图,尺寸是 H×W×C,卷积核是 K×K×C,输出一张特征图。我刚开始做AI ISP时,经常搞混“通道数”和“卷积核个数”的关系。记住:输出通道数 = 卷积核的个数。
关键公式:输出特征图尺寸 = (输入尺寸 - 卷积核尺寸 + 2×Padding) / Stride + 1
举个例子:输入 224×224,卷积核 3×3,Stride=1,Padding=1,输出还是 224×224。这叫“保持分辨率”,在ISP任务里很常见。
池化层:最大池化、平均池化。它的作用就是降采样,减少计算量。但我在项目中踩过一个坑——在AI去噪网络里用了太多池化,结果图像细节全丢了。后来我改用Stride卷积来降采样,效果好很多。
感受野:这个概念很重要。你想想看,一个3×3的卷积核,感受野就是3×3。但堆叠两层3×3卷积,感受野就变成了5×5。为什么?因为第二层能看到第一层3×3区域的信息,而第一层每个点又覆盖了输入上的3×3区域。这就是“堆叠小卷积核替代大卷积核”的原理,参数量还更少。
我的经验:在AI ISP中,感受野决定了网络能看到多大范围的上下文。去噪任务需要大感受野,但也不能太大,否则会模糊边缘。我一般用3×3卷积堆叠4-6层,感受野大概15×15到21×21,效果比较平衡。
4.2 激活函数与归一化层
激活函数,就是给网络引入非线性。没有激活函数,堆再多层也是线性变换,那跟单层网络没区别。
| 激活函数 | 公式 | 优点 | 缺点 |
|---|---|---|---|
| ReLU | max(0, x) | 计算快,缓解梯度消失 | 神经元死亡(负半轴梯度为0) |
| Leaky ReLU | max(αx, x) | 解决神经元死亡 | α需要调参 |
| PReLU | max(ax, x),a可学习 | 自适应负斜率 | 参数量略增 |
| GELU | x·Φ(x) | 在Transformer中表现好 | 计算稍复杂 |
我个人习惯,在CNN里首选ReLU。简单、高效、硬件友好。但在AI ISP的量化部署中,ReLU有个问题——它的输出范围是[0, +∞),量化时不好截断。我建议用ReLU6(min(max(0,x), 6)),把输出限制在0到6之间,量化精度更高。
归一化层:Batch Normalization(BN)是2015年提出的,现在几乎成了CNN的标配。它把每层输出归一化到均值为0、方差为1,再学一个缩放和平移。好处是加速训练、缓解梯度消失、还有一点正则化效果。
但BN在AI ISP芯片上有个大坑——推理时BN是线性变换,可以融合到卷积层里。我做过一个项目,芯片的NPU不支持BN单独计算,必须做“BN融合”。代码实现很简单:
# BN融合到卷积层的伪代码
conv_weight = conv_weight * (gamma / sqrt(running_var + eps))
conv_bias = (conv_bias - running_mean) * (gamma / sqrt(running_var + eps)) + beta
融合之后,推理时就不需要单独算BN了,省掉一次内存访问和计算。这在嵌入式芯片上非常关键。
我曾经踩过的坑:在训练时用了BN,但部署到芯片上时忘了做融合。结果推理结果完全不对,查了两天才发现是BN的running_mean和running_var没有冻结。记住:训练时BN是逐batch计算的,推理时必须用全局统计量。
除了BN,还有Layer Normalization(LN)和Instance Normalization(IN)。LN在RNN/Transformer里用得多,IN在图像风格迁移里常见。但在AI ISP里,BN还是主流。
4.3 常用网络结构:ResNet、UNet、MobileNet
这三个网络,是AI ISP里最常用的骨架。我一个个讲。
4.3.1 ResNet:残差连接
ResNet的核心思想就是“跳跃连接”。为什么需要它?因为网络太深了,梯度传不回去。你想想看,50层网络,梯度从最后一层传到第一层,中间连乘50次,如果每次小于1,梯度就消失了。
残差块的做法:让网络去学习“残差”F(x) = H(x) - x,而不是直接学习H(x)。这样梯度可以通过跳跃连接直接回传,不会衰减。
代码示例:一个基本的残差块
class BasicBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1)
self.bn1 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1)
self.bn2 = nn.BatchNorm2d(out_channels)
# 跳跃连接
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, 1, stride),
nn.BatchNorm2d(out_channels)
)
def forward(self, x):
out = self.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.shortcut(x) # 残差连接
out = self.relu(out)
return out
在AI ISP里,ResNet常用于特征提取。比如做图像增强时,我用ResNet-18作为编码器,效果比VGG好很多,而且训练更快。
4.3.2 UNet:编码器-解码器结构
UNet是图像分割领域的经典网络,但在AI ISP里也大放异彩。为什么?因为它的结构天然适合“图像到图像”的任务——输入一张噪声图,输出一张干净图。
UNet的结构分为两部分:
- 编码器(下采样):逐层提取特征,分辨率降低,通道数增加。
- 解码器(上采样):逐层恢复分辨率,通过跳跃连接融合编码器的特征。
跳跃连接是UNet的精髓。它把编码器的细节信息直接传给解码器,避免了上采样过程中的信息丢失。我在做AI去噪时,对比过有无跳跃连接的效果——有跳跃连接的PSNR高了1.5dB左右。
我的建议:在AI ISP里,UNet的深度不用太深。4层下采样+4层上采样就够了。太深了,小目标(比如噪点)的信息在下采样过程中就丢了,上采样也找不回来。
4.3.3 MobileNet:轻量级网络
MobileNet是为移动端和嵌入式设备设计的。它的核心是“深度可分离卷积”。
普通卷积:一个卷积核同时处理所有通道。深度可分离卷积:先对每个通道单独做卷积(Depthwise),再用1×1卷积融合通道(Pointwise)。
计算量对比:假设输入是 H×W×C,卷积核是 K×K,输出通道是 M:
- 普通卷积:H×W×C×K×K×M
- 深度可分离卷积:H×W×C×K×K + H×W×C×M
当K=3时,深度可分离卷积的计算量大约是普通卷积的1/9到1/8。这个差距在芯片上非常可观。
我在一个AI ISP芯片项目里,把骨干网络从普通卷积换成深度可分离卷积,模型大小从50MB降到了6MB,推理速度提升了5倍,而PSNR只掉了0.3dB。这个trade-off完全值得。
4.4 模型轻量化技术:剪枝、量化、蒸馏
模型做出来了,但跑不动怎么办?轻量化就是干这个的。在AI ISP芯片上,算力和内存都是有限的,必须对模型“动手术”。
4.4.1 剪枝
剪枝就是去掉不重要的连接或通道。说白了,神经网络有很多冗余参数,去掉它们对精度影响不大。
剪枝的流程:
- 训练一个完整的大模型。
- 评估每个通道或权重的重要性(比如用L1范数)。
- 剪掉不重要的部分。
- 微调(Fine-tune)恢复精度。
我常用的方法是“结构化剪枝”——直接剪掉整个卷积核或通道。这样剪完之后,模型结构还是规整的,硬件实现起来方便。非结构化剪枝(剪掉单个权重)虽然压缩率更高,但芯片上的稀疏计算单元不是每家都有,兼容性差。
我曾经犯过的错:一次性剪掉50%的通道,结果模型精度直接崩了。后来我改成“渐进式剪枝”——每次剪5%,微调一下,再剪5%。这样精度下降可控,最终剪掉了40%的通道,精度只掉了0.5%。
4.4.2 量化
量化就是把模型参数从FP32变成INT8甚至INT4。为什么能这么做?因为神经网络对噪声有一定的容忍度。
量化的方式有两种:
- 训练后量化(PTQ):训练完模型后,直接用量化工具转换。简单,但精度损失可能较大。
- 量化感知训练(QAT):在训练过程中模拟量化误差,让模型适应低精度。精度更高,但需要重新训练。
在AI ISP芯片上,我强烈建议用QAT。因为图像任务对精度很敏感,PTQ量化后PSNR可能掉1-2dB,而QAT只掉0.2-0.3dB。
量化关键点:
- 校准数据集:PTQ需要几百张有代表性的图片来计算量化范围。
- 对称量化 vs 非对称量化:ReLU激活后的值都是非负的,用非对称量化更合适。
- per-tensor vs per-channel:per-channel量化精度更高,但硬件支持需要确认。
4.4.3 知识蒸馏
蒸馏就是“大模型教小模型”。大模型(Teacher)知识丰富,小模型(Student)学它的输出分布,而不是直接学硬标签。
蒸馏的损失函数通常包含两部分:
- 硬标签损失:Student的输出与真实标签的交叉熵。
- 软标签损失:Student的输出与Teacher的输出(经过温度系数软化)的KL散度。
我在一个AI ISP项目里,用ResNet-50作为Teacher,MobileNet作为Student。蒸馏之后,MobileNet的精度从原来的92.3%提升到了94.1%,接近ResNet-50的95.2%。而MobileNet的推理速度是ResNet-50的8倍。
我的经验:蒸馏的温度系数T很关键。T越大,软标签越平滑,小模型学到的知识越丰富。我一般从T=4开始试,然后根据验证集精度调整。
4.5 本章小结
这一章内容不少,但都是后面AI ISP实战的基础。我帮你梳理一下重点:
- CNN核心:卷积、池化、感受野——理解特征提取的底层逻辑。
- 激活与归一化:ReLU+BN是黄金组合,但部署时别忘了做BN融合。
- 网络结构:ResNet解决梯度消失,UNet适合图像到图像,MobileNet用深度可分离卷积降低计算量。
- 轻量化:剪枝、量化、蒸馏三件套,是模型上芯片的必经之路。