ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从词袋到Transformer:深入理解Embedding技术原理与应用

从词袋到Transformer:深入理解Embedding技术原理与应用 1. 从“词袋”到“词义”为什么我们需要Embedding如果你在2015年之前接触过自然语言处理NLP那你大概率处理过“词袋”Bag of Words模型。那是一种简单粗暴的文本表示方法把一篇文章看作一个袋子里面装着一个个独立的词统计每个词出现的次数就形成了一个高维稀疏的向量。比如“我喜欢苹果”和“苹果公司发布了新产品”在词袋模型里“苹果”这个词的统计次数都会增加但模型完全无法区分前者是水果后者是科技巨头。这种表示方法丢失了词序、上下文和最重要的——语义。Embedding嵌入或称为词向量技术的出现就是为了解决这个根本问题。它的核心思想是将离散的符号如单词、字符映射到一个连续的、低维的向量空间中并且在这个空间里语义相近的符号其向量表示在几何上也相近。简单说就是让计算机能“理解”“苹果水果”和“橘子”的距离比“苹果水果”和“微软”的距离要近得多。在Transformer架构席卷AI领域之前Word2Vec、GloVe等静态词向量模型已经证明了Embedding的巨大价值。但它们有一个致命缺陷一个词无论出现在什么上下文它的向量表示是固定不变的。这显然不符合语言的实际使用“苹果”在水果店和科技新闻里的意思天差地别。Transformer尤其是其核心机制——自注意力Self-Attention与动态的、上下文相关的Embedding简直是天作之合。在Transformer中一个单词的最终表示是由它自身的基础Embedding与句子中所有其他单词的Embedding经过复杂的交互计算后动态形成的。这使得“苹果”这个词在输入“我吃了一个苹果”和“苹果股价上涨”两个句子后会得到两个完全不同的向量表示从而精准捕捉上下文语义。因此理解Embedding不仅是理解Transformer的起点更是理解现代深度学习如何处理离散符号世界的钥匙。它把人类抽象的语言转换成了机器可以计算和推理的数学对象。2. Embedding的三大核心组件Token, Position, Segment当我们说“把文本输入Transformer”时具体在做什么并不是把一串字符直接扔进去。以句子“我爱自然语言处理”为例它需要被转换成一系列稠密的向量才能被模型处理。在标准的Transformer如BERT中这个转换过程通常包含三个核心的Embedding层词嵌入Token Embedding、位置嵌入Position Embedding和段嵌入Segment Embedding。它们各司其职共同构成了模型理解的基石。2.1 词嵌入Token Embedding从符号到向量的第一步这是最直观的一层。首先我们需要一个词汇表Vocabulary这是一个包含所有模型“认识”的基本单位Token的列表。Token可以是单词如“love”、子词如“natural”可能被拆成“nat”和“##ural”或汉字。流程句子“我爱自然语言处理”经过分词器Tokenizer后可能变成[“我” “爱” “自然” “语言” “处理”]这几个Token。每个Token在词汇表中都有一个唯一的ID例如“我”101“爱”102。词嵌入层本质上就是一个巨大的查找表Look-up Table其维度是[词汇表大小, 隐藏层维度d_model]。我们根据Token ID从这个表中取出对应的行就是一个d_model维的向量。这个向量就是该Token的初始、静态的语义表示。为什么需要学习这个查找表Embedding矩阵中的参数是在预训练过程中从海量文本中学出来的。模型通过上下文任务如掩码语言模型不断调整每个Token对应的向量使得语义相近的Token在向量空间中也逐渐靠近。注意对于中文处理粒度需要仔细考量。按字分词简单且词表小但语义单元破碎按词分词语义完整但面临未登录词OOV和分词歧义问题。如今主流的大模型如BERT、GPT大多采用基于字节对编码BPE或WordPiece的子词分词法能在词表大小和语义粒度间取得较好平衡。2.2 位置嵌入Position Embedding为序列注入顺序信息Transformer的自注意力机制本身是“无序”的。对于一个句子打乱单词顺序后自注意力计算的输出在集合意义上是等价的它无法感知“我爱她”和“她爱我”的区别。因此必须显式地注入位置信息。正弦余弦公式原始Transformer原始论文提出了一种使用固定公式生成的位置编码对于位置pos和维度iPE(pos, 2i) sin(pos / 10000^(2i/d_model))PE(pos, 2i1) cos(pos / 10000^(2i/d_model))这种方法的优点是能够处理比训练时更长的序列外推性且具有相对位置关系的线性变换特性。可学习的位置嵌入如BERT更常见的做法是直接设置一个可学习的矩阵其维度为[最大序列长度, d_model]。每个位置索引对应这个矩阵中的一行向量。在训练时这个矩阵的参数会随模型一起更新。这种方法简单有效但长度受预设最大值限制。如何结合得到词嵌入向量E_token和位置嵌入向量E_pos后通常直接进行元素相加E E_token E_pos。为什么是相加而不是拼接从实践和理论上看相加操作能使模型在后续层中同时学习到语义和位置信息且不会增加额外的参数和计算复杂度。模型有能力在训练中学会区分这两种信息的来源。2.3 段嵌入Segment Embedding处理句子对任务对于需要区分两个句子的任务如问答、自然语言推理段嵌入用来标识一个Token属于句子A还是句子B。实现它也是一个可学习的嵌入向量。通常只有两个或更多类型。例如在句子对[CLS] 我 爱 自然 语言 处理 [SEP] 这 门 技术 很 有趣 [SEP]中第一个句子的所有Token包括[CLS]和第一个[SEP]都加上段嵌入E_A第二个句子的所有Token加上段嵌入E_B。最终输入表示因此一个Token的最终输入表示是三者之和H_input E_token E_pos E_segment这个H_input的维度是[序列长度, d_model]它将被送入Transformer的编码器堆栈。3. 深入原理Embedding矩阵是如何学习的我们常说Embedding是“学”出来的这个过程具体是怎样的它与传统的Word2Vec有何不同理解这一点就能明白Transformer为何强大。3.1 学习目标上下文任务驱动在Word2Vec的CBOW或Skip-gram模型中学习目标是根据上下文预测中心词或根据中心词预测上下文。这是一种静态的、基于局部窗口的预测任务。而在Transformer的预训练如BERT中学习目标更为复杂和有效主要是掩码语言模型MLM。随机掩盖输入序列中15%的Token用[MASK]替换然后让模型根据未被掩盖的上下文来预测被掩盖的原始Token。例如 输入我 [MASK] 自然语言处理目标预测[MASK]位置原本是“爱”。这个任务迫使模型必须深度理解每个Token与全局上下文的关系才能做出准确预测。正是在完成无数个这样的预测任务过程中模型反向传播误差不断调整三个Embedding矩阵以及后续Transformer层的参数使得最终的向量表示能够编码丰富的语义和语法信息。3.2 参数更新反向传播的起点Embedding层是模型的第一层它的梯度来自于深层的损失计算。假设在MLM任务中模型对某个被掩盖位置的预测错了损失函数如交叉熵会产生一个误差信号。这个信号通过链式法则从输出层一直反向传播回Embedding层。词嵌入矩阵这个误差信号会告诉模型“在当前这个上下文里你给这个[MASK]位置分配的向量导致预测成了错误的词。你需要微调这个向量以及影响它的上下文向量让它更接近正确词的向量方向。” 于是词嵌入矩阵中对应Token的向量以及上下文相关Token的向量都会得到微调。位置嵌入矩阵误差信号也会包含位置信息。“在这个序列的第3个位置你的位置向量提供的顺序信息可能不够导致模型混淆了语序。” 因此位置嵌入矩阵中对应位置行的向量也会被更新。动态表征的关键由于同一个Token如“苹果”会在无数不同的上下文不同位置、不同相邻词中被训练它的基础词嵌入向量会收敛到一个“平均意义”上。但是当这个基础向量与不同的位置嵌入、段嵌入相加并经过多层Transformer的自注意力交互后它在每一层、每一个具体上下文中的激活向量都是动态且独特的。这才是Transformer理解一词多义的核心。3.3 可视化理解向量空间几何学习完成后我们可以通过降维技术如t-SNE将高维词向量可视化到2D平面。你会发现语义聚类同义词、近义词会聚集在一起如“汽车”、“轿车”、“货车”。类比关系经典的“国王-男人女人≈女王”的向量运算关系会出现。这证明Embedding空间捕捉到了某种语义上的“方向”和“距离”。上下文偏移同一个词型如“bank”的不同含义河岸、银行可能会分布在不同的区域具体取决于训练语料中上下文的分布。4. 进阶话题与实战中的Embedding理解了基础我们来看看在实际使用和更前沿的模型里Embedding有哪些变化和需要注意的地方。4.1 嵌入层参数共享编码器与解码器的默契在原始的Transformer论文用于机器翻译中有一个精妙的细节编码器的输入嵌入层、解码器的输入嵌入层和解码器的输出线性层在softmax之前共享同一个权重矩阵。当然解码器的输入也会加入位置编码。这样做的好处大幅减少参数量对于大词汇表Embedding矩阵参数极多共享权重能显著降低模型总参数量。训练更稳定高效梯度更新同时作用于这三个部分形成一种协同效应。向量空间对齐迫使模型学习一个统一的语义空间编码器将源语言映射到此空间解码器从此空间生成目标语言逻辑上更一致。实战注意在实现时通常将Embedding矩阵的转置作为输出层的权重。需要确保嵌入维度d_model与模型最终隐藏层维度一致。4.2 位置编码的演进从绝对到相对从固定到外推原始Transformer的 sinusoidal 位置编码虽经典但有其局限。后续研究提出了多种改进相对位置编码自注意力机制计算QK^T时核心是计算词与词之间的关联度。相对位置编码认为重要的不是词在序列中的绝对位置第5个词而是词与词之间的相对距离相距2个词。因此它在计算注意力分数时会加入一个表示相对距离的偏置项。这在长文本理解和生成任务中表现更好也是当前许多先进模型如T5、DeBERTa的标准配置。旋转位置编码RoPE这是LLaMA、GPT-NeoX等主流大模型采用的技术。它通过复数旋转的方式将绝对位置信息巧妙地融入Token的Query和Key向量中。其最大优点是具有距离外推性即模型在训练时只见过一定长度如2048的序列但在推理时能一定程度上处理更长的序列而无需微调。这对于处理长文档至关重要。ALiBiAttention with Linear Biases另一种简单有效的相对位置编码。它不在嵌入层加位置信息而是直接在注意力分数上加上一个与相对距离成负线性关系的偏置惩罚远距离的注意力。实践表明ALiBi的外推能力非常强。踩坑心得当你尝试微调一个预训练模型如BERT来处理长于其训练时最大长度通常是512的文本时直接截断会丢失信息而简单扩展位置嵌入例如将512大小的位置嵌入矩阵扩展到1024新增部分随机初始化通常效果很差。因为模型没有学过这些新位置向量的语义。此时需要考虑使用支持更长上下文的方法或者采用滑动窗口等策略。如果必须处理长文本选择原生支持更长上下文或具备良好外推能力位置编码的模型如使用RoPE的模型是更稳妥的起点。4.3 Embedding作为模型接口检索增强生成RAG中的核心在大语言模型应用中Embedding扮演着连接非参数化知识外部文档和参数化知识模型权重的桥梁其典型应用就是RAG。文档切分与嵌入将知识库文档切分成片段chunks使用一个独立的Embedding模型如BGE、text-embedding-ada-002将每个文本片段编码成一个向量。向量存储将所有向量存入向量数据库如Milvus, Pinecone, FAISS。检索当用户提问时用同样的Embedding模型将问题也编码成向量在向量数据库中执行相似度搜索如余弦相似度找出与问题向量最相关的几个文本片段。生成将这些检索到的文本片段作为上下文与用户问题一起输入给大语言模型让其生成答案。在这里Embedding模型的质量直接决定了检索的准确性从而影响最终答案的质量。一个优秀的Embedding模型需要确保“语义相似的问题和文档片段其向量距离很近”。4.4 视觉TransformerViT中的Embedding图像如何变成序列Transformer不仅用于文本也彻底改变了计算机视觉。在Vision Transformer中Embedding的处理方式独具匠心。图像分块将输入图像例如224x224像素划分成固定大小的 patches例如16x16像素。一个224x224的图像会被分成 (224/16)^2 196个 patches。线性投影每个patch16x16x3768维通过一个可训练的线性层全连接层被映射到一个d_model维的向量。这个线性投影层就扮演了“词嵌入”的角色它将一个图像块“嵌入”到模型空间。添加位置嵌入同样需要为这196个图像块添加位置信息因为模型需要知道哪个块在左上角哪个块在右下角。ViT通常使用可学习的一维位置嵌入。添加分类Token在序列开头添加一个可学习的[class]token其对应的输出向量用于最终的图像分类。通过这种方式ViT成功地将一幅2D图像“嵌入”成了一个1D的向量序列从而可以套用为文本设计的Transformer架构。5. 实操动手实现一个简单的Embedding层理论说了这么多我们动手用PyTorch实现一个结合了词嵌入、位置嵌入和段嵌入的完整输入表示层以加深理解。import torch import torch.nn as nn import math class TransformerEmbedding(nn.Module): 一个完整的Transformer输入嵌入层。 包含词嵌入 位置嵌入 段嵌入可选 def __init__(self, vocab_size, d_model, max_seq_len, n_segments2, dropout0.1): super().__init__() self.d_model d_model # 1. 词嵌入层 self.token_embedding nn.Embedding(vocab_size, d_model) # 2. 位置嵌入层 (可学习方式 更常用) self.position_embedding nn.Embedding(max_seq_len, d_model) # 3. 段嵌入层 (对于句子对任务) self.segment_embedding nn.Embedding(n_segments, d_model) # 4. LayerNorm 和 Dropout (标准配置) self.layer_norm nn.LayerNorm(d_model) self.dropout nn.Dropout(dropout) # 初始化参数 self._init_weights() def _init_weights(self): 用Xavier均匀分布初始化嵌入层参数 nn.init.xavier_uniform_(self.token_embedding.weight) nn.init.xavier_uniform_(self.position_embedding.weight) nn.init.xavier_uniform_(self.segment_embedding.weight) def forward(self, input_ids, segment_idsNone): 前向传播。 Args: input_ids: [batch_size, seq_len] Token IDs segment_ids: [batch_size, seq_len] Segment IDs (0或1) 可为None Returns: embeddings: [batch_size, seq_len, d_model] batch_size, seq_len input_ids.shape device input_ids.device # 1. 获取词嵌入 token_embeds self.token_embedding(input_ids) # [batch, seq, d_model] # 2. 创建位置ID并获取位置嵌入 # 生成 [0, 1, 2, ..., seq_len-1] 并扩展为batch维度 pos_ids torch.arange(seq_len, dtypetorch.long, devicedevice).unsqueeze(0) # [1, seq] pos_ids pos_ids.expand(batch_size, seq_len) # [batch, seq] pos_embeds self.position_embedding(pos_ids) # [batch, seq, d_model] # 3. 组合嵌入 embeddings token_embeds pos_embeds # 4. 如果提供了段ID加上段嵌入 if segment_ids is not None: seg_embeds self.segment_embedding(segment_ids) embeddings seg_embeds # 5. 应用LayerNorm和Dropout (Transformer的标准做法) embeddings self.layer_norm(embeddings) embeddings self.dropout(embeddings) return embeddings # 使用示例 if __name__ __main__: vocab_size 30000 d_model 512 max_seq_len 128 batch_size 4 seq_len 20 # 创建模型 embedding_layer TransformerEmbedding(vocab_size, d_model, max_seq_len) # 模拟输入一批Token ID input_ids torch.randint(0, vocab_size, (batch_size, seq_len)) # 模拟输入句子对任务的段ID (0代表第一句1代表第二句) segment_ids torch.cat([torch.zeros((batch_size, 10)), torch.ones((batch_size, 10))], dim1).long() # 前向计算 output_embeddings embedding_layer(input_ids, segment_ids) print(f输入形状: {input_ids.shape}) print(f输出嵌入形状: {output_embeddings.shape}) # 应为 [4, 20, 512]代码解读与注意事项初始化我们创建了三个独立的nn.Embedding层分别对应词、位置和段。d_model是Transformer模型的隐藏层维度也是所有嵌入向量的统一维度。位置ID生成注意我们在forward函数中动态生成位置ID。这是为了确保无论输入的序列实际长度是多少只要不超过max_seq_len都能正确获取对应位置的位置向量。torch.arange创建了[0, 1, ..., seq_len-1]的序列。相加操作三种嵌入直接进行元素相加。这是标准做法模型有能力在后续层中分离和利用这些信息。LayerNorm与Dropout在相加之后立即应用LayerNorm和Dropout是Transformer架构的常见设计。LayerNorm有助于稳定训练Dropout则是一种正则化手段防止过拟合。参数初始化我们使用Xavier均匀分布初始化嵌入权重这是一种常用的、能促进稳定训练的方法。在实际的Transformer模型如Hugging Face的Transformers库中嵌入层的实现逻辑与此类似但通常会集成更多的功能如padding mask处理和配置选项。通过自己实现一遍你能更深刻地理解输入数据是如何一步步变成模型“看得懂”的数值形式的。6. 避坑指南Embedding实践中的常见问题在实际项目中处理Embedding时经常会遇到一些棘手的问题。这里分享几个我踩过的坑和对应的解决方案。6.1 词汇表外OOV词的处理无论你的词汇表多大总会遇到没见过的词。处理方式至关重要子词分词使用BPE、WordPiece或SentencePiece等子词分词算法可以将未知词拆分成已知的子词单元。例如“ChatGPT”可能被拆成“Chat”和“##GPT”。这是目前最主流、最有效的方法。UNK Token准备一个特殊的[UNK]UnknownToken。所有OOV词都映射到这个Token。缺点是损失了所有信息如果[UNK]过多会严重影响性能。字符级或字节级回退对于子词也无法处理的极端情况如乱码、特殊符号可以回退到字符级或字节级表示。这能保证任何输入都有输出但表示粒度太细计算效率低。个人经验在构建领域特定的NLP系统时如医疗、金融通用模型如BERT的分词器可能在你的领域语料上产生大量子词分割。一个有效的策略是用你的领域语料对原有分词器进行增量训练让它学习到你领域内的高频术语和组合从而减少OOV和不合理的切分。6.2 嵌入矩阵的“冷启动”与迁移学习当你需要向词汇表中添加新词时新词的嵌入向量如何初始化随机初始化最简单但新词向量与原有语义空间不协调需要大量数据重新训练。近义词平均如果新词可以分解或找到语义相近的已知词可以用这些已知词向量的平均来初始化。例如为“智能手机”初始化可以取“智能”和“手机”向量的平均。使用外部词向量用Word2Vec或FastText在大型语料上预训练的词向量来初始化即使模型架构不同也能提供较好的语义起点。在微调中学习如果新增词汇不多且你有足够的标注数据直接在目标任务上微调整个模型包括新的嵌入参数通常是可行的。6.3 位置编码与序列长度外推这是微调预训练模型时的一个经典难题。假设你有一个最大长度为512的预训练BERT但你的任务文档长达2000词。直接截断取前512个Token。简单但丢失大量信息。滑动窗口将长文本分成多个512长度的片段分别输入模型然后聚合结果如取各片段[CLS]向量的平均。常用于文本分类。稀疏注意力使用Longformer、BigBird等引入稀疏注意力机制的模型它们能原生处理更长序列。外推法使用具备良好外推能力的位置编码如RoPE、ALiBi的模型。或者对现有位置嵌入进行插值如将0-511的位置索引线性映射到0-1999但这属于“hack”效果不稳定通常还需要在长文本数据上进一步微调称为“位置插值微调”。6.4 嵌入层的维度灾难与降维d_model维度通常很大如768、1024但在某些下游任务如简单的文本分类中直接使用最后一层的[CLS]向量768维可能过于冗余且容易过拟合。池化除了[CLS]可以尝试对所有Token的输出向量进行平均池化Mean Pooling或最大池化Max Pooling有时效果更好。降维在嵌入向量输入分类器之前可以加一个小的全连接层进行降维如768-256然后再接分类层。这相当于一个瓶颈结构能减少参数有时还能提升泛化能力。多层嵌入融合Transformer不同层捕获不同级别的信息底层更多语法高层更多语义。可以尝试将最后几层的[CLS]向量拼接起来或者加权求和作为最终表示。Embedding远不止是模型输入的第一层那么简单。它是连接离散符号与连续计算世界的桥梁其质量直接决定了模型认知世界的“分辨率”。从静态的Word2Vec到动态的Transformer Embedding从绝对位置编码到相对位置编码从文本到图像Embedding技术的发展史就是AI模型如何更精细、更智能地理解世界信息的一个缩影。理解它是打开Transformer乃至现代深度学习大门的第一把也是最重要的一把钥匙。下次当你调用model.embeddings时希望你能对背后发生的复杂而精妙的映射过程有更生动的认知。
返回列表