【计算语言学实验】基于 Skip-Gram with Negative Sampling (SGNS) 的汉语词向量学习和评估
一、概述
训练语料来源:维基媒体 https://dumps.wikimedia.org/backup-index.html 汉语数据
用word2vec训练词向量,并用所学得的词向量,计算 pku_sim_test.txt 文件中每行两个词间的余弦距离作为两词相似度,并输出到文件中。
二、数据准备及预处理
语料库的下载地址:https://dumps.wikimedia.org/zhwiki/20191120/zhwiki-20191120-pages-articles-multistream.xml.bz2
语料库文章的提取:
下载完成之后,解压缩得到的是一个xml文件,里面包含了许多的文章,也有许多的日志信息。此实验只需要提取xml文件里面的文章就可以了。
可以通过工具WikiExtractor来提取xml文件中的文章。先将整个WikiExtractor项目clone或者下载到本地,通过命令行窗口来运行,命令如下:(每个文件分割的大小为500M)
> git init
> git clone https://github.com/attardi/wikiextractor
> python .\wikiextractor\WikiExtractor.py -b 500M -o zhwiki zhwiki-20190401-pages-articles-multistream.xml.bz2
使用WikiExtractor提取文章,会在指定目录下产生一个AA的文件夹,里面会包含几个文件。
中文简体和繁体的转换:
因为维基百科语料库中的文章内容里面的简体和繁体是混乱的,所以我们需要将所有的繁体字转换成为简体。这里我们利用OpenCC来进行转换。
OpenCC项目地址: https://github.com/BYVoid/OpenCC, 将OpenCC安装到本地电脑后,执行命令:(t2s.json: 繁体转简体)
> opencc -i .\zhwiki\AA\wiki_00
-o .\zhwiki\BB\wiki_00
-c D:\opencc-1.0.4-win32\opencc-1.0.4\share\opencc\t2s.json
正则表达式提取文章内容并进行分词:
当前目录下的segmentWords.py中的代码共执行了三个步骤的操作:
(1)过滤标签内容:使用WikiExtractor提取的文章,会包含许多的,所以需要将这些不相关的内容通过正则表达式来去除。
(2)分词及去停用词:通过jieba对文章进行分词,在分词的时候还需要将停用词去除。
(3)合并保存文件:将分割之后的文章保存到文件中,每一行表示一篇文章,每个词之间使用空格进行分隔。
Jieba项目地址:https://github.com/fxsjy/jieba
#segmentWords.py
import logging
import jieba
import os
import re
def get_stopwords():
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',level=logging.INFO)
#加载停用词表
stopword_set = set()
with open("./stop_words/stopwords.txt",'r',encoding="utf-8") as stopwords:
for stopword in stopwords:
stopword_set.add(stopword.strip("\n"))
return stopword_set
'''
使用正则表达式解析文本
'''
def parse_zhwiki(read_file_path,save_file_path):
#过滤掉<doc>
regex_str = "[^<doc.*>$]|[^</doc>$]"
file = open(read_file_path,"r",encoding="utf-8")
#写文件
output = open(save_file_path,"w+",encoding="utf-8")
content_line = file.readline()
#获取停用词表
stopwords = get_stopwords()
#定义一个字符串变量,表示一篇文章的分词结果
article_contents = ""
cnt = 0
while content_line:
match_obj = re.match(regex_str,content_line)
content_line = content_line.strip("\n")
if len(content_line) > 0:
if match_obj:
#使用jieba进行分词
words = jieba.cut(content_line,cut_all=False)
for word in words:
if word not in stopwords:
article_contents += word+" "
else:
if len(article_contents) > 0:
output.write(article_contents+"\n")
article_contents = ""
cnt += 1
if (cnt % 10000 == 0):
print("已处理", cnt/10000, "万行")
content_line = file.readline()
output.close()
'''
将维基百科语料库进行分类
'''
def generate_corpus():
zhwiki_path = "./zhwiki/BB"
save_path = "./zhwiki/BB"
for i in range(3):
print("开始处理第", i, "个文件")
file_path = os.path.join(zhwiki_path,str("wiki_0%s"%str(i)))
parse_zhwiki(file_path,os.path.join(save_path,"wiki_corpus0%s"%str(i)))
'''
合并分词后的文件
'''
def merge_corpus():
output = open("./zhwiki/BB/wiki_corpus","w",encoding="utf-8")
input = "./zhwiki/BB"
for i in range(3):
print("开始合并第", i, "个文件")
file_path = os.path.join(input,str("wiki_corpus0%s"%str(i)))
file = open(file_path,"r",encoding="utf-8")
line = file.readline()
while line:
output.writelines(line)
line = file.readline()
file.close()
output.close()
if __name__ == "__main__":
# # wiki数据处理
print("开始正则,jieba处理数据")
generate_corpus()
# 文件合并
print("开始合并文件")
merge_corpus()
# 打印数据 显示
input_file = "./zhwiki/BB/wiki_corpus"
file = open(input_file,"r",encoding="utf-8")
line = file.readline()
num = 1
while line:
print(line)
line = file.readline()
num += 1
if num > 10:
break
word2vec模型的训练:
当前目录下的train.py中word2vec的参数设置(size=100, window=5, sg=1, hs=0, negative=5),符合实验要求(前后2窗口,100维,SGNS)。
#train.py
import logging
from gensim.models import word2vec
def main():
logging.basicConfig(format="%(asctime)s:%(levelname)s:%(message)s",level=logging.INFO)
sentences = word2vec.LineSentence("./zhwiki/BB/wiki_corpus")
# size:单词向量的维度
# window: 窗口大小
# sg=1: 使用skip-gram
# hs=0: 使用negative sample
model = word2vec.Word2Vec(sentences, size=100, window=5, sg=1, hs=0, negative=5)
# 保存模型 必须3个一起用
# model.save("./model/wiki_corpus.bin")
# model.save("./model/wiki_corpus.model")
# 训练为一个单独二进制压缩文件 可独立使用
model.wv.save_word2vec_format("./model/wiki_corpus_binary.bin", binary=True)
if __name__ == "__main__":
main()
计算两个词的相似度:
当前目录下的compute.py中的代码共执行了以下步骤:
(1)读取训练得到的模型,以及待计算相似的pku_sim_test.txt文件
(2)字符串以\t\n为分隔符切分为列表格式,并计算相似度
(3)结果保存为result.txt文件
#compute.py
import re
from gensim.models import KeyedVectors
def main():
# 读取模型以及待计算数据
model = KeyedVectors.load_word2vec_format("./model/wiki_corpus_binary.bin", binary=True)
f = open('./pku_sim_test.txt', encoding='utf-8')
out = open('result.txt', 'w', encoding='utf-8')
# 字符串切分为列表
wordlist = []
while True:
line = f.readline()
if not line:
break
wordlist.append(re.split(r'[\t\n]', line))
# 计算相似度
cnt = 0
resTotal = 0.0
for i in range(len(wordlist)):
words = wordlist[i]
try:
res = model.similarity(words[0], words[1])
except KeyError:
words[2] = 'OOV'
wordlist[i] = words
print(words)
continue
words[2] = str("%.4f"%res)
wordlist[i] = words
print(words)
cnt += 1
resTotal += res
print("查到的比例为:%.4f"%(cnt/len(wordlist)))
print("平均相似度为:%.4f"%(resTotal/cnt))
# 结果保存
lines = []
for i in range(len(wordlist)):
line = wordlist[i]
oneline = line[0] + '\t' + line[1] + '\t' + line[2] + '\n'
lines.append(oneline)
out.writelines(lines)
f.close()
out.close()
if __name__ == '__main__':
main()
【计算语言学实验】基于 Skip-Gram with Negative Sampling (SGNS) 的汉语词向量学习和评估的更多相关文章
- word2vec 中的数学原理具体解释(五)基于 Negative Sampling 的模型
word2vec 是 Google 于 2013 年开源推出的一个用于获取 word vector 的工具包,它简单.高效,因此引起了非常多人的关注. 因为 word2vec 的作者 Tomas ...
- word2vec原理(三) 基于Negative Sampling的模型
word2vec原理(一) CBOW与Skip-Gram模型基础 word2vec原理(二) 基于Hierarchical Softmax的模型 word2vec原理(三) 基于Negative Sa ...
- 论文解读(SelfGNN)《Self-supervised Graph Neural Networks without explicit negative sampling》
论文信息 论文标题:Self-supervised Graph Neural Networks without explicit negative sampling论文作者:Zekarias T. K ...
- word2vec改进之Negative Sampling
训练网络时往往会对全部的神经元参数进行微调,从而让训练结果更加准确.但在这个网络中,训练参数很多,每次微调上百万的数据是很浪费计算资源的.那么Negative Sampling方法可以通过每次调整很小 ...
- 词表征 2:word2vec、CBoW、Skip-Gram、Negative Sampling、Hierarchical Softmax
原文地址:https://www.jianshu.com/p/5a896955abf0 2)基于迭代的方法直接学 相较于基于SVD的方法直接捕获所有共现值的做法,基于迭代的方法一次只捕获一个窗口内的词 ...
- DL4NLP——词表示模型(三)word2vec(CBOW/Skip-gram)的加速:Hierarchical Softmax与Negative Sampling
上篇博文提到,原始的CBOW / Skip-gram模型虽然去掉了NPLM中的隐藏层从而减少了耗时,但由于输出层仍然是softmax(),所以实际上依然“impractical”.所以接下来就介绍一下 ...
- Notes on Noise Contrastive Estimation and Negative Sampling
Notes on Noise Contrastive Estimation and Negative Sampling ## 生成负样本 在常见的关系抽取应用中,我们经常需要生成负样本来训练一个好的系 ...
- [DeeplearningAI笔记]序列模型2.7负采样Negative sampling
5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.7 负采样 Negative sampling Mikolov T, Sutskever I, Chen K, et a ...
- 21.实验基于_version进行乐观锁并发控制
21.实验基于_version进行乐观锁并发控制 主要知识点: 实验基于_version进行乐观锁并发控制 1.实验实战演练基于_version进行乐观锁并发控制 (1)先构造一条数据出来 PUT / ...
随机推荐
- 实验1: Cisco路由器基础配置
实验 1: Cisco路由器基础配置 1. 路由器的运行模式:Router> 用户模式,通常用来查看统计信息,但不能修改路由器的设置.Router# 特许模式,可以查看并修改 ...
- VUE 开发报表,非编码方式
官网:http://doc.sougn.com 下载地址:https://pan.baidu.com/share/init?surl=P0O9sjfzC8nuQxirDfjW1A 密码:4oev 先 ...
- virtualbox更新完无法启动的问题(不能为虚拟电脑 Ubuntu 打开一个新任务)
具体错误: 不能为虚拟电脑 Ubuntu 打开一个新任务. VT-x is disabled in the BIOS. (VERR_VMX_MSR_VMXON_DISABLED). 返回 代码: E_ ...
- 【C/C++】概念: VC虚函数布局引发的问题
在网上看到一个非常热的帖子,里面是这样的一个问题: 在打印的时候发现pFun的地址和 &(Base::f)的地址竟然不一样太奇怪了?经过一番深入研究,终于把这个问题弄明白了.下面就来一步步进行 ...
- Request和Session的生命周期
request的生命周期是request请求域,一个请求结束,则request结束 session的生命周期是session会话域,打开一个浏览器请求一个网站的页面后,Session开始,当sessi ...
- Asp.Net Core Identity 骚断腿的究极魔改实体类
前言 默认的 Identity 实体类型在大多数时候已经基本够用,很多时候也只是稍微在 IdentityUser 类中增加一些自定义数据字段,比如头像.这次,我要向园友隆重介绍我魔改之后的 Ident ...
- lua学习之表达式篇
表达式 表达式用于表达值 lua 中表达式可以为数字常量,自变字符串,变量,一元和二元操作符,函数调用.函数定义.table 构造式 算数操作符 一元操作符 -负号 二元操作符 -减号 / ^ % x ...
- Shiro过滤器
Shiro内置过滤器 anon.authBasic.authc.user.logout perms.roles.ssl.port spring.xml <bean id="shiroF ...
- 基于Go的马蜂窝旅游网分布式IM系统技术实践
一.引言 即时通讯(IM)功能对于电商平台来说非常重要,特别是旅游电商. 从商品复杂性来看,一个旅游商品可能会包括用户在未来一段时间的衣.食.住.行等方方面面.从消费金额来看,往往单次消费额度较大.对 ...
- 分区格式化大于2 TiB磁盘
如果您要分区格式化一块大于2 TiB的作数据盘用的云盘(本文统一称为 大容量数据盘,小于2 TiB的数据盘统称为 小容量数据盘),您必须采用GPT分区形式.本文档描述了如何在不同的操作系统里分区格式化 ...