资讯动态

卷积神经网络CNN入门:从卷积核到图像分类实战

发布时间:2026/10/16 1:25:47 来源:尧图企业网站定制
1. 从一个反直觉的问题说起机器凭什么“看”得比人准1.1 先别急着谈原理聊聊“看清楚”这件事到底难在哪你可能觉得“看”这件事再简单不过了。睁眼光线进入眼球大脑处理一下就知道眼前是猫是狗、是红灯还是绿灯。整个过程快到我们根本意识不到中间发生了什么。但如果你真的试着把“看”拆解成一步步可执行的指令就会发现这件事复杂得离谱。我举个具体的例子。假设你面前有一张 224×224 像素的彩色图片每个像素有红绿蓝三个通道的数值范围是 0 到 255。那么这张图在计算机眼里就是一个 224×224×3 的数字矩阵总共大约 15 万个数字。你要从这 15 万个数字里判断出“这是一只猫”难度相当于让你在一堆毫无规律的彩票号码里找出规律——而且这个规律还得适用于你从来没见过的猫。人类视觉系统经过几百万年进化已经内置了大量“硬件加速”视网膜边缘检测、视觉皮层方向选择性神经元、层级化的特征抽象机制。而计算机一开始什么都没有它面对的只是一堆数字。所以问题的本质不是“机器能不能看”而是“我们怎么把‘看’这件事翻译成机器能执行的数学运算”。卷积神经网络Convolutional Neural Network简称 CNN就是目前最成功的一种翻译方案。它的核心思路可以用一句话概括模仿人类视觉皮层的层级处理机制从局部到全局、从低级到高级地提取图像特征。听起来很抽象对吧别急我后面会用最直白的方式把它拆开。1.2 为什么传统方法搞不定“看图”这件事在 CNN 成为主流之前人们尝试过很多让机器“看图”的办法。最朴素的一种叫全连接网络把图片的 15 万个数字拉直成一个长向量然后一层一层地做矩阵乘法最后输出分类结果。这个方法在小图片上勉强能用但一遇到真实场景就崩了。原因有三个第一参数量爆炸。假设第一层隐藏层有 1000 个神经元那么仅这一层的权重数量就是 15 万 × 1000 1.5 亿个参数。这还只是一层。参数量太大带来的直接后果是训练极慢、极易过拟合而且需要海量标注数据才能收敛。第二丢失空间信息。把图片拉直成向量之后原本相邻的像素在向量里可能离得很远。左上角的像素和右下角的像素在向量里的距离跟它和旁边像素的距离可能差不多。但图像的核心信息恰恰藏在空间关系里——猫的耳朵在头顶眼睛在耳朵下方这种位置关系一旦被打乱识别就无从谈起。第三对平移毫无鲁棒性。同一只猫在图片左边和右边拉直后的向量完全不同。全连接网络必须分别学习“左边的猫”和“右边的猫”这显然不合理。我们希望网络学到的是“猫”这个概念本身而不是“猫在某个特定位置”的模板。CNN 针对这三个问题给出了非常优雅的解决方案接下来我逐个拆解。1.3 这篇文章适合谁看能解决什么问题如果你是对深度学习感兴趣但被各种术语劝退的开发者或者你已经用过一些现成的图像分类接口但说不清背后到底发生了什么再或者你正在准备面试、需要把 CNN 讲得让面试官眼前一亮——那这篇内容就是写给你的。我不会堆砌公式也不会只给你一个“卷积就是特征提取”这种正确的废话。我会从“为什么这样设计”出发把每一步的直觉、数学原理、实操细节和踩坑经验都讲清楚。读完你至少能做到两件事一是能用大白话跟别人解释 CNN 到底在干什么二是自己动手搭一个简单的图像分类网络时知道每个参数该怎么调、为什么这么调。2. 卷积到底在“卷”什么把数学运算翻译成人话2.1 用一个手电筒扫过图片的比喻理解卷积卷积这个词听起来很数学但它的直觉非常朴素。想象你拿一个很小的手电筒在一个黑暗的房间里照一张大照片。手电筒的光斑很小只能照亮照片的一小块区域。你从左上角开始每次向右移动一小步照一下记录下你看到的东西照完一行再往下移动一小步继续照。最终你把整张照片都扫了一遍每个位置都记录了一个“局部观察结果”。这个“手电筒”在 CNN 里叫做卷积核也叫滤波器通常是一个 3×3 或 5×5 的小矩阵。每个位置的“观察结果”就是卷积核与对应图像区域做逐元素乘法再求和的数值。扫完整张图之后得到的结果叫做特征图Feature Map。用数学语言描述假设输入图像是 ( I )卷积核是 ( K )那么特征图上位置 ((i,j)) 的值就是[ F(i,j) \sum_{m}\sum_{n} I(im, jn) \cdot K(m,n) ]这个公式看起来吓人但它说的就是“把卷积核盖在图像的一个小区域上对应位置相乘全部加起来”。就这么简单。2.2 为什么卷积核能“看出”边缘和纹理单个卷积核本质上是一个模式匹配器。它只对某种特定的局部模式响应强烈对其他模式响应微弱。我举一个最经典的例子垂直边缘检测。假设有一个 3×3 的卷积核-1 0 1 -1 0 1 -1 0 1当这个卷积核盖在一块“左边暗、右边亮”的图像区域上时左边三列乘以 -1右边三列乘以 1中间一列乘以 0。最终求和的结果是一个很大的正数。反过来如果盖在“左边亮、右边暗”的区域上结果就是一个很大的负数。如果盖在颜色均匀的区域上正负抵消结果接近 0。所以这个卷积核的输出特征图上数值大的位置就代表原图中那里有一条垂直边缘。类似地把卷积核旋转 90 度就能检测水平边缘换成其他数值组合就能检测对角线、斑点、纹理等。这就是 CNN 的第一层通常学到的东西边缘、角点、简单纹理。这些是构成所有复杂视觉图案的基本元素就像积木一样。2.3 权值共享CNN 参数量骤降的关键设计回到之前全连接网络参数量爆炸的问题。CNN 是怎么解决的答案就是权值共享。还是用那个手电筒的比喻你用手电筒扫整张照片的时候用的始终是同一个手电筒不会说照左上角用红色手电筒、照右下角换蓝色手电筒。CNN 也是这样同一个卷积核在整张图片上滑动所有位置共用同一组权重。这个设计带来的好处是巨大的。一个 3×3 的卷积核只有 9 个参数加上偏置是 10 个但它可以扫描任意大小的图片。对比全连接层动辄上亿的参数这简直是降维打击。更重要的是权值共享赋予了 CNN平移不变性。同一只猫出现在图片左边还是右边同一个卷积核都会在对应位置产生强烈响应。网络不需要分别学习“左边的猫”和“右边的猫”它学到的是“猫的耳朵长什么样”“猫的眼睛长什么样”这些与位置无关的局部特征。注意严格来说卷积提供的是“平移等变性”而非“平移不变性”。等变性指的是输入平移后输出也跟着平移不变性指的是输出不随输入平移改变。池化层才真正带来一定程度的平移不变性。但在实际讨论中很多人把这两个概念混着用你心里清楚区别就行。2.4 多通道卷积彩色图片是怎么处理的真实图片通常是 RGB 三通道的所以输入是一个 224×224×3 的三维张量。卷积核也必须对应地变成三维如果卷积核大小是 3×3那么它实际上是 3×3×3第三个维度对应输入通道数。计算的时候卷积核在空间维度上滑动但在通道维度上是“全连接”的——也就是说每个输出值都是 3×3×3 27 个乘积之和。这样得到的特征图是二维的224×224×1。但一个卷积核只能提取一种特征这显然不够。所以实际中我们会用多个卷积核比如 64 个。每个卷积核独立地在输入上滑动产生 64 张特征图叠在一起就是 224×224×64 的输出张量。这 64 个通道分别代表不同种类的局部特征。这里有一个容易混淆的点输入通道数决定每个卷积核的深度输出通道数等于卷积核的个数。这两个数字是独立的不要搞混。3. 从局部到全局CNN 的层级架构是怎么搭起来的3.1 卷积层、激活层、池化层的三明治结构一个典型的 CNN 并不是只有卷积层。它是由三种基本层交替堆叠而成的“三明治”卷积层负责提取局部特征输出特征图。激活层负责引入非线性让网络能拟合复杂函数。池化层负责降采样减小特征图尺寸扩大感受野。这三层组合在一起就构成了一个基本的“卷积块”。多个卷积块串联起来就形成了深度网络。我拿一个经典的配置举例输入 224×224×3 的图片经过第一组卷积块64 个 3×3 卷积核 ReLU 2×2 最大池化输出变成 112×112×64。再经过第二组128 个 3×3 卷积核 ReLU 2×2 最大池化输出变成 56×56×128。如此反复几次最后特征图的空间尺寸越来越小通道数越来越多。这个变化趋势背后的逻辑是随着层数加深网络关注的范围越来越大提取的特征越来越抽象。浅层看到的是边缘和纹理中层看到的是眼睛、鼻子、轮子这些部件深层看到的是整张脸、整辆车。空间尺寸缩小是为了降低计算量通道数增加是为了容纳更多种类的抽象特征。3.2 激活函数为什么 ReLU 成了标配如果没有激活函数多层卷积叠加起来本质上还是一个线性变换跟单层卷积没有本质区别。激活函数的作用就是引入非线性让网络能逼近任意复杂的函数。早期常用的是 Sigmoid 和 Tanh但它们有个致命问题梯度消失。当输入很大或很小时Sigmoid 的导数趋近于 0反向传播时梯度一层层相乘很快就衰减到几乎为零导致浅层参数几乎无法更新。ReLURectified Linear Unit的出现改变了局面。它的定义极其简单( f(x) \max(0, x) )。正数原样输出负数归零。就这么一个简单的函数解决了梯度消失问题正区间导数恒为 1计算速度极快还带来了稀疏激活的好处。当然 ReLU 也有缺点负数区间梯度为零可能导致某些神经元“死亡”永远不再激活。后续出现了 Leaky ReLU、ELU、GELU 等变体但在大多数图像任务中普通 ReLU 依然是性价比最高的选择。实操心得如果你训练 CNN 时发现损失下降很慢或者某些层输出全是零优先检查学习率是不是太大导致 ReLU 神经元大面积死亡。把学习率调小一个数量级试试往往能解决问题。3.3 池化层降维的同时保留关键信息池化层的操作比卷积层还简单。最常用的是最大池化用一个 2×2 的窗口在特征图上滑动每次取窗口内最大的那个值。步长通常设为 2这样输出特征图的尺寸正好是输入的一半。为什么取最大值而不是平均值直觉上的解释是最大值代表了这个局部区域最强烈的特征响应。如果某个区域检测到了边缘那么边缘处的响应值会很大最大池化会把这个强信号保留下来而把周围较弱的响应丢弃。这相当于在说“这个区域有没有边缘有而且在这里。”池化带来的好处有三个一是减小计算量特征图尺寸减半意味着后续计算量减少到四分之一二是扩大感受野让后续卷积核能“看到”更大的范围三是提供一定程度的平移鲁棒性局部小位移不会改变最大池化的输出。但池化也不是没有争议。近年来一些研究表明在某些任务中用步长为 2 的卷积代替池化效果更好因为卷积有可学习的参数而池化是固定的。不过对于入门和大多数常规任务最大池化依然是稳妥的选择。3.4 全连接层与输出层从特征到类别经过多组卷积块之后我们得到了一组高度抽象的特征图。接下来的任务是根据这些特征判断图片属于哪个类别。这一步通常由全连接层完成。全连接层把特征图拉直成一个长向量然后通过一两层神经网络做最终的分类。最后一层的神经元数量等于类别数输出经过 Softmax 函数转换成概率分布。比如做 10 类分类最后一层就是 10 个神经元输出 10 个概率值加起来等于 1。这里有一个常见的误解很多人以为全连接层是 CNN 的“核心”。其实恰恰相反CNN 的核心价值在卷积部分全连接层只是把提取到的特征映射到类别空间。近年来流行的全局平均池化Global Average Pooling甚至直接去掉了全连接层对每张特征图取平均值后直接接 Softmax参数量更少过拟合风险更低。4. 动手搭一个迷你 CNN从零实现图像分类4.1 环境准备与数据加载理论说了这么多不实操等于白学。我用一个经典的图像分类任务来演示完整的流程。数据集选用一个公开的小型彩色图像数据集包含 10 个类别每类约 6000 张 32×32 的图片。这个规模刚好适合单卡训练几分钟就能跑完一轮。环境方面Python 3.8 以上PyTorch 或 TensorFlow 都可以。我以 PyTorch 为例因为它调试起来更直观。import torch import torch.nn as nn import torchvision import torchvision.transforms as transforms transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) trainset torchvision.datasets.CIFAR10( root./data, trainTrue, downloadTrue, transformtransform) trainloader torch.utils.data.DataLoader( trainset, batch_size64, shuffleTrue, num_workers2)归一化那一步很关键。把像素值从 [0, 1] 映射到 [-1, 1]可以让输入数据的均值为 0加速收敛。如果你跳过这一步训练初期损失可能震荡得很厉害。4.2 网络结构定义与参数计算下面定义一个简单的 CNN。结构是两组卷积块 三个全连接层。class MiniCNN(nn.Module): def __init__(self): super().__init__() self.conv1 nn.Conv2d(3, 32, 3, padding1) self.conv2 nn.Conv2d(32, 64, 3, padding1) self.pool nn.MaxPool2d(2, 2) self.fc1 nn.Linear(64 * 8 * 8, 256) self.fc2 nn.Linear(256, 64) self.fc3 nn.Linear(64, 10) self.relu nn.ReLU() def forward(self, x): x self.pool(self.relu(self.conv1(x))) x self.pool(self.relu(self.conv2(x))) x x.view(-1, 64 * 8 * 8) x self.relu(self.fc1(x)) x self.relu(self.fc2(x)) x self.fc3(x) return x来算一下每层的输出尺寸。输入 32×32×3。conv1 用 32 个 3×3 卷积核padding1所以空间尺寸不变输出 32×32×32。池化后变成 16×16×32。conv2 用 64 个 3×3 卷积核输出 16×16×64。再池化变成 8×8×64。拉直后是 4096 维接全连接层。参数量方面conv1 有 3×3×3×32 32 896 个参数conv2 有 3×3×32×64 64 18496 个参数。全连接层 fc1 有 4096×256 256 1048832 个参数。可以看到全连接层占了绝大部分参数这也是为什么现代 CNN 倾向于用全局平均池化替代全连接层。4.3 训练循环与超参数选择训练循环的代码很标准但有几个超参数的选择需要说明。device torch.device(cuda if torch.cuda.is_available() else cpu) net MiniCNN().to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.SGD(net.parameters(), lr0.01, momentum0.9) for epoch in range(20): running_loss 0.0 for i, (inputs, labels) in enumerate(trainloader): inputs, labels inputs.to(device), labels.to(device) optimizer.zero_grad() outputs net(inputs) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() print(fEpoch {epoch1}, Loss: {running_loss/len(trainloader):.4f})学习率设为 0.01配合动量 0.9是 SGD 的经典配置。如果你用 Adam学习率可以设 0.001。批量大小 64 是折中选择太小训练不稳定太大泛化可能变差。实操心得训练 CNN 时第一轮结束后先看看损失有没有降到合理范围。如果损失还在 2.0 以上10 类分类的随机猜测损失是 ln(10)≈2.3说明学习率可能太小或者网络结构有问题。如果损失变成 NaN八成是学习率太大导致梯度爆炸。4.4 数据增强让小数据集也能训出好模型上面用的数据集每类有 6000 张图片已经算比较充裕了。但如果你面对的是每类只有几百张甚至几十张的小数据集就必须靠数据增强来扩充样本多样性。常用的增强手段包括随机水平翻转、随机裁剪、颜色抖动、随机旋转。这些操作在保持图片语义不变的前提下制造出不同的外观变化让网络学到更鲁棒的特征。transform_train transforms.Compose([ transforms.RandomHorizontalFlip(), transforms.RandomCrop(32, padding4), transforms.ColorJitter(brightness0.2, contrast0.2), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ])注意增强只用在训练集上验证集和测试集必须用原始图片否则评估结果不可靠。另外增强力度要适中过度增强会让网络把时间浪费在学习那些人为制造的极端变换上。5. 常见问题与排查技巧实录5.1 训练损失不下降怎么办这是最常见的问题可能的原因和排查顺序如下现象可能原因排查方法损失始终在 2.3 附近学习率太小或网络没学到东西把学习率调大 10 倍试试损失震荡剧烈学习率太大或批量太小减小学习率增大批量损失变成 NaN梯度爆炸减小学习率加梯度裁剪训练损失降但验证损失升过拟合加数据增强、Dropout、权重衰减某些层输出全零ReLU 死亡换 Leaky ReLU 或减小学习率我自己的经验是八成的问题出在学习率上。先用一个很小的学习率跑几轮确认损失能稳定下降然后再逐步调大找到最优值。这个“学习率扫描”的过程虽然笨但非常有效。5.2 过拟合的识别与应对过拟合的典型表现是训练集准确率持续上升验证集准确率在某个点之后开始下降。这说明网络开始“死记硬背”训练样本而不是学习通用规律。应对过拟合的手段按优先级排序增加数据。这是最根本的解决办法但很多时候不现实。数据增强。用变换制造更多样本成本低效果好。Dropout。在全连接层之间随机丢弃一部分神经元强制网络不依赖特定路径。权重衰减。在损失函数里加上参数平方和抑制参数过大。早停。验证集准确率不再上升就停止训练简单粗暴但有效。注意Dropout 在卷积层用得比较少因为卷积层的参数共享本身就有正则化效果。主要用在全连接层丢弃率 0.5 是常见起点。5.3 卷积核大小怎么选3×3 为什么成了主流理论上卷积核越大感受野越大能捕捉的上下文信息越多。但实际中 3×3 几乎成了默认选择原因有两个。第一两个 3×3 卷积堆叠的感受野等于一个 5×5 卷积但参数量更少2×3×318 vs 5×525而且中间多了一次非线性激活表达能力更强。三个 3×3 堆叠等效于一个 7×7参数量优势更明显。第二小卷积核计算效率更高。现代 GPU 对小卷积核的优化非常好3×3 卷积可以充分利用硬件并行性。所以除非有特殊需求卷积核大小从 3×3 开始试就对了。1×1 卷积有另外的用途——它不改变空间尺寸只做通道间的信息融合和降维在 ResNet、Inception 等架构中大量使用。5.4 特征图可视化看看网络到底学到了什么训练完之后你可能好奇网络到底学到了什么。一个直观的办法是把卷积核的输出特征图可视化出来。def visualize_feature_maps(model, image): x image.unsqueeze(0) for name, layer in model.named_children(): if isinstance(layer, nn.Conv2d): x layer(x) x torch.relu(x) # 取前16个通道画出来 fig, axes plt.subplots(4, 4, figsize(8, 8)) for i, ax in enumerate(axes.flat): if i x.shape[1]: ax.imshow(x[0, i].detach().cpu(), cmapviridis) ax.axis(off) plt.show() x torch.max_pool2d(x, 2)跑一下你会发现第一层的特征图还能看出原图的轮廓有些通道对边缘响应强有些对颜色块响应强。到了第二层、第三层特征图就越来越抽象人眼已经很难直接解读了。这正好印证了“层级抽象”的直觉。5.5 迁移学习站在预训练模型的肩膀上如果你手头的数据集很小从零训练一个 CNN 几乎不可能得到好结果。这时候迁移学习就是救命稻草。思路很简单拿一个在大规模数据集上预训练好的模型比如在 ImageNet 上训练的 ResNet把它的卷积层当作固定的特征提取器只训练最后的分类层。因为卷积层学到的边缘、纹理、部件特征具有很强的通用性换个任务照样能用。import torchvision.models as models resnet models.resnet18(pretrainedTrue) for param in resnet.parameters(): param.requires_grad False resnet.fc nn.Linear(512, 10) # 替换最后一层适配新任务 optimizer torch.optim.Adam(resnet.fc.parameters(), lr0.001)如果数据量稍微多一点还可以微调部分深层卷积层让它们适应新任务的特定特征。通常从最后一组卷积块开始解冻学习率设小一点比如 0.0001避免破坏已经学好的通用特征。实操心得迁移学习时新任务的类别数如果和预训练模型差距很大建议先只训练分类层几轮等损失稳定后再解冻卷积层微调。一上来就全网络微调很容易把预训练学到的有用特征破坏掉。6. 感受野、深度与宽度CNN 设计中的权衡艺术6.1 感受野的计算与意义感受野指的是特征图上一个像素对应原图中的区域大小。感受野越大这个像素“看到”的原始信息越多越能捕捉全局上下文。计算感受野有一个递推公式从最后一层往前推每经过一个卷积层核大小 k步长 s感受野 ( R ) 更新为 ( R R \times s (k - s) )。经过池化层同理。举个例子输入 32×32经过一个 3×3 卷积步长 1感受野是 3。再经过 2×2 最大池化步长 2感受野变成 3×2 (2-2) 6。再经过一个 3×3 卷积感受野变成 6×1 (3-1) 8。感受野太小网络只能看到局部细节无法理解整体结构。感受野太大又可能引入过多无关信息增加计算负担。所以设计网络时需要在两者之间找平衡。6.2 深度与宽度的取舍增加深度更多层可以让网络学到更抽象的特征但也会带来梯度消失和训练困难的问题。ResNet 通过残差连接解决了这个问题把输入直接加到输出上让梯度可以“走捷径”回传。这个设计让训练上百层的网络成为可能。增加宽度更多通道可以让每层容纳更多种类的特征但参数量和计算量会平方级增长。MobileNet 等轻量级网络通过深度可分离卷积来降低计算量把标准卷积拆成“逐通道卷积 1×1 逐点卷积”参数量能降到原来的八分之一到九分之一。实际选择时如果算力充足且追求精度优先增加深度如果部署在移动端或嵌入式设备优先考虑轻量级架构。6.3 批归一化让深层网络训练不再痛苦批归一化Batch Normalization是 CNN 发展史上的一个重要里程碑。它的做法是在每个卷积层之后、激活函数之前对每个通道的激活值做标准化减去均值、除以标准差然后再乘以一个可学习的缩放因子、加上一个可学习的偏移量。为什么有效一个直观的解释是它让每层的输入分布保持稳定避免了“内部协变量偏移”问题。深层网络训练时浅层参数更新会导致深层输入分布不断变化批归一化把这个分布拉回标准正态附近让深层更容易学习。实际效果非常明显可以用更大的学习率、对初始化不那么敏感、训练速度显著加快。现代 CNN 几乎标配批归一化有些架构甚至用它替代了 Dropout 的部分功能。注意批归一化在训练和推理时的行为不同。训练时用当前批次的均值和方差推理时用训练过程中累积的滑动平均值。切换模型到评估模式时别忘了调用model.eval()否则推理结果会不稳定。7. 从 CNN 到更远的视觉世界7.1 CNN 的局限性与被挑战的地方CNN 在图像领域统治了将近十年但它并非没有短板。最核心的问题是局部性偏置卷积核只关注局部区域虽然通过堆叠层数可以扩大感受野但对于需要全局推理的任务比如理解整张图的语义关系CNN 的效率并不高。另外CNN 对旋转和尺度变化的鲁棒性有限。同一个物体旋转 90 度CNN 可能需要额外的数据增强才能识别。虽然池化提供了一定程度的平移不变性但旋转和缩放不变性需要靠数据增强或特殊设计来弥补。近年来基于自注意力机制的视觉模型在多个任务上超越了 CNN。自注意力允许每个位置直接关注图中任意其他位置天然具备全局建模能力。但自注意力计算量随图像尺寸平方增长对高分辨率图像不太友好。目前很多先进架构采用 CNN 与自注意力混合的设计取两者之长。7.2 给想深入下去的人几条实用建议如果你读完这篇内容想继续往深处走我的建议是按这个顺序推进第一先把一个经典 CNN 从头训练一遍。不要直接用预训练模型自己定义网络、调参、观察损失曲线。这个过程会让你对 CNN 的每一个组件有肌肉记忆般的理解。第二读几篇里程碑论文的原文。LeNet、AlexNet、VGG、ResNet、MobileNet每篇都代表了一种设计思路的突破。不用全读懂重点看它们的动机和核心创新点。第三动手做可视化。把卷积核权重画出来把特征图激活画出来把注意力热力图叠在原图上。视觉反馈比任何文字描述都直观。第四尝试迁移学习解决一个你自己的实际问题。找一个你感兴趣的图片分类任务收集几百张图片用预训练模型微调。走完整个流程之后你对 CNN 的理解会从“知道”变成“会用”。我个人在实际操作中的体会是CNN 最迷人的地方不在于它的数学有多复杂而在于它的设计哲学极其朴素从局部到全局从简单到复杂用共享权重应对位置变化用层级抽象构建语义理解。这套思路不仅适用于图像对很多其他领域的问题也有启发。理解了这一点你再看任何深度学习架构都能更快地抓住它的核心逻辑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑