文章目录

  • 1 概述
  • 2 词向量工具
    • 2.1 模型训练
    • 2.2 增量训练
    • 2.3 求词语相似度
    • 2.4 求与词语相近的多个词语
  • 3 词向量训练算法
  • 4 词向量训练代码实现
  • 5 总结

转载来源:https://blog.csdn.net/u013510838/article/details/82108381

1 概述

词向量和分词一样,也是自然语言处理中的基础性工作。词向量一方面解决了词语的编码问题,另一方面也解决了词的同义关系,使得基于LSTM等深度学习模型的自然语言处理成为了可能。和分词不同,中英文文本,均需要进行词向量编码。

2 词向量工具

2013年Google开源了word2vec工具,它可以进行词向量训练,加载已有模型进行增量训练,求两个词向量相似度,求与某个词接近的词语,等等。功能十分丰富,基本能满足我们对于词向量的需求。下面详细讲解怎么使用word2vec

2.1 模型训练

词向量模型训练只需要有训练语料即可,语料越丰富准确率越高,属于无监督学习。后面会讲词向量训练算法和代码实现,这儿先说怎么利用word2vec工具进行词向量模型训练。

# gensim是自然语言处理的一个重要Python库,它包括了Word2vec
import gensim
from gensim.models import word2vec# 语句,由原始语句经过分词后划分为的一个个词语
sentences = [['网商银行', '体验', '好'], ['网商银行','转账','快']]# 使用word2vec进行训练
# min_count: 词语频度,低于这个阈值的词语不做词向量
# size:每个词对应向量的维度,也就是向量长度
# workers:并行训练任务数
model = word2vec.Word2Vec(sentences, size=256, min_count=1)# 保存词向量模型,下次只需要load就可以用了
model.save("word2vec_atec")

2.2 增量训练

有时候我们语料不是很丰富,但都是针对的某个垂直场景的,比如网商银行相关的语料。此时我们训练词向量时,可以先基于一个已有的模型进行增量训练,这样就可以得到包含特定语料的比较准确的词向量了。

# 先加载已有模型
model = gensim.models.Word2Vec.load("word2vec_atec")# 进行增量训练
corpus = [['网商银行','余利宝','收益','高'],['贷款','发放','快']] # 新增语料
model.build_vocab(corpus, update=True)  # 训练该行
model.train(corpus, total_examples=model.corpus_count, epochs=model.iter)# 保存增量训练后的新模型
model.save("../data/word2vec_atec")

2.3 求词语相似度

可以利用词向量来求两个词语的相似度。词向量的余弦夹角越小,则相似度越高。

# 验证词相似程度
print model.wv.similarity('花呗'.decode('utf-8'), '借呗'.decode('utf-8'))

2.4 求与词语相近的多个词语

for i in model.most_similar(u"我"):print i[0],i[1]

3 词向量训练算法

词向量可以通过使用大规模语料进行无监督学习训练得到,常用的算法有CBOW连续词袋模型和skip-gram跳字模型。二者没有本质的区别,算法框架完全相同。区别在于,CBOW利用上下文来预测中心词。而skip-gram则相反,利用中心词来预测上下文。比如对于语料 {“The”, “cat”, “jump”, “over”, “the”, “puddle”} ,CBOW利用上下文{“The”, “cat”, “over”, “the”, “puddle”} 预测中心词“jump”,而skip-gram则利用jump来预测上下文的词,比如jump->cat, jump->over。一般来说,CBOW适合小规模训练语料,对其进行平滑处理。skip-gram适合大规模训练语料,可以基于滑窗随机选择上下文词语。word2vec模型训练时默认采用skip-gram。

4 词向量训练代码实现

下面来看一个基于skip-gram的词向量训练的代码实现,这样就能够skip-gram算法有比较深刻的理解。CBOW算法和skip-gram基本相同。代码来自TensorFlow官方教程 https://www.tensorflow.org/tutorials/word2vec

# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_functionimport collections
import math
import os
import random
import zipfileimport numpy as np
from six.moves import urllib
from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf# 1 下载语料文件,并校验文件字节数是否正确
url = 'http://mattmahoney.net/dc/'
def maybe_download(filename, expected_bytes):if not os.path.exists(filename):urllib.request.urlretrieve(url + filename, filename)statinfo = os.stat(filename)if (statinfo.st_size == expected_bytes):print("get text and verified")else:raise Exception("text size is not correct")return filenamefilename = maybe_download("text8.zip", 31344016)# 2 语料处理,弄成一个个word组成的list, 以空格作为分隔符。
# 如果是中文语料,这一步还需要进行分词
def read_data(filename):with zipfile.ZipFile(filename) as f:data = tf.compat.as_str(f.read(f.namelist()[0])).split()return datavocabulay = read_data(filename)
print("total word size %d" % len(vocabulay))
print("100 words at first: ", vocabulay[0:100])# 3 词表制作,根据出现频率排序,序号代表这个单词。词语编码的一种常用方式
def build_dataset(words, n_words):count = [["UNK", -1]]count.extend(collections.Counter(words).most_common(n_words - 1))dictionay = dict()for word, _ in count:# 利用按照出现频率排序好的词语的位置,来代表这个词语dictionay[word] = len(dictionay)# data包含语料库中的所有词语,低频的词语标注为UNK。这些词语都是各不相同的data = list()unk_count = 0for word in words:if word in dictionay:index = dictionay[word]else:index = 0unk_count += 1data.append(index)count[0][1] = unk_count   # unk的个数# 将key value reverse一下,使用数字来代表这个词语reversed_dictionary = dict(zip(dictionay.values(), dictionay.keys()))return data, count, dictionay, reversed_dictionaryVOC_SIZE = 50000
data, count, dictionary, reversed_dictionary = build_dataset(vocabulay, VOC_SIZE)
del vocabulay
print("most common words", count[0:5])
# 打印前10个单词的数字序号
print("sample data", data[:10], [reversed_dictionary[i] for i in data[:10]])# 4 生成训练的batch label对
data_index = 0
# skip_window表示与target中心词相关联的上下文的长度。整个Buffer为 (2 * skip_window + 1),从skip_window中随机选取num_skips个单词作为label
# 最后形成 target->label1 target->label2的batch label对组合
def generate_batch(batch_size, num_skips, skip_window):global data_indexbatch = np.ndarray(shape=(batch_size), dtype=np.int32)labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)# 将skip_window的数据组合放入Buffer中span = 2 * skip_window + 1buffer = collections.deque(maxlen=span)for _ in range(span):buffer.append(data[data_index])data_index = (data_index + 1) % len(data)   # 防止超出data数组范围,因为batch可以取很多次迭代。所以可以循环重复# num_skips表示一个Buffer中选取几个batch->label对,每一对为一个batch,故需要batch_size // num_skips个Bufferfor i in range(batch_size // num_skips):target = skip_windowtargets_to_avoid = [skip_window]# 一个Buffer内部寻找num_skips个labelfor j in range(num_skips):# 寻找label的位置,总共会有num_skips个labelwhile target in targets_to_avoid:   # 中间那个为batch,不能选为target.也不能重复选targettarget = random.randint(0, span - 1)targets_to_avoid.append(target)# 中心位置为batch,随机选取的num_skips个其他位置的为labelbatch[i * num_skips + j] = buffer[skip_window]  #labels[i * num_skips + j, 0] = buffer[target]   # 遍历选取的label# 一个Buffer内的num_skips找完之后,向后移动一位,将单词加入Buffer内,并将Buffer内第一个单词移除,从而形成新的Bufferbuffer.append(data[data_index])data_index = (data_index + 1) % len(data)# 所有batch都遍历完之后,重新调整data_index指针位置data_index = (data_index + len(data) - span) % len(data)return batch, labelsbatch, labels = generate_batch(batch_size=8, num_skips=2, skip_window=1)
for i in range(8):print(batch[1], reversed_dictionary[batch[i]], "->", labels[i, 0], reversed_dictionary[labels[i, 9]])# 5 构造训练模型
batch_size = 128
embedding_size = 128  # 词向量为128维,也就是每一个word转化为的vec是128维的
skip_window = 1   # 滑窗大小为1, 也就是每次取中心词前后各一个词
num_skips = 2     # 每次取上下文的两个词# 模型验证集, 对前100个词进行验证,每次验证16个词
valid_size = 16
valid_window = 100
valid_examples = np.random.choice(valid_window, valid_size, replace=False)# 噪声词数量
num_sampled = 64graph= tf.Graph()
with graph.as_default():train_inputs = tf.placeholder(tf.int32, shape=[batch_size])train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])valid_dataset = tf.constant(valid_examples, dtype=tf.int32)     # 验证集with tf.device("/cpu:0"):# 构造embeddings, 50000个词语,每个词语为长度128的向量embeddings = tf.Variable(tf.random_uniform([VOC_SIZE, embedding_size], -1.0, 1.0))embed = tf.nn.embedding_lookup(embeddings, train_inputs)nce_weights = tf.Variable(tf.truncated_normal([VOC_SIZE, embedding_size], stddev=1.0 / math.sqrt(embedding_size)))nce_biases = tf.Variable(tf.zeros([VOC_SIZE]))# 利用nce loss将多分类问题转化为二分类问题,从而使得词向量训练成为可能,不然分类会是上万的量级loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weights,biases=nce_biases,labels=train_labels,inputs=embed,       # inputs为经过embeddings词向量之后的train_inputsnum_sampled=num_sampled,    # 噪声词num_classes=VOC_SIZE,))optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)# 归一化embeddingsnorm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))normalized_embeddings = embeddings / normvalid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, valid_dataset)similarity = tf.matmul(valid_embeddings, normalized_embeddings, transpose_b=True)init = tf.global_variables_initializer()# 6 训练
num_steps = 100000
with tf.Session(graph=graph) as session:init.run()average_loss = 0for step in xrange(num_steps):# 构建batch,并进行feedbatch_inputs, batch_labels = generate_batch(batch_size, num_skips, skip_window)feed_dict = {train_inputs: batch_inputs, train_labels: batch_labels}# run optimizer和loss,跑模型_, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)average_loss += loss_valif step % 2000 == 0 and step > 0:average_loss /= 2000print("average loss at step ", step, ": ", average_loss)average_loss = 0# 1万步,验证一次if step % 10000 == 0:sim = similarity.eval()for i in xrange(valid_size):valid_word = reversed_dictionary[valid_examples[i]]top_k = 8nearest = (-sim[i, :]).argsort()[1: top_k+1]log_str = "Nearest to %s:" % valid_wordfor k in xrange(top_k):close_word = reversed_dictionary[nearest[k]]log_str = '%s %s,' % (log_str, close_word)print(log_str)final_embeddings = normalized_embeddings.eval()

流程还是很简单的,关键在第四步batch的构建,和第五步训练模型的构建,步骤如下

  1. 下载语料文件,并校验文件字节数是否正确。这儿只是一个demo,语料也很小,只有100M。如果想得到比较准确的词向量,一般需要通过爬虫获取维基百科 网易新闻等既丰富又相对准确的语料素材。一般需要几十上百G的corpus,即语料。谷歌根据不同的语料预训练了一些词向量,参考 https://github.com/Embedding/Chinese-Word-Vectors

  2. 语料处理,文本切割为一个个词语。英文的话以空格为分隔符进行切分即可(有误差,但还好)。中文的话需要通过分词工具进行分割。

  3. 词表制作,词语预编码。根据词语出现频率排序,序号代表这个单词。词语编码的一种常用方式。

  4. 生成训练的batch label对。这是比较关键的一步,也是体现skip-gram算法的一步。
    先取出滑窗范围的一组词,如滑窗大小为5,则取出5个词。

  • 先取出滑窗范围的一组词,如滑窗大小为5,则取出5个词。
  • 位于中心的词为中心词,比如滑窗大小为5,则第三个词为中心词。其他词则称为上下文。
  • 从上下文中随机取出num_skip个词,比如num_skip为2,则从4个上下文词语中取2个。通过随机选取提高了一定的泛化性
  • ->上下文的x->y词组
  • 将滑窗向右移动一个位置,继续这些步骤,直到滑窗到达文本最后
  1. 构造训练模型,这一步也很关键。利用nce loss将多分类问题转化为二分类问题,optimizer优化方法采用随机梯度下降。
  2. 开始真正的训练。这一步比较常规化。送入第四步构建的batch进行feed,跑optimizer和loss,并进行相关信息打印即可。训练结束后,即可得到调整完的词向量模型。

5 总结

基于深度学习的词向量训练方法,具有算法简单通用,语料获取容易,泛化性好的优点。通过学习官方代码,可以对skip-gram等词向量训练算法有比较深入的理解。词向量在文本分析,文本摘要,情感分析等领域都是必须的预处理,可以大大提高自然语言处理的准确度。

自然语言处理5 -- 词向量相关推荐

  1. 干货分享 | 自然语言处理及词向量模型介绍(附PPT)

    云脑科技机器学习训练营第二期,对自然语言处理及词向量模型进行了详细介绍,量子位作为合作媒体为大家带来本期干货分享~ 本期讲师简介 樊向军 云脑科技核心算法工程师,清华大学学士,日本东京大学与美国华盛顿 ...

  2. 自然语言处理之词向量模型(三)

    1. 词向量模型 1.1 实现词向量的挑战 挑战一:如何把词转换为向量?自然语言单词是离散信号,比如"香蕉"."橘子"."水果"在我们看来就 ...

  3. 自然语言处理之词向量技术(二)

    1. 词向量技术 词向量(word2vec)是一种表示自然语言中单词的方法,即把每个词都表示为一个N维空间内的点,即一个高维空间内的向量,通过这种方法,把自然语言计算转换为向量计算.词向量的基本内容包 ...

  4. lda 可以处理中文_自然语言处理——使用词向量(腾讯词向量)

    向量化是使用一套统一的标准打分,比如填写表格:年龄.性别.性格.学历.经验.资产列表,并逐项打分,分数范围[-1,1],用一套分值代表一个人,就叫作向量化,虽然不能代表全部,但至少是个量度.因此,可以 ...

  5. 自然语言处理——使用词向量(腾讯词向量)

    向量化是使用一套统一的标准打分,比如填写表格:年龄.性别.性格.学历.经验.资产列表,并逐项打分,分数范围[-1,1],用一套分值代表一个人,就叫作向量化,虽然不能代表全部,但至少是个量度.因此,可以 ...

  6. 词向量Word2Vec(深度细致分析)

    本文以博客园刘建平Pinard对于word2vec的解释为基础,同时参考了其他相关博客的分析并加入了自己的理解,希望站在巨人的肩膀上进行一定的学习输出.至于本片文章的属性,个人认为是伪原创吧,有需要的 ...

  7. 斯坦福大学深度学习与自然语言处理第二讲:词向量

    斯坦福大学在三月份开设了一门"深度学习与自然语言处理"的课程:CS224d: Deep Learning for Natural Language Processing,授课老师是 ...

  8. 05.序列模型 W2.自然语言处理与词嵌入(作业:词向量+Emoji表情生成)

    文章目录 作业1: 1. 余弦相似度 2. 单词类比 3. 词向量纠偏 3.1 消除对非性别词语的偏见 3.2 性别词的均衡算法 作业2:Emojify表情生成 1. Baseline model: ...

  9. 自然语言处理︱简述四大类文本分析中的“词向量”(文本词特征提取)

    笔者在看各种NLP的论文.文献.博客之中发现在应用过程中,有种类繁多的词向量的表达.笔者举例所看到的词向量有哪些. 词向量一般被看做是文档的特征,不同词向量有不同的用法,本文介绍了四类词向量: Has ...

最新文章

  1. 用gcc gvim编译程序
  2. [转载] FatFs模块功能配置选项
  3. python语言有几种编程方式_零基础自学python语言,有哪几种方法?龟叔说:这套教程带你入门...
  4. 我们应该如何保护用户的密码
  5. Keras官方中文文档:Keras安装和配置指南(Windows)
  6. Graph Embedding图嵌入
  7. 软件测试面试必考的SQL语句
  8. Error 1606 Could Not Access Network Location %SystemDrive%/inetpub/wwwroot/
  9. 尚学堂视频笔记四:常用类
  10. 论文解读:iDRNA-ITF:基于诱导和转移框架识别蛋白质中的DNA和RNA结合残基
  11. 解决 3 errors and 0 warnings potentially fixable with the `--fix` option.问题
  12. ArcGIS水文分析实战教程(5)细说流向与流量
  13. 功能安全b等级_安全B端会议吸引了越来越多的信息安全人群
  14. 社工要掌握哪些计算机基本操作,【作为一名专业社工哪些方面需要注意】- 环球网校...
  15. python学习之旅_第2天
  16. 【P8090 [USACO22JAN] Herdle B】题解
  17. python量化自学书籍推荐_量化投资学习推荐的书籍都有哪些?
  18. RDO远程桌面管理工具
  19. python判断红绿灯
  20. 【网络编程】大端模式和小端模式(大头序和小头序)

热门文章

  1. 微信朋友圈广告投放价格
  2. 为什么很多互联网公司要组建自己的技术团队,而不是选择外包?
  3. 运动步数98800步,新方法!绝对好用!
  4. FFmpeg 硬件加速(硬解码)介绍
  5. Mongodb ObjectId格式
  6. 利用python写个桌面挂件
  7. AlphaFill: AlphaFold预测结构与小分子互作数据库
  8. APICloud-App-Templates
  9. 配置SQL 2012的AlwaysOn高性能组件
  10. [经验教程]华为H6子母路由器一拖三怎么配置安装组网覆盖客厅餐厅和卧室?