介绍
torch.nn.Embedding 是 PyTorch 中用于实现 嵌入层(Embedding Layer)的模块,核心作用是将 离散的整数索引(比如单词的编号 0、1、2…)映射为连续的低维稠密向量(比如 128 维的向量)。
简单来说:
- 输入:一组整数(比如
[1, 5, 3],代表 3 个单词的索引) - 输出:一组对应的稠密向量(比如 3 个 128 维的向量)
- 本质:一个可训练的查找表(lookup table),表中的每一行对应一个索引的嵌入向量,训练过程中这些向量会不断优化。
应用场景
- 自然语言处理(NLP):将单词/字符的索引映射为词向量(如 Transformer、LSTM 的输入层);
- 推荐系统:将用户 ID、物品 ID 映射为稠密向量,用于后续的相似度计算;
- 计算机视觉:将类别索引(如标签编号)映射为向量,辅助分类任务。
语法
torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None, max_norm=None, norm_type=2.0, scale_grad_by_freq=False, sparse=False, _weight=None, device=None, dtype=None)
关键参数:
| 参数 | 作用 |
|---|---|
num_embeddings |
必选,嵌入词典的大小(即有多少个不同的索引/单词需要映射) |
embedding_dim |
必选,每个嵌入向量的维度(比如 128、256,决定向量的表达能力) |
padding_idx |
可选,指定填充索引(比如 NLP 中常用 0 作为 padding,该索引的向量训练时不更新) |
max_norm |
可选,限制嵌入向量的最大范数(防止向量值过大) |
属性
torch.nn.Embedding 作为 nn.Module 的子类,除了继承的通用属性(如 training、_device 等),最核心的是和嵌入向量直接相关的属性,以下是新手必须掌握的关键属性:
| 属性名 | 类型 | 核心作用 |
|---|---|---|
weight |
nn.Parameter |
嵌入层的权重矩阵(查找表),形状为 [num_embeddings, embedding_dim],可训练(除非手动设置 requires_grad=False) |
num_embeddings |
int |
嵌入词典的大小(初始化时传入的参数) |
embedding_dim |
int |
每个嵌入向量的维度(初始化时传入的参数) |
padding_idx |
int/None |
填充索引(初始化时传入的参数,若为 None 则无填充) |
max_norm |
float/None |
嵌入向量的最大范数限制(初始化时传入的参数) |
只读属性 vs 可修改属性
num_embeddings、embedding_dim是 只读属性(初始化后无法修改),如果要调整词典大小/嵌入维度,只能重新创建 Embedding 层。padding_idx、max_norm可以修改(如embedding.padding_idx = 1),修改后会影响后续的前向传播。weight是可修改的,既可以直接改值,也可以修改其requires_grad状态。
填充索引的权重特性
如果设置了 padding_idx,该索引对应的权重在反向传播时梯度会被置 0(即不会更新),保证 padding 向量始终是初始值(默认全 0)。
# 验证 padding_idx=0 的权重梯度
input_idx = torch.tensor([0, 1, 2])
output = embedding(input_idx)
output.sum().backward() # 反向传播
print("\npadding_idx=0 的权重梯度:", embedding.weight.grad[0]) # 输出:全 0
print("非 padding 索引 1 的权重梯度:", embedding.weight.grad[1]) # 输出:非 0
例子
创建、常用属性
import torch.nn as nn
# 创建 Embedding 层
# 词典大小:4(索引 0-4),嵌入维度:3(每个索引映射为 3 维向量),即:权重是4行3列
embedding = nn.Embedding(num_embeddings=4, embedding_dim=3)
print(embedding)
print("嵌入词典的大小:", embedding.num_embeddings) # 4
print("每个嵌入向量的维度:", embedding.embedding_dim) # 3
print("\n=== 权重矩阵(weight) ===")
print("权重weight:", embedding.weight) # 4行3列的张量
# weight 是 nn.Parameter 类型,本质是张量,形状 [num_embeddings, embedding_dim]
print("weight 形状:", embedding.weight.shape) # 输出:torch.Size([10, 4])
print("weight 数据类型:", embedding.weight.dtype) # 输出:torch.float32
# 查看索引 1 对应的嵌入向量(权重矩阵的第 1 行)
print("索引 1 对应的嵌入向量:", embedding.weight[1])
执行结果:
Embedding(4, 3)
嵌入词典的大小: 4
每个嵌入向量的维度: 3
=== 权重矩阵(weight) ===
权重weight: Parameter containing:
tensor([[ 0.5295, -1.9354, 0.3722],
[ 0.6719, -1.4125, -0.0068],
[-0.3018, -1.1436, -0.7975],
[ 0.3823, -1.0013, 0.4396]], requires_grad=True)
weight 形状: torch.Size([4, 3])
weight 数据类型: torch.float32
索引 1 对应的嵌入向量: tensor([ 0.6719, -1.4125, -0.0068], grad_fn=<SelectBackward0>)
创建并使用 Embedding 层
import torch
import torch.nn as nn
# 1. 定义 Embedding 层
# 词典大小:10(索引 0-9),嵌入维度:4(每个索引映射为 4 维向量)
embedding = nn.Embedding(num_embeddings=10, embedding_dim=4)
# 2. 准备输入(整数索引,形状:[批量大小, 序列长度])
# 比如批量大小为 2,每个序列有 3 个索引
input_indices = torch.tensor([[1, 3, 5], [2, 4, 6]])
# 3. 前向传播(获取嵌入向量)
embedded_output = embedding(input_indices)
# 输出结果说明
print("输入索引形状:", input_indices.shape) # torch.Size([2, 3])
print("嵌入输出形状:", embedded_output.shape) # torch.Size([2, 3, 4])
print("索引 1 对应的嵌入向量:")
print(embedded_output[0, 0]) # 第一行第一个索引(1)的 4 维向量
带 padding_idx 的 Embedding 层
# 指定 padding_idx=0,索引 0 的向量训练时不会更新
embedding = nn.Embedding(num_embeddings=10, embedding_dim=4, padding_idx=0)
# 输入包含 padding 索引 0
input_indices = torch.tensor([[0, 1, 3], [0, 0, 2]])
embedded_output = embedding(input_indices)
# 验证:padding_idx=0 的向量梯度会被置 0(训练时不更新)
embedded_output.sum().backward() # 模拟反向传播
print("嵌入层权重的梯度:")
print(embedding.weight.grad)
# 输出中,索引 0 对应的行全为 0,其他索引的行有梯度值
特性与注意事项
- 可训练性:
Embedding层的权重(embedding.weight)是可训练的参数,会在反向传播中更新,这也是“词向量学习”的核心。 - 输入要求:输入必须是 整数类型的张量(
torch.long/torch.int64),不能是浮点型。 - 预训练词向量加载:实际应用中,可加载预训练的词向量(如 Word2Vec、GloVe)初始化
Embedding层:# 假设 pretrained_embeddings 是形状为 [10, 4] 的预训练向量张量 pretrained_embeddings = torch.randn(10, 4) embedding = nn.Embedding(10, 4) embedding.weight.data = pretrained_embeddings # 加载预训练权重 # 如果不想更新预训练向量,设置 requires_grad=False embedding.weight.requires_grad = False - 批量处理:支持批量输入,输入形状一般为
[batch_size, seq_len],输出形状为[batch_size, seq_len, embedding_dim]。
总结
torch.nn.Embedding是将 整数索引 映射为 低维稠密向量 的可训练层,核心是一个查找表;- 核心参数是
num_embeddings(词典大小)和embedding_dim(向量维度),padding_idx是 NLP 中常用的实用参数; - 它是 NLP 模型的基础组件,支持加载预训练向量,也可通过训练学习专属的嵌入表示。