Transformer的位置嵌入详解

在这里插入图片描述

🎯 为什么需要位置嵌入?

核心问题:Transformer的自注意力机制本身是位置无关的

  • 与RNN不同,Transformer并行处理所有token,没有天然的顺序概念
  • 如果不加位置信息,"我爱你"和"你爱我"对模型来说是一样的
  • 但在语言中,词序非常重要

📍 "位置"怎么理解?

位置 = token在序列中的索引

句子:  我    爱    吃    苹果
位置:  0     1     2     3

就这么简单!位置就是每个词在句子中的排列顺序。

🔧 位置嵌入的工作原理

核心思路:为每个位置生成一个向量,与词向量相加

# 伪代码示例
token_embedding = [0.2, 0.5, 0.1, ...]  # 词"苹果"的语义向量
position_embedding = [0.1, 0.3, 0.2, ...] # 位置3的位置向量

final_input = token_embedding + position_embedding

📊 两种主流方法

1️⃣ 固定正弦编码(原始Transformer)

PE(pos, 2i)   = sin(pos / 10000^(2i/d))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d))
  • ✅ 不需要训练
  • ✅ 可处理任意长度序列
  • 使用不同频率的正弦/余弦波

2️⃣ 可学习位置嵌入(BERT等)

position_embeddings = Embedding(max_length=512, d_model=768)
  • ✅ 可以学到更适合任务的位置表示
  • ❌ 受限于最大序列长度

💡 直观例子

输入句子:"猫 吃 鱼"

位置0: "猫" = [词向量_猫] + [位置向量_0]
位置1: "吃" = [词向量_吃] + [位置向量_1]  
位置2: "鱼" = [词向量_鱼] + [位置向量_2]

# 如果是"鱼 吃 猫"
位置0: "鱼" = [词向量_鱼] + [位置向量_0]  ← 注意!向量不同了

🎓 关键要点

  1. 位置 = 序列索引(0, 1, 2…)
  2. 位置嵌入 = 把位置编码成向量
  3. 目的 = 让模型知道词的先后顺序
  4. 方式 = 加到词向量上,一起输入模型

这样Transformer就既知道"这是什么词"(词嵌入),又知道"词在哪里"(位置嵌入)了!

图像Transformer的位置编码详解

🖼️ 图像 vs 文本:位置的区别

维度 文本 图像
空间结构 一维序列 二维平面
位置表示 0, 1, 2, 3… (行, 列)
顺序重要性 强依赖顺序 空间邻近关系

📐 图像如何变成"序列"?

步骤1:图像分块(Patching)

原始图像 224×224 像素
        ↓ 分成 16×16 的 patches
得到 14×14 = 196 个 patches

可视化示例

原图:          分块后:
┌─────────┐    ┌─┬─┬─┬─┐
│         │    │1│2│3│4│  ← 每个小块是一个patch
│  🐱    │ →  ├─┼─┼─┼─┤
│         │    │5│6│7│8│
└─────────┘    └─┴─┴─┴─┘

步骤2:展平成序列

二维排列:        一维序列:
┌──┬──┬──┐      
│ 0│ 1│ 2│      [0, 1, 2, 3, 4, 5, 6, 7, 8]
├──┼──┼──┤   →   
│ 3│ 4│ 5│      但要记住它们的2D位置!
├──┼──┼──┤
│ 6│ 7│ 8│
└──┴──┴──┘

🎯 图像中的"位置"是什么?

位置 = 每个patch在图像中的空间坐标

# 示例:3×3的patch网格
Patch 0: 位置 = (0,0) - 左上角
Patch 1: 位置 = (0,1) - 上方中间
Patch 4: 位置 = (1,1) - 正中心
Patch 8: 位置 = (2,2) - 右下角

🔧 Vision Transformer (ViT) 的位置编码方法

方法1: 1D位置编码(ViT原始论文)

# 简单地按顺序编号
patches = [patch_0, patch_1, ..., patch_195]
position_ids = [0, 1, 2, ..., 195]

# 每个位置学习一个向量
position_embedding = Embedding(196, 768)

简单有效
⚠️ 忽略了2D空间结构

方法2: 2D位置编码(更符合直觉)

# 分别编码行和列
for i in range(14):  # 行
    for j in range(14):  # 列
        pos_embed = row_embed[i] + col_embed[j]

方法3: 相对位置编码

  • 编码patch之间的相对距离
  • 例如:patch_4 和 patch_5 是"水平相邻"

💡 直观例子

输入图像:一只猫的照片 (224×224)

步骤1️⃣ 分成 196 个 patches (14×14 网格)
┌────┬────┬────┬────┐
│耳朵│耳朵│ 空 │ 空 │  ← patches 0-3
├────┼────┼────┼────┤
│眼睛│鼻子│眼睛│ 空 │  ← patches 4-7
├────┼────┼────┼────┤
│ 嘴 │ 嘴 │ 嘴 │ 空 │  ← patches 8-11
└────┴────┴────┴────┘

步骤2️⃣ 每个patch加上位置信息
patch_5 (鼻子) = [图像特征] + [位置向量_5]
                          ↑
                  告诉模型:这是第1行第1列
                  (即图像中心偏左上的位置)

步骤3️⃣ 送入Transformer
模型既知道"这是鼻子"(内容)
又知道"在脸部中心"(位置)

🆚 关键对比

特性 文本位置 图像位置
含义 词在句子中的顺序 Patch在图像中的空间坐标
打乱影响 完全改变语义 破坏空间结构
例子 位置3表示"第4个词" 位置(2,3)表示"第2行第3列"

📊 位置编码的作用

没有位置编码:
模型看到 [天空, 草地, 猫],但不知道谁在上谁在下

有了位置编码:
模型知道 天空(上方) → 猫(中间) → 草地(下方)
         理解出正确的空间布局!

🎓 核心要点

  1. 图像位置 = Patch的2D坐标(虽然常简化为1D)
  2. 分块是关键:先把图像切成小块
  3. 保留空间信息:让模型知道每个patch来自图像的哪个区域
  4. 与文本类比
    • 文本:词的先后
    • 图像:块的上下左右

为什么重要?
如果没有位置编码,同样的patches打乱顺序后,模型会给出相同的结果——但一只猫和一堆散乱的猫碎片可完全不同!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐