自然语言处理之使用gensim.Word2Vec训练词向量进行词义消歧
Posted 猫猫头丁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自然语言处理之使用gensim.Word2Vec训练词向量进行词义消歧相关的知识,希望对你有一定的参考价值。
自然语言处理之使用gensim.Word2Vec训练词向量进行词义消歧
NLP中进行词义消歧的一个非常方便且简单的方法就是训练词向量,通过词向量计算余弦值,来推断某个词在句子中的含义。python中的gensim提供了一个非常方便的方法,一句话就可以训练词向量。不过嘛,正如我们想的那样,肯定是语料库越大越好,但越大呢就训练的时间越长,这也是没办法的事情。
我建议大家用GPU来训练,当当当,强烈推荐AIstudio,非常好用,免费GPU10小时,不用白不用。
哇塞,我刚刚发现百度AIstudio新推出了至尊GPU,赶紧来体验一下,这名字听起来太霸气了!
完整项目的aistudio链接:http://www.sogou.com/labs/resource/cs.php.
可以直接fork哦,有问题的话及时联系我哦。
训练词向量
首先我们来训练词向量,我使用的是搜狗实验室提供的新闻语料,链接如下:
http://www.sogou.com/labs/resource/list_yuliao.php.
我下载的是这个完整版的,648MB,对我来说应该够用了,不过搜狗实验室还提供了一些更大的语料,还有1GB以上的,大家有兴趣的话,可以尝试一下,语料越大,效果越好哦。
下载好语料之后,对语料进行解压
!cd data/data83697 && unzip -q news_sohusite_xml.full.zip
因为语料是新闻的格式,我们这里的话只需要文本部分也就是content部分,所以提取content部分,保存到content.txt文件里面。
cat data/data83697/news_sohusite_xml.dat | iconv -f gbk -t utf-8 -c | grep "<content>" > corpus.txt
接下来,对文本进行一个分词处理,因为是中文,不像英文那样可以直接以空格隔开,所以使用jieba来进行分词。
import jieba
import numpy as np
filePath='corpus.txt'
fileSegWordDonePath ='corpusSegDone_1.txt'
# 打印中文列表
def PrintListChinese(list):
for i in range(len(list)):
print (list[i])
# 读取文件内容到列表
fileTrainRead = []
with open(filePath,'r') as fileTrainRaw:
for line in fileTrainRaw: # 按行读取文件
fileTrainRead.append(line)
# jieba分词后保存在列表中
fileTrainSeg=[]
for i in range(len(fileTrainRead)):
fileTrainSeg.append([' '.join(list(jieba.cut(fileTrainRead[i][9:-11],cut_all=False)))])
if i % 100 == 0:
print(i)
# 保存分词结果到文件中
with open(fileSegWordDonePath,'w',encoding='utf-8') as fW:
for i in range(len(fileTrainSeg)):
fW.write(fileTrainSeg[i][0])
fW.write('\\n')
分好词之后,我们就可以快乐训练啦,有种要炼丹的感觉。
我是在AIStudio里面做的实验,要先安装gensim库,一句话就好,告诉它,把gensim库给我安装上。
!pip install gensim
接下来,我们导入一下各种会用到的包,这一步我基本上都是导入许许多多。
import warnings
import logging
import os.path
import sys
import multiprocessing
import gensim
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
# 忽略警告
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')
正式开始训练词向量
program = os.path.basename(sys.argv[0]) # 读取当前文件的文件名
logger = logging.getLogger(program)
logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s',level=logging.INFO)
logger.info("running %s" % ' '.join(sys.argv))
# inp为输入语料, outp1为输出模型, outp2为vector格式的模型
inp = 'corpusSegDone_1.txt'
out_model = 'corpusSegDone_1.model'
out_vector = 'corpusSegDone_1.vector'
# 训练模型
model = Word2Vec(LineSentence(inp), vector_size=50, window=5, min_count=5,workers=multiprocessing.cpu_count())
# 保存模型
model.save(out_model)
# 保存词向量
model.wv.save_word2vec_format(out_vector, binary=False)
这一步真的还挺漫长的,GPU大概半个多小时左右,如果使用至尊GPU(我还没试过)应该可能会更快一点。
开始词义消歧
首先我们用“苹果”来做一个示范:
先引入刚刚训练好的模型
from gensim.models import Word2Vec
import numpy as np
model = Word2Vec.load('corpusSegDone_1.model')
来查看一下和苹果相似的词
model.wv.most_similar(u"苹果")
哦豁,有点意思哦,和“苹果”最相关的是“微软”、“谷歌”和“苹果公司”。可能有人要疑惑了,奇怪哦,为什么和苹果相似的不是“香蕉”、“葡萄”、“水蜜桃”之类的呢?没错,你发现了我们模型的问题!这个其实是因为我们的新闻语料库的原因,看来我们的新闻语料更偏向于科技方面。
后来,试了一下搜狗实验室的其他语料,惊讶的发现和苹果最相关的竟然是“月饼”还有“水果”!所以这个语料的选择真的非常重要!
接下来我们就来测验一下,看看“用苹果性能好,分辨率高”中的“苹果”究竟是手机还是水果还是其他物品。
我给苹果的含义分了三种语义,“水果”、“手机”、“电影”,它们的使用场景分别是“这个()真好吃,营养价值高”、“()手机配置不高,但整体性能优化的很好”、“()上映了,听说非常精彩”。把这三句话jieba分词一下,来看一看我们的目标句子和这三句话哪个更接近。
content=['用','苹果','性能','好','分辨率','高']
des1=['这个','真','好吃','营养价值','高']
des2=['手机','配置','不高','但','整体','性能','优化','的','很','好']
des3=['上映','了','听说','非常','精彩']
def w2v_mean(essay,model):
ls=np.zeros(50)
for unit in essay:
try:
ls+=np.array(model.wv[unit])
except:
pass
return ls/len(essay)
通过余弦值大小来判断,目标句子与三种语境的相似程度,余弦值越大,代表越接近。
content=w2v_mean(content,model)
d1=w2v_mean(des1,model)
d2=w2v_mean(des2,model)
d3=w2v_mean(des3,model)
print(np.dot(d1,content)/(np.linalg.norm(d1)*(np.linalg.norm(content))))
print(np.dot(d2,content)/(np.linalg.norm(d2)*(np.linalg.norm(content))))
print(np.dot(d3,content)/(np.linalg.norm(d3)*(np.linalg.norm(content))))
来看一看结果吧!
很明显看到,第二种语境下的余弦值大于另外两个,所以我们可以说我们目标句子中的“苹果”就是手机的意思。
是不是非常有趣!
那我们再来试一下“算账”,算账有两种意思,一种是计算账目。如,“你别打扰他,他正在算账呢。” 还有一种是吃亏或失败后与人较量.如,“好了,这回算你赢,下回我再跟你算账!”
首先来看看我们的语料中和“算账”相似的词,效果还可以。
model.wv.most_similar(u"算账")
我相看一看“我正要找你算账”中的“算账”应该是什么意思。(在自我推敲之后,自己也有点不确定,这句话中的“算账”该怎么解释)
content=['我','正要','找你','算账']
des1=['你别','打扰','他','他','正在','呢']
des2=['好','了','这回','算','你','赢','下回','我','再','跟','你']
def w2v_mean(essay,model):
ls=np.zeros(50)
for unit in essay:
try:
ls+=np.array(model.wv[unit])
except:
pass
return ls/len(essay)
content=w2v_mean(content,model)
d1=w2v_mean(des1,model)
d2=w2v_mean(des2,model)
print(np.dot(d1,content)/(np.linalg.norm(d1)*(np.linalg.norm(content))))
print(np.dot(d2,content)/(np.linalg.norm(d2)*(np.linalg.norm(content))))
来看看结果,非常相近,不过第二种对应的余弦值更大一些,那这里的“算账”就解释为“吃亏或失败后与人较量”吧。
语义消歧就是这样啦,大家可以直接点击连接去运行一下代码,非常方便哦!
哦对啦,我开始把讲解更新B站和抖音啦,名字都叫猫猫头丁,欢迎大家来关注啊!!!
B站:https://space.bilibili.com/410893912.
以上是关于自然语言处理之使用gensim.Word2Vec训练词向量进行词义消歧的主要内容,如果未能解决你的问题,请参考以下文章
在 keras 中使用预训练的 gensim Word2vec 嵌入