3. AI ISP 基础:深度学习在图像处理中的应用

各位同学,欢迎来到第三章。从这一章开始,我们正式进入 AI ISP 的核心地带。说实话,很多做传统 ISP 的工程师,一开始对深度学习是有些抵触的。我当年也一样,觉得这东西像个黑盒子,不稳定。但后来发现,传统算法在低光、去噪、超分这些场景下,天花板实在太低了。

深度学习,说白了就是给 ISP 装上了一双能「学习」的眼睛。它不再依赖人工设计的固定规则,而是从海量数据中自己总结出最优的映射关系。这一章,我会带你打好 CNN、ResNet、U-Net 和注意力机制这几个地基。

核心认知: 传统 ISP 是「规则驱动」,AI ISP 是「数据驱动」。前者稳定但上限低,后者上限高但需要精心调教。我们的目标,是把两者的优势结合起来。

3.1 卷积神经网络(CNN)基础

CNN 是几乎所有图像处理深度学习模型的基石。它的核心操作就是「卷积」——用一个小的窗口(卷积核)在图像上滑动,提取局部特征。

我刚开始学的时候,总觉得卷积和图像处理里的滤波是一回事。其实本质上确实很像,但 CNN 的卷积核参数是 学习出来 的,而不是我们手动设定的。

3.1.1 卷积层的核心参数

参数 含义 我的经验
卷积核大小 (Kernel Size) 感受野的大小,常用 3x3 3x3 是黄金尺寸,计算量和感受野平衡得最好
步长 (Stride) 卷积核每次移动的像素数 步长=2 可以替代下采样,减少计算量
填充 (Padding) 在输入边缘补零,控制输出尺寸 Same 填充保证输入输出尺寸一致,方便网络设计
输入/输出通道 (Channels) 特征图的深度 通道数越多,网络表达能力越强,但参数量也越大
避坑指南: 我曾经在一个去噪项目里,为了追求大感受野,一上来就用了 7x7 的卷积核。结果模型参数爆炸,训练速度极慢,效果还没 3x3 堆叠的好。记住,小卷积核堆叠比大卷积核更高效。

3.1.2 激活函数与池化

卷积是线性操作,激活函数负责引入非线性。没有它,再深的网络也只是线性变换的堆叠,毫无意义。

  • ReLU: 最常用,f(x)=max(0,x)。计算快,能缓解梯度消失。但要注意「神经元死亡」问题——一旦输入为负,梯度就永远为0。
  • Leaky ReLU: 给负数部分一个很小的斜率(比如0.01),解决了神经元死亡问题。我在低光图像增强中比较喜欢用这个。
  • 池化(Pooling): 最大池化保留最显著特征,平均池化保留整体信息。现在很多网络用步长卷积代替池化,效果更好。
# 一个简单的 CNN 特征提取块(PyTorch 风格)
import torch.nn as nn

class ConvBlock(nn.Module):
    def __init__(self, in_ch, out_ch):
        super().__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True)
        )
    def forward(self, x):
        return self.conv(x)

3.2 残差网络(ResNet)

你想想看,网络越深,效果应该越好对吧?但实践发现,网络深到一定程度,训练误差反而上升了。这就是著名的「退化问题」。不是过拟合,而是网络太难优化了。

ResNet 的解决方案简单而优雅:让网络去学习残差,而不是直接学习原始映射。它引入了一个「跳跃连接」(Skip Connection),把输入直接加到输出上。

公式很简单:输出 = F(x) + x。如果 F(x) 学不到什么东西,至少还有 x 能传过去。这保证了深层网络至少不会比浅层网络差。

为什么 ResNet 对 ISP 很重要? 在图像恢复任务中,输入和输出往往高度相似(比如去噪、超分)。残差学习天然适合这类任务——网络只需要学习「干净图像 - 噪声图像」这个差值,比直接学习干净图像容易得多。

3.2.1 残差块的结构

我习惯把残差块分为两种:

  • BasicBlock: 两个 3x3 卷积堆叠,适合 ResNet-18/34 等较浅网络。
  • Bottleneck: 1x1 -> 3x3 -> 1x1 的结构,先降维再升维,适合 ResNet-50/101/152 等深层网络。1x1 卷积在这里起到「瓶颈」的作用,大幅减少参数量。
# BasicBlock 实现
class BasicBlock(nn.Module):
    def __init__(self, in_ch, out_ch, stride=1):
        super().__init__()
        self.conv1 = nn.Conv2d(in_ch, out_ch, 3, stride=stride, padding=1)
        self.bn1 = nn.BatchNorm2d(out_ch)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(out_ch, out_ch, 3, padding=1)
        self.bn2 = nn.BatchNorm2d(out_ch)
        
        # 如果维度不匹配,用 1x1 卷积调整
        self.shortcut = nn.Sequential()
        if stride != 1 or in_ch != out_ch:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_ch, out_ch, 1, stride=stride),
                nn.BatchNorm2d(out_ch)
            )
    
    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
注意: 跳跃连接要求输入输出的尺寸和通道数必须一致。如果不一致,需要用 1x1 卷积或补零来对齐。我见过不少新手在这里踩坑,导致维度不匹配的报错。

3.3 U-Net 架构

U-Net 最初是为医学图像分割设计的,但它在图像恢复任务中表现极其出色。为什么?因为它完美解决了「下采样丢失细节」的问题。

U-Net 的结构像一个 U 形:左边是编码器(下采样),右边是解码器(上采样),中间通过「跳跃连接」把编码器的特征图直接拼到解码器上。这样一来,解码器既能利用高层的语义信息,又能保留底层的细节纹理。

3.3.1 U-Net 在 ISP 中的应用

我在做 RAW 域去噪时,U-Net 几乎是首选。原因有三:

  1. 多尺度特征: 下采样让网络看到更大的感受野,理解图像全局结构。
  2. 细节保留: 跳跃连接把浅层的纹理细节直接送到深层,避免细节丢失。
  3. 端到端训练: 输入噪声 RAW 图,输出干净 RAW 图,一气呵成。
# U-Net 的核心——跳跃连接
class UNet(nn.Module):
    def __init__(self):
        super().__init__()
        # 编码器(下采样路径)
        self.enc1 = ConvBlock(3, 64)
        self.enc2 = ConvBlock(64, 128)
        self.enc3 = ConvBlock(128, 256)
        self.enc4 = ConvBlock(256, 512)
        
        # 解码器(上采样路径)
        self.up3 = nn.ConvTranspose2d(512, 256, 2, stride=2)
        self.dec3 = ConvBlock(512, 256)  # 注意:输入是上采样+跳跃连接拼接
        self.up2 = nn.ConvTranspose2d(256, 128, 2, stride=2)
        self.dec2 = ConvBlock(256, 128)
        self.up1 = nn.ConvTranspose2d(128, 64, 2, stride=2)
        self.dec1 = ConvBlock(128, 64)
        
        self.final = nn.Conv2d(64, 3, 1)
    
    def forward(self, x):
        # 编码
        e1 = self.enc1(x)
        e2 = self.enc2(self.pool(e1))
        e3 = self.enc3(self.pool(e2))
        e4 = self.enc4(self.pool(e3))
        
        # 解码 + 跳跃连接
        d3 = self.up3(e4)
        d3 = torch.cat([d3, e3], dim=1)  # 拼接
        d3 = self.dec3(d3)
        
        d2 = self.up2(d3)
        d2 = torch.cat([d2, e2], dim=1)
        d2 = self.dec2(d2)
        
        d1 = self.up1(d2)
        d1 = torch.cat([d1, e1], dim=1)
        d1 = self.dec1(d1)
        
        return self.final(d1)
我的习惯: 在 ISP 任务中,我会把 U-Net 的深度控制在 4-5 层。太深了,底层细节反而会被过度压缩;太浅了,感受野不够,去噪效果差。另外,跳跃连接我用的是拼接(concat)而不是相加(add),因为拼接保留了更多信息。

3.4 注意力机制(Attention Mechanism)

注意力机制,说白了就是让网络学会「关注哪里」和「关注什么」。在图像处理中,不是所有像素都同等重要——边缘、纹理区域比平坦区域更需要精细处理。

我最早接触注意力机制是在 2017 年的 SENet 上。它通过一个轻量级的模块,学习每个通道的重要性权重,然后对特征图进行重新标定。效果出奇的好,而且计算量几乎可以忽略。

3.4.1 通道注意力(SE Block)

SENet 的核心是 Squeeze-and-Excitation:先通过全局平均池化把每个通道压缩成一个标量(Squeeze),再通过两个全连接层学习通道间的依赖关系,输出每个通道的权重(Excitation),最后用这个权重去乘原始特征图。

class SEBlock(nn.Module):
    def __init__(self, channel, reduction=16):
        super().__init__()
        self.squeeze = nn.AdaptiveAvgPool2d(1)
        self.excitation = nn.Sequential(
            nn.Linear(channel, channel // reduction),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel),
            nn.Sigmoid()
        )
    
    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.squeeze(x).view(b, c)
        y = self.excitation(y).view(b, c, 1, 1)
        return x * y  # 通道加权

3.4.2 空间注意力

通道注意力关注「是什么」,空间注意力关注「在哪里」。常用的空间注意力机制包括:

  • CBAM: 先通道注意力,再空间注意力,串联使用。空间注意力部分用最大池化和平均池化生成两个特征图,拼接后通过卷积得到空间权重。
  • Non-local: 计算所有像素之间的相关性,捕捉长距离依赖。计算量较大,但在去噪任务中效果显著。
我的经验: 在 ISP 任务中,我通常把注意力机制放在网络的瓶颈层(最底层)。因为底层特征图尺寸小,计算注意力开销低,而且底层语义信息最丰富,注意力能发挥最大作用。放在浅层的话,计算量大,收益却不高。

3.5 本章知识体系总览

下面这张图,我把本章的核心知识点串在了一起。你可以把它当作一张「地图」,随时回来查阅。

AI ISP 基础:深度学习在图像处理中的知识体系 CNN 基础 卷积 / 池化 / 激活 感受野 / 参数共享 ResNet 跳跃连接 残差学习 / 退化问题 U-Net 编码器-解码器 跳跃连接(拼接) 注意力机制 通道注意力(SE) 空间注意力(CBAM) 自注意力(Non-local) 核心思路 CNN 提取特征 → ResNet 解决深度退化 → U-Net 实现多尺度融合 → 注意力机制聚焦关键信息 这四者组合,构成了现代 AI ISP 的算法基石

3.6 本章小结

这一章的内容,说实话信息量不小。但这些都是后续章节的「砖瓦」,必须打牢。

  • CNN 是特征提取器,理解卷积、池化、感受野是基本功。
  • ResNet 解决了深度网络的训练难题,跳跃连接的思想贯穿整个深度学习史。
  • U-Net 是图像恢复任务的利器,编码器-解码器+跳跃连接的结构至今仍是主流。
  • 注意力机制 让网络学会「聚焦」,通道注意力和空间注意力各有侧重。
给新手的建议: 不要急着跑大模型。先用手写数字识别(MNIST)或 CIFAR-10 这些小数据集,把 CNN、ResNet、U-Net 的代码亲手敲一遍,理解每一行代码的作用。我当年就是这么过来的,基础打得牢,后面做项目才不慌。