首页
学习
活动
专区
工具
TVP
发布

周末AI课堂 理解词嵌入 代码篇 机器学习你会遇到的“坑”

AI课堂开讲,就差你了!

很多人说,看了再多的文章,可是没有人手把手地教授,还是很难真正地入门AI。为了将AI知识体系以最简单的方式呈现给你,从这个星期开始,芯君邀请AI专业人士开设“周末学习课堂”——每周就AI学习中的一个重点问题进行深度分析,课程会分为理论篇和代码篇,理论与实操,一个都不能少!

来,退出让你废寝忘食的游戏页面,取消只有胡吃海塞的周末聚会吧。未来你与同龄人的差异,也许就从每周末的这堂AI课开启了!

读芯术读者交流群,请加小编微信号:zhizhizhuji。等你。后台回复“周末AI课堂”,查阅相关源代码。

全文共2526字,预计学习时长5分钟

我们在上一节中已经看到,得到词向量的途径是通过训练神经网络得到,我们最后需要的只是输入层到投影层的权值矩阵,代表着词向量。这样做就意味着得到的词向量并不是唯一的,它依赖着语料库、神经网络的结构、参数的设置等因素。那么如何确保我们得到的是一个合理的词向量,而非只是针对特定任务的呢?截至目前,这一问题我们无法得到有效的保证,但可以通过增加数据、充分挖掘数据间的关系来改善。

Word2Vec

一种改善的办法就是,将原本的词只与上文有关的机制改为与上下文都有关,反映到神经网络上,原来的模型会把某个词前面的N-1个词作为输入,该词作为输出。取而代之,我们可以选择两种机制:

• 一种是CBOW,它就是将前后N个词作为输入,该词作为输出。

• 一种是Skip-Gram,它是将某词作为输入,其前后N个词作为输出。

如图,CBOW会左右的两个词一起作为输入,该词作为输出来训练网络,Skip-gram则恰好反过来。

在实际训练中,这两项技术对于文本的处理有所不同。CBOW会把每个词作为输出,训练时只需要做一次的BP(后向传播),但是skip-gram输出的最少也是两个词,我们假设是K次,训练时就需要做K次的BP,在遍历相同长度的文本情况下,训练开销更大。

但是在skip-gram,每个词都可以接受来自于周围词的权重调整,这样的调整使得到的词向量更准确。对于生僻词的出现,CBOW使用生僻词作为输出,去调整K个词的词向量时,比起其他的高频词影响很小(被平均掉),使得生僻词在训练中不会起到很大作用。相反的,Skip-gram把生僻词作为输入,可以接受周围词的调整,是独立于其他词进行训练。结果就是,skip-gram会比CBOW对生僻词的表现更好。

使用这些技术训练出来的词向量,会在语义上有着非常有趣的分布,下面举两个例子:

。不仅如此,在词语的形式上,也有

。也就是说,我们在词向量所张成的空间上,如果语言通过了相同形式的转化,包括同义词,反义词,那么我们可以用数值上的运算来表达这种转化。

如图,在英语和西班牙语上分别训练词向量,选取数字1,2,3,4,5,在他们各自的空间上利用主成分分析(PCA)降维,得到的分布几乎是一致的,数字的使用在不同语言中是类似的,说明训练得到的词向量包含了这一层关系。

使用词向量

目前,各类语种的大规模训练而来的词向量已经非常成熟,我们直接可以使用,但比使用更重要的是,我们基于语料库如何得到它们?在接下来的实践中,为方便,我们会使用gensim库和jieba分词库,对词向量的训练做一个简单的示例,其中,可能需要一点点《射雕英雄传》的知识。

gensim是一个较为高级的python库,提供了语料处理工具,LSI,LDA等传统方法,同时,它所内建的神经网络并不包含隐层(如果我们把embedding层不看作隐层的话),训练速度会非常快,对电脑配置要求并不高,自从进入深度学习之后,这是很少见的可以在个人笔记本上流畅运行的模型。

我们从网上可以很方便的下载到《射雕英雄传》这部小说,我们基于这部小说将其简单的分词:

import jieba

with open('shediaoyingxiongzhuan.txt', errors='ignore', encoding='utf-16') as f:

lines = f.readlines()

for line in lines:

seg_list = jieba.cut(line)

with open('shediaoyingxiongzhuan_new.txt', 'a', encoding='utf-8') as n:

n.write(' '.join(seg_list))

print("jieba finish")

注意,我这里提供的小说编码格式为‘utf-16’,但在写入新文件时,为了避免后续的编码问题,直接使用了‘utf-8’。新文件仍然保存在当前目录下。我们这里不做语法分析、去存停用词等预处理工作,只使用jieba分词将我们的句子打散。

from gensim.models import word2vec

sentences = word2vec.Text8Corpus('shediaoyingxiongzhuan_new.txt')

model = word2vec.Word2Vec(sentences,window=5,min_count=5,size=400)

接下来我们使用gensim提供的word2vec类直接对整个文本进行训练,这里面有两个参数,min_count=5表示出现次数少于5次的词,将不会被训练;window=5表示我们使用skip-gram时,窗口的大小,就是一个词与前后多少个词放在一起被训练;size=400,是指embedding层的维度有多少,它决定着我们得到的词向量的大小。这些参数都可以进行细致的调节。

当我们训练完成以后,就可以查看效果。虽然不存在一个确定性的度量指标,但一般的,我们有这么几种方法来大概估计词向量的优劣:

• 词向量的相似度,比如余弦的大小。

• 类比法,比如我们在上文提到的king-queen和man-woman。

• 降维可视化,比如t-SNE和PCA,将词向量的维数降到3维或者2维。

• 聚类,希望看到同一类的东西聚集,不同类的东西分离。

我们选用降维做可视化来直观感受词向量在空间中的相对位置。首先,我们可以通过相似度计算,得出某一词的相近词,这里我们选用“黄蓉”为例:

for e in model.most_similar(positive=['黄蓉'], topn=10):

print(e[0], e[1])

郭靖 0.9720229506492615

欧阳克 0.9623762965202332

欧阳锋 0.9269372224807739

穆念慈 0.9042879343032837

柯镇恶 0.9001784324645996

杨铁心 0.894554853439331

陆冠英 0.8909748792648315

梅超风 0.8906383514404297

杨康 0.8814554810523987

洪七公 0.8773152828216553

可以看出,她与郭靖距离最近,因为在小说中很多地方,都是黄蓉和郭靖一起出现的,第二位是欧阳克,毕竟欧阳克是黄蓉的舔狗。黄药师或者东邪为什么没有出现在其中,成了一个较为费解的问题。我的猜想是,有黄药师在的地方,都会叫她“蓉儿”,而不是“黄蓉”,但我们在搜索“蓉儿”的时候,会发现jieba已经将其分成了“蓉”和“儿”,所以这个问题的考证要依靠更为精细的分词方法。

接下来,我们对这几个人做PCA降维,看一下它们在空间上的表现形式:

import matplotlib.pyplot as plt

from sklearn.decomposition import PCA

import numpy as np

word=[e[0] for e in model.most_similar(positive=['黄蓉'], topn=10)]

word.append('黄蓉')

y=np.array(word)

vec_array=np.zeros((len(word),400))

for i in range(len(word)):

dim_vec=model[word[i]]

vec_array[i]=dim_vec

plt.rcParams['font.family']=['Arial Unicode MS']#这一行是让matplotlib显示中文

pca=PCA(2)

X=pca.fit_transform(vec_array)

plt.figure(figsize=(10,10)

for j in y:

plt.scatter(X[y==j,0],X[y==j,1],s=200)

plt.text(X[y==j,0]+0.05,X[y==j,1]+0.05,j)

plt.legend()

plt.show()

如图,可以看出一个非常有趣的事实,发生爱恋关系的人在空间上表现出了类似恶词向量关系。杨康和穆念慈的词向量,与黄蓉和郭靖的词向量,他们之间的关系非常近,几乎有:

至少在金庸这部小说里面,这个关系是成立的。我们将其单独提取出来,就变成了:

如图,我们可以看出,他们之间的一一对应,就和上文中的king和queen,man和woman的关系是一样的。

读芯君开扒

课堂TIPS

• gensim另外一些较为简单的使用方法,包括计算词与词的相似度,词组与词组的相似度,还可以查看每个词的向量等等,我们可以进行增量训练把模型训练的更好,从而得到更为有趣的结果,这些都写在官方文档中,非常简单易用。

• matplotlib并不支持中文的显示,你可以绕过这个问题,去使用英文的语料库去练习。如果想解决这个问题,就用如下方法查看可用的中文字体,然后在代码中声明即可。

import matplotlib

font = sorted([f.name for f in matplotlib.font_manager.fontManager.ttflist])

#如果有可用的字体,就进行如下添加,将‘Arial Unicode MS’换做你拥有的中文字体名称

import matplotlib.plot as plt

plt.rcParams['font.family']=['Arial Unicode MS']

• 得到的词向量,其实只是问题的开始,我们可能会遇到主题分类,情感分析,智能问答,语音翻译问题,这就需要我们用所得到的词向量再放入新的学习器,在解决了词向量的问题后,我们会在下一节讲解RNN。

留言 点赞 发个朋友圈

我们一起分享AI学习与发展的干货

作者:唐僧不用海飞丝

如需转载,请后台留言,遵守转载规范

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190106A0WZ5N00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券