维基百科中文数据训练word2vec词向量模型——基于gensim库
上文我们使用了 gensim
库中的 Word2vec
模块训练词向量模型,本篇我们通过 tensorflow
自己手写代码来训练词向量模型,并测试词与词之间的相似度,主要步骤大体如下:
tensorflow
训练模型的构建、训练(图的构建、初始化操作、会话开启、训练模型)准备环境:
Windows10 64位
tensorflow-gpu-1.9.0
(我电脑使用的这个,不过本篇cpu版本的即可,安装方式自行百度,gpu版本安装比较麻烦)jieba
Python3.6
(我用的是 Anaconda
)Pycharm
本篇代码可见: Github
本篇我们使用的数据是小说《斗破苍穹》,通过对《斗破苍穹》文本数据的训练,我们希望从中找出指定词最相似的 n
个词,此外我们还有一个停用词文本文件。
为了模型可以快速训练,所以这里这是使用了一部小说,如果模型的效果要更好,可以扩大数据量。
当然,看到这些文本数据,我们自然而然会想到,分词、去停用词
set
集合代码如下:
# step 1 读取停用词,构建停用词set集合
stop_words = []
with open('stop_words.txt', encoding='utf-8') as f: # 读取stop_words.txt,每行为一个词
line = f.readline() # 按行读取
while line:
stop_words.append(line[:-1]) # 去除每行后面的换行符并添加到stop_words中
line = f.readline()
stop_words = set(stop_words) # 通过set函数去除重复词
print('停用词读取完毕,共{n}个单词'.format(n=len(stop_words)))
代码如下:
# step2 读取文本,预处理,分词,得到词典
all_word_list = [] # 用于记录所有的词,即词典
sentence_list = [] # 用于记录所有样本的样本list,如:[["今天","天气","不错"],["我","是","谁"],...,["","",""]]
line_sum = 1
with open('wiki_zh_jian.txt', encoding='utf-8') as f:
line = f.readline() # 按行读取
while line: # 判断有没有读取到文件末尾,没有就执行循环语句
print("正在处理第", line_sum, "行")
while '\n' in line:
line = line.replace('\n', '') # 将'\n'替换为''
while ' ' in line:
line = line.replace(' ', '') # 将' '替换为''
if len(line) > 0: # 如果句子非空
raw_words = list(jieba.cut(line, cut_all=False)) # 使用jieba分词
dealed_words = [] # 用于记录去除停用词以及规定词后的词
for word in raw_words:
# 如果词不属于停用词且不是['qingkan520', 'www', 'com', 'http']中的词
if word not in stop_words and word not in ['qingkan520', 'www', 'com', 'http']:
all_word_list.append(word) # 将该词添加到样本的词list中
dealed_words.append(word) # 将该词添加到处理后的词list中
sentence_list.append(dealed_words) # 每行为一个样本,并将处理过的词list添加到样本list
line = f.readline() # 读取下一行
line_sum += 1
word_count = collections.Counter(all_word_list) # 计数器,返回dict类型,{"单词1":15,"单词2":5,"单词3":2}
# 表示单词1出现了15次,单词2出现了5次,单词3出现了2次,依次类推
print('文本中总共有{n1}个单词,不重复单词数{n2},选取前30000个单词进入词典'
.format(n1=len(all_word_list), n2=len(word_count)))
word_count = word_count.most_common(30000) # 返回一个TopN列表,如:[("单词1",15),("单词2",5),("单词3",2)]
word_list = [x[0] for x in word_count] # 取出TopN列表中的单词,放到word_list中,构成["单词1","单词2","单词3"]
print(word_list[:100])
tensorflow
训练模型的构建、训练 本节通过 word2vec
类来实现,主要包括:
1. 初始化参数 __init__
vocab_list=None
, 词典默认为None,需用户传入embedding_size=200
, 词向量维度,默认为200win_len=3
, 单边窗口长,也就是上下文,考虑某个词的前面3个词,后面3个词num_sampled=1000
, 负采样个数,默认1000learning_rate=1.0
, 学习率logdir='/tmp/simple_word2vec'
, tensorboard记录地址model_path=None
模型路径,用于训练好后加载模型用程序执行到此类时,先执行
__init__
。根据模型训练时传入的参数,__init__
进行:参数的获取、词的映射(词典)、图的定义、操作初始化(会话创建、会话开启、记录摘要)
2. 图的定义 build_graph
3. 操作初始化 init_op
4. 训练模型 train_by_sentence
5. 计算相似度概率
6. 模型保存
7. 模型加载
具体内容可看代码部分,其中有大量的注释
主要是从词典选择两个词,然后计算出它们之间的相似度。结果如下:
0 sentences dealed, loss: 392.29644775390625
1000 sentences dealed, loss: 246.87802124023438
2000 sentences dealed, loss: 185.36923217773438
3000 sentences dealed, loss: 109.7376708984375
4000 sentences dealed, loss: 102.31909942626953
5000 sentences dealed, loss: 87.00853729248047
6000 sentences dealed, loss: 92.63105773925781
7000 sentences dealed, loss: 60.69317626953125
8000 sentences dealed, loss: 47.703128814697266
9000 sentences dealed, loss: 51.7804069519043
['天地', '级别']
[['片刻', '一笑', '笑', '实力', '斗之气', '斗技', '挥手', '实在', '少年', '这位'],
['萧战', '摇头', '时', '薰', '点头', '一口气', '小医仙', '笑', '少年', '心头']]
0.049292885 0.011192114
从上面结果中,我们好像也看不出什么,主要是因为数据量比较小,训练出来的模型效果不是很好,我们可以自己找一个大点的数据集进行训练。但是整个过程还是能够很好的完成的。