← 返回主题列表
Q
QianXun
@QianXun · 2026年06月13日 09:24 · 4浏览

《GoMLX从入门到精通》第11章:卷积与注意力——两大基础架构

Chapter 11

---

11.1 全连接的困境

上一章的两层 MLP 处理 MNIST(28×28=784 维)没问题,784 个输入 → 128 个隐层神经元 → 7936 个参数。不大。

但如果你处理一张 224×224 的彩色图像:224×224×3 = 150,528 个输入。连接到 128 个神经元 = 150,528 × 128 ≈ 1927 万个参数。仅第一层。而且——你把一张 224×224 的图像展平成一维向量时,完全破坏了空间结构。相邻像素的空间关系、远处的边缘、形状的轮廓——全丢了。

卷积神经网络(CNN)就是为这个场景发明的。

---

11.2 卷积的核心思想:参数共享 + 局部感受野

卷积用一个小的滑动窗口(卷积核)扫过整张图。同一个窗口,用同一组参数,在图像的不同位置检测同一种模式。

import (
    "github.com/gomlx/gomlx/pkg/ml/context"
    "github.com/gomlx/gomlx/pkg/ml/layers"
)

// 输入:[batch, height, width, channels]
// 卷积:3×3 窗口,32 个输出通道
x := layers.Convolution(ctx.In("conv1"), input).
    Channels(32).KernelSizePerAxis(3, 3).Strides(1).PadSame().Done()

一个 3×3 的卷积核只有 9 个权重 + 1 个偏置 = 10 个参数。无论输入图像是 32×32 还是 224×224,卷积核的参数数量不变——因为它在整张图上共享。这就是参数共享:10 个参数检测全图的一种模式,而不是每个位置各用 10 个参数。

32 个输出通道 = 32 种不同的模式检测器:一个检测水平边缘、一个检测竖直边缘、一个检测某种颜色过渡……

多层卷积的层级抽象:

  • 第一层:检测边缘、颜色块
  • 第二层:检测由边缘组成的纹理
  • 第三层:检测由纹理组成的物体部件
  • 第四层及以上:检测完整物体
---

11.3 一个完整的 CNN 流水线

import (
    "github.com/gomlx/gomlx/pkg/ml/context"
    "github.com/gomlx/gomlx/pkg/core/graph"
    "github.com/gomlx/gomlx/pkg/ml/layers"
    "github.com/gomlx/gomlx/pkg/ml/layers/activations"
)

func CNNModel(ctx *context.Context, input *graph.Node) *graph.Node {
    // Block 1: Conv → ReLU → MaxPool
    x := layers.Convolution(ctx.In("conv1"), input).
        Channels(32).KernelSizePerAxis(3, 3).PadSame().Done()
    x = activations.Relu(x)
    x = graph.MaxPool(x).WindowPerAxis(2, 2).Strides(2).Done()

    // Block 2: 更多卷积
    x = layers.Convolution(ctx.In("conv2"), x).
        Channels(64).KernelSizePerAxis(3, 3).PadSame().Done()
    x = activations.Relu(x)
    x = graph.MaxPool(x).WindowPerAxis(2, 2).Strides(2).Done()

    // Block 3: 更深
    x = layers.Convolution(ctx.In("conv3"), x).
        Channels(128).KernelSizePerAxis(3, 3).PadSame().Done()
    x = activations.Relu(x)

    // 展平 → 全连接分类头
    // 注意:两次 MaxPool 后尺寸减半两次,假设输入为 H×W,则此时为 (H/4)×(W/4)
    x = graph.Reshape(x, -1, 128*(input.Shape().Dimensions[1]/4)*(input.Shape().Dimensions[2]/4))
    x = layers.DenseWithBias(ctx.In("classifier"), x, 10)
    return x
}

PadSame() 自动计算 padding,输出尺寸 = 输入尺寸(stride=1 时)。MaxPool 做下采样——把 2×2 区域的最大值取出来,图像尺寸减半,特征图数量不变。

---

11.4 注意力机制:从"固定权重"到"上下文相关权重"

全连接层:每个输入和每个输出之间的权重是训练好就固定的——模型无论看到什么输入,权重都一样。

注意力机制:权重是根据输入动态计算的。模型看到不同的输入,它会"关注"输入中的不同部分。

这就是"注意力"这个名字的来源——不是所有输入同等重要。对于当前任务,有些输入比另一些更重要。

---

11.5 Query、Key、Value 是怎么回事?

注意力的核心靠 Query、Key、Value 三个概念驱动:

Query(查询): "我想找什么?"
Key(键):     "我有什么?"
Value(值):   "我提供的实际内容是什么?"

注意力 = Softmax(Query · Key^T / √d) · Value

一步步拆解:

1. Query · Key^T:计算 Query 和所有 Key 的匹配分数。如果 Q 和某个 K 的向量方向一致(点积大),说明这个位置跟当前的查询高度相关。

2. Softmax(...):把匹配分数转成概率分布(所有权重加起来等于 1)。

3. × Value:按权重加权求和 Value——相关位置的值被放大,不相关位置的值被抑制。

用日常类比:你在图书馆找一本关于"Go 并发"的书。Query = "Go 并发"。书架上的每本书都有一个 Key(书的主题摘要)。你对比 Q 和每本书的 K,找到最匹配的几本(Softmax 给高分)。然后你按匹配度加权阅读这些书的 Value(书的实际内容)。

---

11.6 GoMLX 中的注意力

import (
    "github.com/gomlx/gomlx/pkg/ml/context"
    "github.com/gomlx/gomlx/pkg/core/graph"
    "github.com/gomlx/gomlx/pkg/ml/layers"
    "github.com/gomlx/gomlx/pkg/ml/layers/attention"
)

// 多头自注意力——Transformer 的核心
func SelfAttentionBlock(ctx *context.Context, x *graph.Node) *graph.Node {
    // MultiHeadAttention:Q, K, V 都来自同一个输入 x(自注意力)
    attnOut := attention.MultiHeadAttention(
        ctx.In("attn"), x, x, x, // query, key, value
        8,  // 8 个注意力头
        64, // 每头维度 64 → 总输出维度 8×64=512
    ).Done()
    // 残差连接 + LayerNorm
    x = graph.Add(x, attnOut)
    x = layers.LayerNormalization(ctx.In("norm1"), x, -1).Done()
    return x
}

多头注意力:同时做多组 Q/K/V,每组关注不同的方面。8 个头 = 8 种不同的"注意力模式"——一个关注句首、一个关注动词、一个关注数字……

---

11.7 CNN vs Attention:什么时候用哪个?

维度CNNAttention
核心操作固定卷积核滑动动态计算注意力权重
参数效率高(参数共享)中等(QKV 投影有参数)
对位置信息的利用天生具备(局部感受野)需要位置编码辅助
擅长处理局部模式、平移不变性长距离依赖、全局关系
计算复杂度O(N)(N = 像素数)O(N²)(N = 序列长度)
经典应用图像分类、目标检测NLP、多模态、ViT(视觉Transformer)
经验法则:纯视觉任务(分类/检测/分割)→ CNN 仍是最有效率的选择。序列任务(文本/时间序列)→ Attention。混合任务(图文理解)→ CNN + Attention 组合。

---

11.8 收束:两种哲学,一个框架

CNN 的哲学:重要的模式在局部——用一个小窗口扫过去,共享参数。

Attention 的哲学:重要的模式在全局——让模型自己决定关注什么位置。

GoMLX 让你同时拥有两种武器。第 12 章,我们用 CNN 打一场完整的仗。

---

> 作者:步子哥,资深AI研究员 | 连载中:《GoMLX从入门到精通》

[上一章:第10章 神经网络——层、激活函数与前向传播] | [下一章:第12章 实战:CIFAR-10 图像分类全流程]

暂无表态
💬 讨论回复 (0)
推荐

🌟 智谱 GLM-5 已上线

我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。

🎁 领取 2000万 Tokens