CBOW一个用于快速训练得到词向量的神经网络模型,它的核心原理是中心词的前R个词和后R个词来预测中心词。

它的网络模型相比NNLM模型来说,最大的变化是直接去除隐层的非线性激活过程,以此来加速网络的训练速度。

CBOW的输入:
假设中心词wiw_{i}wi的上下文C(wi)={wj∣j∈[i−R,i)∩[i+1,i+R)}C(w_{i})=\{w_{j}|j \in [i-R,i) \cap [i+1,i+R)\}C(wi)={wjj[iR,i)[i+1,i+R)},也就上文为中心词的前R个词,下文为中心词的后R个词。每次词的词向量为e(wi)e(w_{i})e(wi).那么输入到网络中的向量是这2R−12R-12R1个上下文词向量的平均值。即:

X=12R−1∑w′∈C(wi)e(w′)X=\frac{1}{2R-1}\sum_{w'\in C(w_{i})}e(w')X=2R11wC(wi)e(w)
而其中的e(wi)e(w_{i})e(wi)则定义为从词向量矩阵W∣V∣×∣D∣W_{|V|\times|D|}WV×D中取出词wiw_{i}wi对应的那一行,或者那一列。∣V∣|V|V是这个待研究的预料库的词典的大小,一般为4000~7000。∣D∣|D|D是我们选择的词向量的长度,一般为50~500即可。

虽然我们知道e(wi)e(w_{i})e(wi)是将词wiw_{i}wi对应的那一行词向量取出来,直观上也觉得很简单,然而这个“取”的过程并不好实现,尤其是GPU不好实现,GPU最愿意看到的是矩阵乘法那样子的东西。那么,能不能将这个"取"的过程,写成一个矩阵乘法的形式呢?

还真可以!

我们知道,某个单位正交基ei⃗=(0,0,0,…,1,…,0)\vec{e_{i}}=(0,0,0,\dots,1,\dots,0)ei

=(0,0,0,,1,,0),就是第i列的位置为1,其它位置为0的特殊向量,这个形式刚好又与我们常见到的one-hot向量一样。而ei⃗\vec{e_{i}}ei

左乘一个矩阵WWW,恰好就是将WWW的第i行单独取出来。于是这个将wiw_{i}wi的词向量从W∣V∣×∣D∣W_{|V|\times|D|}WV×D"取"出的过程恰好就可以表示为ei⃗×W∣V∣×∣D∣\vec{e_{i}}\times W_{|V|\times|D|}ei

×
WV×D
ei⃗\vec{e_{i}}ei

恰好也就是wiw_{i}wi的one-hot向量。
我们再看刚刚的输入公式:
X=12R−1∑w′∈C(wi)e(w′)X=\frac{1}{2R-1}\sum_{w'\in C(w_{i})}e(w')X=2R11wC(wi)e(w)
把它具体化就是:
X=12R−1∑w′∈C(wi)(w′的one−hot向量)×W∣V∣×∥D∣X=\frac{1}{2R-1}\sum_{w'\in C(w_{i})}(w'的one-hot向量)\times W_{|V|\times\|D|}X=2R11wC(wi)(wonehot)×WV×D
而对于这个求和来说,里面有一个公共的因子W∣V∣×∥D∣W_{|V|\times\|D|}WV×D。将它提取出来,原式变成:
X=12R−1(∑w′∈C(wi)(w′的one−hot向量))×W∣V∣×∥D∣X=\frac{1}{2R-1}(\sum_{w'\in C(w_{i})}(w'的one-hot向量))\times W_{|V|\times\|D|}X=2R11(wC(wi)(wonehot))×WV×D
再做一点点变形:
X=(12R−1∑w′∈C(wi)(w′的one−hot向量))×W∣V∣×∥D∣X=(\frac{1}{2R-1}\sum_{w'\in C(w_{i})}(w'的one-hot向量) ) \times W_{|V|\times\|D|}X=2R11wC(wi)(wonehot))×WV×D
我们发现,我们可以先计算上下文词的One-hot的平均向量,再用这个向量是左乘矩阵。这么做的好处是可以大大的减少计算量,变形前需要计算2R-1次矩阵乘法,变形后只需一次矩阵乘法!

另外,值得一提的是,为什么这个模型叫做词袋模型呢?我们看到,上面这个输入,其实会将wiw_{i}wi上下文对应的词向量都加起来求平均向量。显然因为向量加法的交换性,导致这个计算过程中上下文词是可以打断顺序的!而这与我们对语言的理解也是吻合的,举个例子:

这一是个很好的明说词袋模型的例子。你会发现前一句话中有些词序是混乱的,但是你依然知道这段文字在表达什么意思。

CBOW的输出:p(w′∣C(wi))p(w'|C(w_{i}) )p(wC(wi)),
其中p(w′∣C(wi))p(w'|C(w_{i}))p(wC(wi))=softmax(X1×∣D∣×W∣D∣×∣V∣′)softmax(X_{1\times|D|} \times W'_{|D|\times|V|})softmax(X1×D×WD×V)
这个输出p(w′∣C(wi))p(w'|C(w_{i}))p(wC(wi))是一个形状为1×∣V∣1\times |V|1×V的行向量,其实是给定一个上下文C(wi)C(w_{i})C(wi)后模型认为其中心为词典里面各个词w′w'w的概率。然而,我们的目标是使得这个分布里面wiw_{i}wi对应的概率最大。因些,我们将将p(w′∣C(wi))p(w'|C(w_{i}))p(wC(wi))的第i个数提取出来,同样的为了完成这个“提取”任务,我们只需要将p(w′∣C(wi))p(w'|C(w_{i}))p(wC(wi))左乘一个单位正交基e⃗i\vec e_{i}e

i,即可,这个正交基恰好又是wiw_{i}wi的one-hot向量。

于是我们的目标函数就是:
L(θ)=(wi的one−hot向量)×softmax(X1×∣D∣×W∣D∣×∣V∣′)L(\theta)=(w_{i}的one-hot向量)\times softmax(X_{1\times|D|} \times W'_{|D|\times|V|})L(θ)=(wionehot)×softmax(X1×D×WD×V)
最大化这个目标函数即可。一般L(θ)L(\theta)L(θ)会比较小,于是我们会转而最大化L′(θ)=log(L(θ))L'(\theta)=log(L(\theta))L(θ)=log(L(θ))。一般又是最小化某个函数,于是我们会转而最小化L′′(θ)=−log(L(θ))L''(\theta)=-log(L(\theta))L(θ)=log(L(θ))

以上就是CBOW的核心原理。

接下来,我们就来实现之。
TextLoader类的实现:
TextLoader类主要实现对原始预料文本文件进行词典提取、生成批训练数据等功能。

class TextLoader(object):def __init__(self,input_data_path,Context_length=10,batch_size=10,min_frq = 3):self.Context_length = Context_length #定义上下文的长度self.V =  {} # 将词映射到在词典中的下标self.inverseV ={} #将下标映射到词典中的某个词self.raw_text =list()self.x_data =list()self.y_data =list()self.number_batch = 0self.batch_size = batch_sizeraw_text = []#输入原始数据并统计词频V = dict() #{'word':frq}with open(input_data_path,"r",encoding="utf8") as fp:lines = fp.readlines()for line in lines:line =line.split(" ")line = ['<START>']+line+['<END>']                        #为每句话加上<START>,<END>raw_text += linefor word in line:if word in V:V[word] +=1else:V.setdefault(word,1)#清除词频太小的词,同时为各个词建立下标到索引之间的映射self.V.setdefault('<UNK>',0)self.inverseV.setdefault(0,'<UNK>')cnt = 1for word in V:if V[word] <= min_frq:continueelse:self.V.setdefault(word,cnt)self.inverseV.setdefault(cnt,word)cnt +=1self.vacb_size = len(self.V)#将文本由字符串序列转换为词的下标的序列for word in raw_text:self.raw_text +=[self.V[word] if word in self.V else self.V['<UNK>']]#生成batchesself.gen_batch()def gen_batch(self):self.x_data =[]self.y_data =[]for index in range(self.Context_length,len(self.raw_text)-self.Context_length):#index的前Context,加上index的后Context个词,一起构成了index词的上下文x = self.raw_text[(index-self.Context_length):index]+ self.raw_text[(index+1):(self.Context_length+index)]y = [ self.raw_text[index] ]self.x_data.append(x)self.y_data.append(y)self.number_batch =int( len(self.x_data) / self.batch_size)def next_batch(self):batch_pointer =  random.randint(0,self.number_batch-1)x = self.x_data[batch_pointer:(batch_pointer+self.batch_size)]y = self.y_data[batch_pointer:(batch_pointer+self.batch_size)]return x ,y

TextLoader每次返回的训练batch里面的词是各个词在词典中的下标,在训练阶段,我们需要将其转换为向量。
训练逻辑:

#coding:utf-8
__author__ = 'jmh081701'
import  tensorflow as tf
import  numpy as np
import  jsoncorpus_path = "data\\input.en.txt"
embedding_word_path = corpus_path+".ebd"
vacb_path = corpus_path+".vab"
data = TextLoader(corpus_path,batch_size=300)embedding_word_length = 50
learning_rate =0.0001
#输入
input_x  = tf.placeholder(dtype=tf.float32,shape=[None,data.vacb_size],name="inputx")
input_y  = tf.placeholder(dtype=tf.float32,shape=[None,data.vacb_size],name='inputy')
W1 = tf.Variable(name="embedding_word",initial_value=tf.truncated_normal(shape=[data.vacb_size,embedding_word_length],stddev=1.0/(data.vacb_size)))
#W1其实就是 词向量矩阵
W2 = tf.Variable(tf.truncated_normal(shape=[embedding_word_length,data.vacb_size],stddev=1.0/data.vacb_size))
#计算过程
#累加所有上下文的one-hot向量,然后取平均值,再去乘以词向量矩阵;其效果就是相当于,选择出所有的上下文的词向量,然后取平均
hidden = tf.matmul(input_x,W1)
output = tf.matmul(hidden,W2) #batch_size * vacb_size的大小
output_softmax = tf.nn.softmax(output)
#取出中心词的那个概率值,因为iinput_y是一个one-hot向量,output_softmax左乘一个列向量,就是将这个列的第i行取出
output_y = tf.matmul(input_y,output_softmax,transpose_b=True)
loss = tf.reduce_sum(- tf.log(output_y)) #将batch里面的output_y累加起来
train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss)with tf.Session() as sess:sess.run(tf.initialize_all_variables())max_epoch =10000for epoch in range(1,max_epoch):_x,_y = data.next_batch()#生成本次的输入x =[]y =[]for i in range(0,len(_x)):#将Context*2 -1 个向量,求和取平均为一个向量,用于将来和词向量矩阵相乘vec = np.zeros(shape=[data.vacb_size])for j in range(0,len(_x[i])):vec[ _x[i][j] ] += 1vec /= len(_x[i])x.append(vec)y_vec = np.zeros(shape=[data.vacb_size])y_vec[_y[i]] = 1y.append(y_vec)_loss,_ = sess.run([loss,train_op],feed_dict={input_x:x,input_y:y})if (epoch % 100 )==0 :print({'loss':_loss,'epoch':epoch})#保存词向量_W1 = sess.run(W1,feed_dict={input_x:[np.zeros([data.vacb_size])],input_y:[np.zeros([data.vacb_size])]})#每一行就是对应词的词向量np.save(embedding_word_path,_W1)with open(vacb_path,"w",encoding='utf8') as fp:json.dump(data.inverseV,fp)print("Some TEST:")print("<START>:",_W1[data.V['<START>']])print("<END>:",_W1[data.V['<END>']])print("<UNK>:",_W1[data.V['<UNK>']])print("you:",_W1[data.V['you']])print("are:",_W1[data.V['are']])print("is:",_W1[data.V['is']])print("Find Some Word pairs With high similarity")

一些输出:

Some TEST:
<START>: [-0.32865554 -0.32892272 -0.32865554 -0.32903448 -0.32862166 -0.3286371-0.32855278 -0.32865041 -0.3287456   0.32913685  0.3284275   0.3293942-0.32878074  0.32895386 -0.3293958   0.32897744 -0.3285544   0.32878345-0.32894143 -0.32877466  0.32910895 -0.32860583 -0.32861212  0.328917350.3287292   0.32835644 -0.32884252 -0.32896605 -0.32906595  0.328671160.3286172   0.3290027  -0.32881436 -0.32877848  0.328693   -0.328744350.3287963  -0.3290643  -0.3288444  -0.32919246 -0.32911804  0.3285764-0.3288233   0.32885128 -0.32878864 -0.32906076 -0.32880557  0.328894170.32867458  0.3288717 ]
<END>: [-0.32887468 -0.32819295 -0.32811585 -0.32842168 -0.32838833 -0.32807946-0.328573   -0.32846293 -0.32863003  0.32853135  0.3285702   0.3289579-0.32843226  0.32874456 -0.32906574  0.32823783 -0.328379    0.32890162-0.32847401 -0.32865068  0.32868966 -0.32853377 -0.32895073  0.328661350.32829925  0.3286695  -0.3279959  -0.32863376 -0.32822555  0.328690920.3287056   0.32847905 -0.328476   -0.3285315   0.3284099  -0.328464840.32861754 -0.32874164 -0.32856745 -0.3281496  -0.32804772  0.32813182-0.32847726  0.32866627 -0.32860965 -0.32843712 -0.32851657  0.328480060.3284792   0.32827806]
<UNK>: [-0.33541423 -0.33470714 -0.3370783  -0.33635023 -0.33554107 -0.33692467-0.3357885  -0.3362881  -0.33724156  0.3363039   0.3367789   0.33465096-0.33774552  0.334528   -0.33478507  0.3361384  -0.33670798  0.3359792-0.33699095 -0.3372743   0.33699647 -0.3349662  -0.3352877   0.336070630.3360799   0.3374416  -0.33622378 -0.3356342  -0.33574662  0.335159570.33587998  0.33657932 -0.3346068  -0.33668125  0.3373789  -0.335788640.33600768 -0.3351044  -0.33618957 -0.33537337 -0.33528054  0.33497527-0.33659405  0.33648187 -0.33672735 -0.3356181  -0.33677348  0.33580790.33754358  0.33513647]
you: [ 7.5410731e-05 -2.2068098e-05  1.5926472e-04 -3.7533080e-041.5225924e-04  5.7152174e-05  1.1864441e-04  1.8325352e-04-3.3901614e-04  1.2916526e-04  1.3833319e-05  2.6736190e-04-4.7140598e-05  2.6220654e-04  3.6094731e-04 -3.7336904e-051.6925091e-04  3.0941452e-04  6.1381006e-06  8.4891668e-053.2646640e-04  2.9357689e-04  1.1827118e-05 -3.3071122e-04-6.8303793e-06  1.6745779e-04 -3.6067510e-04  5.1347135e-051.4563915e-04  1.7205811e-04  4.1834958e-04  2.2660226e-045.4340864e-05  5.7893725e-05  4.7014220e-04  1.5608841e-052.5751774e-04  2.9816956e-04 -3.2765078e-04  7.9145197e-05-1.4246249e-04  1.0391908e-04 -4.8424668e-06  1.1221454e-043.8156973e-04 -1.1834640e-04 -4.6865684e-05  2.7329332e-04-3.1904834e-05  1.3008594e-04]
are: [-0.2812496  -0.2820716  -0.27766886 -0.2796223  -0.28174222 -0.2794273-0.28108445 -0.28041014 -0.27624518  0.27735004  0.2795439   0.28412956-0.27596313  0.28378895 -0.28383565  0.27873477 -0.27815878  0.27781972-0.2785313  -0.27764395  0.27687937 -0.28168035 -0.28165868  0.279152660.27918822  0.27295998 -0.28038228 -0.280024   -0.2794214   0.27954790.2802325   0.2777838  -0.28295064 -0.27867603  0.27600077 -0.279593830.2796351  -0.2815734  -0.27917543 -0.28051388 -0.2809812   0.28227493-0.2791555   0.28032318 -0.27791157 -0.28050876 -0.2775616   0.282031830.27543807  0.280927  ]
is: [-0.32220727 -0.32266894 -0.31880832 -0.32086748 -0.32186344 -0.3214381-0.32217908 -0.3221054  -0.3179382   0.31926474  0.32116815  0.32492614-0.31819957  0.32392636 -0.32451728  0.32015812 -0.3204411   0.3186195-0.3208769  -0.31925762  0.31855124 -0.32200468 -0.32246563  0.32011450.31962588  0.31499264 -0.32167593 -0.32168335 -0.32059893  0.31988680.3216786   0.3199376  -0.32269898 -0.3208138   0.31806418 -0.320537980.32106066 -0.3218284  -0.31995344 -0.32122964 -0.3216572   0.3230505-0.32118168  0.32176948 -0.31983265 -0.32104513 -0.31971234  0.323686660.31785336  0.32170975]

看起来跟我们经验还是吻合的,哈哈哈
本blog的项目:
https://github.com/jmhIcoding/CBOW.git

自然语言处理——CBOW模型相关推荐

  1. 改进版的CBOW模型

    复习 首先复习一下之前的CBOW笔记. 采用推理的方法认知单词.CBOW模型这里面主要是: CBOW模型的核心思路:给出周围的单词(上下文)时,预测目标词处会出现什么单词. 要用神经网络处理单词,需要 ...

  2. Word2vec之CBOW 模型

    Word2vec之CBOW 模型 CBOW模型流程举例 假设我们现在的语料库是这一个简单的只有四个单词的文本: Step 1. 得到上下文词的one-hot向量作为输入,同时得到预期的输出one-ho ...

  3. word2vec原理(五):skip-gram和CBOW模型代码实现

    目录 代码一 代码二 第一部分代码对于skip-gram和CBOW模型是通用的,第二部分是实现skip-gram模型的代码. 代码一: import os from six.moves.urllib. ...

  4. CBOW模型的学习、Trainer类的实现

    CBOW 模型的学习的实现:给神经网络准备好学习数据.然后求梯度,并逐步更新权重参数. Trainer类:学习的类. 初始化:类的初始化程序接收神经网络(模型)和优化器(SGD.Momentum.Ad ...

  5. CBOW模型正向传播、矩阵乘积层实现

    把矩阵乘积称为MatMul节点: 下面这个图表示矩阵乘积y=xW的计算图 .因为考虑了mini-batch 处理,假设x中保存了N个数据.此时x .W.y 的形状分别是 N×D.D×H .N×H . ...

  6. 采用推理的方法认知单词、CBOW模型

    基于计数的方法,根据一个单词周围的单词的出现频数来表示该单词.需要生成所有单词的共现矩阵,再对这个矩阵进行 SVD,以获得密集向量,如果语料库处理的单词数量非常大,将需要大量的计算资源和时间.基于计数 ...

  7. GPT-J 自然语言处理 AI 模型

    GPT-J 是一个基于 GPT-3,由 60 亿个参数组成的自然语言处理 AI 模型.该模型在一个 800GB 的开源文本数据集上进行训练,并且能够与类似规模的 GPT-3 模型相媲美 2020 年, ...

  8. Word2Vec之Skip-Gram与CBOW模型

    Word2Vec之Skip-Gram与CBOW模型 word2vec是一个开源的nlp工具,它可以将所有的词向量化.至于什么是词向量,最开始是我们熟悉的one-hot编码,但是这种表示方法孤立了每个词 ...

  9. 谈谈Word2Vec的CBOW模型

    0x00 背景 最近在做毕设,需要使用Google的word2vec.查阅了相关资料,总结后,写下这篇. 注,本文大多取自以下内容: cbow例子,取自知乎,已取得答主同意 word2vec数学原理详 ...

最新文章

  1. MFC Initinstance中DoModal()返回-1
  2. 思科cisco解决方案:思科ACI解决方案和Nexus_9000交换机
  3. 计算机运行一会内存占用巨大,Win8电脑程序占用很大内存怎么办?
  4. eBPF技术应用云原生网络实践系列之基于socket的service | 龙蜥技术
  5. html span标签 不换行(有时span带中文时候是可以自动换行的)
  6. 【数据结构算法】二:上三角、下三角中求数组地址--【下标的计算】
  7. Eclipse CDT 编译wxWidgets
  8. ESXI上的新建虚机绑定已使用过的静态ip无法ping通网关的奇怪现象
  9. 35线性映射02—— 线性映射概念与运算、矩阵表示
  10. ArcFace免费人脸识别 Demo [Android]
  11. ASP.NET MVC 5 笔记
  12. python 文件写入多个参数_如何将多个参数写入txt文件(字符串和变量)
  13. Java爬虫学习——实例:获取起点中文网站小说并保存成txt文件
  14. Zeppelin0.8.1上操作hive(使用jdbc解释器)
  15. L9110H电机驱动模块-FPGA
  16. C语言alloc函数总结
  17. 中国全国地面站点数据(1981-2010)、月平均气象、月平均降水、月平均相对湿度、月最大降水、月最高温度最低温度、月最高温平均值最低温平均值、高低温站点基础数据,气候数据
  18. 计算机专业论文指导教师评语,指导老师论文评语
  19. 尚硅谷 尚医通学习笔记
  20. 付费入群怎么做_微信群怎么设置付费才可以进入

热门文章

  1. 小米手机怎么设置农历生日提醒
  2. 20年后的计算机450作文,20年后的高科技作文450字
  3. 免费在线PHP加密、解密、混淆源代码工具- toolfk.com
  4. 零前端基础硬刚《象棋》- 持续更新
  5. 京东携冯氏零售力推智能结算台,无界零售生态圈再度扩容...
  6. 神经网络如何识别图像,神经网络图像识别原理
  7. 图标 DIY 模板,轻松创建 iOS 应用图标
  8. wordpress禁用谷歌字体,提高古腾堡编辑器速度
  9. 对 HTML 语义化的理解
  10. SRS视频服务器-docker部署srs4.0:带SRT功能