行业资讯
📅 2026/8/17 16:26:09
从Word2Vec到GPT:手搓Embedding,理解词向量如何注入语义
上周我试图向一位刚接触大模型的朋友解释为什么一个简单的“苹果”输入到模型里能输出关于水果、公司甚至手机的不同回答。我提到了“Embedding”这个词他立刻反问“所以它就是个查表工具把词变成一串数字对吧”这个理解很普遍但也很容易让人止步于此。如果Embedding仅仅是一个静态的“词到向量”的映射表那它和一本电子词典有什么区别为什么它能让GPT“理解”上下文甚至进行复杂的推理我们常说的“词向量注入意义”这个“注入”的动作究竟是怎么发生的今天我们不谈复杂的数学公式而是尝试“手搓”一下这个核心过程。我们将从一个最朴素的问题开始如何让计算机“感受”到一个词的意义然后一步步构建我们自己的理解框架看看从原始的文本符号到模型能够处理的、富含语义的稠密向量中间到底经历了怎样的“炼金术”。你会发现Embedding远不止是编码它本质上是在为语言构建一个可计算的“意义空间”。1. 从符号到意义我们到底想让计算机“学会”什么在深入技术细节之前我们必须先统一认知当我们谈论一个词的“意义”时我们在谈论什么对于人类来说“苹果”的意义来源于视觉红色的圆球、味觉甜、触觉光滑、文化伊甸园的果实和语境“我买了一个苹果” vs. “苹果发布了新手机”。计算机没有这些感官和经验它只有文本符号。因此给计算机注入意义本质上是一个表示学习问题我们能否找到一种方法将离散的、符号化的词语映射到一个连续的、低维的数学空间向量空间中并且在这个空间里词语之间的几何关系如距离、方向能够反映它们之间的语义关系。这就是著名的“分布假说”在计算层面的体现一个词的意义由其上下文决定。上下文相似的词意义也相近。例如“猫”和“狗”经常出现在“宠物”、“喂养”、“可爱”等相似的上下文中所以它们的向量表示应该在空间中彼此靠近。所以我们“手搓”Embedding的目标就清晰了输入海量的文本语料句子、段落。过程设计一个学习任务让模型通过观察词语的上下文来调整其向量表示。输出一个词表其中每个词都对应一个固定长度的稠密向量。核心要求在这个向量空间中语义相近的词距离近语义相关的词有特定的方向关系如“国王”-“男人”“女人”≈“女王”。2. “手搓”核心Skip-gram 模型的极简实现理解了目标我们来看一个经典且直观的实现方案Word2Vec中的Skip-gram模型。它完美地体现了“通过上下文学习词义”的思想。我们不依赖任何深度学习框架用最基础的Python和NumPy来勾勒其骨架理解其灵魂。假设我们有一个极小的语料库[the, cat, sat, on, the, mat]。词汇表大小为6。2.1 构建数据定义“上下文”Skip-gram的任务是给定一个中心词如sat预测它周围一定窗口大小如2内的上下文词[the, cat, on, the]。首先我们需要将词语数字化。最直接的方法是One-hot编码import numpy as np vocab [the, cat, sat, on, mat] # 简单去重 word_to_index {word: i for i, word in enumerate(vocab)} VOCAB_SIZE len(vocab) EMBEDDING_DIM 3 # 为了演示我们使用极小的维度3 # 例如“cat”的one-hot向量 cat_index word_to_index[cat] cat_one_hot np.zeros(VOCAB_SIZE) cat_one_hot[cat_index] 1 # 输出: [0., 1., 0., 0., 0.]这个向量维度高等于词表大小、极度稀疏且无法表达任何语义关系。所有词在one-hot空间里都是正交的“猫”和“狗”的距离与“猫”和“飞机”一样远。2.2 设计模型两个矩阵的故事Skip-gram的精妙之处在于它用两个矩阵来完成学习输入矩阵 W_in形状为(VOCAB_SIZE, EMBEDDING_DIM)。它的每一行就是一个词的输入向量中心词向量。输出矩阵 W_out形状为(EMBEDDING_DIM, VOCAB_SIZE)。它的每一列对应一个词的输出向量上下文词向量。模型的前向传播过程如下输入中心词的one-hot向量x如cat。与W_in相乘得到该词的稠密向量表示h x · W_in。这步操作本质上就是查表从W_in中取出对应行。将h与W_out相乘得到对所有词表词的得分scores h · W_out。对scores应用softmax函数得到一个概率分布y_hat表示每个词作为其上下文词的概率。# 初始化两个矩阵 W_in np.random.randn(VOCAB_SIZE, EMBEDDING_DIM) * 0.01 W_out np.random.randn(EMBEDDING_DIM, VOCAB_SIZE) * 0.01 def forward(center_word_idx): 极简前向传播 # 1. 获取中心词向量 (查表) h W_in[center_word_idx] # 形状: (EMBEDDING_DIM,) # 2. 计算对所有词的得分 scores np.dot(h, W_out) # 形状: (VOCAB_SIZE,) # 3. 计算概率分布 (简易softmax未考虑数值稳定性) exp_scores np.exp(scores) y_hat exp_scores / np.sum(exp_scores) return h, y_hat # 尝试输入“cat” center_idx word_to_index[cat] h_cat, prob_dist forward(center_idx) print(f中心词 cat 的向量: {h_cat}) print(f预测的上下文词概率分布前3: {prob_dist[:3]})此时W_in和W_out是随机的所以预测的概率分布也是随机的。h_cat就是“猫”当前随机的Embedding。2.3 关键学习反向传播与意义“注入”模型如何学习我们需要一个损失函数来衡量预测分布y_hat和真实分布y的差距。对于Skip-gram真实分布y是多个上下文词的one-hot向量的平均或者使用负采样等技巧简化。我们使用交叉熵损失。然后通过反向传播计算损失对W_in和W_out的梯度并用梯度下降法更新这两个矩阵。这就是“注入意义”的魔法时刻当模型看到(cat, sat)这样一个中心词上下文词配对时它会调整W_in中“cat”对应的行即“cat”的向量和W_out中“sat”对应的列使它们的内积得分增大。同时对于随机采样的非上下文词负样本模型会调整参数使它们的内积减小。经过海量(中心词上下文词)配对的训练后W_in矩阵的每一行——即每个词的输入向量——就被调整到了一个位置上。这个位置是由该词在所有训练样本中遇到的上下文词共同“推拉”形成的。最终W_in就是我们想要的词向量查找表。语义相似的词因为拥有相似的上下文在训练过程中被相似的上下文词“推拉”最终在向量空间中聚集到一起。3. 从Word2Vec到GPTEmbedding的演进与深化我们“手搓”的Skip-gram是一个伟大的起点但它是一个静态的、上下文无关的Embedding。无论“苹果”出现在什么句子中它的向量都是固定的。这显然不符合语言的实际使用情况。现代大模型如GPT系列的Embedding机制要复杂和强大得多其核心演进体现在以下几点3.1 从静态到动态上下文感知的Embedding在GPT等Transformer架构中词的初始表示依然是查找一个固定的Embedding矩阵类似于W_in这被称为Token Embedding。但关键的一步在于这个初始向量会立刻与Positional Embedding位置编码相加让模型知道词在序列中的顺序。然后这个结合了词义和位置信息的向量会输入到多层的Transformer Block中。在每一层的自注意力机制里每个词的向量都会根据序列中所有其他词的向量进行动态调整。一个词会“注意”到对当前语义理解最重要的其他词并吸收它们的信息。因此GPT中一个词的最终表示是经过多层网络、基于整个输入句子上下文动态计算出来的。同一个词“苹果”在“吃苹果”和“苹果手机”两个句子中经过Transformer层处理后的向量表示是不同的。这才是真正的“上下文感知”。3.2 从词到子词更精细的粒度Word2Vec以词为单位。但对于大型语料库词表会爆炸百万级且无法处理未登录词OOV。GPT系列使用Byte Pair Encoding (BPE)或类似的子词分词算法。它将词拆分为更小的子词单元如playing - [play, ing]。这样做的好处词表可控用较小的词表如5万覆盖几乎无限的词汇。共享语义playing,played,player共享子词play它们的Embedding天生就有关联。处理新词即使遇到新词unhackable也能拆分为已知子词[un, hack, able]并组合其向量表示。Embedding矩阵现在对应的是子词Token模型学习的是这些更基础单元的表示。3.3 从单一任务到预训练任务驱动Word2Vec的训练任务是“预测上下文”这是一个自监督任务。GPT的Embedding学习则被整合进一个更宏大的预训练任务中自回归语言建模即预测下一个词。在这个任务下模型为了尽可能准确地预测“The cat sat on the ___”它必须学会为the,cat,sat,on,the生成优质的上下文感知表示。理解这些表示之间的关系猫“坐”在某个东西“上”。最终将整个句子的语义浓缩用于预测最可能的mat。这个任务比Skip-gram的局部上下文预测要困难得多也全面得多。它迫使模型学习语法、逻辑、常识甚至一定程度的推理能力。而这些能力都编码在了经过海量文本预训练后的Embedding矩阵和Transformer参数中。此时的Embedding已经不是一个独立的模块而是整个语言理解系统的基础设施和起点。4. 实践启示如何用好Embedding理解了Embedding的原理和演进我们在实际项目中应用它时思路会更加清晰。以下是一些关键的实践启示和决策点。4.1 选型何时用静态何时用动态特性静态Embedding (如Word2Vec, GloVe)动态/上下文Embedding (如BERT, GPT的输出)核心一个词一个固定向量。一个词在不同上下文中有不同向量。优点轻量、快速、计算开销小易于存储和检索。语义表达精准能处理一词多义理解力强。缺点无法处理一词多义语义粒度粗。计算成本高需运行完整模型存储不便需存整个序列的向量。适用场景对速度要求高、语义相对固定的场景如• 关键词扩展• 简单文本分类的特征• 基于内容的推荐物品描述相似度对语义精度要求高、需要深度理解的任务如• 智能问答理解问题细微差别• 语义检索用问题找答案而非关键词匹配• 文本蕴含、情感分析等复杂NLU任务决策建议如果你的任务像“查找相似商品”用静态Embedding足矣性价比最高。如果你的任务像“根据一段复杂的用户描述推荐电影”则需要动态Embedding来捕捉深层意图。4.2 流程从文本到向量应用的通用Pipeline无论选用哪种Embedding一个稳健的工程化流程通常包含以下步骤文本预处理清洗去噪、标准化、分词按所选模型的Tokenizer。一致性是关键训练和应用阶段必须使用完全相同的分词器。向量化静态直接查找预训练好的Embedding矩阵。处理OOV词用零向量、随机向量或所有词向量的平均。动态将分词后的ID序列输入预训练模型取指定层的输出如BERT取最后一层CLS token的向量或所有token向量的平均。存储与检索生成的向量存入向量数据库如Milvus, Pinecone, Qdrant或传统数据库的向量扩展如PgVector。检索时使用余弦相似度或内积进行近似最近邻搜索。应用层将检索到的相似向量映射回原始文本或物品完成推荐、搜索、分类等任务。4.3 避坑指南新手常犯的五个错误忽略分词对齐用BERT的分词器切分文本却用Word2Vec的模型去查表结果必然错误。必须保证分词器与Embedding模型一一对应。盲目使用最后一层对于BERT等模型不同层的向量捕获不同层次的信息底层更多语法高层更多语义。对于某些任务如词性标注中间层的向量可能更有效。需要根据任务进行实验。对长文本简单平均将一篇长文档所有词的向量取平均会丢失结构和关键信息。更好的做法是使用句子向量再平均、使用[CLS]向量、或者使用专门的长文本编码模型。不处理OOV词直接忽略或报错会影响系统覆盖度。必须有明确的OOV策略并在评估时考虑其影响。认为向量相似就等于语义相同Embedding空间是统计驱动的。“数据”和“数字”向量可能很近因为它们上下文相似但在某些精确场景下需要区分。必要时需要在Embedding之上增加业务规则或微调。4.4 进阶微调与领域适配预训练的Embedding是在通用语料如维基百科、网页上训练的。如果你的领域非常垂直如医学、法律、金融通用Embedding可能表现不佳。解决方案是微调继续预训练在领域语料上继续用语言模型任务训练更新Embedding层和部分模型权重。任务微调在你的下游任务如分类、问答数据上端到端地微调整个模型Embedding层也会随之调整更适应领域语言特点。这个过程可以看作是让通用的“意义空间”在你的专业领域里进行一次“精修”让向量之间的几何关系更能反映你领域内的语义关联。回过头看最初的问题Embedding给词“注入”意义并不是一个一蹴而就的魔法。它是一个系统性的工程通过设计一个巧妙的预测任务如预测上下文或下一个词利用海量文本数据驱动模型将离散符号映射到一个连续空间。在这个空间里语义的相似性、关联性被转化为可计算的几何关系。从静态的Word2Vec到动态的GPT演进的方向是让这个“意义空间”越来越细腻、越来越贴合真实的语言使用场景。所以下次当你调用一句model.encode(text)时可以想到这背后是一套精巧的、从数据中蒸馏意义的机制在运作。理解它不仅能帮你更好地使用Embedding也能让你在遇到语义搜索不准、文本匹配效果不好时拥有从底层排查和优化的思路——是分词不对是模型不匹配还是需要对领域知识进行微调这才是从“会用”到“理解”的关键一步。