您现在的位置是:首页 >技术交流 >人工智能学习(六)之语言大模型Word2Vec网站首页技术交流

人工智能学习(六)之语言大模型Word2Vec

power-辰南 2025-02-12 12:01:02
简介人工智能学习(六)之语言大模型Word2Vec

一、语言模型基础

在深入探讨 Word2Vec 之前,理解语言模型的基础知识至关重要。语言模型旨在计算一个句子在自然语言中出现的概率P(w_1,w_2,w_3,.....,w_n),即其中wi表示句子中的第i个单词。

(一)基于统计的语言模型

  1. 原理:基于统计的语言模型运用链式法则将句子概率分解为一系列条件概率的乘积,即p(w_1,w_2,......,w_n) = p(w_1)p(w_2|w_1)p(w_3|w_1,w_2)...p(w_n|w_1,w_2,....w_n-_1)通过对大量文本数据的统计分析,我们可以估算这些概率值。例如,在一个包含众多英语句子的语料库中,统计 “the” 这个词在句首出现的频率,以此估计p(w=the);统计在 “the” 之后出现 “dog” 的频率,从而估计p(w_2=dog|w1=the)
  2. 问题:然而,随着句子长度n的增加,条件概率p(w=n|w_1,w_2,...w_n-_1)的计算变得极为复杂。因为要考虑前面所有单词的组合情况,参数数量呈指数级增长。以一个简单的例子来说,如果词汇表大小为V,那么在计算p(w=n|w_1,w_2,...w_n-_1)时,参数数量将达到V^n级别,这在实际应用中几乎是无法处理的。

(二)N - gram 模型

  1. 简化策略:为了简化计算,N - gram 模型引入了马尔可夫假设,即假设一个词的出现概率只依赖于它前面的N-1个词。在二元模型N=2中,;在三元模型N=3中,。例如,在二元模型中,我们只需要关注相邻两个词之间的关系,如 “我 喜欢”“喜欢 吃” 等组合出现的频率,以此来估计条件概率。
  2. 优点与局限:这种简化极大地减少了参数数量。在二元模型中,参数数量从V^n降低到V^2,使得计算变得可行。然而,N - gram 模型仍然存在数据稀疏问题。特别是当处理长文本或生僻词时,由于某些词组合在训练数据中出现的次数较少,导致估计的概率不准确。例如,对于一些专业领域的罕见术语组合,在普通语料库中可能几乎不会出现,那么在 N - gram 模型中就难以准确估计其概率。

二、Word2Vec 模型

Word2Vec 作为一种高效的词向量生成模型,旨在通过训练将单词映射到低维向量空间,使语义相近的单词在向量空间中距离相近。它主要包含两种模型架构:连续词袋模型(CBOW)和跳字模型(Skip - Gram)。

(一)连续词袋模型(CBOW)

  1. 实际场景理解:想象你正在阅读一篇关于美食的文章,看到 “我 走进 一家 餐厅,点了一份____,味道 很棒” 这样一句话。根据上下文 “我走进一家餐厅,点了一份” 以及 “味道很棒”,你可以推测出空白处可能是 “披萨”“牛排” 等食物相关的词汇。CBOW 模型就是模拟人类这种根据上下文预测当前词的能力。
  2. 模型结构与计算过程
    • 输入层:假设我们设定上下文窗口大小为m。对于给定的句子,以某个词为中心,取其前后各m个词作为上下文。这些上下文词首先被转换为独热编码向量,每个独热编码向量的维度等于词汇表大小V。例如,词汇表中有 10000 个单词,那么每个独热编码向量就是 10000 维,其中只有对应单词位置的元素为 1,其余均为 0。
    • 隐藏层:输入层的每个独热编码向量与一个权重矩w_1(维度为V*NN是我们预先设定的词向量维度,比如 300)相乘,进行线性变换。这个过程将高维稀疏的独热向量映射到一个N维的隐藏层向量。可以将这个隐藏层向量看作是对上下文词信息的一种浓缩表示,它综合了上下文词的特征。多个上下文词对应的隐藏层向量通常会进行累加或平均操作,得到一个统一的隐藏层表示。
    • 输出层:隐藏层向量再与另一个权重矩阵w_2(维度为N*V相乘,映射回V维空间。然后通过 softmax 函数将这个V维向量转换为概率分布,该概率分布表示每个单词作为中心词的可能性。softmax 函数的公式为,其中z是输出层未经过 softmax 变换的向量,j表示向量的第j个元素。例如,经过 softmax 变换后,得到的概率分布向量中,“披萨” 对应的概率可能是 0.7,“汉堡” 对应的概率可能是 0.1 等,概率总和为 1。

  3. 训练过程:在训练阶段,我们希望模型预测出的中心词概率分布与真实的中心词情况尽可能一致。真实的中心词用独热编码向量表示,通过最小化预测概率与真实概率之间的交叉熵损失来更新权重矩阵w_1w_2。交叉熵损失函数的公式为:,其中y_i是真实概率(中心词的独热编码向量中第i个元素),是预测概率(经过 softmax 变换后的概率分布向量中第i个元素)。如果模型预测的中心词概率与真实情况偏差较大,损失值就会较大,通过反向传播算法,调整权重矩阵,使得损失值逐渐减小,从而使模型的预测更加准确。经过大量文本数据的训练后,权重矩阵w_1的行向量就成为了每个词的词向量。

(二)跳字模型(Skip - Gram)

  1. 实际场景理解:同样以美食文章为例,当看到 “披萨” 这个词时,我们可以联想到它周围可能出现的词,如 “美味”“芝士”“烤箱” 等。跳字模型就是基于中心词去预测其周围的上下文词。
  2. 模型结构与计算过程
    • 输入层:中心词被转换为独热编码向量,维度同样为V
    • 隐藏层:与 CBOW 类似,通过权重矩阵w_1(维度为V*N将输入的独热编码向量映射到N维隐藏层向量,实现对中心词信息的特征提取。
    • 输出层:隐藏层向量再与权重矩阵w_2(维度为N*V相乘,映射到V维空间,然后通过 softmax 函数转换为每个单词作为上下文词的概率分布。
  3. 训练过程:训练时,对于每个中心词,会对其上下文窗口内的所有词进行预测。计算预测的上下文词概率分布与真实的上下文词(独热编码向量表示)之间的交叉熵损失,通过反向传播算法更新权重矩阵w_1w_2。由于跳字模型对每个中心词都要预测多个上下文词,所以训练样本数量比 CBOW 更多,计算量相对较大。但它在处理低频词时表现更好,因为即使某个低频词出现次数少,但通过其周围的高频词,跳字模型也能更好地捕捉到它与其他词的关系。例如,对于一些罕见的地方特色美食名称,跳字模型可以通过其周围描述口感、制作方法等常见词汇来学习到该低频词的语义特征。

三、训练优化技巧

(一)负采样(Negative Sampling)

  1. 问题背景:在原始的 Word2Vec 训练中,计算 softmax 概率时需要对词汇表中的所有V个词进行归一化计算,这在词汇表很大时计算量极其巨大。例如,当词汇表大小V=10000时,每次计算 softmax 概率都需要对 10000 个词进行指数运算和求和运算,计算成本很高。
  2. 解决方法:负采样的方法是从词汇表中随机采样一小部分负样本(非上下文词),假设采样k个负样本。在训练时,只对正样本(上下文词)和这k个负样本计算损失并更新权重。具体来说,对于每个中心词 - 上下文词对(正样本),随机选择k个不在该上下文窗口内的词作为负样本。例如,在预测 “披萨” 的上下文词时,正样本可能是 “美味”,负采样得到的负样本可能是 “汽车”“书本”“电脑” 等。这样,在计算损失时,只需要考虑这k+1个样本(1 个正样本和k个负样本),而不是词汇表中的所有V个词,大大减少了计算量。负采样的核心思想是通过对少量负样本的学习,让模型区分正样本和负样本,从而近似地学习到真实的概率分布。

(二)分层 Softmax(Hierarchical Softmax)

  1. 原理:分层 Softmax 将词汇表构建成一棵哈夫曼树,树的叶子节点是词汇表中的词。哈夫曼树的构建原则是根据单词在语料库中的频率,频率越高的单词离根节点越近。在计算某个词的概率时,不需要对所有词进行计算,而是沿着从根节点到该叶子节点的路径进行。从根节点开始,每次根据当前节点的左右子节点的概率决定向左还是向右走,直到到达目标词对应的叶子节点。例如,对于一个词w,假设根节点有两个子节点A和B,模型会计算选择A和B的概率,然后根据概率选择其中一个子节点继续向下走,直到找到词w对应的叶子节点。这样,计算概率的复杂度从O(V)降低到O(logV),大大提高了计算效率。
  2. 优势:这种方法在处理大规模词汇表时效果显著,能够在不损失太多精度的情况下,大幅减少计算量。特别是对于那些低频词,由于它们在哈夫曼树中处于较低的层次,计算其概率的路径相对较短,计算量也相应减少。

四、Word2Vec 的优点与应用场景

(一)优点

  1. 分布式表示:Word2Vec 生成的词向量是分布式表示,每个维度都蕴含着一定的语义信息。这种表示方式能够捕捉单词之间丰富的语义关系,如语义相似性和类比关系。例如,在一个训练好的词向量空间中,“国王”“王后”“王子”“公主” 等词的向量在空间中距离较近,并且满足 “国王” - “男人” + “女人”≈“王后” 这样的类比关系。这表明词向量不仅能表示单词的语义相似性,还能通过向量运算反映出语义之间的逻辑联系。
  2. 计算效率高:相比传统的基于统计的语言模型,Word2Vec 的训练过程相对简单,计算效率高。它通过采用 CBOW 和 Skip - Gram 等模型架构,以及负采样和分层 Softmax 等优化技巧,能够快速处理大规模的文本数据。在实际应用中,可以在较短的时间内对大量文本进行训练,生成有效的词向量。
  3. 通用性强:训练得到的词向量可以应用于多种自然语言处理任务,具有很强的通用性。无需针对每个具体任务重新训练词向量,而是可以直接将预训练的词向量应用到不同的任务中。例如,在文本分类任务中,可以将文本中的词转换为词向量后,通过平均或其他方式将文本表示为一个向量,输入到分类模型中进行分类;在命名实体识别中,利用词向量能更好地识别出文本中的实体;在机器翻译中,词向量也能帮助模型理解不同语言单词之间的对应关系等。

(二)应用场景

  1. 文本分类:在新闻分类领域,假设有政治、经济、娱乐、科技等多个类别。我们可以将新闻文本中的每个词转换为词向量,然后通过平均池化或其他方式将整个文本表示为一个固定维度的向量。将这个向量输入到分类模型(如支持向量机、神经网络等)中,模型根据词向量所携带的语义信息进行分类,判断该新闻属于哪个类别。例如,一篇关于股票市场波动的新闻,其中包含 “股票”“市场”“经济数据” 等词,这些词的词向量能够反映出文本的经济领域特征,帮助模型准确地将其分类为经济新闻。
  2. 信息检索:在搜索引擎中,当用户输入一个查询词时,将查询词和文档中的词都转换为词向量。通过计算查询词向量与文档中词向量的相似度(如余弦相似度),来判断文档与查询词的相关性,从而返回相关的文档。例如,用户输入 “人工智能发展现状”,搜索引擎将这些词转换为词向量后,在文档库中寻找词向量与之相似度高的文档,提高检索的准确性和效率。
  3. 推荐系统:在电影推荐系统中,将电影的描述文本中的词转换为词向量,通过分析用户历史观看电影的描述词向量,推荐与用户兴趣相似的电影。比如,用户经常观看科幻类电影,电影描述中包含 “宇宙”“外星生物”“未来科技” 等词,系统根据这些词的词向量,寻找其他具有相似词向量特征的电影推荐给用户。同时,在商品推荐、音乐推荐等领域,Word2Vec 词向量也能发挥类似的作用,通过分析用户行为和物品描述的语义关系,提供个性化的推荐服务。

五、词向量相关解释

(一) 高维空间的布局与定位

词向量空间是高维度抽象空间,假设词向量维度为 300,即有 300 个坐标轴。每个单词以其词向量在该空间中定位,如同三维空间中一个点由(x, y, z)坐标确定。例如 “苹果” 的词向量坐标决定其在语义宇宙的独特位置。

(二)语义相似性与关联的体现

语义相近单词在空间中距离近,形成 “语义社区”。如 “香蕉”“橙子” 等水果类单词聚集。不仅如此,具有语义关联的词存在空间联系,如 “国王”“王后”“王子”“公主” 围绕 “皇室” 概念形成区域,且 “国王” 到 “王后” 的向量偏移类似于 “男人” 到 “女人”,体现类比关系。

(三)连续性与平滑性的意义

词向量空间具连续性和平滑性,从一个单词到语义相近单词是平滑过渡。如从 “小狗” 到 “大狗”,词向量变化连续。这使模型能对未见词组合合理推测,基于周边词向量关系 “插值”。

(四)主题聚类与星系结构

整个词向量空间可看作由不同主题 “星系” 组成,每个 “星系” 包含相关单词。如 “体育” 星系有 “篮球”“运动员” 等词,“科技” 星系有 “计算机”“代码” 等词。不同主题 “星系” 相对独立又通过跨主题词微弱联系。

六、Word2Vec训练代码实例

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
import random
from sklearn.decomposition import PCA

# 示例文本数据
text = """Natural language processing (NLP) is a subfield of artificial intelligence (AI)
that focuses on the interaction between computers and human language.
It enables machines to understand, interpret, and generate human language in a valuable way.
NLP techniques are used in various applications such as chatbots, machine translation, and text summarization.
Machine learning plays a crucial role in NLP, allowing models to learn patterns and relationships in language data."""

# 数据预处理
def preprocess(text):
    # 转换为小写并去除标点符号
    text = text.lower()
    text = text.replace('.', '').replace(',', '').replace('(', '').replace(')', '').replace(':', '').replace(';', '')
    tokens = text.split()
    return tokens

tokens = preprocess(text)
print(tokens)


# 构建词汇表
vocab = set(tokens)
vocab_size = len(vocab)

# 构建单词到索引和索引到单词的映射
word_to_idx = {word: idx for idx, word in enumerate(vocab)}
idx_to_word = {idx: word for idx, word in enumerate(vocab)}

# 生成训练数据(Skip - Gram)
def generate_training_data(tokens, word_to_idx, window_size):
    data = []
    for i in range(len(tokens)):
        for j in range(max(0, i - window_size), min(len(tokens), i + window_size + 1)):
            if i != j:
                data.append((word_to_idx[tokens[i]], word_to_idx[tokens[j]]))
    return data

window_size = 2
data = generate_training_data(tokens, word_to_idx, window_size)
print(data)

# 定义数据加载器
def get_batch(data, batch_size):
    random.shuffle(data)
    start_index = 0
    while start_index < len(data):
        end_index = min(start_index + batch_size, len(data))
        batch = data[start_index:end_index]
        x = torch.tensor([item[0] for item in batch], dtype=torch.long)
        y = torch.tensor([item[1] for item in batch], dtype=torch.long)
        yield x, y
        start_index = end_index

# 定义 Word2Vec 模型(Skip - Gram)
class SkipGramModel(nn.Module):
    def __init__(self, vocab_size, embedding_dim):
        super(SkipGramModel, self).__init__()
        self.input_embeddings = nn.Embedding(vocab_size, embedding_dim)
        self.output_embeddings = nn.Embedding(vocab_size, embedding_dim)

    def forward(self, center_words):
        center_embeds = self.input_embeddings(center_words)
        return center_embeds

# 超参数设置
embedding_dim = 100
batch_size = 32
epochs = 100
learning_rate = 0.01

# 初始化模型、损失函数和优化器
model = SkipGramModel(vocab_size, embedding_dim)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# 训练循环
for epoch in range(epochs):
    total_loss = 0
    for inputs, targets in get_batch(data, batch_size):
        optimizer.zero_grad()
        center_embeds = model(inputs)
        output_embeds = model.output_embeddings.weight
        scores = torch.matmul(center_embeds, output_embeds.t())
        loss = criterion(scores, targets)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}/{epochs}, Loss: {total_loss / len(data)}')

# 获取词向量
word_embeddings = model.input_embeddings.weight.detach().numpy()

# 定义计算相似度的函数
def cosine_similarity(word1, word2, word_embeddings, word_to_idx):
    idx1 = word_to_idx[word1]
    idx2 = word_to_idx[word2]
    vec1 = word_embeddings[idx1]
    vec2 = word_embeddings[idx2]
    dot_product = np.dot(vec1, vec2)
    norm1 = np.linalg.norm(vec1)
    norm2 = np.linalg.norm(vec2)
    similarity = dot_product / (norm1 * norm2)
    return similarity

# 验证相似度
word1 = 'natural'
word2 = 'language'
similarity = cosine_similarity(word1, word2, word_embeddings, word_to_idx)
print(f'The cosine similarity between "{word1}" and "{word2}" is: {similarity}')

# 可视化词向量
def visualize_word_embeddings(word_embeddings, idx_to_word, num_words=10):
    pca = PCA(n_components=2)
    reduced_embeddings = pca.fit_transform(word_embeddings)

    plt.figure(figsize=(10, 8))
    for i in range(num_words):
        word = idx_to_word[i]
        x, y = reduced_embeddings[i]
        plt.scatter(x, y)
        plt.annotate(word, (x, y), textcoords="offset points", xytext=(0, 10), ha='center')
    plt.title('Word Embeddings Visualization')
    plt.show()

visualize_word_embeddings(word_embeddings, idx_to_word)

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。