《CBOW 词向量转化实战:让自然语言处理 “读懂” 文字背后的含义》

文章目录

前言

在自然语言处理领域,让计算机理解人类语言的语义一直是研究难点。传统的独热编码等词表示方法,仅能孤立标识单词,无法体现词间语义联系。

词向量转换与词嵌入技术的诞生打破了这一困局。它们将离散单词映射为连续向量,挖掘单词间语义关联,把单词嵌入低维空间,使语义相近的词自然聚类。如今,这项技术已深度融入文本分类、机器翻译等任务,成为 NLP 模型理解语义的核心基础。接下来,我们将深入解析其原理、方法及应用。

一、自然语言模型

语言模型是自然语言处理的关键技术,常见类型包括传统统计语言模型和神经网络语言模型。传统统计语言模型中的 N - gram 模型,基于统计计算文本中连续 N 个词出现的概率以预测下一词,如二元语法计算词对概率,其优势在于简单高效,但存在无法处理长距离语义依赖、数据稀疏等问题;神经网络语言模型中,递归神经网络语言模型(RNN - LM)能捕捉长期依赖关系,却面临梯度消失与爆炸难题,影响长序列处理效果,长短时记忆网络语言模型(LSTM - LM)作为 RNN 改进版,通过门控机制优化信息流动,可有效处理长序列,例如记住长句开头关键信息辅助后续处理,门控循环单元语言模型(GRU - LM)则简化 RNN 结构,合并部分门和状态,在部分任务中效果良好且计算效率更高。

统计语言模型存在的问题

1、由于参数空间的爆炸式增长,它无法处理(N>3)的数据。

举例理解:

中文有成千上万的词汇,四词组合的可能性超过100亿种(相当于给每个汉字搭配3个伙伴的所有可能性)。即使你每天背100个组合,也要273万年才能背完------这就是参数空间的爆炸式增长。统计语言模型就像一个只能死记硬背的学生,当需要记忆的组合超过三词时,它的"大脑"就完全装不下了。

2、没有考虑词与词之间内在的联系性。

假设你学过:

"小狗在公园奔跑"和"小猫在草地跳跃",但从未学过"小猫在公园奔跑"。

人类会自动联想:既然"小狗"和"小猫"都是宠物,"奔跑"和"跳跃"都是动作,那么新句子应该合理。但传统统计模型就像一个只认字面意思的机器人:

它认为"小狗"和"小猫"是完全不同的词,"奔跑"和"跳跃"也没有任何关联,只要没亲眼见过"小猫在公园奔跑"这个具体组合,就认为概率为零。

这就好比只允许用完全相同模具做蛋糕,稍微改动形状就被判定为"不可能",而不知道面粉、鸡蛋这些原料之间本来就有通用性。

总结:这两个问题的本质,第一个是"容量问题":模型记忆力有限;第二个是"理解力问题":模型缺乏抽象能力。

二、词向量转换

1.onehot编码

One-Hot 编码(独热编码)是一种将离散型分类变量(如文字、符号、类别标签)转换为数值型向量的方法。它的核心思想是为每个类别分配一个唯一的二进制向量,向量中只有一位是 1(表示当前类别),其余均为 0。机器学习模型(如神经网络、逻辑回归)只能处理数值数据,无法直接使用文本或类别标签。编码的目的是将非数值信息转化为数值形式。

假设你需要将"我爱中国"这些自然语言输入计算机,但计算机只能处理数字。如果想让计算机能够认识这些文字,则需要通过 One-Hot 编码后:

我 → [1, 0, 0,0]

爱 → [0, 1, 0,0]

中→ [0, 0, 1,0]

国→ [0,0, 0, 1]

每个汉字对应一个"独一无二"的二进制向量,就像为每个类别分配了一个"身份证号"。

编码过程

步骤 1:确定所有可能的类别,例如动物类别为 [猫, 狗, 鸟]。

步骤 2:为每个类别分配一个位置索引,例如:猫→0,狗→1,鸟→2。

步骤 3:生成二进制向量,向量的长度等于类别总数,仅在对应索引位置设为 1,其余为 0。

onehot独热编码存在的问题

1、维度灾难:当类别数量极大时(例如 10,000 个城市),编码后的特征维度爆炸,导致计算效率下降。

例子:假设我们有一个语料库,语料库总共有4960个汉字,将这4960个词转换为onehot向量,矩阵非常稀疏,出现维度灾难。例如有一句话为"我爱北京天安门",传入神经网络输入层的数据为:7x4960的矩阵,这个矩阵是由0和1组成的矩阵,随着语料库的增加,这个矩代表每一个汉字所需的维度也越多,出现了维度爆炸问题。

2、无法表达相似性:所有类别被视为完全独立,例如"猫"和"狗"的相似性无法体现(它们的向量距离相同)。

总结

One-Hot 编码是处理离散特征的基础方法,核心是通过二进制向量唯一标识每个类别。虽然简单有效,但在高基数(类别多)场景下需谨慎使用,此时可考虑嵌入(Embedding)或特征哈希(Hashing)等优化方案。

2.词嵌入

为了解决维度灾难,通过神经网络训练,将每个词都映射到一个较短的词向量上来。词向量的维度一般需要在训练时自己来指定。现在很常见的例如300维。

例如有一句话为"我爱北京天安门",通过神经网络训练后的数据为:

0.62,0.12,0.01,0,0,0,0,....,0

0.1,0.12,0.001,0,0,0,0,....,0

0,0,0.01,0.392,0.39, 0,....,0

0,0,0,1,0,0.01,0.123,....,0.11

"我爱北京天安门"这句话的矩阵由7x4960转换为7x300,可以看出矩阵中维度的数字已经不再是0和1,而是变为了浮点数。

这种将高维度的词表示转换为低维度的词表示的方法,我们称之为词嵌入(word embedding)。

(1)Word2Vec

Google研究团队里的Tomas Mikolov等人于2013年的《Distributed Representations ofWords and Phrases and their Compositionality》以及后续的《Efficient Estimation of Word Representations in Vector Space》两篇文章中提出的一种高效训练词向量的模型,也就是word2vec。

Word2Vec的两种模型结构,CBOW(Continuous Bag-of-Words):根据上下文预测中心词。Skip-Gram:根据中心词预测上下文。

CBOW模型

CBOW模型是以上下文词汇预测当前词,即用ω(t−2)、ω(t−1)、 ω(t+1)、 ω(t+2)预测ω(t)。

假设此时要预测"由",即通过"我命"和"我不"来预测,中间字"由"。

Skip_Gram模型

Skip_Gram模型是以当前词预测其上下文词汇,即用ω(t)预测ω(t−2)、ω(t−1)、 ω(t+1)、 ω(t+2)。

假设此时要使用"由",预测"我命"和"我不"的内容。

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7c6a271943e74b89b809aed01d0174ee.png![=440x](https://i-blog.csdnimg.cn/direct/794ddb4b79e942aba5e2c8c6638af8f8.png)

3、词嵌入模型的训练

(1)模型训练的过程

1、当前词的上下文词语的one-hot编码输入到输入层。

2、这些词分别乘以同一个矩阵WVN后分别得到各自的1 N 向量。

3、将多个这些1N 向量取平均为一个1 N 向量。

4、将这个1N 向量乘矩阵 W'V N ,变成一个1V 向量。
5、将1
V 向量softmax归一化后输出取每个词的概率向量1V
6、将概率值最大的数对应的词作为预测词。
7、将预测的结果1
V 向量和真实标签1V 向量(真实标签中的V个值中有一个是1,其他是0)计算误差
8、在每次前向传播之后反向传播误差,不断调整 WV
N和 W'V*N矩阵的值。

假定语料库中一共有4960个词,则词编码为4960个01组合,现在压缩为300维。


当新来一个字时,我们可以将这个字的onehot向量与CBOW中训练得到的矩阵相乘就可以实现词嵌入,将词向量的维度由4960维降到300维。

(2)损失函数的选择

softmax交叉熵损失函数实现多分类,公式为:

三、CBOW模型实现词嵌入

1、导入必要的库

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim#
from tqdm import tqdm,trange#显示进度条
import numpy as np

2、读取文本,创建词库

python 复制代码
CONTEXT_SIZE=2 #设置词左边和右边选择的个数(即上下文词汇个数)

raw_text ="""We are about to study the idea of a computational process.
            Computational processes are abstract beings that inhabit computers.
            As they evolve, processes manipulate other abstract things called data.
            The evolution of a process is directed by a pattern of rulescalled a program. 
            People create programs to direct processes. 
            In effectwe conjure the spirits of the computer with our spells.""".split()#语料库

#中文的语句,你可以选择分词,也可以选择分字
vocab = set(raw_text)#集合。词库,里面内容独一无人
vocab_size = len(vocab)
word_to_idx = {word:i for i, word in enumerate(vocab)}      #for循环的复合写法,第1次循环,i得到的索引号,word 第1个年
idx_to_word = {i: word for i, word in enumerate(vocab)}
        

3、构造CBOW网络的输入和输出

python 复制代码
data =[]#获取上下文词,将上下文词作为输入,目标词作为输出。构建训练数据集。
for i in range(CONTEXT_SIZE, len(raw_text)-CONTEXT_SIZE):#(2,60)
    context =(
        [raw_text[i-(2-j)]for j in range(CONTEXT_SIZE)]
        +[raw_text[i+j+ 1] for j in range(CONTEXT_SIZE)])
        #获取上下文词(['we"'are"'to''study'])

    target = raw_text[i]    #获取目标词'about'
    data.append((context,target))   #将上下文词和目标词保存到data中[((['we"'are 'to''study'])'about')]

4、定义文本转onehot的函数

python 复制代码
def make_context_vector(context,word_to_idx):#将上下文词转换为one-hot
    idxs =[word_to_idx[w] for w in context]
    return torch.tensor(idxs,dtype=torch.long)#

5、定义CBOW网络

python 复制代码
class CBOW(nn.Module):
    def __init__(self,vocab_size,embedding_dim):
        super(CBOW,self).__init__()
        self.embeddings=nn.Embedding(vocab_size,embedding_dim)
        self.proj=nn.Linear(embedding_dim,128)
        self.output=nn.Linear(128,vocab_size)


    def forward(self,inputs):
        embeds=sum(self.embeddings(inputs)).view(1,-1)
        out=F.relu(self.proj(embeds))
        out=self.output(out)
        nll_prob=F.log_softmax(out,dim=-1)
        return nll_prob

6、优化器损失函数初始化,加载模型到设备中

python 复制代码
device='cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'

model=CBOW(vocab_size,10).to(device)	#将模型加载到设备中,设置CBOW网络的输入和输出vocab_size是指语料库的大小,10是指你要将语料库压缩到多少维。

optimizer=optim.Adam(model.parameters(),lr=0.001)	#创建优化器

loss_funcation=nn.NLLLoss()	#损失函数初始化

7、模型的训练

python 复制代码
losses=[]
model.train()

for epoch in tqdm(range(200)):
    for context,target in data:
        context_vector=make_context_vector(context,word_to_idx).to(device)
        target=torch.tensor([word_to_idx[target]]).to(device)

        train_predict=model(context_vector)
        loss=loss_funcation(train_predict,target)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

8、预测

python 复制代码
context=['People','create','to','direct']
context_vector=make_context_vector(context,word_to_idx).to(device)

model.eval()
predict=model(context_vector)
max_idx=int(predict.argmax(1))
print(idx_to_word[max_idx])

完整代码展示

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim#
from tqdm import tqdm,trange#显示进度条
import numpy as np
#任务:已经有了语料库,
# 1、构造训练数据集,(单词,词库,)#真实的单词模型,
# 每一个单词的词性,你训练大量的输入文本,
CONTEXT_SIZE=2 #设置词左边和右边选择的个数(即上下文词汇个数)

raw_text ="""We are about to study the idea of a computational process.
            Computational processes are abstract beings that inhabit computers.
            As they evolve, processes manipulate other abstract things called data.
            The evolution of a process is directed by a pattern of rulescalled a program. 
            People create programs to direct processes. 
            In effectwe conjure the spirits of the computer with our spells.""".split()#语料库


#中文的语句,你可以选择分词,也可以选择分字
vocab = set(raw_text)#集合。词库,里面内容独一无人
vocab_size = len(vocab)
word_to_idx = {word:i for i, word in enumerate(vocab)}      #for循环的复合写法,第1次循环,i得到的索引号,word 第1个年
idx_to_word = {i: word for i, word in enumerate(vocab)}

data =[]#获取上下文词,将上下文词作为输入,目标词作为输出。构建训练数据集。
for i in range(CONTEXT_SIZE, len(raw_text)-CONTEXT_SIZE):#(2,60)
    context =(
        [raw_text[i-(2-j)]for j in range(CONTEXT_SIZE)]
        +[raw_text[i+j+ 1] for j in range(CONTEXT_SIZE)])
        #获取上下文词(['we"'are"'to''study'])

    target = raw_text[i]    #获取目标词'about'
    data.append((context,target))   #将上下文词和目标词保存到data中[((['we"'are 'to''study'])'about')]
def make_context_vector(context,word_to_idx):#将上下文词转换为one-hot
    idxs =[word_to_idx[w] for w in context]
    return torch.tensor(idxs,dtype=torch.long)#


class CBOW(nn.Module):
    def __init__(self,vocab_size,embedding_dim):
        super(CBOW,self).__init__()
        self.embeddings=nn.Embedding(vocab_size,embedding_dim)
        self.proj=nn.Linear(embedding_dim,128)
        self.output=nn.Linear(128,vocab_size)


    def forward(self,inputs):
        embeds=sum(self.embeddings(inputs)).view(1,-1)
        out=F.relu(self.proj(embeds))
        out=self.output(out)
        nll_prob=F.log_softmax(out,dim=-1)
        return nll_prob

device='cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'

model=CBOW(vocab_size,10).to(device)

optimizer=optim.Adam(model.parameters(),lr=0.001)


loss_funcation=nn.NLLLoss()

losses=[]
model.train()

for epoch in tqdm(range(200)):
    total_loss=0
    for context,target in data:
        context_vector=make_context_vector(context,word_to_idx).to(device)
        target=torch.tensor([word_to_idx[target]]).to(device)

        train_predict=model(context_vector)
        loss=loss_funcation(train_predict,target)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_loss+=loss.item()
    losses.append(total_loss)
    print(losses)

context=['People','create','to','direct']
context_vector=make_context_vector(context,word_to_idx).to(device)

model.eval()
predict=model(context_vector)
max_idx=int(predict.argmax(1))
print(idx_to_word[max_idx])

总结

统计语言模型受限于记忆容量与语义抽象能力,One-Hot 编码的稀疏性与语义孤立问题促使词嵌入技术诞生。Word2Vec 通过 CBOW 和 Skip-Gram 模型,基于上下文共现学习低维语义向量,并借助负采样等优化方法实现高效训练,完成了从符号表示到语义建模的跨越。然而,静态词嵌入难以捕捉序列数据的时序依赖与长期关联,而 ** 循环神经网络(RNN)** 及其改进变体 LSTM(长短期记忆网络)通过动态建模序列中的状态传递与记忆机制,弥补了这一缺陷,成为处理时序数据的核心技术。从词嵌入到 RNN/LSTM,自然语言处理逐步构建起从 "词级语义表示" 到 "序列动态建模" 的完整体系,为后续复杂任务奠定了关键基础。

相关推荐
yzx9910133 分钟前
集成学习实际案例
人工智能·机器学习·集成学习
CodeJourney.4 分钟前
DeepSeek与WPS的动态数据可视化图表构建
数据库·人工智能·信息可视化
jndingxin5 分钟前
OpenCV 图形API(62)特征检测-----在图像中查找最显著的角点函数goodFeaturesToTrack()
人工智能·opencv·计算机视觉
努力犯错7 分钟前
昆仑万维开源SkyReels-V2,解锁无限时长电影级创作,总分83.9%登顶V-Bench榜单
大数据·人工智能·语言模型·开源
小华同学ai14 分钟前
40.8K star!让AI帮你读懂整个互联网:Crawl4AI开源爬虫工具深度解析
人工智能
文慧的科技江湖27 分钟前
图文结合 - 光伏系统产品设计PRD文档 -(慧哥)慧知开源充电桩平台
人工智能·开源·储能·训练·光伏·推理
白熊18831 分钟前
【计算机视觉】CV实战项目 - 基于YOLOv5与DeepSORT的智能交通监控系统:原理、实战与优化
人工智能·yolo·计算机视觉
gis收藏家43 分钟前
几何编码:启用矢量模式地理空间机器学习
人工智能·机器学习
不吃酸的柠檬1 小时前
MATLAB 中的图形绘制
人工智能·机器学习·matlab