ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

卷积神经网络CNN原理解析:从卷积池化到LeNet与PyTorch实战

卷积神经网络CNN原理解析:从卷积池化到LeNet与PyTorch实战 1. 从一张找猫的图说起CNN到底在干什么先说个我自己的经历。几年前刚接触深度学习的时候我以为卷积神经网络是个特别高深的东西直到有位前辈拿了一张猫的照片问我你一眼就能看出这是猫靠的是什么我说靠眼睛。他说其实你的眼睛也没那么聪明它只是先看到边缘、再看到轮廓、最后才把这些拼成猫这个整体概念。CNN干的就是这件事只不过它把这三步变成了可训练的数字流程。这句话基本就是卷积神经网络Convolutional Neural Network简称 CNN的核心思想。如果你搜过卷积神经网络结构图大概率会看到一堆方块层层堆叠——输入层、卷积层、池化层、全连接层、输出层。图看得懂但不知道每层为什么要这么设计。这篇文章我就按一个做过图像项目的人的视角把这些方块一个个拆开讲尽量不用那些让人头大的数学符号堆砌同时把每个设计背后的为什么讲透。CNN 是什么一句话它是专门为处理具有网格状结构数据最典型的就是图像而设计的一类神经网络。它能做什么把一张原始像素图逐步抽象成边缘→纹理→局部形状→整体物体的特征层级最终输出这是猫或者这是狗的判断。它适合谁看如果你满足下面任意一条这篇内容就是写给你的刚学完多层感知机前馈神经网络好奇图像任务为什么不能直接用它看过李宏毅老师的 CNN 课程理论听懂了但一到写代码就发懵已经会调torchvision的模型但说不清每一层到底在算什么需要给别人讲 CNN想找一个通俗但不失真的解释口径。我会从最基础的为什么图像不能直接喂给前馈网络讲起然后是卷积这个操作到底在算什么、池化层是干吗的、一个经典网络长什么样、怎么用几行代码把它跑起来最后聊几个我在实际项目中踩过的坑。全程配场景别怕没有微积分。2. 图像任务为什么不能用前馈神经网络直接硬上2.1 一张图展平之后空间信息就没了先说前馈神经网络Fully Connected Network / MLP处理图像的常规做法把图像拉平成一维向量。一张 224×224 的彩色图有 224×224×3 150528 个像素。第一层如果是 1000 个神经元那么光是这一个全连接层就有 150528×1000 ≈ 1.5 亿个参数。这还只是第一层。参数多不是最要命的要命的是展平这个动作本身就把图像的空间结构毁掉了。在图像里相邻像素是强相关的——左上角的像素和它右边的像素共同构成了一条边横着排的像素和竖着排的像素含义完全不同。可一旦拉平成一维数组原本上下左右的位置关系就变成了一串线性序号网络得从零开始反复学习第 3 个像素和第 4 个像素挨着这种它本可以直接拿到的信息。打个比方。这就像你要认识一个人本来可以看他的正脸完整的二维构图结果你把他的五官打印在一条长长的纸带上还剪碎了打乱顺序。网络要花极大的代价才能把这些碎片重新拼回一张脸。2.2 权重不共享带来的两个致命后果前馈网络处理图像还有第二个问题同一类特征在不同位置出现时网络要分别学一遍。假设我们要检测竖直边缘。在图像左上角出现的竖直边缘和右下角出现的竖直边缘本质上是一模一样的模式。但全连接网络里左上角的像素对应一组权重右下角的像素对应另一组完全不同的权重网络得用两套独立的参数去学同一个东西。这就带来了两个后果第一个后果是参数量爆炸也就是上面算的那 1.5 亿。模型大到难以训练过拟合几乎是必然的。第二个后果更隐蔽——位置不变性极差。因为网络是在特定的位置上学到的特征一旦物体换了个位置、挪动了几十像素模型的判断就可能崩掉。我早期做过一个数字识别的小项目用全连接网络训练测试集里数字略微偏移一点准确率就掉一大截当时百思不得其解后来才明白根子在这里。2.3 局部感受野与权值共享CNN 的两把钥匙CNN 用两个核心设计同时解决了上面所有问题这也是它的精髓所在理解了这两点CNN 就理解了一大半。第一把钥匙是局部感受野Local Receptive Field。单个神经元不再一次性看整张图而只看一个很小的局部区域比如 3×3 或 5×5 的窗口。这符合图像的天然特性关键的视觉模式边缘、角点、纹理都是局部的没必要让一个神经元去关心整张图的所有像素。这直接把连接数从全图降到局部窗口。第二把钥匙是权值共享Weight Sharing。同一个卷积核一组权重在整张图上滑动走到哪里都用同一组参数。检测竖直边缘的那个核在左上角用它在右下角还是用它。这就把参数量从每个位置一套参数降到了一个核一套参数。两个设计叠加起来的效果相当惊人。前面那个 150528×1000 的全连接层有 1.5 亿参数而一个 3×3 卷积核处理同样输入的参数是 3×3×3 27 个输入三通道。即便是 64 个这样的卷积核总共也才 27×64 1728 个参数。差了将近十万倍。这就是为什么 CNN 能在图像任务上碾压前馈网络——不是它更聪明而是它把图像先验知识局部性、平移不变性编码进了网络结构里。我把这个对比整理成表更直观一些对比维度前馈神经网络卷积神经网络输入处理方式展平为一维向量保持二维/三维结构单个神经元感受范围全图所有像素局部窗口如 3×3参数是否共享不共享每个位置一套共享一个核扫全图典型参数量级亿级千级到万级平移鲁棒性弱位置一变就失效强同一特征任何位置都能识别对图像先验的利用几乎不用直接编码局部性与平移不变性提示如果你面试被问到图像处理为啥用 CNN 不用前馈神经网络把参数爆炸和丢失空间结构两点答出来是及格补上权值共享带来的平移不变性才算答到点子上。3. 卷积这个操作到底在算什么3.1 卷积核是一块特征探测器很多人被卷积这个词唬住其实它做的事特别朴素拿一个小窗口卷积核在大图上从左到右、从上到下滑动每滑到一个位置就把窗口覆盖的那块区域和卷积核做逐元素相乘再求和得到一个数。滑完整张图就得到一张新的二维图叫特征图Feature Map。举个例子最清楚。假设图像某个 3×3 局部是1 1 1 0 0 0 1 1 1卷积核是1 0 -1 1 0 -1 1 0 -1逐元素相乘求和(1×1 1×0 1×(-1)) (0×1 0×0 0×(-1)) (1×1 1×0 1×(-1)) 0 0 0 0。换一块区域试试1 0 1 1 0 1 1 0 1同样计算(1×1 0×0 1×(-1)) (1×1 0×0 1×(-1)) (1×1 0×0 1×(-1)) 3 3 3 9。看出规律了吗这个卷积核对左边亮右边暗的竖直边界响应很强输出 9对左右对称的区域响应为 0。它就是一台竖直边缘探测器。如果我把这个核转置一下就变成了水平边缘探测器。这就是 CNN 最底层的工作方式——网络不需要人去设计这些核而是通过训练自动学出来学到的核往往就是各种方向的边缘、纹理、颜色斑块检测器。3.2 步长、填充、通道三个必须搞懂的参数实际写代码时卷积层总有三个参数绕不开步长stride、填充padding、输出通道数。搞不清它们你连输出尺寸都算不对。步长stride是卷积核每次滑动的格数。stride1 时逐像素滑动输出图尺寸和输入差不多stride2 时每隔一个像素滑动输出图长宽各缩小一半。步长越大输出越小计算越快但可能漏掉细节。实际项目里 1 和 2 是最常用的3 以上很少见。填充padding是在图像边界外补一圈像素通常是补 0。为什么需要它因为卷积核滑到边缘时覆盖范围会超出图像如果不填充输出图会比输入小一圈多层叠加后图像会越来越小。更关键的是边缘像素参与卷积的次数远少于中心像素边缘信息容易被稀释。padding1对 3×3 核能让输出尺寸和输入保持一致这个配置被叫做 same padding是最常见的默认选项。输出尺寸的计算公式必须记住我见过太多人手写网络时在这一步出错输出边长 (输入边长 2 × padding - 卷积核边长) / 步长 1拿个例子验证输入 224卷积核 3padding 1stride 1 —— (224 2 - 3)/1 1 224。确实保持不变。如果换成 stride2 —— (224 2 - 3)/2 1 112.5除不尽实际会向下取整得到 112。输出通道数则取决于你用几个卷积核。用 64 个核就得到 64 张特征图堆叠成的 64 通道输出。每个通道代表一种被检测出来的特征。这解释了一个常见的疑惑为什么特征图越往后通道越多因为浅层在检测简单特征边缘、颜色种类有限深层需要组合出复杂特征眼睛、轮子、文字笔画需要的特征种类自然就多了。3.3 激活函数没有它深层卷积等于白搭每次卷积之后都会跟一个激活函数最常用的是 ReLUmax(0, x)。很多人把它当惯例照抄不知道为什么。关键在于卷积本身是线性运算。两个线性操作堆在一起数学上仍然等价于一个线性操作。这意味着如果卷积层之间没有非线性激活无论你叠多少层整个网络的能力和只有一层是一样的。加了 ReLU 这种非线性函数网络才真正获得了层层抽象的能力才能表达复杂的函数关系。ReLU 相比早期的 Sigmoid还有个实际好处是梯度不容易消失。Sigmoid 在输入很大或很小时导数趋近于 0梯度反向传播几层之后就衰减到几乎为零深层网络根本训不动。ReLU 在正区间导数恒为 1梯度能顺畅传到底层。这也是为什么 2012 年之后几乎所有主流 CNN 都用 ReLU 家族。现在一些新网络会用 GELU、SiLU思路类似效果略好但差异不大新手阶段用 ReLU 完全够。4. 池化层和整体结构CNN 是怎么一层层抽象的4.1 池化真正解决的问题不是降维池化层Pooling最常见的说法是降维、减少计算量。这话对但只说了一半而且不是最重要的那一半。池化更本质的作用是带来一定程度的平移不变性和空间压缩。以最大池化Max Pooling为例2×2 窗口、步长 2就是在每个 2×2 的小块里取最大值。假设某个边缘在图像里稍微移动了一两个像素只要它还落在同一个 2×2 窗口内池化后的结果就完全一样。也就是说细微的位置偏移被池化抹平了。我举个生活化的类比。你在一张远景照片里找一个人如果照片分辨率极高人稍微挪一步结果就变但如果先把照片按 2×2 网格缩小一半再找人挪一两像素对缩小后的图几乎没有影响。池化就是在做这件事——用分辨率的损失换取对位置的宽容度。顺带说池化也显著降低了后续层的计算量和参数量。一个 2×2 池化让特征图长宽各减半面积变成原来的四分之一后面所有卷积的开销都跟着降。4.2 卷积堆叠的顺序为什么是 Conv-ReLU-Pool看经典的 CNN 结构图你会发现几乎都是卷积 → 激活 → 池化这样一组一组地重复。这个顺序不是随便定的每一步都有它的逻辑先卷积是为了提取局部特征紧接着 ReLU是为了引入非线性让特征的组合能力增强最后池化是在当前抽象层级上做一次空间浓缩把已经提取到的特征固化下来同时缩小尺寸为下一轮更抽象的提取做准备。重复这个组合网络的特征抽象层级就逐级上升。第一组学到的是边缘和颜色第二组把边缘组合成纹理和简单形状第三组组合成物体的部件比如眼睛、耳朵、轮子更深的组则组合成完整的物体概念。这跟人类视觉皮层的信息处理路径高度相似也是 CNN 被叫做仿生的原因之一。这里补一个容易被忽略的点池化的位置不是绝对的。现在很多新式网络比如各种 ResNet 变体会用 stride2 的卷积来代替池化效果往往还更好因为池化是固定的取最大值操作没有可学习参数而带步长的卷积是可学习的下采样。新手阶段用经典池化没问题但要记住它不是唯一选择。4.3 全连接层与 Softmax从特征到分类结果经过若干组卷积池化我们得到一堆特征图。最后一步要把它变成这是几号类别的结果靠的是全连接层和 Softmax。全连接层的作用是把二维的特征图拉平然后用一组权重把所有特征综合起来做加权判断。如果说卷积层负责看清全连接层就负责下结论。它把分散在各个通道、各个位置的特征整合成一个全局判断。Softmax 则把全连接层输出的原始分数logits转换成概率分布——所有类别的概率加起来等于 1最大的那个概率对应的类别就是预测结果。它的公式是exp(xi) / sum(exp(xj))本质是把任意实数映射到 (0,1) 区间并且归一化。实际写代码时这一步通常和损失函数合并用CrossEntropyLoss一句搞定不需要单独写。顺带说一个坑全连接层是 CNN 中参数最密集的部分。以经典结构为例卷积部分可能只占几十万参数而最后的全连接层能占到上千万。这也是为什么后来的网络设计越来越倾向于用全局平均池化Global Average Pooling替代全连接层——直接在每个通道上求平均值参数量为零效果还不差。我在一个移动端项目里就吃过这个亏全连接层让模型体积大到部署不进去换成全局平均池化后瞬间轻松。5. 从 LeNet-5 到代码落地一个能跑起来的完整流程5.1 LeNet-5理解 CNN 的最佳标本要理解完整的 CNN 结构LeNet-5 是最好的起点。它是 1998 年 Yann LeCun 提出的手写数字识别网络结构极简但五脏俱全一共 7 层层类型配置输出尺寸输入输入层单通道灰度图32×32×1C1卷积层6 个 5×5 核stride 128×28×6S2平均池化2×2 窗口stride 214×14×6C3卷积层16 个 5×5 核10×10×16S4平均池化2×2 窗口stride 25×5×16C5卷积层120 个 5×5 核1×1×120F6全连接层84 个神经元84输出全连接 Softmax10 个类别10注意 C5 那层输入已经是 5×5卷积核也是 5×5所以输出正好是 1×1相当于用一个卷积实现了全连接。这种卷积代替全连接的技巧至今仍在用。LeNet-5 用今天的眼光看很原始——平均池化早就被最大池化取代也没有 BatchNorm、Dropout 这些现代组件。但它的层级逻辑和现代 CNN 完全一致看懂它再看 ResNet、VGG 只是层数多了、技巧多了本质没变。5.2 用 PyTorch 复现一个 LeNet 风格网络理论讲完来点能跑的。下面这段代码是我常用的 LeNet 改进版把平均池化换成最大池化加了 ReLU在 MNIST 上跑几分钟就能到 99% 左右准确率import torch import torch.nn as nn import torch.nn.functional as F class SimpleCNN(nn.Module): def __init__(self, num_classes10): super().__init__() # 第一组卷积 激活 池化 self.conv1 nn.Conv2d(in_channels1, out_channels6, kernel_size5, stride1, padding2) self.pool nn.MaxPool2d(kernel_size2, stride2) # 第二组 self.conv2 nn.Conv2d(6, 16, kernel_size5, stride1, padding0) # 全连接 self.fc1 nn.Linear(16 * 5 * 5, 120) self.fc2 nn.Linear(120, 84) self.fc3 nn.Linear(84, num_classes) def forward(self, x): x self.pool(F.relu(self.conv1(x))) # 32x32 - 16x16 x self.pool(F.relu(self.conv2(x))) # 16x16 - 5x5 x torch.flatten(x, 1) # 展平 x F.relu(self.fc1(x)) x F.relu(self.fc2(x)) return self.fc3(x)跑起来非常简单model SimpleCNN() criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3) for epoch in range(5): for images, labels in train_loader: optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step()第一次写这段代码时最容易错的地方是self.fc1 nn.Linear(16 * 5 * 5, 120)里的16 * 5 * 5。这个数字必须和卷积部分输出的特征图大小严丝合缝对上写错一个数就会在 forward 时报维度不匹配的错。后面我会专门讲怎么用打印尺寸的方式定位这类问题。5.3 现代架构的三个关键演进LeNet 之后的网络演进理解了这三步基本就够用了第一步是加深——从 AlexNet 到 VGG。AlexNet2012把网络加深到 8 层引入 ReLU 和 Dropout一举拿下 ImageNet 冠军。VGG2014把深度加到 16-19 层核心贡献是证明了堆叠小卷积核3×3比用大卷积核5×5、7×7更好——两个 3×3 卷积的感受野等于一个 5×5但参数更少、非线性更强。这个结论至今仍是网络设计的黄金准则。第二步是残差连接——ResNet 的突破。网络深到一定程度后准确率不升反降这不是过拟合而是梯度传不下去导致的退化问题。ResNet2015引入跳跃连接skip connection让梯度可以绕过卷积层直接向后传一举把网络深度推到上百层甚至上千层。这个设计的思路其实非常朴素让网络学残差输入和输出之间的差值比学完整映射更容易最坏情况下残差为零、网络退化成恒等映射至少不会变差。第三步是结构自动化与注意力——NAS、EfficientNet 与 Transformer 思路的引入。早期靠人手工调网络结构后来出现了神经架构搜索NAS让机器自己搜EfficientNet 提出了用统一系数同时缩放深度、宽度和分辨率的复合缩放方法再往后Vision Transformer 等把自注意力机制引入图像领域挑战了卷积的统治地位。但要注意在数据量不极端大的场景下精心调优的 CNN 仍然非常能打不是新架构一出现就要立刻换。6. 我踩过的那些坑尺寸对不上、过拟合与学习率6.1 维度不匹配最常见的报错最好用的排查法写 CNN 遇到的第一大报错就是维度不匹配比如RuntimeError: mat1 and mat2 shapes cannot be multiplied。问题的根源永远只有一个全连接层输入维度算错了。我的固定排查法是这样在 forward 函数里加一行打印看在展平之前特征图到底是什么尺寸。def forward(self, x): x self.pool(F.relu(self.conv1(x))) x self.pool(F.relu(self.conv2(x))) print(x.shape) # 调试用看清尺寸再决定fc1的输入 x torch.flatten(x, 1) ...跑一遍控制台会告诉你真实尺寸比如[64, 16, 5, 5]那正确答案就是16*5*5。不要靠脑子算人脑算卷积尺寸出错率极高直接打印最快。这个习惯我从第一次踩坑之后就一直保持后来接手的每一个 CNN 项目开头都会先跑一次尺寸检查。还有一个高频错误是输入图像的通道数对不上。如果你用单通道灰度的卷积核去接三通道彩色输入或者反过来都会报错。判断方法是看数据集加载后的张量形状——[batch, channels, height, width]第二个维度就是通道数千万别跟 batch 搞混。6.2 过拟合训练集 99%测试集 60%这是我做花分类项目时遇到的经典情况训练准确率一路飙到 99% 以上验证集死死卡在 60% 上下。典型的过拟合。当时试了几种手段按效果排序说说数据增强是性价比最高的。对图像做随机翻转、随机裁剪、轻微旋转、颜色抖动本质上是凭空造出了大量新样本。我用随机水平翻转 随机裁剪这一招验证准确率直接从 60% 提到了 78%代价只是几行代码。要注意增强幅度别太夸张——你把猫的图片翻转还是猫但你要是把它旋转 180 度可能就变成了倒立的猫模型反而学乱。Dropout 也很有效。在全连接层之间加nn.Dropout(0.5)训练时随机关掉一半神经元逼着网络不要依赖某几个特定神经元泛化能力会明显提升。但注意 Dropout 只应该在训练时开启评估和推理时应关闭PyTorch 里用model.eval()自动处理这一点很多人不知道推理时不切换模式导致结果不稳定。权重衰减Weight Decay是另一种正则化思路通过在损失里加上权重的平方和抑制权重变得过大。配合 Adam 的weight_decay1e-4是个不错的起点。最后实在不行就减模型容量。如果数据量本来就小堆一个很深的网络必然会过拟合不如老老实实回到浅层网络。6.3 学习率训练不收敛的最大嫌疑犯学习率learning rate设错会表现出两种截然相反的症状认清它们能省下大量调参时间。症状一损失值震荡甚至增大NaN。说明学习率太大每步迈得太狠直接跨过了最低点。我的做法是从大往下试每次除以 10先试 0.1不行试 0.01再不行试 0.001。绝大多数任务在 1e-3 附近能跑通。症状二损失下降极慢几轮下来几乎不动。说明学习率太小每步挪一点点半天走不到最低点。这种时候通常可以往上调 3 到 10 倍。更省心的做法是用学习率调度器比如CosineAnnealingLR或StepLR训练初期用大学习率快速下降后期自动调小做精细收敛。我现在基本都会配一个调度器手动调学习率的次数少了很多。注意换了优化器要重新调学习率。同一套学习率在 SGD 上合适喂给 Adam 可能就太大。Adam 的典型起点是 1e-3SGD 是 1e-2这是两者更新方式差异决定的不能直接照搬。7. 卷积的几个进阶玩法与实际应用场景7.1 3D 卷积当数据多了一个维度前面讲的都是 2D 卷积处理的是单张图像长、宽两个空间维度。但有些数据的自然结构本身就是三维的比如视频多了一维时间、医学 CT 扫描多了一维深度、点云体素。这时候就要用3D 卷积。3D 卷积核的形状是(深度, 高, 宽)比如 3×3×3它在三个维度上同时滑动。相比把视频拆成一张张独立画面用 2D 卷积处理3D 卷积能捕捉跨帧的时序信息——比如一个动作的姿态变化单帧看不出是挥手还是静止但连续几帧一起看就能判断。代价是计算量暴增参数量和显存占用通常是同等的 2D 卷积的数倍。我在做一个动作识别的小实验时对比过同一份视频数据2D CNN 只能靠把多帧堆叠成通道这种取巧方式间接利用时序而 3D CNN 直接建模时空准确率高了几个点但训练时间翻倍。所以选不选 3D CNN得看你的任务里时间维度重不重要以及你的算力扛不扛得住。7.2 CNN 不只用来做图像分类很多人对 CNN 的印象停留在图像分类其实它的应用范围要广得多凡是数据能表示成网格状的都有 CNN 的用武之地目标检测不仅要判断图里有什么还要框出在哪里。代表算法如 YOLO 系列、Faster R-CNN核心都是 CNN 提取特征后接检测头输出边界框和类别。语义分割对图像中每个像素分类把不同物体用不同颜色区分开。医疗影像里勾画肿瘤边界、自动驾驶里区分路面和行人都用这类方法。人脸识别把一张人脸映射成一个特征向量再比对两张脸的向量相似度判断是不是同一个人。非图像领域一维 CNN1D Conv在文本分类、语音识别、心电图分析里也常用因为文本序列、音频波形、心电信号本质上也是一种一维网格。我印象比较深的是一个用 CNN 做设备故障诊断的项目。把振动传感器采集的时序信号转成频谱图然后当成图像喂给 CNN 做分类判断设备处于正常、异常还是严重故障状态。整套思路和图像分类几乎一样只是输入换了个来源。这种把非图像问题转换成图像问题的思路是 CNN 落地中非常实用的一招。7.3 迁移学习小数据集下的现实解法实际项目里你手头往往只有几百上千张图从零训练一个 CNN 必然过拟合。这时候正确姿势是迁移学习拿一个在大数据集上预训练好的模型比如在 ImageNet 上训过的 ResNet把它的卷积层权重直接搬过来只替换和重训最后的分类层。为什么这样做有效因为预训练模型的浅层学到的是通用的边缘、纹理、颜色特征这些特征对所有图像任务都适用深层学到的是更抽象、更任务相关的特征才需要针对你的数据微调。这就是 CNN 特征层级通用性带来的实际红利。两种常见做法做法操作适用场景特征提取冻结全部卷积层只训最后的分类层数据量很小几百张、任务和原任务接近微调解冻部分或全部卷积层用小学习率一起训数据量中等、任务和原任务差异较大微调时有个关键细节学习率要调小通常设成从头训练时的 1/10 甚至 1/100。因为预训练权重已经是很优的起点学习率太大反而会把这些宝贵的权重破坏掉。我第一次做迁移学习时没注意这点直接沿用大学习率结果验证准确率先掉一大截再慢慢爬回来白折腾了几个小时。8. 给不同阶段读者的一点个人建议关于 CNN 的学习路径我按自己的经验给几条实在的建议不搞虚的。如果你是初学者先把 LeNet 手写一遍别一上来就啃 ResNet。很多人卡在 CNN 门口是因为一开始就去看上百层的网络结构图被各种跳跃连接、分组卷积搞晕。LeNet 只有七层把它的每一层尺寸变化手动算一遍你就会对 CNN 有实感后面再看深层网络只是量的积累。李宏毅老师的 CNN 课程讲到感受野和卷积核的时候建议对照一张真实的图像做一遍手动卷积拿纸笔算几个位置比看十遍视频印象都深。如果你已经能调通模型但效果一般优先在数据和增强上花时间而不是急着换架构。我这些年最大的体会是CNN 项目里数据质量 合理增强带来的提升往往超过换个新架构。见过太多人花几天调网络结构准确率涨 1%而认真做一遍数据清洗和增强涨 10% 都不稀奇。如果你在做落地的工程记住推理效率和精度是要权衡的。课堂作业只看准确率但真部署到手机或嵌入式设备上模型大小、推理延迟、内存占用都是硬指标。全局平均池化替代全连接、用深度可分离卷积MobileNet 的核心替代普通卷积这些技巧能在精度损失有限的前提下大幅瘦身值得提前了解。还有一个我反复强调的习惯永远先用小数据、少轮次把整条链路跑通再上全量数据和深层网络。我见过太多人一上来就设 100 个 epoch、上最深的网络结果跑了两小时才发现数据路径写错了。先用几十张图、2 个 epoch 验证数据加载对、前向能过、损失能降、保存能存这条链路确认无误后再放大规模能省下大量等待时间。这个习惯看起来笨但在我做过的每一个项目里都实实在在救过场。CNN 这套东西说到底就是把局部看、滑着看、层层抽象这三个直觉变成了可训练的数学结构。理解了这三点剩下的都是工程细节和调参经验遇到新架构也不用怕拆开来还是这几样东西的组合。
返回列表