AI 词向量模型详解:让机器理解词语的奥秘
词向量模型:让机器理解词语的语义关系 本文系统介绍了词向量技术的发展与应用。传统One-Hot编码存在维度灾难和语义缺失问题,而词向量通过低维稠密向量实现语义编码。重点讲解了Word2Vec模型(包括CBOW和Skip-Gram架构)及其优化技术(层次Softmax和负采样),并提供了Python实现示例。同时介绍了GloVe模型如何结合全局统计与局部上下文信息,通过共现矩阵构建更优的词向量表示。
词向量模型详解:让机器理解词语的奥秘
导读:为什么"国王"减去"男人"加上"女人"等于"女王"?词向量如何让计算机理解词语的语义?本文将带你深入探索词向量模型的世界。
一、从One-Hot到Dense:词表示的革命
1.1 传统方法的困境
在深度学习时代之前,我们如何表示一个词?最常见的方法是One-Hot编码:
# 假设词典:["apple", "banana", "orange", "grape"]
"apple" → [1, 0, 0, 0]
"banana" → [0, 1, 0, 0]
"orange" → [0, 0, 1, 0]
"grape" → [0, 0, 0, 1]
问题显而易见:
- ❌ 维度灾难:词典多大,向量就多长(动辄数万维)
- ❌ 语义鸿沟:任意两个词的内积都是0,无法衡量相似度
- ❌ 数据稀疏:每个词都是孤岛,无法泛化
1.2 词向量的核心思想
分布假说(Distributional Hypothesis):“一个词的语义由其上下文决定” —— J.R. Firth, 1957
词向量(Word Embedding)将每个词映射到一个低维、稠密、连续的向量空间,让语义相似的词在空间中距离更近。
# 词向量示例(维度=300)
"king" → [0.21, -0.32, 0.15, ..., 0.42]
"queen" → [0.19, -0.30, 0.18, ..., 0.39]
"man" → [0.25, -0.28, 0.12, ..., 0.45]
"woman" → [0.23, -0.26, 0.14, ..., 0.41]
# 神奇的向量运算:king - man + woman ≈ queen
二、Word2Vec:词向量的开山之作
2013年,Google的Tomas Mikolov团队提出了Word2Vec,引爆了NLP领域。它包含两种训练架构:
2.1 CBOW(Continuous Bag-of-Words)
核心思想:用上下文预测中心词
上下文:[the, cat, on, mat] → 预测中心词:sat
训练样本:
输入:the, cat, on, mat (one-hot编码)
输出:sat (概率分布)
模型结构:
输入层 → 投影层(求平均) → 输出层(Softmax)
↓ ↓ ↓
上下文词 隐藏层向量 词汇表概率分布
适用场景:频繁词、训练速度快
2.2 Skip-Gram
核心思想:用中心词预测上下文
中心词:sat → 预测上下文:[the, cat, on, mat]
训练样本:
输入:sat
输出:the, cat, on, mat (多个预测任务)
模型结构:
输入层 → 投影层 → 输出层(多个Softmax)
↓ ↓ ↓
中心词 词向量 每个上下文词的概率
适用场景:稀有词、小数据集、效果更好
2.3 关键技术:Hierarchical Softmax & Negative Sampling
原始Softmax计算复杂度为O(V),V是词典大小(可能数十万)。Word2Vec引入了两种优化:
Hierarchical Softmax(层次Softmax)
- 使用Huffman树组织词汇表
- 复杂度降至O(log V)
- 对低频词效果更好
Negative Sampling(负采样)
- 将多分类问题转化为多个二分类问题
- 每次只更新正样本 + 少量负样本(通常5-20个)
- 公式:
J(θ)=logσ(woTwc)+∑i=1kEwi∼Pn[logσ(−wiTwc)]J(\theta) = \log \sigma(w_o^T w_c) + \sum_{i=1}^{k} \mathbb{E}_{w_i \sim P_n} [\log \sigma(-w_i^T w_c)]J(θ)=logσ(woTwc)+i=1∑kEwi∼Pn[logσ(−wiTwc)]
其中:
- wcw_cwc:中心词向量
- wow_owo:上下文词向量
- kkk:负样本数量
- PnP_nPn:噪声分布(通常是词频的3/4次方)
2.4 Word2Vec代码实战
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
import numpy as np
# 准备语料(分词后的句子列表)
sentences = [
["the", "cat", "sat", "on", "the", "mat"],
["the", "dog", "played", "in", "the", "garden"],
["cats", "and", "dogs", "are", "pets"]
]
# 训练Word2Vec模型
model = Word2Vec(
sentences,
vector_size=100, # 向量维度
window=5, # 上下文窗口大小
min_count=1, # 忽略词频低于此值的词
workers=4, # 并行线程数
sg=1, # 1=Skip-gram, 0=CBOW
negative=5, # 负采样数量
epochs=10 # 训练轮数
)
# 查看词向量
print("cat的词向量:", model.wv['cat'])
print("向量维度:", len(model.wv['cat']))
# 查找相似词
print("\n与'cat'最相似的词:")
for word, similarity in model.wv.most_similar('cat', topn=5):
print(f" {word}: {similarity:.4f}")
# 向量运算
print("\n向量运算示例:")
result = model.wv.most_similar(
positive=['king', 'woman'],
negative=['man'],
topn=1
)
print(f"king - man + woman ≈ {result[0][0]} (相似度: {result[0][1]:.4f})")
# 计算相似度
print(f"\ncat和dog的相似度: {model.wv.similarity('cat', 'dog'):.4f}")
print(f"cat和apple的相似度: {model.wv.similarity('cat', 'apple'):.4f}")
# 保存和加载模型
model.save('word2vec.model')
# model = Word2Vec.load('word2vec.model')
三、GloVe:全局统计与局部上下文的完美结合
2014年,斯坦福大学的Jeffrey Pennington等人提出了GloVe(Global Vectors)。
3.1 核心思想
Word2Vec只利用局部上下文信息,而GloVe结合了:
- 全局矩阵分解(如LSA)的统计优势
- 局部上下文窗口(如Word2Vec)的预测能力
3.2 共现矩阵
GloVe首先构建词-词共现矩阵 XXX,其中 XijX_{ij}Xij 表示词 jjj 出现在词 iii 上下文中的次数。
# 示例共现矩阵(简化版)
# the cat sat on mat
# the 0 2 1 1 0
# cat 2 0 1 1 1
# sat 1 1 0 1 1
# on 1 1 1 0 1
# mat 0 1 1 1 0
3.3 损失函数
GloVe的目标是最小化以下损失:
J=∑i,j=1Vf(Xij)(wiTw~j+bi+b~j−logXij)2J = \sum_{i,j=1}^{V} f(X_{ij}) (w_i^T \tilde{w}_j + b_i + \tilde{b}_j - \log X_{ij})^2J=i,j=1∑Vf(Xij)(wiTw~j+bi+b~j−logXij)2
其中:
- wiw_iwi:词 iii 的主向量
- w~j\tilde{w}_jw~j:词 jjj 的上下文向量
- bi,b~jb_i, \tilde{b}_jbi,b~j:偏置项
- f(Xij)f(X_{ij})f(Xij):加权函数,防止过大共现次数主导训练
加权函数设计:
f(x)={(x/xmax)αif x<xmax1otherwisef(x) = \begin{cases} (x/x_{max})^\alpha & \text{if } x < x_{max} \\ 1 & \text{otherwise} \end{cases}f(x)={(x/xmax)α1if x<xmaxotherwise
通常 α=0.75,xmax=100\alpha = 0.75, x_{max} = 100α=0.75,xmax=100
3.4 GloVe代码实战
# 方法1:使用gensim(需要自己构建共现矩阵)
from gensim.scripts.glove2word2vec import glove2word2vec
from gensim.models import KeyedVectors
# 下载预训练的GloVe向量
# 从 https://nlp.stanford.edu/projects/glove/ 下载
# 转换GloVe格式为word2vec格式
glove2word2vec(
glove_input_file='glove.6B.100d.txt',
word2vec_output_file='glove.6B.100d.word2vec.txt'
)
# 加载模型
model = KeyedVectors.load_word2vec_format('glove.6B.100d.word2vec.txt')
# 方法2:使用torchvision(自动下载)
import torch
from torchtext.vocab import GloVe
# 加载预训练GloVe
glove = GloVe(name='6B', dim=100)
# 查询词向量
vector = glove['cat']
print(f"cat的向量形状: {vector.shape}")
# 查找最相似词
def find_similar_words(word, vocab, vectors, topk=5):
idx = vocab.stoi.get(word)
if idx is None:
return []
vector = vectors[idx]
scores = torch.mm(vectors, vector.unsqueeze(1)).squeeze()
top_indices = scores.argsort(descending=True)[:topk+1]
return [(vocab.itos[i.item()], scores[i].item())
for i in top_indices if vocab.itos[i.item()] != word]
similar = find_similar_words('cat', glove.vocab, glove.vectors)
print(f"\n与'cat'相似的词: {similar}")
四、FastText:处理未登录词的利器
2016年,Facebook AI Research提出了FastText,解决了Word2Vec和GloVe的一个致命缺陷:无法处理未登录词(OOV, Out-of-Vocabulary)。
4.1 核心创新:子词(Subword)信息
FastText将每个词表示为字符n-gram的集合,加上特殊边界符号。
# 以"apple"为例,n=3
# 添加边界符号: <apple>
# 提取3-gram:
# [<ap, app, ppl, ple, le>, <ap, app, ppl, ple, le>]
# 实际包括: <ap, app, ppl, ple, le> + 完整词apple
# 词向量 = 所有n-gram向量的和
vector("apple") = Σ vector(n-gram_i)
4.2 优势
- 处理OOV词:即使词不在词典中,也能通过字符n-gram生成向量
- 捕捉形态学信息:相似拼写的词共享n-gram,向量相近
- 适合形态丰富的语言:如德语、俄语、土耳其语
4.3 FastText代码实战
from gensim.models import FastText
# 准备语料
sentences = [
["the", "cat", "sat", "on", "the", "mat"],
["the", "dog", "played", "in", "the", "garden"],
["cats", "and", "dogs", "are", "pets"]
]
# 训练FastText模型
model = FastText(
sentences,
vector_size=100,
window=5,
min_count=1,
workers=4,
sg=1, # 1=Skip-gram, 0=CBOW
negative=5,
epochs=10,
min_n=3, # 最小n-gram长度
max_n=6 # 最大n-gram长度
)
# 获取词向量(包括OOV词)
print("cat的词向量:", model.wv['cat'])
# 关键:查询未登录词
oov_word = "kittens" # 假设这个词不在训练集中
if oov_word in model.wv:
print(f"\n{oov_word}的词向量:", model.wv[oov_word])
else:
# FastText会为OOV词生成向量
print(f"\n{oov_word}是未登录词,但FastText仍能生成向量")
print(f"向量形状: {model.wv[oov_word].shape}")
# 查找相似词
print(f"\n与'dog'相似的词:")
for word, sim in model.wv.most_similar('dog', topn=5):
print(f" {word}: {sim:.4f}")
# 保存模型
model.save('fasttext.model')
五、词向量的可视化与评估
5.1 降维可视化
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import numpy as np
def visualize_word_embeddings(model, words, method='pca'):
"""可视化词向量"""
# 获取词向量
vectors = [model.wv[word] for word in words]
vectors = np.array(vectors)
# 降维到2D
if method == 'pca':
reducer = PCA(n_components=2)
else:
from sklearn.manifold import TSNE
reducer = TSNE(n_components=2, random_state=42)
vectors_2d = reducer.fit_transform(vectors)
# 绘图
plt.figure(figsize=(10, 8))
plt.scatter(vectors_2d[:, 0], vectors_2d[:, 1])
for i, word in enumerate(words):
plt.annotate(word, (vectors_2d[i, 0], vectors_2d[i, 1]))
plt.title(f'Word Embeddings Visualization ({method.upper()})')
plt.grid(True, alpha=0.3)
plt.show()
# 使用示例
words = ['king', 'queen', 'man', 'woman', 'prince', 'princess', 'boy', 'girl']
visualize_word_embeddings(model, words, method='pca')
5.2 内在评估(Intrinsic Evaluation)
# 1. 词相似度任务
from scipy.stats import spearmanr
def evaluate_word_similarity(model, test_data):
"""
评估词相似度
test_data: [(word1, word2, human_score), ...]
"""
model_scores = []
human_scores = []
for word1, word2, human_score in test_data:
if word1 in model.wv and word2 in model.wv:
model_scores.append(model.wv.similarity(word1, word2))
human_scores.append(human_score)
correlation, _ = spearmanr(model_scores, human_scores)
return correlation
# 2. 词类比任务
def evaluate_word_analogies(model, analogy_data):
"""
评估词类比
analogy_data: [(word1, word2, word3, expected_word4), ...]
"""
correct = 0
total = len(analogy_data)
for word1, word2, word3, expected in analogy_data:
result = model.wv.most_similar(
positive=[word2, word3],
negative=[word1],
topn=1
)
if result[0][0] == expected:
correct += 1
return correct / total
# 示例测试数据
analogy_test = [
('king', 'queen', 'man', 'woman'),
('paris', 'france', 'tokyo', 'japan'),
('good', 'better', 'bad', 'worse')
]
accuracy = evaluate_word_analogies(model, analogy_test)
print(f"类比任务准确率: {accuracy:.2%}")
5.3 外在评估(Extrinsic Evaluation)
在实际NLP任务中评估词向量效果:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
def evaluate_on_downstream_task(model, texts, labels):
"""
在下游任务(如文本分类)中评估词向量
"""
# 将文本表示为词向量的平均
def text_to_vector(text):
words = text.lower().split()
vectors = [model.wv[w] for w in words if w in model.wv]
if not vectors:
return np.zeros(model.vector_size)
return np.mean(vectors, axis=0)
X = np.array([text_to_vector(text) for text in texts])
y = np.array(labels)
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 训练分类器
clf = LogisticRegression(max_iter=1000)
clf.fit(X_train, y_train)
# 评估
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
return accuracy
# 示例
texts = ["I love this movie", "Terrible film", "Amazing story", "Boring plot"]
labels = [1, 0, 1, 0] # 1=正面, 0=负面
accuracy = evaluate_on_downstream_task(model, texts, labels)
print(f"情感分类准确率: {accuracy:.2%}")
六、预训练词向量资源
6.1 常用预训练模型
| 模型 | 语言 | 维度 | 下载地址 |
|---|---|---|---|
| Word2Vec (Google) | 英文 | 300 | https://code.google.com/archive/p/word2vec/ |
| GloVe | 英文 | 50-300 | https://nlp.stanford.edu/projects/glove/ |
| FastText | 多语言 | 300 | https://fasttext.cc/docs/en/pretrained-vectors.html |
| 中文Word2Vec | 中文 | 300 | https://github.com/Embedding/Chinese-Word-Vectors |
6.2 加载预训练模型
from gensim.models import KeyedVectors
# 加载Google Word2Vec(二进制格式)
# model = KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)
# 加载GloVe(文本格式)
# model = KeyedVectors.load_word2vec_format('glove.6B.100d.txt', no_header=True)
# 加载FastText
from gensim.models import FastText
# model = FastText.load_fasttext_format('cc.en.300.bin')
七、词向量的局限性与演进
7.1 主要局限
-
一词多义问题
# "bank"在"river bank"和"bank account"中意思不同 # 但Word2Vec/GloVe只能给出一个向量 -
上下文无关
- 无法根据句子语境调整词义
-
静态表示
- 训练完成后向量固定,无法微调适应新任务
7.2 演进方向
静态词向量 → 动态词向量 → 预训练语言模型
(Word2Vec) (ELMo) (BERT, GPT)
ELMo(Embeddings from Language Models):
- 使用双向LSTM
- 根据上下文生成动态词向量
- 同一词在不同语境有不同表示
BERT及Transformer模型:
- 基于Self-Attention机制
- 深度双向上下文
- 成为当前NLP的标准工具
八、实战建议与最佳实践
8.1 如何选择词向量模型?
| 场景 | 推荐模型 | 理由 |
|---|---|---|
| 快速原型、小数据集 | FastText | 训练快,处理OOV |
| 通用NLP任务 | GloVe/Word2Vec预训练 | 效果好,资源丰富 |
| 形态丰富语言 | FastText | 子词信息有用 |
| 需要上下文理解 | BERT等 | 动态表示 |
| 资源受限环境 | 自己训练Word2Vec | 控制维度,轻量化 |
8.2 训练技巧
# 1. 数据预处理
def preprocess_text(text):
# 转小写
text = text.lower()
# 去除标点
import re
text = re.sub(r'[^\w\s]', '', text)
# 分词
return text.split()
# 2. 超参数调优建议
hyperparams = {
'vector_size': [100, 200, 300], # 维度:100-300通常足够
'window': [3, 5, 10], # 窗口:小窗口捕获语法,大窗口捕获语义
'min_count': [1, 5, 10], # 过滤低频词
'negative': [5, 10, 15], # 负样本数
'epochs': [10, 20, 50], # 训练轮数
'learning_rate': [0.025, 0.05] # 学习率
}
# 3. 增量训练
# 模型可以在新数据上继续训练
model.build_vocab(new_sentences, update=True)
model.train(new_sentences, total_examples=len(new_sentences), epochs=5)
8.3 常见问题解决
问题1:内存不足
# 使用迭代器而非加载全部数据到内存
def sentence_generator(file_path):
with open(file_path, 'r') as f:
for line in f:
yield preprocess_text(line)
model = Word2Vec(vector_size=100, min_count=1)
model.build_vocab(sentence_generator('large_corpus.txt'))
model.train(sentence_generator('large_corpus.txt'),
total_examples=1000000, epochs=10)
问题2:训练太慢
# 使用多进程
model = Word2Vec(sentences, workers=8) # 使用8个CPU核心
# 减少负样本数
model = Word2Vec(sentences, negative=5) # 默认是5,可以减少
# 降低维度
model = Word2Vec(sentences, vector_size=100) # 而非300
问题3:效果不佳
- 增加训练数据量
- 调整窗口大小(语义任务用大窗口,语法任务用小窗口)
- 使用预训练向量初始化
- 增加训练轮数
九、总结与展望
核心要点回顾
- 词向量的本质:将离散符号映射到连续向量空间,捕捉语义相似性
- Word2Vec:CBOW和Skip-gram两种架构,负采样加速训练
- GloVe:结合全局统计和局部上下文
- FastText:引入子词信息,解决OOV问题
- 评估方法:内在评估(相似度、类比)+ 外在评估(下游任务)
未来趋势
- 多模态词向量:结合文本、图像、音频
- 知识增强词向量:融入知识图谱信息
- 低资源语言:跨语言迁移学习
- 可解释性:理解词向量学到的语义
学习资源
-
论文:
- Word2Vec: “Efficient Estimation of Word Representations in Vector Space”
- GloVe: “GloVe: Global Vectors for Word Representation”
- FastText: “Enriching Word Vectors with Subword Information”
-
课程:
- Stanford CS224N: Natural Language Processing with Deep Learning
- Coursera: Natural Language Processing Specialization
-
工具:
- Gensim: https://radimrehurek.com/gensim/
- spaCy: https://spacy.io/
- Hugging Face: https://huggingface.co/
结语
词向量是NLP领域的基石技术,尽管BERT等预训练模型已经崛起,但理解词向量的原理仍然是每个NLP工程师的必修课。它们轻量、高效、可解释,在许多场景下仍然是首选方案。
希望这篇文章能帮助你深入理解词向量的奥秘!如果有任何问题,欢迎在评论区讨论。
Happy Embedding! 🚀
参考文献:
- Mikolov, T., et al. (2013). Efficient Estimation of Word Representations in Vector Space. ICLR.
- Pennington, J., et al. (2014). GloVe: Global Vectors for Word Representation. EMNLP.
- Bojanowski, P., et al. (2017). Enriching Word Vectors with Subword Information. TACL.
更多推荐


所有评论(0)