欢迎光临
我们一直在努力

现代卷积神经网络(二):NiN与GoogLeNet,打破常规的结构魔法

上一篇我们讲了 AlexNet 和 VGG,它们都把“深度 CNN 真能做事”这件事证明得很扎实。

AlexNet 更像是一次突破:堆更深、更宽的卷积层,性能明显上去了。VGG 则把网络设计“模块化”:一组组 3×3 卷积 + 最大汇聚,像积木一样反复堆叠,结构清晰、好复用。

但网络越深、通道越多,问题也就越明显:

  • 全连接层太重
    卷积层辛苦提特征,最后一展平接全连接层,参数量会瞬间爆炸,不仅训练慢,还特别吃显存。

  • 卷积核大小很难选
    1×1、3×3、5×5 各有优点。小核抓细节,大核看范围,到底该选谁?只选一个尺度就容易漏掉另一种特征。

  • 于是,今天的两个主角就登场了:

    • NiN(Network in Network,网络中的网络):用 1×1 卷积在“每个像素位置”做小型处理,再配合全局平均汇聚,削弱甚至替代笨重的全连接层。
    • GoogLeNet:用 Inception 块把多种卷积路线并行,让网络自己学会组合不同尺度的特征。

    一、先认识 1×1 卷积:最小但很关键

    在理解 NiN 和 GoogLeNet 之前,我们必须先把 1×1 卷积讲清楚,因为它是这两类网络里的“高频零件”。

    很多小白第一次看到 1×1 卷积会疑惑:卷积核只有一个格子,它连旁边像素都看不到,有什么用?

    答案是:

    1×1 卷积不负责看空间邻居,它主要负责融合通道信息、改变通道数量。

    换句话说,它不是在“看邻居”,而是在“调通道”。所以它虽然小,但很关键。

    说明一下:本文统一用“通道”这个说法,你也可能在别的资料里看到它被称为“特征图数”或“feature maps”。本质都是指同一维度上的多张特征图。

    假设某一层的输出形状是:

    批量大小 x 64通道 x 高 x 宽

    某个像素位置上,不是只有一个数字,而是有 64 个通道值。1×1 卷积会在同一个位置,把这 64 个数字加权组合成新的通道。

    你可以把它理解成:

    • 空间位置不动(不看邻居);
    • 只在“通道维度”做一次线性组合,再加上非线性激活。

    所以它像什么?

    它像一个“站在每个像素点上的小型全连接层”,专门把通道信息重新混合。

    如果输出通道数是 32,那么每个像素点上的 64 维向量,就会被变换成 32 维向量,这就是“降维”;反过来变成 128 维,就是“升维”。

    举个更具体的小例子(只看一个像素点):

    原来这个像素点有 3 个通道值: [2, 0, 1]
    1×1 卷积想要输出 2 个通道

    第 1 个输出通道 = 2*0.5 + 0*0.2 + 1*0.1 = 1.1
    第 2 个输出通道 = 2*(-0.3) + 0*0.7 + 1*0.4 = -0.2

    你可以看到,1×1 卷积做的其实就是“通道方向的加权组合”。

    这里的权重没有“必须加起来等于 1”的要求,它们是训练中自动学习的参数,可以是任意实数(正的、负的都可以),还通常会带一个偏置项。只有在像注意力这类“归一化权重”的场景,才会特意让权重和为 1。

    再用一个小示意图把过程画出来(只看一个像素点):

    输入通道(3个): [x1, x2, x3]
    | | |
    | | | (权重矩阵)
    v v v
    输出通道(2个): [y1, y2]

    y1 = w11*x1 + w12*x2 + w13*x3
    y2 = w21*x1 + w22*x2 + w23*x3

    这说明 1×1 卷积的“过程结果”就是:在同一空间位置上,把多个通道线性组合成新的通道。

    1×1 卷积常见作用有三个(也是它在现代 CNN 里最常见的三种“岗位”):

  • 升维:把通道数变多,增强表达能力。
  • 降维:把通道数变少,减少后续计算量。
  • 通道融合:让不同通道之间产生新的组合。
  • 这颗“小螺丝”,后面会反复出现,你会发现它是“省计算 + 增表达”的万能小工具。


    二、NiN:把全连接层变轻

    1. 全连接层为什么麻烦?

    传统 CNN 常见结构是:

    卷积层 -> 汇聚层 -> 卷积层 -> 汇聚层 -> 展平 -> 全连接层 -> 输出

    问题就出在“展平 -> 全连接层”。

    展平之后,本来是一个 C×H×WC\\times H\\times WC×H×W 的三维特征图,直接被拉成一条超长向量。然后再接全连接层,就会产生大量参数。

    简单画一下这个过程:

    特征图(C x H x W)
    | 展平
    v
    超长向量(长度 = C*H*W)
    | 全连接
    v
    分类输出

    结果就是:只要 C、H、WC、H、WCHW 稍微大一点,全连接层的参数量就会急剧增长。

    假设卷积层最后输出:

    512通道 x 7高 x 7宽

    一展平就是:

    512 x 7 x 7 = 25088

    如果再接一个 4096 神经元的全连接层,参数量大约是:

    25088 x 4096 ≈ 1亿

    这还只是其中一层。参数多会带来三个麻烦:

    • 训练慢;
    • 占显存;
    • 容易过拟合(尤其是数据集不够大时)。

    NiN 的思路就是:能不能少用这种庞大的全连接层?甚至让它“隐身”,只用卷积和汇聚完成分类?

    2. NiN 块:卷积后面接小网络

    NiN 的全称是 Network in Network,直译就是“网络中的网络”。

    它的想法是:普通卷积层只是在局部区域里提取特征,但每个位置上不同通道之间的组合也很重要。那就在普通卷积后面,加上几个 1×1 卷积,让每个像素位置都拥有一个“小型网络”来处理通道信息。

    你可以把一个 NiN 块理解成:

    • 先用常规卷积“看空间”;
    • 再用 1×1 卷积“拌通道”;
    • 把通道混合得更聪明。

    用流程图直观表示就是:

    #mermaid-svg-2DmzKZC4uFPBx7z9{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2DmzKZC4uFPBx7z9 .error-icon{fill:#552222;}#mermaid-svg-2DmzKZC4uFPBx7z9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2DmzKZC4uFPBx7z9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .marker.cross{stroke:#333333;}#mermaid-svg-2DmzKZC4uFPBx7z9 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2DmzKZC4uFPBx7z9 p{margin:0;}#mermaid-svg-2DmzKZC4uFPBx7z9 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .cluster-label text{fill:#333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .cluster-label span{color:#333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .cluster-label span p{background-color:transparent;}#mermaid-svg-2DmzKZC4uFPBx7z9 .label text,#mermaid-svg-2DmzKZC4uFPBx7z9 span{fill:#333;color:#333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .node rect,#mermaid-svg-2DmzKZC4uFPBx7z9 .node circle,#mermaid-svg-2DmzKZC4uFPBx7z9 .node ellipse,#mermaid-svg-2DmzKZC4uFPBx7z9 .node polygon,#mermaid-svg-2DmzKZC4uFPBx7z9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2DmzKZC4uFPBx7z9 .rough-node .label text,#mermaid-svg-2DmzKZC4uFPBx7z9 .node .label text,#mermaid-svg-2DmzKZC4uFPBx7z9 .image-shape .label,#mermaid-svg-2DmzKZC4uFPBx7z9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-2DmzKZC4uFPBx7z9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2DmzKZC4uFPBx7z9 .rough-node .label,#mermaid-svg-2DmzKZC4uFPBx7z9 .node .label,#mermaid-svg-2DmzKZC4uFPBx7z9 .image-shape .label,#mermaid-svg-2DmzKZC4uFPBx7z9 .icon-shape .label{text-align:center;}#mermaid-svg-2DmzKZC4uFPBx7z9 .node.clickable{cursor:pointer;}#mermaid-svg-2DmzKZC4uFPBx7z9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .arrowheadPath{fill:#333333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2DmzKZC4uFPBx7z9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2DmzKZC4uFPBx7z9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2DmzKZC4uFPBx7z9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2DmzKZC4uFPBx7z9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2DmzKZC4uFPBx7z9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2DmzKZC4uFPBx7z9 .cluster text{fill:#333;}#mermaid-svg-2DmzKZC4uFPBx7z9 .cluster span{color:#333;}#mermaid-svg-2DmzKZC4uFPBx7z9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2DmzKZC4uFPBx7z9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2DmzKZC4uFPBx7z9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-2DmzKZC4uFPBx7z9 .icon-shape,#mermaid-svg-2DmzKZC4uFPBx7z9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2DmzKZC4uFPBx7z9 .icon-shape p,#mermaid-svg-2DmzKZC4uFPBx7z9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2DmzKZC4uFPBx7z9 .icon-shape .label rect,#mermaid-svg-2DmzKZC4uFPBx7z9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2DmzKZC4uFPBx7z9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2DmzKZC4uFPBx7z9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2DmzKZC4uFPBx7z9 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    输入特征图

    普通卷积 kxk

    ReLU

    1×1 卷积

    ReLU

    1×1 卷积

    ReLU

    输出特征图

    这个流程的结果是:既保留空间信息,又在通道维度上做更复杂的组合。

    代码如下:

    from torch import nn

    def nin_block(in_channels, out_channels, kernel_size, strides, padding):
    # NiN 块:一个普通卷积 + 两个 1×1 卷积
    # 普通卷积负责提取局部空间特征,后面的 1×1 卷积负责通道混合与非线性变换
    return nn.Sequential(
    # 主卷积:决定感受野大小、步幅与边界填充
    nn.Conv2d(in_channels, out_channels,
    kernel_size, stride=strides, padding=padding),
    nn.ReLU(),
    # 1×1 卷积:在每个像素位置上做通道融合,等价于位置上的小型全连接层
    nn.Conv2d(out_channels, out_channels, kernel_size=1),
    nn.ReLU(),
    # 再叠一层 1×1 卷积:进一步增加通道间的非线性组合能力
    nn.Conv2d(out_channels, out_channels, kernel_size=1),
    nn.ReLU()
    )

    你可以把这个块理解成:

  • 先用普通卷积看局部空间;
  • 再用两个 1×1 卷积混合通道;
  • 每一步后面都接 ReLU,增加非线性表达能力。
  • 这样做的好处是:空间信息和通道信息都能被充分处理,但参数量又不会像大规模全连接层那样“爆炸”。

    3. 全局平均汇聚:不再暴力展平

    NiN 还有一个非常重要的设计:全局平均汇聚(Global Average Pooling)。

    传统做法:

    最后特征图 -> 展平 -> 全连接层 -> 类别分数

    NiN 的做法:

    最后特征图的通道数 = 类别数 -> 每个通道求平均 -> 类别分数

    举个例子,假设要做 10 分类。NiN 让最后一层卷积直接输出 10 个通道:

    • 第 1 个通道负责“类别 1”的证据;
    • 第 2 个通道负责“类别 2”的证据;
    • 第 10 个通道负责“类别 10”的证据。

    每个通道可能还是一张小图,比如 5×5。全局平均汇聚就把每张小图求一个平均值,得到 10 个数,正好对应 10 个类别。

    这一步的直觉是:

    • 如果某个通道整体都“亮”,说明它的类别证据强;
    • 平均一下,就得到一个稳定的类别分数。

    而且这种做法几乎不引入额外参数,对过拟合更友好。

    nn.AdaptiveAvgPool2d((1, 1))

    这行代码的意思是:不管输入特征图的高宽是多少,都平均汇聚成 1×1。

    你可以把它理解成“把一整张特征图压成一个代表值”。

    举个更直观的小例子(只看一个通道):

    输入特征图是 2×2:
    [[1, 3],
    [5, 7]]

    全局平均汇聚结果 = (1 + 3 + 5 + 7) / 4 = 4

    这说明它并不关心空间位置细节,而是只保留“整体强度”。

    再用一个小示意图表示它的过程和结果:

    通道内的特征图(5×5) –> 求平均 –> 一个数(该通道的分数)

    4. NiN 的入门记忆法

    NiN 的核心可以记成两句话:

    用 1×1 卷积在每个像素位置上做通道融合。
    用全局平均汇聚减少对大型全连接层的依赖。

    它让 CNN 变得更轻,也启发了后面很多网络设计,比如后来几乎所有现代 CNN 都会用到全局平均汇聚的思路。


    三、GoogLeNet:不同卷积路线一起上

    VGG 的思路很统一:几乎都用 3×3 卷积。

    但真实图片很复杂。有些特征很小,比如边缘、纹理;有些特征更大,比如眼睛、轮子、脸部轮廓。不同大小的卷积核,擅长看的范围不一样。

    如果只用一种卷积核,你就像只拿一种“放大镜”去看世界,细节可能很清楚,但整体结构又看不全。

    那到底该用哪个?

    GoogLeNet 的回答很直接:

    不要只选一个,让它们并行工作。

    这就是 Inception 块。

    它的核心思想是:同一层里开多条路,让网络自己学会拼不同尺度的特征。

    1. Inception 块的四条路线

    一个 Inception 块里,输入会被分成四条路线:

  • 1×1 卷积路线
    负责快速做通道变换。

  • 1×1 卷积 + 3×3 卷积路线
    先降维,再看中等范围。

  • 1×1 卷积 + 5×5 卷积路线
    先降维,再看更大范围。

  • 最大汇聚 + 1×1 卷积路线
    先提取强特征,再调整通道数。

  • 四条路线的输出高宽保持一致,最后在通道维度上拼接起来。

    可以把它想成“四个小专家各自做一份报告,最后把报告合并”。

    用一张并行流程图表示:

    #mermaid-svg-HvprAXUxbdGnrdDp{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HvprAXUxbdGnrdDp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HvprAXUxbdGnrdDp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HvprAXUxbdGnrdDp .error-icon{fill:#552222;}#mermaid-svg-HvprAXUxbdGnrdDp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HvprAXUxbdGnrdDp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HvprAXUxbdGnrdDp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HvprAXUxbdGnrdDp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HvprAXUxbdGnrdDp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HvprAXUxbdGnrdDp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HvprAXUxbdGnrdDp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HvprAXUxbdGnrdDp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HvprAXUxbdGnrdDp .marker.cross{stroke:#333333;}#mermaid-svg-HvprAXUxbdGnrdDp svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HvprAXUxbdGnrdDp p{margin:0;}#mermaid-svg-HvprAXUxbdGnrdDp .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-HvprAXUxbdGnrdDp .cluster-label text{fill:#333;}#mermaid-svg-HvprAXUxbdGnrdDp .cluster-label span{color:#333;}#mermaid-svg-HvprAXUxbdGnrdDp .cluster-label span p{background-color:transparent;}#mermaid-svg-HvprAXUxbdGnrdDp .label text,#mermaid-svg-HvprAXUxbdGnrdDp span{fill:#333;color:#333;}#mermaid-svg-HvprAXUxbdGnrdDp .node rect,#mermaid-svg-HvprAXUxbdGnrdDp .node circle,#mermaid-svg-HvprAXUxbdGnrdDp .node ellipse,#mermaid-svg-HvprAXUxbdGnrdDp .node polygon,#mermaid-svg-HvprAXUxbdGnrdDp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HvprAXUxbdGnrdDp .rough-node .label text,#mermaid-svg-HvprAXUxbdGnrdDp .node .label text,#mermaid-svg-HvprAXUxbdGnrdDp .image-shape .label,#mermaid-svg-HvprAXUxbdGnrdDp .icon-shape .label{text-anchor:middle;}#mermaid-svg-HvprAXUxbdGnrdDp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HvprAXUxbdGnrdDp .rough-node .label,#mermaid-svg-HvprAXUxbdGnrdDp .node .label,#mermaid-svg-HvprAXUxbdGnrdDp .image-shape .label,#mermaid-svg-HvprAXUxbdGnrdDp .icon-shape .label{text-align:center;}#mermaid-svg-HvprAXUxbdGnrdDp .node.clickable{cursor:pointer;}#mermaid-svg-HvprAXUxbdGnrdDp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HvprAXUxbdGnrdDp .arrowheadPath{fill:#333333;}#mermaid-svg-HvprAXUxbdGnrdDp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HvprAXUxbdGnrdDp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HvprAXUxbdGnrdDp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HvprAXUxbdGnrdDp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HvprAXUxbdGnrdDp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HvprAXUxbdGnrdDp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HvprAXUxbdGnrdDp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HvprAXUxbdGnrdDp .cluster text{fill:#333;}#mermaid-svg-HvprAXUxbdGnrdDp .cluster span{color:#333;}#mermaid-svg-HvprAXUxbdGnrdDp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HvprAXUxbdGnrdDp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HvprAXUxbdGnrdDp rect.text{fill:none;stroke-width:0;}#mermaid-svg-HvprAXUxbdGnrdDp .icon-shape,#mermaid-svg-HvprAXUxbdGnrdDp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HvprAXUxbdGnrdDp .icon-shape p,#mermaid-svg-HvprAXUxbdGnrdDp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HvprAXUxbdGnrdDp .icon-shape .label rect,#mermaid-svg-HvprAXUxbdGnrdDp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HvprAXUxbdGnrdDp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HvprAXUxbdGnrdDp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HvprAXUxbdGnrdDp :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    输入特征图

    1×1 卷积

    1×1 卷积

    3×3 卷积

    1×1 卷积

    5×5 卷积

    3×3 最大汇聚

    1×1 卷积

    通道拼接

    输出特征图

    结果就是:同一层同时看到小范围、中范围、大范围的特征,再把它们合在一起。

    import torch
    from torch import nn
    from torch.nn import functional as F

    class Inception(nn.Module):
    def __init__(self, in_channels, c1, c2, c3, c4):
    super().__init__()

    # 路线1:1×1 卷积,快速做通道变换
    self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)

    # 路线2:先 1×1 降维,再用 3×3 看中等范围
    self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)
    self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)

    # 路线3:先 1×1 降维,再用 5×5 看更大范围
    self.p3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)
    self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)

    # 路线4:先最大汇聚提强特征,再用 1×1 调整通道数
    self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
    self.p4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)

    def forward(self, x):
    # 四条路线并行计算,最后在通道维度拼接
    p1 = F.relu(self.p1_1(x))
    p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))
    p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
    p4 = F.relu(self.p4_2(self.p4_1(x)))

    # dim=1 表示在通道维度拼接
    return torch.cat((p1, p2, p3, p4), dim=1)

    这段代码看起来比 VGG 复杂,但主线很清楚:

    同一个输入,走四条不同路线;每条路线看问题的角度不同;最后把结果合并。

    换个说法:网络不需要在“选一个卷积核”,而是直接把多个尺度都用上,再让自己学会如何组合。

    2. 为什么路线里经常先放 1×1 卷积?

    如果直接对很多通道做 5×5 卷积,计算量会很大。GoogLeNet 在 3×3 和 5×5 卷积前面加 1×1 卷积,常常是为了先减少通道数。

    可以直观理解成:先把“厚厚的一摞书”压薄,再让大卷积核去翻。这样既保留信息,又不会让计算量爆炸。

    给一个具体的“参数量对比”小例子:

    假设输入通道 = 128,输出通道 = 32

    直接 5×5 卷积参数量:
    5*5*128*32 = 102,400

    先 1×1 降维到 16 通道,再做 5×5:
    1*1*128*16 = 2,048
    5*5*16*32 = 12,800
    总计 = 14,848

    结果非常直观:先降维再卷积,参数量大幅减少。

    举个直观例子:

    512通道 -> 先用1×1压到32通道 -> 再做5×5卷积

    这样后面的 5×5 卷积就轻很多。

    所以,GoogLeNet 里的 1×1 卷积很像一个“中转站”:

    • 先把厚厚的通道压薄;
    • 再交给大卷积核处理;
    • 最后把不同路线的结果拼起来。

    3. GoogLeNet 的价值

    GoogLeNet 的厉害之处在于:它很深,但参数量并不夸张。

    它综合使用了几个关键思想:

    • 多路线并行,提取不同尺度特征;
    • 1×1 卷积降维,减少计算量;
    • 借鉴全局平均汇聚,减少大型全连接层。

    它告诉我们:

    网络不一定只能一层接一层往下排,也可以在同一层里分出多条路,再把结果合并。


    四、NiN 和 GoogLeNet 对比

    网络重点设计解决的问题小白记忆
    NiN 1×1 卷积 + 全局平均汇聚 全连接层太重 用小网络替代大尾巴
    GoogLeNet Inception 多路线并行 卷积核大小难选择 1×1、3×3、5×5 一起上

    这两个网络都体现了一个变化:

    CNN 不再只是简单地“卷积、汇聚、全连接”,而是开始认真设计网络内部的信息流动方式。

    对新手来说,可以把它理解成:以前只是“堆层数”,现在开始“讲策略”。

    再用一个生活化的对比小例子:

    如果你关心“轻量、省参数” -> 更像 NiN
    如果你关心“多尺度、多视角” -> 更像 GoogLeNet


    五、小结

    这一篇你需要记住四件事:

  • 1×1 卷积虽然不看邻居像素,但能融合通道、升降维、减少计算量,是现代 CNN 的高频工具。
  • NiN 用 1×1 卷积增强局部表达,用全局平均汇聚减少全连接层,让网络更轻、更不容易过拟合。
  • GoogLeNet 的 Inception 块让多种卷积路线并行,自动覆盖不同尺度的特征。
  • 现代 CNN 的设计重点,逐渐从“堆更多层”变成“让信息更聪明地流动”。
  • 如果用一句话收尾:

    NiN 让网络变轻,GoogLeNet 让网络变聪明。

    下一篇我们要面对一个更深层的问题:网络越深真的越好吗?为什么有时加深之后反而更难训练?这就要轮到 批量规范化(Batch Normalization) 和 ResNet 出场了。

    (注:文档部分内容参考《动手学深度学习》)
    《动手学深度学习》现代卷积神经网络:https://zh.d2l.ai/chapter_convolutional-modern/index.html

    赞(0)
    未经允许不得转载:171主机测评 » 现代卷积神经网络(二):NiN与GoogLeNet,打破常规的结构魔法
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址