4、卷积神经网络基础:卷积层、池化层、激活函数、全连接层、经典CNN架构(ResNet/VGG)
好,咱们今天来聊聊卷积神经网络。说实话,这是整个AI绘画和风格迁移的基石。你想想看,不管是Stable Diffusion还是Midjourney,底层都离不开CNN这套东西。我个人习惯把CNN比作「眼睛」——它教会了机器怎么看图。
我记得刚入行那会儿,总觉得CNN是个黑盒子。后来踩的坑多了,才慢慢摸清楚每个组件到底在干嘛。今天我就把这些经验掰开了讲给你听。
4.1 卷积层:特征提取的核心
卷积层说白了就是「滑动窗口」。一个小矩阵(我们叫它卷积核)在图像上滑来滑去,每次做点乘运算。嗯,这里要注意:卷积核不是随便选的,它是训练出来的。
核心概念:卷积核就是特征检测器。一个核检测边缘,另一个检测纹理,再一个检测颜色。层数越深,检测的东西越抽象。
我在项目中遇到过一个问题:输入图像是512x512,卷积核是3x3,步长是1,不填充。输出尺寸是多少?答案是510x510。为什么会这样?因为边缘像素没法被卷积核覆盖到。
这里有个公式,我建议你记下来:
输出尺寸 = (输入尺寸 - 卷积核尺寸 + 2 * 填充) / 步长 + 1
举个例子:
输入: 32x32
卷积核: 5x5
填充: 2
步长: 1
输出: (32 - 5 + 4) / 1 + 1 = 32
你看,加了填充之后,输出尺寸和输入一样。这叫「Same卷积」,在ResNet里用得特别多。
我的小技巧:做风格迁移时,我一般用3x3的卷积核。太小了感受野不够,太大了参数太多。3x3是个黄金尺寸。
4.2 池化层:降维的艺术
池化层干嘛用的?说白了就是「压缩」。把一张大图缩小,保留最重要的信息。最常见的两种:最大池化和平均池化。
你想想看,一张256x256的图,经过2x2的最大池化,变成128x128。信息量少了,但关键特征还在。这就像你看一幅画,退后两步看,轮廓反而更清晰了。
| 池化类型 | 做法 | 适用场景 |
|---|---|---|
| 最大池化 | 取窗口内最大值 | 纹理、边缘检测 |
| 平均池化 | 取窗口内平均值 | 背景、平滑区域 |
| 全局平均池化 | 整个特征图取平均 | 替代全连接层(ResNet用) |
避坑指南:我曾经在风格迁移项目里用了太多池化层,结果生成图像模糊得一塌糊涂。后来发现,池化层会丢失细节信息。做图像生成任务时,尽量少用池化,改用步长卷积来降采样。
4.3 激活函数:引入非线性
没有激活函数,神经网络就是一堆线性变换的叠加。那跟单层网络有什么区别?所以激活函数是必须的。
我个人最常用的是ReLU。为什么?简单、快、效果好。你看它的公式:
ReLU(x) = max(0, x)
就这么简单。负数全干掉,正数保留。这带来了稀疏性,也让梯度消失问题大大缓解。
不过ReLU有个问题——「神经元死亡」。如果某个神经元一直输出负数,它的梯度永远是0,再也学不动了。我在VGG训练时就遇到过,后来换成了Leaky ReLU:
Leaky ReLU(x) = max(0.01x, x)
给负数一个很小的斜率,至少还能学。
经验之谈:做风格迁移时,我建议用ReLU或Leaky ReLU。Sigmoid和Tanh在深层网络里梯度消失太严重,别用。
4.4 全连接层:决策者
全连接层就是传统的神经网络层。每个输入节点都连接到每个输出节点。说白了,它负责把卷积层提取的特征「综合」起来,做出最终判断。
举个例子:VGG16最后有三个全连接层,尺寸分别是4096、4096、1000(ImageNet分类数)。参数量有多大?你算算:7x7x512 = 25088个输入,连到4096个神经元,光这一层就有1亿多个参数。
嗯,这里要注意。全连接层是参数量大户。ResNet为什么用全局平均池化替代全连接层?就是为了减少参数量,防止过拟合。
# 全连接层示例(PyTorch)
self.fc = nn.Sequential(
nn.Linear(25088, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, 1000)
)
我的建议:做风格迁移时,尽量少用全连接层。用卷积层+全局池化代替,参数量少,效果反而更好。
4.5 经典CNN架构:VGG与ResNet
聊完了基础组件,咱们看看两个经典架构。这两个我在项目里都用过无数次,各有各的脾气。
4.5.1 VGG:简单粗暴的堆叠
VGG的思路特别简单:全部用3x3卷积,全部用2x2最大池化。然后一层层堆上去。VGG16有16层可学习参数,VGG19有19层。
我记得第一次跑VGG16,显存直接爆了。为什么?因为VGG最后三个全连接层太吃参数了。后来我学乖了,用VGG做特征提取时,只取卷积部分,不要全连接层。
VGG16结构简图:
Conv3-64 → Conv3-64 → Pool
Conv3-128 → Conv3-128 → Pool
Conv3-256 → Conv3-256 → Conv3-256 → Pool
Conv3-512 → Conv3-512 → Conv3-512 → Pool
Conv3-512 → Conv3-512 → Conv3-512 → Pool
FC-4096 → FC-4096 → FC-1000
VGG的优点:结构规整,容易理解,特征提取能力强。
VGG的缺点:参数量大(约1.38亿),计算慢,容易过拟合。
4.5.2 ResNet:残差学习的革命
ResNet解决了深层网络的一个大问题——退化。按理说网络越深效果越好,但实际上层数多了,准确率反而下降。为什么会这样?梯度消失是一方面,另一方面是「恒等映射」学不好。
ResNet的解决方案特别巧妙:引入残差连接。说白了,就是让网络学习「残差」而不是直接学习映射。
残差块公式:
输出 = F(x) + x
其中F(x)是卷积层学到的残差
x是输入(通过捷径连接直接传过来)
你想想看,如果F(x)学成0,输出就等于输入。这比让网络自己去学恒等映射容易多了。所以ResNet可以堆到152层甚至更深,效果还越来越好。
我在风格迁移项目里,经常用ResNet50作为编码器。它的残差结构让梯度传播更顺畅,训练起来比VGG快不少。
| 架构 | 层数 | 参数量 | 特点 |
|---|---|---|---|
| VGG16 | 16 | 1.38亿 | 结构简单,特征清晰 |
| ResNet50 | 50 | 2550万 | 残差连接,可训练更深 |
| ResNet101 | 101 | 4450万 | 更深,适合复杂任务 |
避坑指南:我曾经在ResNet里把捷径连接的维度搞错了。输入是256通道,输出是512通道,直接相加会报错。解决办法是用1x1卷积调整维度,或者用padding。这个细节一定要注意。
4.6 实战建议:怎么选?
好,最后给点实战建议。做AI绘画和风格迁移时,怎么选这些架构?
- 追求速度:用轻量级网络,比如MobileNet或ShuffleNet。VGG太慢了。
- 追求质量:用ResNet50或ResNet101。残差结构能保留更多细节。
- 做特征提取:VGG的浅层特征(纹理、边缘)很清晰,适合风格迁移。
- 做内容重建:ResNet的深层特征(语义信息)更稳定。
我个人习惯是:风格迁移用VGG19的浅层特征,内容重建用ResNet50的深层特征。两者结合,效果最好。
最后一个小技巧:不管用哪个架构,记得用预训练权重。ImageNet上训好的模型,特征提取能力已经很强了。你只需要微调,不用从头训。这能省下大量时间和算力。
嗯,CNN基础就聊到这儿。下一章咱们讲损失函数和优化器,到时候会用到今天讲的这些知识。你先把卷积、池化、激活函数这些概念吃透,后面就好办了。