PyTorch深度学习实战 |词嵌入和位置编码

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 本文介绍了PyTorch中词嵌入(Embedding)和位置编码(Positional Encoding)的实现与应用。词嵌入通过Word2Vec、GloVe等技术将单词转换为连续向量,其中使用nn.Embedding层加载预训练词向量,并展示如何可视化词向量间的语义关系(如"king-man≈queen-woman")。位置编码部分详细解释了如何通过正弦/余弦函数为词向量添加位置信息,包含公式推导和代码实现(PositionalEncoding类)。文章提供了完整的PyTorch代码示

 词嵌入

 引入    

   只要是使用深度学习模型处理 NLP 问题:在模型中就需要添加,Embedding 层。比如在

Transformers 中的左下角和右下角就有两个词嵌入层。

image.gif

Embedding层负责将离散的单词数据转换称连续且固定长度的向量,简单来说:

词向量:用一个d维空间的向量表示一个词

词嵌入:就是将一个词嵌入到一个特定的向量空间

image.gif

如果我们想把一句话,作为神经网络的输入,比如Are you OK? 神经网络是没有办法直接处理这个

文本的,我们需要先将Are you OK?基于词表vocab转换称整数索引序列的形式,例如转换称【1,

2,3,4】,然后再基于Embedding层,将整数索引序列转换成单词向量的序列,这里假设每个单

词用4维的向量表示,那么4个词的句子Are you OK? 就会被转换为 4×4 的词向量矩阵。每行对应

一个单词。得到输入文本的向量矩阵后,才可以使用神经网络对文本进行特征提取和处理。

image.gif

下面我们会从3个方面解释词嵌入 (Embedding) 技术

(1)词嵌入的作用 (2)嵌入矩阵的计算 (3)Embedding 层的使用

词嵌入的作用

      词嵌入是一种将词汇表中的词或短语映射为固定长度向量的技术我们可以将高维且稀疏的单词

索引转为低维且连续的向量转换后的连续向量可以表示出单词与单词之间的语义关系。此时我们使

用词嵌入技术,就可以把4个高纬稀疏的的向量,转换成4个低纬连续的向量,转换后的向量,每个

维度都是一个浮点数,这里我们就把向量映射到一个7维的空间中。

image.gif

为了进一步表示词与词之间的关系,我们可以把词向量,基于降维算法,降成2维,从而使单词向

量在平面上绘制出来。此时就会发现语义相近的词语在向量空间中距离相近。词嵌入可通过向量的

数学运算体现词语的语义关联,例如:向量(“king”) - 向量(“man”) ≈ 向量(“queen”) - 向量

(“woman”)。词嵌入技术的核心价值:将自然语言中的词语转换为数值向量,并通过向量体现词

语间的语义关系;为机器翻译、文本分类、语义检索等高级 NLP 任务提供基础支撑。

image.gif

嵌入矩阵

为了实现词嵌入,我们会使用特定的词嵌入算法,例如通过 Word2Vec、FastText、GloVe 等词嵌

入算法,训练得到一个通用的嵌入矩阵,该矩阵即为模型中的 Embedding 层。具体来说嵌入矩阵

的行就是语料库中词语的个数,嵌入矩阵的列表示词语的维度。设词表中包括5000个单词,每个

单词用一个128维的向量表示。我们将嵌入矩阵用E来表示。

image.gif

嵌入矩阵的使用方法有两种形式:

基于矩阵相乘:将单词的独热编码向量与嵌入矩阵相乘,得到对应的词向量(本质是矩阵乘法实现

的映射)。

基于索引查找:直接通过单词在词汇表中的索引,从嵌入矩阵中提取对应的行向量(是实际工程中

更高效的常用方式)。

比如我们对Are you OK? 这句话进行编码,每个词是一个5000维的向量,整个句子是一个4*5000

矩阵我们将该矩阵记作V。然后我们把独热编码矩阵和嵌入矩阵相乘,就得到句子的嵌入向量矩

阵。

image.gif

另一种方式是索引查找,句子中的每个词都对应着,词表中的一个整数索引,然后我们直接获取索

引在嵌入句子对应的行就好了。

image.gif

Embedding 层的使用

下面我们会使用torch.nn来创建一个Embedding 层,并使用这个Embedding 层计算单词的词向

量,并实现可视化。

from torchtext.vocab import import GloVe  # 导入GloVe词向量
# 简单介绍
# GloVe词向量,它是斯坦福大学的研究者在2014年开发和发布的
# GloVe和word2vec与fasttext,是当前最常用的3个词向量版本
# 6B表示了模型是基于60 亿个单词的语料库训练的
# 300表示一个单词,使用300维的向量表示
glove = GloVe(name='6B', dim=300)

image.gif

import torch
from torch import nn
# 使用nn.Embedding创建词嵌入层
# 将glove.vectors,通过from_pretrained接口,导入到Embedding层中
# 此时的embedding层,就载入了GloVe词向量数据
embedding = nn.Embedding.from_pretrained(glove.vectors)
# 打印embedding层中的weight的尺寸
print(f"embedding.shape: {embedding.weight.shape}")

image.gif

程序输出:embedding.shape: torch.Size([400000, 300])表示 Embedding 层的权重矩阵尺寸为

“400000 个单词 × 300 维向量”,对应 GloVe 预训练词向量的词汇量与维度。

# 将man、woman、king、queen等8个词语的词向量,绘制到二维平面上
words = ['man', 'woman', 'king', 'queen', 'cat', 'dog', 'mother', 'father']
indices = []
for word in words:
    # 将单词word,通过glove的词汇表,转换为单词的索引
    index = glove.stoi[word]
    # 将这些索引保存到indices数组中
    indices.append(index)
    # 打印单词word和索引index的对应关系
    print(f"{word} -> {index}")

image.gif

程序输出:man -> 300 woman -> 787 king -> 691 queen -> 2060 cat -> 5450 dog -> 2926 mother

-> 808 father -> 629

# 将索引列表,使用torch.tensor,转为张量的形式
indices = torch.tensor(indices)
# 将索引列表转换为,词向量的矩阵
vectors = embedding(indices).detach().numpy()
# 打印vector的尺寸
print(f"vectors.shape: {vectors.shape}")

image.gif

程序输出:vectors.shape: (8, 300)这段代码的核心是从 Embedding 层中提取目标单词的词向量:

(8, 300)表示词向量矩阵的尺寸为 “8 个单词 × 300 维向量”,对应 8 个目标单词各自的 300 维

GloVe 词向量。

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# 使用PCA降维算法,将向量vectors进行降维
pca = PCA(n_components=2)
vectors_2d = pca.fit_transform(vectors)
# 将单词和向量,绘制到二维平面上
plt.scatter(vectors_2d[:, 0], vectors_2d[:, 1])
for i, word in enumerate(words):
    plt.annotate(word,
                 xy=(vectors_2d[i, 0], vectors_2d[i, 1]),
                 xytext=(-10, 10),
                 textcoords='offset points')
plt.show()

image.gif

用 PCA 算法将 300 维的词向量降维至 2 维(适配二维平面展示);

通过 matplotlib 绘制降维后的向量散点图,并为每个点标注对应的单词;

完整代码

from torchtext.vocab import GloVe  # 导入GloVe词向量
# 简单介绍
# GloVe词向量,它是斯坦福大学的研究者在2014年开发和发布的
# GloVe和word2vec与fasttext,是当前最常用的3个词向量版本
# 6B表示了模型是基于60 亿个单词的语料库训练的
# 300表示一个单词,使用300维的向量表示
glove = GloVe(name='6B', dim=300)
import torch
from torch import nn
# 使用nn.Embedding创建词嵌入层
# 将glove.vectors,通过from_pretrained接口,导入到Embedding层中
# 此时的embedding层,就载入了GloVe词向量数据
embedding = nn.Embedding.from_pretrained(glove.vectors)
# 打印embedding层中的weight的尺寸
print(f"embedding.shape: {embedding.weight.shape}")
# 将man、woman、king、queen等8个词语的词向量,绘制到二维平面上
words = ['man', 'woman', 'king', 'queen', 'cat', 'dog', 'mother', 'father']
indices = []
for word in words:
    # 将单词word,通过glove的词汇表,转换为单词的索引
    index = glove.stoi[word]
    # 将这些索引保存到indices数组中
    indices.append(index)
    # 打印单词word和索引index的对应关系
    print(f"{word} -> {index}")
# 将索引列表,使用torch.tensor,转为张量的形式
indices = torch.tensor(indices)
# 将索引列表转换为,词向量的矩阵
vectors = embedding(indices).detach().numpy()
# 打印vector的尺寸
print(f"vectors.shape: {vectors.shape}")
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# 使用PCA降维算法,将向量vectors进行降维
pca = PCA(n_components=2)
vectors_2d = pca.fit_transform(vectors)
# 将单词和向量,绘制到二维平面上
plt.scatter(vectors_2d[:, 0], vectors_2d[:, 1])
for i, word in enumerate(words):
    plt.annotate(word,
                 xy=(vectors_2d[i, 0], vectors_2d[i, 1]),
                 xytext=(-10, 10),
                 textcoords='offset points')
plt.show()

image.gif


位置编码 (PositionalEncoding)

     为什么给词向量的每个维度,加上位置编码,就能给这个词向量加上位置信息呐?为什么可以

直接将词向量和位置编码相加?为什么这样的操作就是有实际意义?将正弦和余弦的常量信息,直

接加到词向量上,不会破坏词向量本身的信息吗?

image.gif

下面我们将从4个方面详细介绍位置编码,位置编码 (PositionalEncoding):(1)什么是位置编码

(2) 如何计算位置编码(3)位置编码的真正意义(4)位置编码的代码实现

什么是位置编码

     下面我们用机器翻译为例说明位置编码,待翻译英文Are you OK?会从下方的左侧位置输入,

中文标注 你好吗?会从下方的右侧位置输入,当Are you OK?和你好吗?进入到Transformer中,

会被第一个组件,词向量层处理,词向量层把单词变成词向量,“位置编码的目的是,将位置信

息‘附加’到原始的信息上。

如何计算位置编码?

d表示位置编码向量的维度,这里我们举出的例子中维度是4。

pos表示序列中的位置,比如,Are--->0,you--->1,OK--->2,?--->3

image.gif

i表示位置编码向量维度索引的一半,比如:

第0维维度,2*0=0,所以i=0,2i=0

第1维维度,2*0+1=1,所以i=1,2i=0

第2维维度,2*1=1,所以i=1,2i=2

第3维维度,2*1+1=2,所以i=1.2i=2

image.gif

        在 Transformer 模型中,词向量(Word Embeddings)的表示是通过将输入的词嵌入

(Embedding)词向量矩阵和位置编码(Positional Encoding)矩阵相加得到的。

image.gif

位置编码的意义

   位置编码 (PositionalEncoding):     增加额外的位置信息帮助模型更好地理解语言的顺序性

质,通过绝对足够充分的训练数据:使模型能够学会理解 “词向量”+“位置编码” 的复合特征最终完

成对文本的整体理解。

代码实现

(1)定义词向量矩阵

词向量矩阵(形状:[5, 4]),word_embeds

word_embeds = torch.tensor([
    [0.4002, 0.9882, 0.6261, 0.1502],  # Are
    [0.3413, 0.9284, 0.9349, 0.8958],  # you
    [0.5347, 0.2969, 0.7019, 0.6293],  # OK
    [0.8704, 0.4956, 0.3794, 0.5646]   # ?
])
print("图片中的词向量矩阵:")
print(word_embeds)

image.gif

(2)初始化位置编码模块(embed_dim=4,max_pos=5)

     [5, 4]的矩阵(5 个位置,每个位置 4 维),pos的大小是5*1的代表,位置索引,计算

embed_dim=4
max_pos=5
# 1. 生成位置索引(0到max_pos-1)
pos = torch.arange(max_pos).unsqueeze(1)  # 形状:[max_pos, 1]
print(pos)
# 2. 计算正余弦编码的频率项(公式中的10000^(2i/d_model)的倒数)
div_term = torch.exp(torch.arange(0, embed_dim, 2) * (-math.log(10000.0) / embed_dim))
print(div_term)
# 3. 初始化位置编码矩阵(全零)
pe = torch.zeros(max_pos, embed_dim)  # 形状:[max_pos, embed_dim]
print(pe)
# 4. 填充偶数维度(用正弦函数)
pe[:, 0::2] = torch.sin(pos * div_term)  # 0::2表示从0开始,步长为2的列(偶数维)
print(pe[:, 0::2])
# 5. 填充奇数维度(用余弦函数)
pe[:, 1::2] = torch.cos(pos * div_term)  # 1::2表示从1开始,步长为2的列(奇数维)
print(pe[:, 1::2])
print(pos_encoder.pe[:4])  # 取前4个位置的编码

image.gif

image.gif

(3)完整代码

import torch
import torch.nn as nn
import math
# 1. 定义位置编码模块(复用之前的实现)
class PositionalEncoding(nn.Module):
    def __init__(self, embed_dim: int, max_pos: int = 10):
        super().__init__()
        pos = torch.arange(max_pos).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, embed_dim, 2) * (-math.log(10000.0) / embed_dim))
        pe = torch.zeros(max_pos, embed_dim)
        pe[:, 0::2] = torch.sin(pos * div_term)
        pe[:, 1::2] = torch.cos(pos * div_term)
        self.register_buffer('pe', pe)
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        seq_len = x.size(0)
        return x + self.pe[:seq_len]  # 这里x是[序列长度, 词向量维度],无需批次维度
# 2. 构造图片中的词向量矩阵(形状:[5, 4])
word_embeds = torch.tensor([
    [0.4002, 0.9882, 0.6261, 0.1502],  # Are
    [0.3413, 0.9284, 0.9349, 0.8958],  # you
    [0.5347, 0.2969, 0.7019, 0.6293],  # OK
    [0.8704, 0.4956, 0.3794, 0.5646]   # ?
])
print("图片中的词向量矩阵:")
print(word_embeds)
# 3. 初始化位置编码模块(embed_dim=4,max_pos=5)
pos_encoder = PositionalEncoding(embed_dim=4, max_pos=5)
print("\n图片对应的位置编码矩阵:")
print(pos_encoder.pe[:4])  # 取前4个位置的编码
# 4. 计算“词向量 + 位置编码”的结果
output = pos_encoder(word_embeds)
print("\n最终相加结果:")
print(output)

image.gif

【1】参考:小黑黑讲AI

目录
相关文章
|
16天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
6015 30
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
1天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
572 135
|
11天前
|
存储 定位技术 数据库
CodeGraph 如何让 Claude Code减少 7 成工具调用?
CodeGraph 为 Coding Agent 提供本地代码知识图谱,把函数、类、调用链和框架路由提前整理成“项目地图”,减少盲目搜索和文件读取。它不是新 Agent,而是上下文基础设施,让 Agent 更快找到正确代码路径,平均减少 7 成工具调用。
1187 3
|
8天前
|
人工智能 安全 定位技术
CodeGraph深度解析 让Claude Code工具调用直降七成的核心原理与实操教程
如今以Claude Code为代表的AI编程智能体已经成为开发者日常编码、项目重构、漏洞修复的必备工具。但在长期使用过程中,几乎所有开发者都会遇到同一个明显痛点:AI虽然具备强大的代码生成与分析能力,却常常陷入盲目探索的循环中。
990 1
|
18天前
|
人工智能 自然语言处理 供应链
|
9天前
|
人工智能 弹性计算 安全
阿里云618活动时间、活动入口、优惠活动详细解读
2026年阿里云618创新加速季已全面开启,作为年度力度最大的云产品促销活动,本次大促覆盖轻量应用服务器、ECS云服务器、GPU云服务器、数据库、AI算力、安全服务、CDN等全品类产品,推出5亿元算力补贴、新用户限时秒杀、普惠满减、企业专享、免费试用、云大使返佣等多重福利,个人开发者、中小企业、AI团队均可享受专属低价。本文将系统梳理2026年阿里云618活动的完整时间节点、官方参与入口、各类优惠细则、使用规则、热门产品推荐及实操代码,帮助用户精准参与、高效省钱,以最低成本完成上云部署。
810 5
|
9天前
|
运维
欢迎报名|2026 Agentic AICon—智能体基础设施与AgentOps专场,邀您参会
欢迎报名|2026 Agentic AICon—智能体基础设施与AgentOps专场,邀您参会
1442 0