当前位置: 首页 > news >正文

Embedding 学习笔记

通过 8 道由浅入深的问题,系统理解深度学习中的 Embedding 概念。 本笔记包含:原题、个人作答、详细解析。


学习背景

Embedding(嵌入)是深度学习中将"离散符号"转换为"稠密向量"的核心技术。它解决了神经网络"只能输入张量"这一限制下,如何处理单词、用户 ID、商品 ID 等非数值型数据的问题。


第 1 题:动机题 —— One-hot 的问题

题目

假设要做电影评论情感分类,词表 1 万个词。最朴素的做法是把每个词变成 one-hot 向量:

  • "好" →[0, 0, ..., 1, 0, ..., 0](1 万维,第 372 位是 1)
  • "棒" →[0, 1, 0, ..., 0](1 万维,第 2 位是 1)

问:用 one-hot 喂神经网络有什么问题?至少说出 2 个。

我的回答

工程量大,只能分析严格的好坏词。

解析

方向对,但只说到一半。完整的 one-hot 4 个核心问题:

1. 维度灾难("工程量大"对应这点 ✅)

  • 1 万个词 → 每个词都是 1 万维向量,99.99% 都是 0
  • 现实词表常达 5 万~10 万,向量太稀疏,存储和计算都浪费

2. 没有语义信息(这点最关键,初答没抓到)

  • "猫" =[0,0,1,0,...],"狗" =[0,1,0,0,...],"桌子" =[1,0,0,0,...]
  • 任意两个 one-hot 向量的距离完全相等(都是 √2)
  • 在 one-hot 空间里,"猫"和"狗"的距离 = "猫"和"桌子"的距离,模型看不出"猫狗都是动物"

3. 不可学习

  • One-hot 是死的,训练再久它也不会变

4. 泛化差

  • 训练时见过"好看",没见过"漂亮",模型完全不知道这俩相关

核心结论

Embedding 的核心动机:把高维稀疏的 one-hot 压缩成低维稠密、且语义相近的词向量也相近的表示。


第 2 题:本质题 —— Embedding 向量从哪来?

题目

Embedding 通常被描述成"把一个词映射成一个稠密向量",比如:

  • "猫" →[0.2, -0.5, 0.8, 0.1, ...](64 维)

问:这个 64 维向量是怎么"产生"的?是人类设计的、查字典查到的、还是其他?

我的回答

是机器自己生成的。

解析

✅ 完全正确!更精确地说:

  • Embedding 矩阵的初始值是随机的(一开始毫无意义)
  • 训练过程中,它和模型的其他参数一起被梯度下降优化
  • 最终学出来的向量,是模型为了完成任务"自己摸索出来的最佳数字表示"

核心结论

Embedding 是可学习参数,不是预先定义的字典。它和"权重矩阵 W"是同等地位的可训练对象。


第 3 题:代码题 —— Embedding 内部结构

题目

import torch.nn as nn embedding = nn.Embedding(num_embeddings=10000, embedding_dim=64) word_id = torch.tensor([42]) vector = embedding(word_id) print(vector.shape)

  1. embedding这个对象的内部"长什么样"?
  2. embedding(word_id)这一步到底在做什么运算

我的回答

10000×64 的矩阵?转成数字矩阵?

解析

第 1 问:"10000×64 的矩阵" ✅ 完全正确!

nn.Embedding(10000, 64)内部就是一个形状为(10000, 64)的矩阵,每一行对应一个词的 64 维向量:

维度0 维度1 维度2 ... 维度63 词0: [ 0.21, -0.5, 0.8, ..., 0.1] 词1: [-0.3, 0.4, 0.2, ..., -0.7] 词2: [ 0.5, 0.1, -0.9, ..., 0.3] ... 词9999:[ 0.0, -0.2, 0.6, ..., 0.4]

第 2 问:关键认知需要纠正!

embedding(word_id)做的不是矩阵乘法,而是查表(取行)

embedding = nn.Embedding(10000, 64) embedding(torch.tensor([42])) # 等价于: embedding.weight[42] # 直接取第 42 行

它就是个查字典操作:给我编号 42,我就把矩阵的第 42 行返回给你。

为什么这点重要?

理论上,one-hot 乘以 embedding 矩阵也能得到同样结果:

[0,0,...,1,...,0] @ W(10000×64) = W 的第 42 行 ↑ 第 42 位是 1

但这种乘法 99.99% 在乘 0,完全是浪费。所以工程上直接用查表实现,速度快几百倍

核心结论

Embedding 是"索引"不是"乘法"。理解这点能帮你看懂工程实现。


第 4 题:语义题 —— 神经网络怎么学到语义?

题目

人们常说:"训练好的 embedding 中,语义相近的词,向量也相近。" 比如:

vec("国王") - vec("男人") + vec("女人") ≈ vec("女王")

问:神经网络从来没有人告诉它"国王和女王是相关的",它是怎么学到这种语义关系的?关键的"训练信号"来自哪里?

我的回答

通过 embedding 的相似数字。

解析

⚠️ 这个回答描述的是结果,但没回答原因

答案的关键是:上下文(context)

经典的 Word2Vec 训练任务:

给定句子: "国王 在 城堡 里 统治" "女王 在 城堡 里 统治" "国王 戴着 王冠" "女王 戴着 王冠"

训练目标:根据上下文预测中心词(或反过来)。

模型注意到:

  • "国王"和"女王"总是出现在相似的上下文里(城堡、统治、王冠...)
  • 为了让模型在这些相似上下文中都能预测对,它必须给"国王"和"女王"分配相似的向量
  • 训练完成后,这两个词的向量自然就靠在一起了

核心思想(语言学上叫"分布假说")

"You shall know a word by the company it keeps." —— J.R. Firth, 1957 (一个词的意义由它周围的词决定)

核心结论

训练信号不是"有人告诉模型它们相关",而是**"它们出现在相似的语境里"** 这个统计规律,被神经网络通过反向传播自动发现。

你不需要标注任何"语义相似"的数据,只要让模型读海量文本做"完形填空",它自动就学出了语义。


第 5 题:推广题 —— 哪些数据适合 Embedding?

题目

Embedding 不仅能用在词上,还能用在用户 ID、商品 ID、棋盘位置、类别变量等。

问:什么样的数据适合用 Embedding?

(提示:对比"图像像素"和"用户 ID"——为什么图像不需要 embedding,但用户 ID 需要?)

我的回答

图像本身有红绿蓝的数据,但是用户 ID 没有数据信息。

解析

✅ 直觉非常正确!抓到了本质。提炼成更通用的判断标准:

适合 Embedding 的数据:离散符号(Discrete Symbols)

特征:

  • ✅ 取值是离散的、有限的(用户 ID、商品 ID、单词、类别)
  • ✅ 编号本身没有数值意义(用户 #42 和用户 #43 不是"相邻"的)
  • ✅ 编号之间没有大小关系("星期一"和"星期二"在数值上差 1,但语义上没那种线性关系)

不适合(不需要)Embedding 的数据:连续数值、有真实意义的数字

特征:

  • ❌ 取值连续(像素值 0~255、温度、价格)
  • ❌ 数值本身有意义(像素 200 比像素 100 更亮,这是真实的物理意义)
  • ❌ 可以直接做数学运算

对比清晰版

数据编号意义处理方式
像素值 200"亮度是 200",本身有意义直接用 / 归一化
用户 ID 42"随便编的号",没含义查 Embedding
单词编号 42"词表里的位置",没含义查 Embedding
温度 25°C"温度是 25 度",有物理含义直接用
类别 "星期三" → 3编号无意义查 Embedding

核心结论

Embedding 是"离散符号 → 稠密向量"的可学习翻译器。 判断要不要用 embedding,看输入是不是编号无意义的离散符号


第 6 题:陷阱题 —— Embedding 工作流程

题目

哪段代码对、哪段错?为什么?

# 代码 A embedding = nn.Embedding(10000, 64) text = "我爱深度学习" vector = embedding(text) # 代码 B embedding = nn.Embedding(10000, 64) token_ids = torch.tensor([101, 234, 567, 890]) vector = embedding(token_ids) print(vector.shape)

我的回答

B 报错,A 输出形式 10000×64,不知道什么环节。

解析

❌ 答反了!正确答案:A 报错,B 正确

代码 A 错在哪?

embedding(text) # text = "我爱深度学习"

nn.Embedding的输入必须是整数张量(索引),不能直接喂字符串!

正确流程是 3 步

原始文本 "我爱深度学习" ↓ 第 1 步:分词(Tokenization) ['我', '爱', '深度', '学习'] ↓ 第 2 步:映射成整数 ID(查词表) [101, 234, 567, 890] ← 这一步把字符串变成数字 ↓ 第 3 步:Embedding 查表 tensor of shape (4, 64) ← 每个词变成 64 维向量

关键认知Embedding 不负责"文字到数字"的转换,它只负责"整数 ID → 向量"的转换。前面的分词和 ID 映射要靠Tokenizer(分词器)完成。

代码 B 输出的形状

token_ids = torch.tensor([101, 234, 567, 890]) # shape: (4,) vector = embedding(token_ids) # shape: (4, 64)

输入 4 个 ID → 输出 4 个 64 维向量,所以是(4, 64)

注意这里4就是行,是那10000行的子集

# ========== 第一步:准备工作(训练前一次性完成)==========

# Tokenizer 训练(基于大语料统计)
# 生成词表 vocab.txt:(生成就固定不动了)
# "我" → 101
# "爱" → 234
# "深度" → 567
# "学习" → 890
# ... 共 10000 个词

# ========== 第二步:模型定义(搭建模型结构时)==========

import torch
import torch.nn as nn

# 创建一个 10000×64 的 embedding 矩阵
# 初始值是随机的!还没经过训练,向量没有意义
embedding = nn.Embedding(10000, 64)

# ========== 第三步:使用流程(每次前向传播)==========

# 1) 用 Tokenizer 把文本转成 ID(查固定的对照表)
text = "我爱深度学习"
token_ids = torch.tensor([101, 234, 567, 890]) # 来自固定词表
print(token_ids.shape) # torch.Size([4])

# 2) 用 Embedding 把 ID 转成向量(查可学习的矩阵)
vectors = embedding(token_ids)
print(vectors.shape) # torch.Size([4, 64])

# ========== 第四步:训练(这里 Embedding 矩阵会被更新)==========

# 训练循环中,loss.backward() + optimizer.step() 会更新
# embedding.weight 这个 (10000, 64) 矩阵的数值
# Tokenizer 词表始终不动

通用规则

输入 shape: (...) 输出 shape: (..., embedding_dim) 例: (4,) → (4, 64) 单个句子 4 个 token (32, 100) → (32, 100, 64) 32 个句子,每句 100 个 token,一共32*100行embedding 10000行子集

核心结论

Embedding 在完整 NLP 流程中的位置

原始文本 → [Tokenizer] → 整数 ID → [Embedding] → 稠密向量 → [模型主体] → 输出 ↑ ↑ 字符串变数字 数字变向量

整个流程像装配线,分工明确。


第 7 题:对比题 —— PCA vs Embedding

题目

考虑两种方案,把 1 万个词的词表变成 64 维向量:

  • 方案 A:用 PCA 对 one-hot 矩阵降维到 64 维
  • 方案 B:用nn.Embedding(10000, 64)在下游任务上训练

问:这两种方案得到的 64 维向量有什么本质区别?哪种通常效果更好?

我的回答

PCA 其实不太了解。

解析

先补 PCA 知识

PCA(主成分分析):一种线性降维方法。把高维数据投影到低维空间,保留方差最大的方向。它是无监督的,不需要任务标签,只看数据本身的统计结构。

两种方案的本质区别

PCA 降维nn.Embedding 训练
学习目标保留数据方差服务下游任务
是否监督无监督有监督(跟着任务一起学)
数学本质线性变换(一次到位)梯度下降迭代优化
是否任务相关不相关强相关

关键洞察

  • PCA 给所有词分配的向量,对所有任务都一样——情感分析、机器翻译、命名实体识别都用同一套向量。
  • nn.Embedding 学到的向量,是为了让你的特定任务表现最好而调整的——做情感分析任务时,"好"和"棒"会被拉到一起;做语法分析任务时,可能"动词"会被拉到一起。

通常哪个效果好?Embedding 训练几乎总是赢,因为它是任务驱动的。但如果数据极少,PCA 这类简单方法有时反而更稳。

核心结论

Embedding 不是"通用的词向量",而是"为任务而生的词向量"。 这也是为什么大模型的 embedding 那么强——它们见过的数据和任务足够多,学出的向量足够通用。


第 8 题:综合题 —— 维度的权衡

题目

现代大模型(如 GPT、BERT)的 embedding 维度往往是 768、1024、4096 甚至更高。

  1. 维度选大还是小,各有什么权衡?
  2. 1 万个词、每个 64 维 vs 1 万个词、每个 4096 维,参数量差多少?
  3. 如果只有 1000 条训练数据,你会选 64 维还是 4096 维?

我的回答

不会。embedding 的大小和 batch 的大小的区别是什么?

解析

先回答反问:embedding_dim vs batch_size 有什么区别?

batch_size = 32 # 每次处理 32 个句子 seq_length = 100 # 每个句子 100 个 token embedding_dim = 64 # 每个 token 用 64 维向量表示 vocab_size = 10000 # 词表大小 embedding = nn.Embedding(vocab_size, embedding_dim) input_ids = torch.randint(0, 10000, (batch_size, seq_length)) # (32, 100) output = embedding(input_ids) # (32, 100, 64)

形状演化:

input: (32, 100, ) ↑ ↑ batch 序列长度 output: (32, 100, 64) ↑ ↑ ↑ batch 序列长度 embedding_dim
概念含义维度作用
batch_size一次处理多少个样本训练时的并行度,不影响模型结构
embedding_dim每个符号用多少维向量表示模型的"表达容量",模型结构的一部分

类比

  • batch_size = 一次同时教多少个学生
  • embedding_dim = 每个词用多丰富的语义来描述

batch_size 改了,模型本身不变(只是训练效率不同);embedding_dim 改了,模型结构变了(参数量不一样了)。

回到原题

1. 维度大小的权衡

维度优点缺点
维度大(4096)表达能力强,能捕捉细微语义差别参数多、容易过拟合、训练慢
维度小(64)参数少、训练快、不易过拟合表达能力有限,可能欠拟合

2. 参数量对比

10000 词 × 64 维 = 64 万参数 (~2.5 MB) 10000 词 × 4096 维 = 4096 万参数 (~160 MB)

64 倍!这意味着:

  • 显存占用差 64 倍
  • 需要的训练数据差很多倍(参数越多越容易过拟合)

3. 1000 条数据,选哪个?

毫无疑问选 64 维

原因:参数量必须和数据量匹配。4096 维有 4 千万参数,1000 条数据连"塞牙缝"都不够,模型会严重过拟合——它会"背"下训练集而不是"学"规律。

经验法则(粗略版)

数据量推荐 embedding_dim
< 1 万32~128
1 万~100 万128~512
100 万+512~4096
上亿(GPT 级别)4096~12288

核心结论

embedding_dim 是模型容量参数,必须和数据规模匹配。盲目加大维度只会让模型过拟合,而不是变强。


总结:3 个最重要的核心认知

复习时重点掌握这 3 点:

1. Embedding 是"查表"不是"乘法"

embedding(torch.tensor([42])) # 等价于 embedding.weight[42]

理论上是"one-hot @ 矩阵",工程上直接索引取行,速度快几百倍。

2. Embedding 学到语义靠的是"上下文统计"

"You shall know a word by the company it keeps."

模型从来没被告知"国王和女王相关",它只是发现这两个词出现在相似上下文里,于是给了它们相似向量。核心训练信号 = 上下文共现统计

3. Embedding 在完整流程中的位置

原始文本 → [Tokenizer] → 整数 ID → [Embedding] → 稠密向量 → [模型主体] → 输出 ↑ ↑ 字符串变数字 数字变向量

Embedding不负责字符串处理,它只接受整数索引输出向量。前面的分词和编号要靠 Tokenizer 完成。


关键概念速查表

概念定义关键点
One-hot用一个长向量、只有一位是 1 表示符号维度高、稀疏、无语义
Embedding把离散符号映射为稠密向量的查找表可学习、稠密、有语义
embedding_dim每个符号对应的向量维度模型容量参数
vocab_size词表大小(能处理的不同符号数)决定 embedding 矩阵的行数
Tokenizer把原始文本切分并编号的工具Embedding 的"前置处理器"
batch_size一次训练处理的样本数训练超参,与模型结构无关
分布假说词的意义由其上下文决定Embedding 学到语义的理论基础

延伸学习方向

掌握这些基础后,可以进一步学习:

  1. Word2Vec / GloVe:经典的预训练词向量算法
  2. Position Embedding:Transformer 中的位置编码
  3. Tokenizer 的演化:从字粒度 → BPE → WordPiece → SentencePiece
  4. 预训练 Embedding 的迁移使用:直接用 BERT/GPT 的 embedding 做特征
  5. Embedding 可视化:用 t-SNE / UMAP 把高维 embedding 投到 2D 看效果
http://www.jsqmd.com/news/717874/

相关文章:

  • Si826x数字隔离门驱动器:工业电机控制的高效解决方案
  • Kubernetes攻防 特殊路径挂载导致的容器逃逸
  • 《池上》唐·白居易
  • Linux系统下的深度学习环境配置:从入门到精通
  • 启动mysql失败/usr/libexec/mysqld: Operation not permitted
  • 零基础玩转Qwen2.5-VL-7B:RTX 4090专属视觉助手,开箱即用图文交互
  • Python + FastAPI+ uniapp 健身房预约系统
  • 图形验证码的技术原理与应用场景深度解析
  • OpenClaw 安全复盘:“龙虾”漏洞到底发生了什么?
  • 2026年国内数字化档案管理系统Top5推荐
  • 别再为水下AI发愁了!手把手教你用虎鲸开源的UATD声呐数据集(含10类目标、9200张图)
  • 3步搭建零成本眼动追踪系统:eyeLike开源项目完全指南
  • Pixel Aurora Engine 模拟电路设计辅助:Proteus仿真图智能生成案例
  • 如何通过智能清理工具彻底解决Windows系统卡顿问题:专业指南
  • 【AI开发工具】Anaconda 完整安装与使用教程
  • 一年读完12本书,硬核搞定AI大模型入门!建议收藏!
  • 别再只调超参了!给ResNet50加上SE模块,我的图像分类准确率提升了3%
  • 2026上半年最值得关注的10款IT运维软件
  • 造相-Z-Image-Turbo 数据结构优化:提升大规模LoRA加载与管理效率
  • 春联生成模型资源优化:解决C盘空间不足的部署技巧
  • Phi-4-mini-flash-reasoning中小企业应用:低成本构建专业级逻辑推理能力
  • 如何免费解锁原神60帧限制:终极FPS解锁器完全指南
  • Python3.11环境配置全攻略:Miniconda镜像手把手教学
  • Phi-4-mini-reasoning算法精讲:十大排序算法原理与模型实现对比
  • 打包 Android beeware briefcase
  • 第八章:打印与导出
  • 抖音无水印下载终极方案:douyin-downloader 完整实战教程
  • Youtu-Parsing效果展示:复杂表格与手写体混合文档精准解析案例
  • 算法题(子串)
  • 微信点餐小程序