2.1 词嵌入技术基础 词嵌入的概念与意义 词嵌入是将离散的词语转换为连续向量空间中的点,实现语义的数学化表示: 语义映射:将词语的语义关系转换为向量空间中的几何关系 降维表示:将高维稀疏的one-hot编码压缩为低维稠密向量 相似性计算:通过向量运算量化词语间的语义相似度 词嵌入技术的核心思想来自于分布式语义假说:一个词语的含义可以通过其上下文来定义。通过在大规模文本语料上进行训练,算法能够学习到词语间的语义关系,并将其编码为向量空间中的几何关系。
词嵌入是将离散的词语转换为连续向量空间中的点,实现语义的数学化表示:
词嵌入技术的核心思想来自于分布式语义假说:一个词语的含义可以通过其上下文来定义。通过在大规模文本语料上进行训练,算法能够学习到词语间的语义关系,并将其编码为向量空间中的几何关系。
在传统的自然语言处理中,词语通常使用one-hot编码表示:
词语:机器学习 编码:[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] 维度:V=12(词汇表大小)
One-hot编码存在以下严重问题:
词嵌入使用低维稠密向量表示词语,例如:
"机器学习" → [0.23, -0.45, 0.67, 0.12, -0.34, 0.89, -0.56, 0.43] "人工智能" → [0.21, -0.43, 0.65, 0.15, -0.32, 0.87, -0.54, 0.41] "深度学习" → [0.25, -0.47, 0.69, 0.14, -0.36, 0.91, -0.58, 0.45]
这样的表示具有以下优势:
Word2Vec是Google在2013年提出的词嵌入模型,包含两种主要架构:
1. CBOW(Continuous Bag of Words)
上下文词语 --> 中间词 [学生, 在, 学校, 里] --> 学习
CBOW通过上下文词语预测中间词语,学习到的向量能够反映词语的语法和语义信息。
2. Skip-gram
中间词 --> 上下文词语 学习 --> [学生, 在, 学校, 里]
Skip-gram通过中间词语预测上下文词语,更适合处理低频词语和不规则表达。
Word2Vec的核心是softmax函数和负采样技术:
Softmax函数:
P(w_j | w_i) = exp(u_j · v_i) / Σ(exp(u_k · v_i))
其中:
w_i 是中心词w_j 是候选词v_i 是中心词的输入向量u_j 是候选词的输出向量负采样:为了避免计算整个词汇表的softmax,使用负采样方法,只计算正样本和少量负样本的损失函数。
import numpy as np from collections import defaultdict class Word2Vec: def __init__(self, vector_size=100, window=5, min_count=5): self.vector_size = vector_size self.window = window self.min_count = min_count self.vocab = {} self.word_vectors = {} self.context_vectors = {} def build_vocab(self, sentences): """构建词汇表""" word_counts = defaultdict(int) # 统计词频 for sentence in sentences: for word in sentence: word_counts[word] += 1 # 过滤低频词 self.vocab = { word: idx for word, count in word_counts.items() if count >= self.min_count } # 初始化词向量 for word, idx in self.vocab.items(): self.word_vectors[word] = np.random.normal(0, 0.1, self.vector_size) self.context_vectors[word] = np.random.normal(0, 0.1, self.vector_size) def generate_training_data(self, sentences): """生成训练数据""" training_data = [] for sentence in sentences: for i, word in enumerate(sentence): if word not in self.vocab: continue # 生成上下文窗口 for j in range(max(0, i-self.window), min(len(sentence), i+self.window+1)): if j == i or sentence[j] not in self.vocab: continue positive_sample = (self.vocab[word], self.vocab[sentence[j]]) training_data.append(positive_sample) return training_data def train(self, training_data, epochs=10, learning_rate=0.01): """训练Word2Vec模型""" for epoch in range(epochs): total_loss = 0 for center_word, context_word in training_data: # 获取向量 v_center = self.word_vectors[center_word] u_context = self.context_vectors[context_word] # 计算softmax scores = np.dot(list(self.word_vectors.values()), u_context) exp_scores = np.exp(scores) probs = exp_scores / np.sum(exp_scores) # 计算梯度 grad_output = probs.copy() grad_output[center_word] -= 1 # 更新向量 word_list = list(self.word_vectors.keys()) for i, word in enumerate(word_list): if i == center_word: self.word_vectors[word] -= learning_rate * np.dot(u_context, grad_output) else: self.context_vectors[word] -= learning_rate * np.dot(v_center, grad_output) total_loss += -np.log(probs[center_word]) print(f"Epoch {epoch+1}, Loss: {total_loss}")
GloVe(Global Vectors for Word Representation)是斯坦福大学提出的词嵌入模型,基于全局词-词共现矩阵的统计信息。
核心思想:词向量的点积应该近似等于对数共现概率:
w_i · w_j = log P(i|j)
其中:
w_i 和 w_j 是两个词的向量P(i|j) 是词j出现时词i出现的条件概率GloVe使用加权最小二乘法:
J = Σ_{i,j=1}^{V} f(X_{ij}) (w_i · w_j + b_i + b_j - log X_{ij})²
其中:
X_{ij} 是词i和词j的共现次数f(X_{ij}) 是权重函数,用于调节高频词的影响b_i 和 b_j 是偏置项| 特性 | Word2Vec | GloVe |
|---|---|---|
| 训练目标 | 局部上下文预测 | 全局统计关系 |
| 数学基础 | 概率模型 | 线性代数模型 |
| 计算效率 | 高(在线学习) | 中等(批处理) |
| 语义表示 | 上下文语义 | 全局语义关系 |
| 词向量质量 | 良好 | 更稳定 |
FastText是Facebook在2016年提出的词嵌入模型,主要创新在于:
FastText将词语表示为其n-gram字符序列的向量和:
"机器学习" = ["机器", "学习", "器学", "习学"] vector("机器学习") = vector("机器") + vector("学习") + vector("器学") + vector("习学")
这种表示方式具有以下优势:
from collections import defaultdict class FastText: def __init__(self, vector_size=100, ngram_min=3, ngram_max=5): self.vector_size = vector_size self.ngram_min = ngram_min self.ngram_max = ngram_max self.word_vectors = {} self.ngram_vectors = {} def generate_ngrams(self, word): """生成词语的n-gram""" ngrams = [] word = f"<{word}>" # 添加边界标记 for n in range(self.ngram_min, self.ngram_max + 1): for i in range(len(word) - n + 1): ngram = word[i:i+n] ngrams.append(ngram) return ngrams def get_word_vector(self, word): """获取词语的完整向量表示""" if word not in self.word_vectors: # 计算n-gram向量和 ngrams = self.generate_ngrams(word) word_vector = np.zeros(self.vector_size) for ngram in ngrams: if ngram in self.ngram_vectors: word_vector += self.ngram_vectors[ngram] self.word_vectors[word] = word_vector return self.word_vectors[word]
BERT(Bidirectional Encoder Representations from Transformers)是Google在2018年提出的双向Transformer模型,代表了NLP领域的重大突破。
核心特点:
import torch import torch.nn as nn class BERTEmbeddings(nn.Module): def __init__(self, vocab_size, hidden_size, max_position_embeddings, type_vocab_size): super().__init__() self.word_embeddings = nn.Embedding(vocab_size, hidden_size) self.position_embeddings = nn.Embedding(max_position_embeddings, hidden_size) self.token_type_embeddings = nn.Embedding(type_vocab_size, hidden_size) self.LayerNorm = nn.LayerNorm(hidden_size, eps=1e-12) self.dropout = nn.Dropout(0.1) def forward(self, input_ids, token_type_ids=None): seq_length = input_ids.size(1) position_ids = torch.arange(seq_length, dtype=torch.long, device=input_ids.device) position_ids = position_ids.unsqueeze(0).expand_as(input_ids) words_embeddings = self.word_embeddings(input_ids) position_embeddings = self.position_embeddings(position_ids) token_type_embeddings = self.token_type_embeddings(token_type_ids) embeddings = words_embeddings + position_embeddings + token_type_embeddings embeddings = self.LayerNorm(embeddings) embeddings = self.dropout(embeddings) return embeddings
| 应用场景 | 推荐模型 | 理由 |
|---|---|---|
| 通用语义搜索 | Word2Vec | 简单高效,语义效果良好 |
| 学术研究 | GloVe | 数学理论基础扎实 |
| 形态复杂语言 | FastText | 处理OOV和形态变化 |
| 高级语义理解 | BERT | 上下文感知,深度语义 |
| 实时搜索 | DistilBERT | 轻量级,推理速度快 |
| 长文档 | Longformer | 处理长文本序列 |
训练性能:
推理性能:
开始 ├── 是否需要处理OOV词汇? │ ├── 是 → FastText │ └── 否 → 继续判断 ├── 是否需要上下文感知? │ ├── 是 → BERT/DistilBERT │ └── 否 → 继续判断 ├── 训练数据规模如何? │ ├── 小 → Word2Vec │ └── 大 → GloVe ├── 推理延迟要求? │ ├── 严格 → Word2Vec │ └── 宽松 → 可选择高级模型 └── 计算资源? ├── 充足 → BERT └── 有限 → Word2Vec/FastText
场景:用户搜索"苹果手机",需要包含"iPhone"相关商品。
解决方案:
# 使用Word2Vec构建同义词映射 synonyms = { "苹果": ["苹果", "Apple", "iphone", "iPhone"], "手机": ["手机", "手机", "phone", "Phone"] } def expand_query(query): expanded = [query] for word in query.split(): if word in synonyms: expanded.extend(synonyms[word]) return expanded
效果:
场景:用户提问"怎么重置密码",需要匹配相关问题。
解决方案:
# 使用BERT计算语义相似度 def semantic_similarity(query, faq_questions): query_vector = get_bert_embedding(query) similarities = [] for question in faq_questions: question_vector = get_bert_embedding(question) similarity = cosine_similarity(query_vector, question_vector) similarities.append((question, similarity)) return sorted(similarities, key=lambda x: x[1], reverse=True)
效果:
场景:研究人员查找特定技术领域的论文。
解决方案:
# 使用GloVe处理技术术语 def build_tech_domain_embedding(domain_terms): domain_vector = np.zeros(vector_size) for term in domain_terms: if term in vocabulary: domain_vector += word_vectors[term] return domain_vector / len(domain_terms) # 计算文献相关性 def calculate_paper_relevance(paper_text, domain_vector): paper_vector = average_embedding(paper_text.split()) return cosine_similarity(paper_vector, domain_vector)
效果: