1. 从一节公开课说起计算机视觉到底在解决什么问题很多人第一次接触“计算机视觉”这个词是在某门深度学习公开课的某一讲里。视频里讲师放了一张图片说“让机器看懂这张图”然后开始讲卷积、边缘检测、池化。看完之后感觉懂了但关掉视频又说不清楚它到底能干什么。我自己当年也是这个状态笔记记了好几页真正动手跑代码的时候才发现理论和落地之间隔着一条不小的沟。这篇内容就是围绕“计算机视觉”这个主题把我在学习深度学习相关课程时积累的笔记、踩过的坑、以及后来在实际项目里验证过的经验做一次系统性的梳理。它适合刚学完神经网络基础、准备进入视觉方向的人也适合已经能跑通Demo但说不清原理的人。核心关键词就一个计算机视觉。我会从它解决的问题讲起一路讲到卷积网络的细节、实操中的参数选择、以及那些只有真正跑过模型才会知道的注意事项。先说清楚它是什么。计算机视觉简单讲就是让计算机从图像或视频中提取信息、做出判断的一类技术总称。人眼看一张照片能瞬间分辨出猫、狗、桌子、马路但计算机看到的只是一个数字矩阵每个像素是0到255之间的数值。视觉任务要做的就是从这个矩阵里找出规律最终输出我们想要的结论——这张图里有没有猫、猫在哪个位置、这只猫是什么品种。它能做的事情大致分几类图像分类这张图是什么、目标检测图里有什么、分别在哪、语义分割每个像素属于什么类别、图像生成根据描述造一张图。不同任务对应不同的网络结构和训练方式但底层都离不开卷积这个核心操作。这也是为什么几乎所有视觉课程都会花大量篇幅讲卷积神经网络因为它是整个方向的基石。提示如果你连全连接网络的前向传播和反向传播都还没搞明白建议先补上这一课再来看视觉内容。卷积网络本质上是在全连接的基础上加了“局部连接”和“权值共享”两个约束基础不牢会越看越糊涂。2. 为什么视觉任务不能直接用全连接网络2.1 参数量爆炸这个硬伤假设你有一张224乘224的彩色图片展平之后是224乘224乘3也就是大约15万个输入值。如果第一层隐藏层只放1000个神经元光这一层的权重参数就是1.5亿个。这还只是一层深一点的网络参数量会到几十亿。参数量大带来的直接后果是显存装不下、训练慢、极易过拟合。我早期做过一个实验用全连接网络去分类一批32乘32的小图参数量勉强能接受但准确率怎么调都上不去。后来换成卷积结构同样的数据参数量降了一个数量级准确率反而涨了十几个点。这个对比让我真正理解了为什么视觉领域必须用卷积。2.2 图像的空间结构被浪费了全连接网络把图片展平成一维向量这一步操作直接把像素之间的空间关系丢掉了。原本相邻的两个像素展平之后可能隔了很远网络很难学到“局部特征”。但图像的核心信息恰恰藏在局部结构里——边缘、角点、纹理这些都是相邻像素之间的关系。卷积操作保留了这种空间结构。一个3乘3的卷积核在图片上滑动每次只看一个小窗口这样学到的就是局部特征。而且同一个卷积核在整个图片上共享意味着不管猫出现在左上角还是右下角同一个“猫耳朵检测器”都能起作用。这就是平移不变性的来源也是卷积网络在视觉任务上碾压全连接网络的根本原因。2.3 卷积到底在算什么用一个具体的例子说明。假设有一个5乘5的灰度图用一个3乘3的卷积核去卷它。卷积核从左上角开始覆盖图片的3乘3区域对应位置相乘再求和得到一个数。然后卷积核向右滑动一格再算一个数。滑完一行再往下滑。最终得到一个3乘3的输出这叫特征图。这个过程用生活化的类比就像你拿一个放大镜在图片上逐块扫描每扫一块就记录一个“匹配分数”。卷积核里的数值就是“你关心的模式”分数高说明这块区域和模式很像。训练网络的过程就是让卷积核里的数值自动调整直到它能检测出对分类最有用的模式。注意卷积核的数值不是人工设计的是反向传播学出来的。早期层学到的往往是边缘、颜色块这类低级特征深层学到的是眼睛、轮子这类高级语义特征。这个“从低级到高级”的层次结构是卷积网络可解释性的重要来源。3. 卷积网络的核心组件逐个拆解3.1 卷积层特征提取的主力卷积层有几个关键参数需要理解清楚。卷积核大小常见的有3乘3、5乘5、7乘7。3乘3是最常用的因为两个3乘3堆叠的感受野等于一个5乘5但参数量更少、非线性更强。步长控制卷积核滑动的间隔步长为1时输出尺寸基本不变步长为2时输出尺寸减半相当于下采样。填充是在图片边缘补零目的是控制输出尺寸让边缘像素也能被充分卷积。输出尺寸的计算公式是输出边长等于输入边长减去卷积核大小加上两倍填充再除以步长最后加1。这个公式我建议背下来调网络结构的时候会反复用到。举个例子输入32卷积核5填充0步长1输出就是32减5加0除以1再加1等于28。如果填充2输出就变回32这就是所谓的“same padding”。3.2 池化层降维和抗扰动池化层不做卷积它只是在一个小窗口里取最大值或平均值。最大池化最常用窗口2乘2、步长2效果是把特征图的长宽各减半参数量减少四分之三。池化的作用是减少计算量、扩大感受野、增强对小幅平移的鲁棒性。但池化也有争议。有些新架构用步长为2的卷积代替池化认为池化丢失了太多信息。我自己的经验是在小数据集上池化能有效防止过拟合在大数据集上用卷积下采样可能效果更好。没有绝对的对错要看具体任务和数据量。3.3 激活函数引入非线性卷积和池化都是线性操作堆再多层也等价于一个线性变换。激活函数的作用是引入非线性让网络能拟合复杂函数。视觉任务里最常用的是ReLU因为它计算简单、梯度不容易消失。但ReLU有个问题叫“神经元死亡”——如果某个神经元的输入长期为负梯度就永远是零这个神经元就废了。后来出现了Leaky ReLU、ELU等变体在负半轴给一个很小的斜率避免死亡问题。我在实际项目里默认用ReLU如果发现训练后期loss不降了会换成Leaky ReLU试试。这个切换成本很低但有时候能救活一个模型。3.4 批归一化训练加速器批归一化是视觉网络里的标配。它在每一层之后把输出重新标准化到均值为0、方差为1的分布然后再缩放平移。这样做的好处是允许更大的学习率、减少对初始化的敏感、有一定正则化效果。我做过对比实验同一个网络加批归一化之后训练轮数能减少三分之一最终准确率还略高。但要注意批归一化在训练和推理时的行为不一样。训练时用当前批次的均值和方差推理时用全局统计量。如果推理时忘了切换模式结果会完全乱掉。这个坑我踩过排查了半天才发现是模式没切对。4. 一个完整视觉项目的实操流程4.1 数据准备比模型更重要的环节很多人把精力全花在调网络结构上但实际项目中数据质量对最终效果的影响往往更大。我经手过一个图像分类任务一开始准确率卡在70%上不去后来花了两天时间清洗数据、剔除标注错误的样本、做数据增强准确率直接跳到85%。模型一行没改。数据增强是视觉任务里性价比最高的操作。常用的手段包括随机裁剪、随机翻转、颜色抖动、旋转、缩放。这些操作等价于凭空造出更多训练样本能显著降低过拟合。但要注意增强的力度要和任务匹配。比如识别数字的任務翻转增强就不合适因为6翻转过来变成9标签就错了。提示数据增强只在训练时做验证和测试时绝对不能用。我见过有人在验证集上也做随机裁剪导致每次验证结果都不一样完全没法比较模型好坏。4.2 网络结构设计从简单开始新手最容易犯的错误是一上来就搭一个很深的网络。我的建议是先用一个浅层的小网络跑通全流程确认数据管道没问题、训练能收敛、评估指标合理然后再逐步加深加宽。一个典型的入门级卷积网络结构是这样的卷积层加ReLU加池化重复两到三次然后展平接全连接层最后接输出层。卷积核数量从32开始每经过一次池化翻倍。这个结构在MNIST和CIFAR-10上都能跑到不错的准确率而且训练快、容易调试。4.3 训练配置学习率和批大小学习率是最重要的超参数没有之一。太大导致震荡不收敛太小导致收敛太慢。常用的起点是0.001配合Adam优化器。如果训练loss震荡厉害就降到0.0001。如果loss下降太慢就升到0.01试试。批大小影响梯度估计的稳定性。批太小梯度噪声大训练不稳定批太大显存吃紧而且泛化性能可能下降。常用的批大小是32、64、128。我的习惯是从64开始根据显存占用调整。学习率调度也很关键。固定学习率往往不是最优的常用的策略是每隔若干轮把学习率乘以0.1或者用余弦退火。我实测下来余弦退火在大多数任务上比固定学习率好最终准确率能高出一到两个点。4.4 评估与调优看准指标再动手训练过程中要同时监控训练集和验证集的loss与准确率。如果训练loss降但验证loss升说明过拟合了需要加正则化或数据增强。如果两个都降但验证准确率不涨可能是模型容量不够需要加深网络。如果两个都不降可能是学习率太大或数据有问题。混淆矩阵是分类任务里非常有用的工具。它能告诉你哪些类别容易被混淆。比如猫和狗的分类器如果混淆矩阵显示大量猫被预测成狗那就要针对性地补充猫的样本或者检查标注是否有问题。只看总体准确率会掩盖很多细节。5. 那些只有跑过模型才知道的坑5.1 显存不够用的几种解法显存溢出是视觉任务里最常见的报错。解法有几个减小批大小、用更小的输入尺寸、用梯度累积模拟大批次、用混合精度训练。混合精度是我最推荐的方式它把部分计算转成半精度浮点显存占用能降三分之一到一半速度还能提升而且对最终精度的影响通常很小。但混合精度有个坑某些操作在半精度下会溢出。如果发现loss变成NaN先检查是不是混合精度导致的。解决办法是给这些操作加一个缩放因子或者把这几层强制转回单精度。5.2 过拟合的判断和处理过拟合的典型表现是训练准确率远高于验证准确率。处理手段按优先级排序第一加数据增强第二加Dropout第三加权重衰减第四减小模型容量。我一般按这个顺序试因为数据增强不增加推理成本Dropout和权重衰减会稍微影响训练速度减小模型容量是最后手段。Dropout在卷积网络里的用法和全连接网络不太一样。全连接层后面通常加Dropout卷积层后面一般不加因为卷积层参数量少本身就不容易过拟合。如果非要在卷积层加Dropout率要设得很低比如0.1。5.3 迁移学习小数据集的救命稻草如果你的数据集只有几千张图从零训练一个卷积网络几乎不可能得到好结果。这时候要用迁移学习拿一个在大数据集上预训练好的网络把最后的分类层换成你自己的类别数然后微调。微调有两种策略一种是只训练最后的分类层前面的卷积层冻结另一种是所有层都参与训练但用很小的学习率。数据量越少冻结的层应该越多。我一般先冻结所有卷积层训练几轮等分类层稳定了再解冻最后几个卷积块一起微调。这样比一上来就全解冻效果更稳。注意迁移学习时预处理必须和预训练模型保持一致。比如预训练用的是ImageNet的均值和方差你也要用同样的值去归一化你的数据。这个细节很容易被忽略但影响很大。5.4 常见问题速查表问题现象可能原因排查方向loss变成NaN学习率太大、混合精度溢出降低学习率、检查混合精度配置验证准确率不涨过拟合、数据标注错误加数据增强、检查标注质量训练速度极慢数据加载瓶颈、批大小太小检查数据管道、增大批大小显存溢出批太大、输入尺寸太大减小批、用混合精度、梯度累积推理结果全错训练推理模式未切换检查批归一化和Dropout的模式6. 从分类到检测视觉任务的进阶路线6.1 目标检测的基本思路分类任务只回答“图里有什么”检测任务还要回答“在哪里”。主流做法是在图片上生成大量候选框对每个框判断类别并回归位置偏移。两阶段方法先筛选候选框再分类精度高但速度慢单阶段方法直接在每个位置预测类别和框速度快但小目标检测稍弱。我建议的进阶路线是先把分类做熟理解卷积特征提取的流程然后再看检测。检测网络里的骨干部分就是分类网络只是后面接了额外的预测头。分类没搞明白直接看检测会觉得很乱。6.2 数据标注的注意事项检测任务需要标注边界框标注质量直接影响模型上限。我见过一个项目标注框普遍偏大导致模型学出来的框也偏大定位精度始终上不去。重新标注之后同样的网络结构定位误差降了一半。标注时要注意框要贴紧目标边缘不要留太多空白遮挡目标要标注可见部分小目标不要漏标。如果预算允许至少让两个人独立标注一批数据计算一致性一致性低说明标注标准不清晰需要重新对齐。6.3 视觉任务的落地考量实验室里跑出高准确率是一回事真正部署到生产环境是另一回事。落地时要考虑推理速度能不能满足业务要求、模型大小能不能塞进目标设备、对光照和角度的鲁棒性够不够、异常输入怎么处理。我的一般做法是先训练一个大模型追求精度上限然后用知识蒸馏或剪枝压缩成小模型最后在真实场景数据上做一轮微调。这个过程比单纯调网络结构复杂得多但也是视觉技术真正产生价值的地方。7. 我个人在实际操作中的几点体会学计算机视觉这几年最大的感受是理论看一遍就够代码要反复写。卷积的计算过程看视频觉得很简单但自己手写一遍前向传播和反向传播才会真正理解每个维度的变化。我建议每个学视觉的人都用numpy手写一个小的卷积网络不用深两三层就够写完再去看框架的API会有豁然开朗的感觉。另一个体会是不要迷信最新架构。每年都有新网络刷新榜单但很多改进在具体任务上带来的提升很有限。把ResNet这类经典结构吃透把数据管道和训练流程做扎实比追新架构的收益大得多。我见过太多人花大量时间复现最新论文结果数据增强没做对、学习率没调好最终效果还不如老老实实用ResNet。最后分享一个小技巧训练视觉模型时先把图片尺寸调小跑一遍完整流程确认代码没问题、loss能降再放大尺寸正式训练。这样能省下大量等待时间也更容易定位问题。我早期经常直接上大尺寸结果跑了一晚上发现数据路径写错了白白浪费算力。