十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

卷积神经网络(CNN)核心原理与实战:从LeNet到ResNet的演进与应用

卷积神经网络(CNN)核心原理与实战:从LeNet到ResNet的演进与应用 1. 项目概述从“黑箱”到“白盒”理解CNN的视觉密码刚接触深度学习那会儿卷积神经网络CNN对我来说就是个“黑箱”。我知道它看图很准能识别人脸、分辨猫狗甚至能在医学影像里找到病灶但一打开那些层层叠叠的结构图什么卷积层、池化层、全连接层脑袋就嗡嗡的。后来在几个图像项目里硬着头皮用上了调参调到怀疑人生才慢慢摸到点门道。我发现很多教程把CNN讲得太“玄学”了要么是一堆复杂的数学公式吓退新手要么是只给代码不说人话。今天我就想抛开那些故弄玄虚的部分用一个从业者的视角把CNN从里到外、从原理到实操掰开揉碎了讲清楚。这不仅仅是介绍一个工具更是理解现代计算机视觉乃至许多序列处理任务没错CNN不只用于图像的基石。无论你是想入门深度学习的学生还是需要在项目中应用CNN的工程师或是好奇技术原理的产品经理我希望这篇超过5000字的详解能成为你手边一份随时可查、看了能用的实战指南。2. 核心思路拆解CNN为何是图像处理的“天选之子”在深入细节之前我们必须先回答一个根本问题为什么是CNN传统的全连接神经网络ANN把一张图片的所有像素“拍扁”成一长串数字输入网络这带来了两个致命问题。第一是参数爆炸。一张100x100的灰度图就有1万个像素点如果第一个隐藏层有1000个神经元那么仅这一层就需要1000万10k * 1k个权重参数。对于彩色图3通道和高分辨率图像这个数字会变得完全不可管理导致模型训练极慢且极易过拟合。第二是忽略了像素间的空间关系。对于图像识别而言一个像素点与它上下左右邻居的关系远比它与图像另一角像素的关系重要得多。把图像“拍扁”等于丢弃了这种至关重要的二维空间结构信息。CNN的设计哲学正是为了解决这两个核心痛点。它的思路不是用“蛮力”连接一切而是引入了三个关键的先验假设或者说“归纳偏置”让网络结构更贴合图像数据的本质2.1 局部连接像探照灯一样扫描图像CNN的卷积层不再让一个神经元连接整个输入图像而是只连接输入数据的一个小局部区域比如3x3或5x5的窗口。这个窗口就像一个“探照灯”在图像上从左到右、从上到下依次滑动。每个神经元只“看”这个窗口内的像素并学习从这个局部区域中提取特征如边缘、角点、纹理。这极大地减少了参数数量因为无论输入图像多大一个卷积核即一组固定的权重的参数只由窗口大小决定。2.2 参数共享一个特征探测器走天下这是CNN最精妙的设计之一。同一个卷积核及其权重会被重复应用于输入图像的所有位置。这意味着网络在图像左下角学到的用于检测“垂直边缘”的规则同样适用于图像右上角。这背后的假设是一个有用的特征比如边缘可能出现在图像的任何位置。参数共享不仅再次大幅削减了参数量从“每个位置一套权重”变为“一套权重用于所有位置”还赋予了模型平移不变性的潜力——无论猫在图片的左边还是右边同样的特征探测器都能找到它。2.3 层次化特征提取从边缘到部件再到物体CNN通过堆叠多个卷积层构建了一个从简单到复杂的特征层次结构。浅层网络靠近输入的层的卷积核通常学习到的是最基础、通用的特征比如各种方向的边缘、色块、斑点。这些特征组合起来在中间层形成更复杂的模式比如纹理、网格、车轮、眼睛轮廓等“部件”。最后在深层网络这些部件进一步组合形成高级的、语义化的特征比如“猫脸”、“汽车轮子”、“建筑窗户”。这种模拟了人类视觉系统V1区识别边缘V4区识别形状IT区识别物体的层次化处理是CNN强大表征能力的核心。注意很多人误以为CNN的“卷积”就是严格的数学卷积运算。在实际的深度学习框架如PyTorch, TensorFlow中更准确的说法是“互相关”运算。两者区别在于卷积核是否翻转。但在CNN的语境下由于卷积核的参数是通过学习得到的翻转与否并不影响其表达能力因此大家通常混用这两个术语你只需要知道实际代码里执行的是互相关即可。3. 核心组件深度剖析不只是卷积和池化理解了核心思想我们再来拆解CNN的每一个核心组件。它们就像乐高积木不同的搭建方式构成了ResNet、Inception、DenseNet等各式各样的复杂模型。3.1 卷积层特征提取的发动机卷积层是CNN的绝对核心。它的操作可以用一个生动的比喻拿着一张小卡片卷积核在一张大图片输入特征图上滑动每到一个位置就做一次点乘求和得到一个数字所有位置得到的数字组成一张新的“特征图”。输入与输出输入通常是一个三维张量[高度 宽度 通道数]。对于第一层通道数就是颜色通道RGB为3灰度图为1。经过卷积后输出是另一个三维张量[新高度 新宽度 卷积核个数]。每个卷积核都会生成一张独立的二维特征图所有特征图堆叠起来就形成了输出的通道维度。核心参数详解卷积核大小常见的有1x1, 3x3, 5x5, 7x7。3x3是最主流的选择因为它能在保持感受野增长的同时通过堆叠两层3x3卷积可以获得一层5x5卷积的感受野使用更少的参数9 vs 25和更多的非线性激活使网络更深、表达能力更强。步长卷积核每次滑动的像素距离。步长为1是最常见的选择它保留了最多的空间信息。步长为2则相当于对特征图进行下采样长宽减半常用于替代池化层。填充为了控制输出特征图的大小我们可以在输入图像的边缘补上一圈0零填充。paddingsame意味着进行填充使得输出特征图的长宽与输入相同在步长为1时paddingvalid意味着不填充输出尺寸会缩小。1x1卷积的妙用别小看这个最小的卷积核。它在现代CNN架构中扮演着关键角色1降维/升维灵活地增加或减少特征图的通道数控制计算量。2跨通道信息整合在保持空间尺寸不变的情况下对通道维度进行线性组合可以看作每个像素点上的一个小型全连接网络。3引入额外的非线性在1x1卷积后接激活函数增加网络非线性表达能力。3.2 激活函数引入非线性的灵魂如果没有激活函数无论堆叠多少层卷积整个网络仍然等价于一个线性变换无法拟合复杂函数。激活函数为网络注入了非线性。ReLUf(x) max(0, x)。这是目前最主流、默认的选择。它计算简单、收敛快能有效缓解梯度消失问题。但它也有“神经元死亡”的问题一旦输入为负梯度恒为0该神经元可能永远无法被再次激活。实践中合理的权重初始化和使用变体如Leaky ReLU, PReLU可以缓解。Sigmoid与Tanh在CNN中已较少用于隐藏层。Sigmoid输出在0-1之间适合做概率输出但其两端饱和区梯度接近于0容易导致梯度消失。Tanh输出在-1到1之间是零中心的但同样有梯度饱和问题。Swish/SiLU等新函数在一些最新研究中表现优于ReLU但尚未完全取代其地位。3.3 池化层信息浓缩与空间不变性池化层通常在卷积层之后对特征图进行下采样。它有两个主要目的1逐步降低空间尺寸减少后续层的计算量和参数。2引入一定的平移、旋转、尺度不变性。因为池化操作如取最大值对特征的小范围平移不敏感。最大池化在池化窗口如2x2内取最大值。这是最常用的池化方式它能保留最显著的特征如纹理、边缘在实践中效果通常最好。平均池化取窗口内的平均值。它对背景信息更友好但有时会弱化强特征。全局平均池化将整个特征图HxW池化为一个值取所有像素的平均值。常用于网络末端替代传统的全连接层将每个通道的特征图直接转换为一个标量大大减少了参数并强制了特征图与类别之间的对应关系使模型更具可解释性。3.4 全连接层从特征到决策在经历了若干轮“卷积-激活-池化”后我们得到了高级的、语义化的特征图。全连接层的作用是将这些分布式的特征表示“整合”起来映射到最终的样本标记空间比如1000个图像类别。你可以把它理解为整个网络的“决策委员会”。然而全连接层参数巨多通常占整个网络参数的80%以上容易过拟合。因此现代架构如GoogLeNet, ResNet倾向于使用全局平均池化来替代末尾的全连接层或者使用Dropout等正则化技术。3.5 批归一化层训练过程的稳定器批归一化层并非CNN原生组件但已成为现代深度网络不可或缺的一部分。它在一个小批量Batch的数据上对每个特征通道进行归一化减均值、除以标准差然后进行缩放和偏移。它的好处是革命性的允许使用更高的学习率加速模型收敛。减少对权重初始化的依赖。起到轻微的正则化效果因为每个批次的均值/方差是噪声估计。 在CNN中BN层通常被插入在卷积层之后、激活函数之前也有研究支持放在激活之后。4. 经典网络架构演进与实战启示只看组件不够我们必须看看大师们如何用这些“乐高”搭建出摩天大楼。网络架构的演进史就是一部与梯度消失、网络退化、计算效率搏斗的历史。4.1 LeNet-5开山鼻祖Yann LeCun于1998年提出的用于手写数字识别的网络。结构非常简单卷积 - 池化 - 卷积 - 池化 - 全连接 - 全连接 - 输出。它验证了“卷积-池化”组合的有效性但受限于当时的数据和算力。4.2 AlexNet深度学习的号角2012年ImageNet竞赛冠军将CNN带入大众视野。关键贡献使用ReLU作为激活函数缓解梯度消失训练更快。使用Dropout来减少全连接层的过拟合。使用重叠的最大池化。使用数据增强随机裁剪、水平翻转来增加数据多样性。首次在GPU上成功训练大型CNN。4.3 VGGNet深度与规整之美其核心思想是堆叠更小的卷积核全部使用3x3。2个3x3卷积堆叠其有效感受野相当于一个5x5卷积3个堆叠则相当于一个7x7。这样做的好处是1参数更少3个3x3卷积的参数为3x3x327而一个7x7卷积参数为49。2引入了更多的非线性激活函数使决策函数更具判别力。VGGNet结构非常规整VGG16, VGG19易于理解和迁移学习但参数量巨大计算成本高。4.4 GoogLeNet (Inception v1)宽度与效率之道面对“网络越深参数越多计算越慢”的问题GoogLeNet提出了Inception模块在同一个层级上并行使用不同尺寸的卷积核1x1, 3x3, 5x5和池化操作最后在通道维度上进行拼接。其核心创新是引入了1x1卷积来进行降维在3x3和5x5卷积之前先用1x1卷积减少通道数极大降低了计算量。这种“网络中的网络”结构在增加网络宽度和多样性的同时巧妙地控制了计算复杂度。4.5 ResNet跨越深度的里程碑当网络深度增加到几十甚至上百层时一个反直觉的现象出现了网络性能不升反降。这不是过拟合而是网络退化问题——深层网络的反向传播梯度越来越难以有效传递。ResNet的解决方案是残差学习。它不再让堆叠的层直接拟合一个潜在映射H(x)而是让它们拟合残差F(x) H(x) - x。这样原始映射就变成了 F(x) x。这个简单的快捷连接或称恒等映射使得梯度可以直接从深层反向传播到浅层极大地缓解了梯度消失/爆炸问题使得训练成百上千层的网络成为可能。ResNet是当前应用最广泛的Backbone之一。4.6 轻量化网络演进MobileNet, ShuffleNet为了将CNN部署到手机、嵌入式设备轻量化网络成为重点。其核心思想是分解标准卷积。MobileNet v1使用深度可分离卷积将标准卷积分解为深度卷积每个通道单独卷积和逐点卷积1x1卷积整合通道信息。这能大幅减少计算量和参数量。MobileNet v2引入了倒残差结构和线性瓶颈。与ResNet先降维再升维不同它先升维用1x1卷积增加通道数提供更丰富的特征空间再进行深度卷积最后用线性激活的1x1卷积降维。这在高维空间进行非线性变换效果更好。ShuffleNet核心是通道混洗。在分组卷积中不同组之间的信息不流通。ShuffleNet通过“混洗”操作让不同组的特征在通道维度上重新排列促进了组间信息交换在保证精度的同时进一步降低了计算成本。5. 超越图像CNN的跨界应用与变体CNN的威力早已不局限于图像。其核心能力——从局部相关数据中提取层次化特征——使其在诸多序列和结构化数据上大放异彩。5.1 一维卷积网络处理序列数据将二维卷积核的其中一个维度尺寸设为1就得到了一维卷积。它沿着序列时间方向滑动非常适用于时间序列分析如传感器数据、股票预测和自然语言处理如文本分类、情感分析。在NLP中一个词嵌入序列可以看作是一个“图像”其中“高度”是词向量维度“宽度”是句子长度。不同宽度的卷积核可以捕捉不同长度的词序列特征类似n-gram。5.2 图卷积网络处理非欧数据传统CNN处理的是规整的网格数据如图像像素、序列时间步。但现实世界中很多数据是图结构如社交网络、分子结构、知识图谱。GCN的核心思想是在图的谱域或空域上定义卷积操作让节点能够聚合其邻居节点的信息。这使得CNN的思想得以应用于社交推荐、药物发现、交通预测等领域。5.3 在特定领域的精妙应用医学图像分割如U-Net采用编码器-解码器结构并添加了跳跃连接将编码器的高分辨率细节特征与解码器的上采样语义特征相结合实现了像素级的精确分割在TEM图像识别晶体区域、缺陷位置等方面效果卓越。目标检测如YOLO, Faster R-CNNCNN作为骨干网络提取特征后续接上区域建议网络和检测头完成“是什么物体”和“在哪里”的联合任务。注意力机制与CNN的结合虽然注意力机制源于Transformer但其“动态加权”的思想已被融入CNN。例如SENet通过全局平均池化获得通道级的全局信息然后通过一个小型网络学习每个通道的重要性权重让网络更关注信息量大的通道。这可以看作是一种轻量级的通道注意力。6. 从零构建与训练一个CNN模型以PyTorch为例理论说再多不如动手跑一遍。我们以经典的CIFAR-10数据集10类32x32小图像为例构建一个简化版的VGG风格网络。6.1 环境准备与数据加载import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import torchvision import torchvision.transforms as transforms import matplotlib.pyplot as plt import numpy as np # 数据预处理归一化并做简单增强 transform_train transforms.Compose([ transforms.RandomHorizontalFlip(), # 随机水平翻转 transforms.RandomCrop(32, padding4), # 随机裁剪 transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), # CIFAR-10的均值和标准差 ]) transform_test transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) # 加载数据集 trainset torchvision.datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform_train) trainloader torch.utils.data.DataLoader(trainset, batch_size128, shuffleTrue, num_workers2) testset torchvision.datasets.CIFAR10(root./data, trainFalse, downloadTrue, transformtransform_test) testloader torch.utils.data.DataLoader(testset, batch_size100, shuffleFalse, num_workers2) classes (plane, car, bird, cat, deer, dog, frog, horse, ship, truck)6.2 定义一个简单的CNN模型我们定义一个包含卷积块ConvBNReLUPooling的简单网络。class SimpleCNN(nn.Module): def __init__(self, num_classes10): super(SimpleCNN, self).__init__() # 特征提取部分 self.features nn.Sequential( # 卷积块1: 输入[3,32,32] nn.Conv2d(3, 64, kernel_size3, padding1), # 输出[64,32,32] nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.Conv2d(64, 64, kernel_size3, padding1), # 输出[64,32,32] nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), # 输出[64,16,16] # 卷积块2 nn.Conv2d(64, 128, kernel_size3, padding1), # 输出[128,16,16] nn.BatchNorm2d(128), nn.ReLU(inplaceTrue), nn.Conv2d(128, 128, kernel_size3, padding1), # 输出[128,16,16] nn.BatchNorm2d(128), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), # 输出[128,8,8] # 卷积块3 nn.Conv2d(128, 256, kernel_size3, padding1), # 输出[256,8,8] nn.BatchNorm2d(256), nn.ReLU(inplaceTrue), nn.Conv2d(256, 256, kernel_size3, padding1), # 输出[256,8,8] nn.BatchNorm2d(256), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), # 输出[256,4,4] ) # 分类器部分 self.classifier nn.Sequential( nn.Dropout(p0.5), # 丢弃层防止过拟合 nn.Linear(256 * 4 * 4, 1024), nn.ReLU(inplaceTrue), nn.Dropout(p0.5), nn.Linear(1024, 512), nn.ReLU(inplaceTrue), nn.Linear(512, num_classes) ) def forward(self, x): x self.features(x) x torch.flatten(x, 1) # 将特征图展平 [batch, 256*4*4] x self.classifier(x) return x net SimpleCNN() print(net)6.3 训练与评估循环device torch.device(cuda:0 if torch.cuda.is_available() else cpu) net.to(device) criterion nn.CrossEntropyLoss() # 交叉熵损失函数适用于多分类 optimizer optim.SGD(net.parameters(), lr0.1, momentum0.9, weight_decay5e-4) # 使用带动量的SGD并加入L2正则化 scheduler optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max200) # 使用余弦退火调整学习率 def train(epoch): net.train() running_loss 0.0 for i, data in enumerate(trainloader, 0): inputs, labels data[0].to(device), data[1].to(device) optimizer.zero_grad() # 梯度清零 outputs net(inputs) # 前向传播 loss criterion(outputs, labels) # 计算损失 loss.backward() # 反向传播 optimizer.step() # 参数更新 running_loss loss.item() if i % 100 99: # 每100个batch打印一次 print(f[Epoch {epoch 1}, Batch {i 1}] loss: {running_loss / 100:.3f}) running_loss 0.0 scheduler.step() # 每个epoch后调整学习率 def test(): net.eval() correct 0 total 0 with torch.no_grad(): # 测试时不计算梯度节省内存和计算 for data in testloader: images, labels data[0].to(device), data[1].to(device) outputs net(images) _, predicted torch.max(outputs.data, 1) # 取概率最大的类别 total labels.size(0) correct (predicted labels).sum().item() accuracy 100 * correct / total print(fAccuracy on the 10000 test images: {accuracy:.2f} %) return accuracy # 开始训练 for epoch in range(50): # 训练50个epoch train(epoch) if (epoch 1) % 5 0: # 每5个epoch测试一次 test() print(Finished Training)实操心得在训练初期损失下降很快但准确率可能停滞不前这是正常的因为网络正在学习基础特征。使用学习率预热开始几个epoch用很小的学习率和余弦退火调度器往往比固定学习率或阶梯下降获得更好的效果。对于CIFAR-10一个设计良好的简单CNN达到85%以上的准确率是合理的基准。7. 实战避坑指南与高级技巧纸上得来终觉浅绝知此事要躬行。下面这些坑我几乎每一个都踩过。7.1 数据层面质量决定上限数据增强是必须的对于图像任务随机裁剪、水平翻转是最基础的。还可以尝试色彩抖动、旋转、CutMix、MixUp等更高级的增强。这相当于免费获得了更多训练数据是防止过拟合最有效的手段之一。归一化参数要对transforms.Normalize的均值和标准差必须是你自己训练集的统计值而不是随便抄来的ImageNet参数。用错参数会导致模型收敛慢甚至不收敛。类别不平衡处理如果某些类别的样本特别少可以考虑在损失函数中使用类别权重nn.CrossEntropyLoss(weightclass_weights)或对少数类进行过采样。7.2 模型层面结构与初始化从预训练模型开始除非你的数据集非常大且与ImageNet等通用数据集差异巨大否则强烈建议使用在ImageNet上预训练好的模型如ResNet-50作为起点进行迁移学习。你可以冻结前面的卷积层特征提取器只训练最后的全连接层分类器或者用较小的学习率微调整个网络。这能节省大量时间和计算资源并通常获得更好的性能。权重初始化很重要不要使用默认的初始化。对于使用ReLU的网络nn.init.kaiming_normal_(He初始化) 是标准做法。对于某些层nn.init.xavier_normal_(Glorot初始化) 也可能有效。PyTorch中许多层已内置了合理的初始化。谨慎使用DropoutDropout在全连接层效果显著但在卷积层中使用要小心因为它可能会破坏卷积固有的空间相关性。如果要用概率p通常设置得较小如0.1-0.2。BN层本身也有正则化效果有时可以替代或减少Dropout的使用。7.3 训练过程监控与调参一定要画损失/准确率曲线这是诊断模型状态的“心电图”。训练损失不下降可能是学习率太低、网络结构有问题。训练损失下降但验证损失上升这是典型的过拟合需要加强正则化更多数据增强、Dropout、权重衰减或减少模型复杂度。两者都抖动得厉害可能是学习率太高了。学习率是最重要的超参数使用学习率查找器如PyTorch Lightning中的lr_find来找到一个合适的初始学习率范围。通常选择损失仍在快速下降但尚未暴增的那个点附近的值。梯度裁剪特别是在处理RNN或非常深的网络时梯度爆炸可能导致训练不稳定。使用torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)可以裁剪梯度范数稳定训练。7.4 部署与优化模型剪枝与量化为了部署到资源受限的设备可以对训练好的模型进行剪枝移除不重要的权重连接和量化将32位浮点参数转换为8位整数。PyTorch和TensorFlow都提供了相应的工具。这能在精度损失很小的情况下大幅减少模型体积和推理时间。使用TensorRT/OpenVINO等推理引擎对于生产环境不要直接使用训练框架进行推理。使用NVIDIA的TensorRT或Intel的OpenVINO等工具可以对模型进行图优化、层融合、精度校准从而获得数倍甚至数十倍的推理加速。8. 常见问题排查速查表遇到问题别慌张按这个清单一步步排查。问题现象可能原因排查步骤与解决方案训练损失居高不下1. 学习率过低2. 网络结构错误如激活函数放在BN之前3. 数据预处理错误如归一化参数错误4. 损失函数用错如分类问题用了MSE1. 增大学习率或使用学习率查找器。2. 检查模型forward流程确保顺序是Conv - BN - ReLU。3. 检查数据加载和transform打印几批数据看看数值范围。4. 确认任务类型和损失函数是否匹配。验证准确率远低于训练准确率过拟合1. 模型过于复杂2. 训练数据不足3. 正则化不够1. 简化模型减少层数、通道数。2. 增加数据增强的强度和多样性。3. 增加Dropout率、增大权重衰减系数。训练损失为NaN1. 学习率过高2. 数据中包含异常值如NaN或inf3. 损失函数或网络层计算不稳定如除零1. 大幅降低学习率。2. 检查数据清洗流程。3. 在网络中加入梯度裁剪检查各层输出是否有异常值。GPU内存溢出1. Batch Size过大2. 模型参数量或中间激活值过大3. 存在内存泄漏如张量长期不释放1. 减小Batch Size但可能影响BN统计和收敛稳定性可尝试梯度累积。2. 使用更小的模型或检查是否有不必要的缓存如torch.no_grad。3. 使用torch.cuda.empty_cache()并确保在验证/测试时使用with torch.no_grad()。模型预测所有样本为同一类1. 类别极度不平衡模型倾向于预测多数类2. 学习率太大导致优化“跑飞”3. 最后一层全连接层或损失函数有误1. 使用加权的损失函数或重采样。2. 降低学习率并检查训练初期的损失曲线。3. 检查模型输出维度是否等于类别数Softmax是否被正确应用CrossEntropyLoss自带Softmax。最后我想分享一个最深的体会理解CNN乃至任何深度学习模型最好的方式就是动手实现一个简化版。不要满足于调包。尝试用NumPy从零实现卷积、池化操作你会对步长、填充、输入输出尺寸的计算有刻骨铭心的理解。然后再用PyTorch/TensorFlow这样的框架去构建和训练一个真正的模型去观察损失曲线去调试超参数。这个从理论到实践再从实践反馈加深理论理解的过程是任何教程都无法替代的。CNN的世界还在快速演进注意力机制、动态卷积、神经架构搜索等新技术不断融入但万变不离其宗其局部连接、参数共享和层次化提取的核心思想依然是照亮你探索深度学习道路的一盏明灯。
返回列表