三十二-用影视剧字幕语料库生成词向量
利用搜索引擎的原理实现的聊天机器人效果差强人意,为了对庞大的语料库进一步运用,打算利用LSTM-RNN来做训练,第一步需要把中文语料转成算法可以识别的向量形式,最强大的word embedding工具莫过于word2vec了,本节跟大家分享我是怎么用三千万影视剧字幕语料库生成词向量的
对语料库切词¶
因为word2vec的输入需要是切好词的文本文件,但我们的影视剧字幕语料库是回车换行分隔的完整句子,所以我们先对其做切词,有关中文切词的方法请见《教你成为全栈工程师(Full Stack Developer) 三十四-基于python的高效中文文本切词》,为了对影视剧字幕语料库切词,我们来创建word_segment.py文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # coding:utf-8 import sys reload(sys) sys.setdefaultencoding( "utf-8" ) import jieba from jieba import analyse def segment(input, output): input_file = open(input, "r") output_file = open(output, "w") while True: line = input_file.readline() if line: line = line.strip() seg_list = jieba.cut(line) segments = "" for str in seg_list: segments = segments + " " + str output_file.write(segments) else: break input_file.close() output_file.close() if __name__ == '__main__': if 3 != len(sys.argv): print "Usage: ", sys.argv[0], "input output" sys.exit(-1) segment(sys.argv[1], sys.argv[2]); |
使用方法:
1 | python word_segment.py subtitle/raw_subtitles/subtitle.corpus segment_result |
生成的segment_result文件内容就像下面的样子:
1 2 3 | …… 这件 事 对不起 我 并 不 直率 只有 在 梦 中 才能 表白 在 思绪 错乱 之前 现在 只想 马上 见到 你 夜晚 在 月光 下 哭泣 深夜里 无法 打电话 给 你 纯情 的 我 该 怎么办 心 就 如 万花筒 一般 月亮 的 光芒 引导 着 我 与 你 相会 无数次 星座 闪耀 的 瞬间 来 占卜 恋爱 的 方向 同样 都 是 在 地球 上 出生 的 奇迹 的 罗曼史 我 相信 奇迹 的 罗曼史 小小 兔 在 哪 你 在 哪里 找到 了 吗 到处 都 没 看到 难道 被 敌人 … 总之 分头 寻找 继续 找 吧 暗黑 女王 Black Lady 的 诞生 不 愉快 的 往日 回忆 会 在 内心深处 留下 创伤 想起 坏心肠 的 妈妈 及 冷酷 的 父亲 吧 是 青蛙 会 跌倒 的 谁 叫 你 不 听 妈妈 的话 不 可以 哭 妈妈 最 讨厌 了 爸爸 拉 我 起来 自己 站 起来 不向 你 伸出手 的 父母 就是 不爱 你 的 证据 是 你 自己 跌倒 不好 站 起来 快 回想起来 那些 更 可恨 的 事情 吧 怎么 一个 人站 着 发呆 今天 是 我 的 生日 生日 ? 对 呀 可是 爸 …… |
统计一下这个文件如下:
1 2 3 4 | [root@centos $] ls -lh segment_result -rw-r--r-- 1 lichuang staff 1.1G 10 9 18:59 segment_result [root@centos $] wc segment_result 0 191925623 1093268485 segment_result |
0行是因为没有在行尾加回车符,一共是191925623列,1093268485个字符
用word2vec生成词向量¶
想了解word2vec的原理请见《自己动手做聊天机器人 二十五-google的文本挖掘深度学习工具word2vec的实现原理》,如果因为被墙获取不到word2vec可以从https://github.com/warmheartli/ChatBotCourse/tree/master/word2vec获取,直接make编译好后会生成一些二进制文件,我要用到的是word2vec
执行
1 2 3 4 5 | ./word2vec -train ../segment_result -output vectors.bin -cbow 1 -size 200 -window 8 -negative 25 -hs 0 -sample 1e-4 -threads 20 -binary 1 -iter 15 Starting training using file ../segment_result Vocab size: 260499 Words in train file: 191353657 Alpha: 0.039254 Progress: 21.50% Words/thread/sec: 96.67k |
生成的vectors.bin就是我们想要的词向量,只不过是二进制格式,这时我们可以用word2vec自带的distance工具来验证一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ./distance vectors.bin Enter word or sentence (EXIT to break): 漂亮 Word: 漂亮 Position in vocabulary: 722 Word Cosine distance ------------------------------------------------------------------------ 很漂亮 0.532610 厉害 0.440603 身材 0.430269 beautiful 0.413831 棒 0.410241 帅呆了 0.409414 干得 0.407550 不错 0.402978 好美 0.401329 可爱 0.399667 猕猴桃 0.391512 好 0.388109 配当 0.387999 真棒 0.387924 太棒了 0.384184 真不错 0.377484 …… |
词向量二进制文件的格式及加载
word2vec生成的词向量二进制格式是这样的:
词数目(空格)向量维度 第一个词(空格)词向量(大小为200sizeof(float))第二个词(空格)词向量(大小为200sizeof(float))…… 所以写了一个加载词向量二进制文件的python脚本,后面会用到,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # coding:utf-8 import sys import struct import math import numpy as np reload(sys) sys.setdefaultencoding( "utf-8" ) max_w = 50 float_size = 4 def load_vectors(input): print "begin load vectors" input_file = open(input, "rb") # 获取词表数目及向量维度 words_and_size = input_file.readline() words_and_size = words_and_size.strip() words = long(words_and_size.split(' ')[0]) size = long(words_and_size.split(' ')[1]) print "words =", words print "size =", size word_vector = {} for b in range(0, words): a = 0 word = '' # 读取一个词 while True: c = input_file.read(1) word = word + c if False == c or c == ' ': break if a < max_w and c != '\n': a = a + 1 word = word.strip() # 读取词向量 vector = np.empty([200]) for index in range(0, size): m = input_file.read(float_size) (weight,) = struct.unpack('f', m) vector[index] = weight # 将词及其对应的向量存到dict中 word_vector[word.decode('utf-8')] = vector input_file.close() print "load vectors finish" return word_vector if __name__ == '__main__': if 2 != len(sys.argv): print "Usage: ", sys.argv[0], "vectors.bin" sys.exit(-1) d = load_vectors(sys.argv[1]) print d[u'真的'] |
运行方式如下:
1 | python word_vectors_loader.py vectors.bin |
效果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | begin load vectors words = 49804 size = 200 load vectors finish [-1.09570336 2.03501272 0.3151325 0.17603125 0.30261561 0.15273243 -0.6409803 0.06317 0.20631203 0.22687016 0.59229285 -1.10883808 1.12569952 0.16838464 1.27895844 -1.18480754 1.6270808 -2.62790298 0.43835989 -0.21364243 0.05743926 -0.77541786 -0.19709823 0.33360079 0.43415883 -1.28643405 -0.95402282 0.01350032 -0.20490573 0.80880177 -1.47243023 -0.09673293 0.05514769 1.00915158 -0.11268988 0.68446255 0.08493964 0.27009442 0.33748865 -0.03105624 -0.19079798 0.46264866 -0.53616458 -0.35288206 0.76765436 -1.0328685 0.92285776 -0.97560757 0.5561474 -0.05574715 -0.1951212 0.5258466 -0.07396954 1.42198348 1.12321162 0.03646624 -1.54316568 0.34798017 0.64197171 -0.57232529 0.14402699 1.75856864 -0.72602183 -1.37281013 0.73600221 0.4458617 -1.32631493 0.25921029 -0.97459841 -1.4394536 0.18724895 -0.74114919 1.50315142 0.56819481 0.37238419 -0.0501433 0.36490002 -0.14456141 -0.15503241 -0.04504468 1.18127966 1.465729 -0.13834922 -0.1232961 -0.14927664 0.67862391 2.46567917 -1.10682511 0.71275675 1.04118025 0.23883103 -1.99175942 0.40641201 0.73883104 -0.37824577 0.88882846 -0.87234962 0.71112823 0.33647302 -1.2701565 -1.15415645 1.41575384 -2.01556969 -0.85669023 -0.0378141 -0.60975027 0.0738821 0.19649875 0.02519603 -0.78310513 0.40809572 0.55079561 1.79861426 -0.01188554 -0.14823757 -0.97098011 -2.75159121 1.52366722 -0.41585007 0.78664345 0.43792239 1.03834045 1.18758595 0.18793568 -1.44434023 -1.55205989 0.24251698 1.05706048 -1.52376628 -0.60226047 -0.41849345 -0.30082899 -1.32461691 0.29701442 0.36680841 -0.72046149 -0.16455257 -0.02307599 -0.74143982 0.10319671 -0.5436908 -0.85527682 -0.81110024 -1.14968359 -1.45617366 0.57568634 -1.10673392 -0.48830599 1.38728273 -0.46238521 1.40288961 -0.92997569 0.90154368 0.09381612 -0.61220604 -0.40820527 1.2660408 -1.02075434 0.98662543 0.81696391 0.06962785 0.83282673 -0.12462004 1.16540051 0.10254569 1.03875697 0.05073663 1.50608146 0.49252063 0.09693919 0.38897502 -0.0673333 -0.30629408 -2.1759603 0.5477249 -1.46633601 1.54695141 -0.83080739 -0.49649978 1.05921662 -0.60124737 -0.72645563 -1.44115663 -0.6903789 0.38817915 -0.11854757 -0.18087701 -0.41152322 -0.98559368 -1.46712041 1.63777673 -0.64418262 -0.56800991 1.79656076 -0.80431151 0.99533188 0.06813133 -0.73489577 -0.67567319 0.64855355] |
总结¶
考虑到运行时间的关系,以上示例中多数是我抽取了部分语料数据,因此你真正执行时数值可能会不一样。至此,我们已经做到用影视剧字幕语料库(获取方式《自己动手做聊天机器人 二十九-重磅:近1GB的三千万聊天语料供出》)生成词向量并能够通过python加载起来,下一步就是如何运用了,敬请关注