NLP Embedding,CBOW

NLP Embedding,Word2vec

Word2vec:CBOW介绍

1. 目的,流程梳理

​ NLP任务中需要将词以向量方式表示(嵌入数学空间中,word embedding),最原始的是one-hot编码,但是会导致词向量的维度太大,所以通常会使用分布式表示。本文主要围绕向量化方法word2vec中的CBOW展开。

​ 总体而言,Word2Vec是借助预测词的过程,根据中间词与上下文之间的关系来训练Embedding矩阵,从而达到将One-Hot编码降维的效果,避免词向量过于冗长,降低复杂度。注意,word2vec的最终目的是那个embedding矩阵。

下面会介绍word2vec的具体过程,负采样的原理,以及一个demo实战。

2. word2vec 具体过程

Word2Vec是一个根据词的临近关系预测周围词的过程,会设置一个滑动窗口,在不断滑动的同时收集样本。

这里主要介绍CBOW。在CBOW目的是根据前后词预测中间词,就会收集如下的样本:

todaya
isa
gooda
daya

而后构建一个三层的神经网络模型,通过这个模型来计算 p r e d i c t i o n prediction prediction向量。

在这里插入图片描述

输入层:上下文单词的One-Hot。

中间层:输入的 m m m个单词的One-Hot分别乘以共享的输入权重矩阵 W v × n W_{v\times n} Wv×n v v v为词库大小, n n n为自己设定的降维目的, W W W为初始化权重矩阵 ),得到一个 m × n m\times n m×n的矩阵,进行简单加权平均得到一个 1 × n 1\times n 1×n大小的向量 s u m sum sum

输出层: s u m sum sum向量和整个 W v × n W_{v\times n} Wv×n相乘,即 s u m sum sum向量和所有词向量求余弦值。**然后经过softmax得到 p r e d i c t i o n prediction prediction向量。 p r e d i c t i o n prediction prediction向量中每个维度的值代表每个词的概率。将 p r e d i c t i o n prediction prediction向量与正确词汇的one-hot编码之间的损失(一般是交叉熵)作为优化参数的依据。

说得更清晰一点:

假设词库单词50000个( v v v),需要化成300( n n n)维,窗口大小为5( m + 1 m+1 m+1,因为窗口包括前后词和本词)。

输入:4×50000

中间层:4×300 -> 300

输出层:50000

(softmax和交叉熵的具体内容放在笔记末尾。)

3. 负采样

负采样:

请关注word2vec具体过程中的加粗字体部分,这是负采样优化的部分。

可以看到,每次预测都需要将 s u m sum sum向量与词库中所有词向量求余弦,如果按照上文中的50000维降成300维的做法,需要求余弦50000次。这一步非常浪费,实际上我们想要的是 W v × n W_{v\times n} Wv×n矩阵,这个预测工作只是工具。

因此,可以选择多个负样本( v ′ − 1 v^{'}-1 v1不正确的 n n n维向量)和一个正样本(正确词的 n n n维向量)组成 W v ′ × n ′ W_{v'\times n}^{'} Wv×n

比如,选择40个负样本,一个正样本,就只需要求余弦41次,大大减少工作量(当然,负采样每次让一个训练样本仅仅更新一小部分的权重)。

在这里插入图片描述

可以看出,改变的是prediction向量。prediction向量的计算流程图的改变如下:

在这里插入图片描述

4. demo

以下是我曾经做过的一个用于豆瓣电影评论预测评分的BiLSTM,在此单拎出它的word2vec部分进行展示。word2vec部分使用的是THUCNews数据库,由于实际训练数据集比较大(约需训练8h左右),不便放在Jupyter中展示,此处仅以 THUCNews/体育 部分为例展示训练过程。

(完整数据集在http://thuctc.thunlp.org/#%E8%8E%B7%E5%8F%96%E9%93%BE%E6%8E%A5,如想复现word2vec demo可点击链接选择数据集下的体育部分。)

from typing import TextIO
from MySentences import MySentences
import os
# jieba分词库
import jieba
import jieba.analyse
# gensim词向量训练库
from gensim.test.utils import common_texts, get_tmpfile
from gensim.models import Word2Vec
from gensim.models import word2vec
import numpy as np

分词:以体育为例

train_tokens = []
sum = 0
set = {''}
# File = './temp'
File = './THUCNews_files'
Files1 = os.listdir(File) # 得到该文件夹下的所有文件名(包含后缀),输出为列表形式
for file1 in Files1:
file11 = File+'/'+file1
files= os.listdir(file11)
for file in files:
with open(file11 + '/' + file, encoding='utf-8') as f1:
# 对每个文档的内容进行分词
document = f1.read()
document_cut = jieba.cut(document, cut_all=False)
# 分词之后用空格隔开并去掉标点符号
result = ' '.join(document_cut).replace(',', '').replace('。',
'').replace('?', '').replace('!', '') \
.replace('“', '').replace('”', '').replace(':', '').replace(';',
'').replace('…', '').replace('(',
'').replace(
')', '') \
.replace('—', '').replace('《', '').replace('》', '').replace('、',
'').replace('‘', '') \
.replace('’', '')
train_tokens.append(list(result.split()))
for word in result.split():
set.add(word)
# 处理好的语料文档的路径
datapath = './THUCNews_files_tokens/'+file1+'/a.txt'
with open(datapath, 'a', encoding="utf-8") as f2:
f2.write(result)
print(len(set))
#分好token后的句子中,以体育为例,展示训练过程
num_tokens = [ len(tokens) for tokens in train_tokens ]
num_tokens = np.array(num_tokens)
print(num_tokens)
print(np.sum(num_tokens))

116720

[386 834 857 … 200 308 703]

8130954

np.mean(num_tokens)
np.log(num_tokens)
np.max(num_tokens)

7851

import matplotlib.pyplot as plt
plt.hist(np.log(num_tokens), bins=100)
plt.xlim((0,10))
plt.ylabel('number of tokens')
plt.xlabel('length of tokens')
plt.title('Distribution of tokens length')
plt.show()

在这里插入图片描述

语料库中“体育”主题部分共8130954个词,最长评论有7851个词,经取对数处理后,评论长度基本呈正

态分布。由于整体语料库为体育部分十倍以上,为了迎合整体大语料,提高训练速度,在使用

Word2Vec训练时,使用CBOW模型进行训练。

from gensim.test.utils import common_texts, get_tmpfile
from gensim.models import Word2Vec
sentences=[]
f1=open('./THUCNews_files_tokens/体育/a.txt','r',encoding='utf8').readlines()
for line in f1:
sentences.append(line.split())
model = word2vec.Word2Vec(sentences,sg=0, vector_size=100,window=5, min_count=1,
workers=4)
model.save('ipynbtry')
import gensim.models
model = gensim.models.Word2Vec.load("ipynbtry")
#查看足球的向量
#查看与体育相关的词语的与之相似词
print(model.wv['足球'])
for word in ['足球','篮球','乒乓球','体育馆','体育','羽毛球','运动员','教练','跑步']:
print(word+":")
for key in model.wv.similar_by_word(word, topn=5):
print(key)

足球:

(‘足坛’, 0.7249346971511841)

(‘中国篮球’, 0.7049357891082764)

(‘足球运动’, 0.6868180632591248)

(‘篮球’, 0.6663395166397095)

(‘篮球运动’, 0.657491147518158)

篮球:

(‘篮球运动’, 0.7422261238098145)

(‘文化’, 0.6905624866485596)

(‘运动员’, 0.6898443698883057)

(‘足球运动’, 0.6897315979003906)

(‘中国篮球’, 0.6821549534797668)

可以看到,在该语料范围内,训练效果还是很出色的,模型很大程度捕捉到了语义相关性,

应该认为推广到全部训练集上也能保持较好的效果

5.一些补充

5.1 Softmax and Cross Entropy
Softmax:

通过Softmax函数就可以将多分类的输出值转换为范围在[0, 1]和为1的概率分布。

计算公式如下:
S i = e i ∑ j e j S_{i}=\frac{e^{i}}{\sum_{j}{e^{j}}} Si=jejei

Cross Entropy:

是一种损失函数(loss function),计算公式如下:
H ( p , q ) = − ∑ p ( x i ) l o g ( q ( x i ) ) H(p,q)=-\sum{p(x_{i})log(q(x_{i}))} H(p,q)=p(xi)log(q(xi))

交叉熵与KL散度的关系:

KL散度公式:
D K L ( p ∣ ∣ q ) = ∑ p ( x i ) l o g ( p ( x i ) q ( x i ) ) D_{KL}(p||q)=\sum p(x_{i})log(\frac{p(x_{i})}{q_(x_i)}) DKL(p∣∣q)=p(xi)log(q(xi)p(xi))
KL散度的值越小表示两个分布越接近。

将其变形得到:
D K L ( p ∣ ∣ q ) = ∑ p ( x i ) l o g ( p ( x i ) ) − ∑ p ( x i ) l o g ( q ( x i ) ) = − H ( p ( x ) ) + [ − ∑ p ( x i ) l o g ( q ( x i ) ) ] D_{KL}(p||q)=\sum p(x_{i})log(p(x_{i}))-\sum p(x_{i})log(q(x_{i}))\\ =-H(p(x))+[-\sum p(x_{i})log(q(x_{i}))] DKL(p∣∣q)=p(xi)log(p(xi))p(xi)log(q(xi))=H(p(x))+[p(xi)log(q(xi))]
可以看到,其中后半部分即为我们的交叉熵。KL散度来评估predict和label之间的差别,因为前半部分是常量,所以常用交叉熵来代替KL散度,实际效果不变。

小白一枚,如果有错误,希望大家多多帮助指正,一起学习!

参考文章:

  1. 一条水里的鱼:白话Word2vec原理以及层softmax、负采样的实现。https://blog.csdn.net/qq_40859560/article/details/10921172

  2. 小虎AI实验室:轻松理解CBOW模型。https://blog.csdn.net/u010665216/article/details/78724856

  3. 意念回复:机器学习算法(十三):word2vec。https://blog.csdn.net/weixin_39910711/article/details/103696103

  4. https://zhuanlan.zhihu.com/p/61944055

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
CBOW(Continuous Bag-of-Words)模型是一种用于自然语言处理的神经网络模型,它的输入是上下文中的词汇,输出是中心词汇。CBOW 模型的代码实现如下: ```python import numpy as np from keras.preprocessing.text import Tokenizer from keras.utils import to_categorical from keras.models import Sequential from keras.layers import Dense, Embedding, Lambda # 设置超参数 vocab_size = 5000 embedding_dim = 100 window_size = 2 # 构建语料库 corpus = [ 'I like playing soccer with my friends', 'He enjoys playing basketball on weekends', 'The cat loves drinking milk every morning' ] # 将语料库转化为词向量矩阵 tokenizer = Tokenizer(num_words=vocab_size) tokenizer.fit_on_texts(corpus) sequences = tokenizer.texts_to_sequences(corpus) # 构建训练数据集 x_train = [] y_train = [] for sequence in sequences: for i in range(window_size, len(sequence) - window_size): context = sequence[i-window_size:i] + sequence[i+1:i+window_size+1] target = sequence[i] x_train.append(context) y_train.append(target) x_train = np.array(x_train) y_train = to_categorical(y_train, num_classes=vocab_size) # 构建 CBOW 模型 model = Sequential() model.add(Embedding(vocab_size, embedding_dim, input_length=window_size * 2)) model.add(Lambda(lambda x: np.mean(x, axis=1), output_shape=(embedding_dim,))) model.add(Dense(vocab_size, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam') # 训练 CBOW 模型 model.fit(x_train, y_train, epochs=50, verbose=1) # 输出词向量矩阵 embeddings = model.get_weights()[0] print(embeddings) ``` 在上面的代码中,我们首先读取语料库,将其转化为词向量矩阵,并且根据窗口大小构建训练数据集。然后,我们构建 CBOW 模型,其中使用了 Embedding 层和 Lambda 层,最后将模型训练得到的词向量矩阵输出。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值