本文介绍

  1. wordvec的概念
  2. 语言模型训练的两种模型CBOW+skip gram
  3. word2vec 优化的两种方法:层次softmax+负采样
  4. gensim word2vec默认用的模型和方法

未经许可,不要转载。


机器学习的输入都是数字,而NLP都是文字; 为了让机器学习应用在NLP上,需要把文字转换为数字,把文字嵌入到数学空间。

1. 词表示:

  • 词的独热表示:onehot (词之间是孤立的)

    • onehot:
      • 思想:假设词表大小为N, 则每个单字表示为N维向量; 每个单字只有1位为1,其他为0;茫茫0海中一个1
      • 缺点:词之间是孤立的;维度太大
  • 词的分布式表示:(能描述词之间的语义关系)

    • 基于矩阵的分布式表示
    • 基于聚类的分布式表示
    • 基于神经网络的分布表示,词嵌入 word embedding
      • 将01表示改为浮点数表述;降维
      • word2vec是用神经网络训练语言模型(NNLM)过程中得到的参数.
  • 其他概念

    • 语言模型: 就是一段文字成为句子的概率; 经常用的ngram, n=2或3

2. NNLM 神经网络语言模型

用神经网络训练语言模型,常见有两种; 用上下文预测term(CBOW), 用term预测上下文(skip-gram),结构一般是简单三层网络,一个输入层、一个隐含层、一个输出层。

2.1 CBOW 连续词袋模型

  • 变量:词表大小V, 要嵌入到N维空间中,C/2是窗口大小,即上下文取几个term(不算当前term);- N一般取50~300
  • 步骤:参考自 https://www.zhihu.com/question/44832436
    • input layer:窗口内的C个词的onehot表示
    • input layer -> hidden layer:(V维表示降到N维表示)
      • 通过权重矩阵WV×NWV×N ,将 V×CV×C映射为 N×CN×C
    • hidden layer + 激活函数:C个词表示为1个词
      • word2vec中激活函数,用了简单取平均;
    • hidden layer -> output layer:1个N维词还原到高维V维中;
      • 通过权重矩阵WN×V ,将 N×1映射为 V×1
    • output layer + softmax 激活函数,将值归一化到0~1之间 y
    • 用BP+梯度下降优化cost function y和真实y之间的距离,迭代优化参数 WW
    • 收敛result:y是V维向量,每个元素取值0~1, 将最大元素值,还原为onehot编码,就是最终结果了。

2.2 skip-gram 语言模型

思路同CBOW, 只是输入是1个词,输出是C个词;
一般用BP训练得到参数,预测用一次前向传播;

3. word2vec用的优化方法

word2vec结合了CBOW, skip-gram的方法 训练得到参数W, 但在计算中做了很多优化;
可以看到,NNLM计算中,两个问题导致计算量大;

  1. 词表维度大;
  2. softmax计算量大;

下面介绍两种优化方法;

3.1 hierarchical softmax 层次softmax

/ˌhī(ə)ˈrärkikəl/

  • huffman: 带权路径长度最短为目标,可以用log(V)长度的编码表示

    带权路径长度WPL:

  • 层次softmax
    softmax需要对每个词语都计算输出概率,并进行归一化,计算量很大;
    进行softmax的目的是多分类,那么是否可以转成多个二分类问题呢, 如SVM思想? 从而引入了层次softmax

    • 示意图

    • 为什么有效?

      • 1)用huffman编码做词表示
      • 2)把N分类变成了log(N)个2分类。 如要预测的term(足球)的编码长度为4,则可以把预测为'足球',转换为4次二分类问题,在每个二分类上用二元逻辑回归的方法(sigmoid);
      • 3)逻辑回归的二分类中,sigmoid函数导数有很好的性质,σ(x)=σ(x)(1σ(x))
      • 4)采用随机梯度上升求解二分类,每计算一个样本更新一次误差函数
    • 参考自:http://flyrie.top/2018/10/31/Word2vec_Hierarchical_Softmax/

    • gensim的word2vec 默认已经不采用分层softmax了, 因为log21000=10也挺大的;如果huffman的根是生僻字,则分类次数更多;

3.2 高频词抽样+负采样

为了解决NNLM中softmax过程的计算性能问题,通常有几种优化技巧:

  1. 将常见的单词组合(word pairs)或者词组作为单个“words”来处理
  2. 对高频次单词进行抽样来减少训练样本的个数
  3. 对优化目标采用“negative sampling”方法,这样每个训练样本的训练只会更新一小部分的模型权重,从而降低计算负担

参考自:https://www.jianshu.com/p/56554a63410f

3.2.1 对高频词抽样

主要思想是少训练没有区分度的高频term;
对于我们在训练原始文本中遇到的每一个单词,它们都有一定概率被我们从文本中删掉,而这个被删除的概率与单词的频率有关。词频越高(stopword),抽样越少;

  • 抽样率 P(wi)=(Z(wi)t+1)×tZ(wi)=tZ(wi)+tZ(wi) ,其中

    • Z(wi)是词在语料中的出现概率,反比关系,越高频词抽的越少;

    • t是设定的阈值,正比关系,t越大,不同频率单词的采样概率差异越大; gensim word2vec中默认值是0.001

    • 抽样率直观理解

      import numpy as np
      import matplotlib.pyplot as plt
      
      x = np.array(range(1, 100)) / 1000.0
      t1 = 0.001
      t2 = 0.0001
      y1 = np.power(t1/x, 0.5) + t1/x
      y2 = np.power(t2/x, 0.5) + t2/x
      plt.plot(x, y1, '-', label='t=0.001')
      plt.plot(x, y2, '-', label='t=0.0001')
      plt.legend()
      

3.2.2 负采样 Negative sampling

  • 问题:在NNLM中对于每个样本w, 都要更新一次hidden->output的参数阵WN×V,计算量很大;比如词表大小V=10000, N=300, 那么权重矩阵有300万个参数;
  • 思想:如果每次只更新目标词(正例 positive word)和少数几个负例(negative words), 那么计算量会显著减少; 比如如果我们每次只更新M=1+5个,则更新了6*300=1800, 1800/300万=0.06%; 计算量减少了3个数量级。
  • negative words如何选择:根据词表中出现的概率,出现概率越高,被选作负样本的概率越高;
    • P(wi)=f(wi)3/4vj=0f(wj)3/4, 其中f(wj)是出现的概率,3/4是经验值,比线性关系更弱化了些;

4. gensim word2vec默认参数(CBOW+负采样)

默认用了CBOW模型,采用高频词抽样+负采样进行优化;

from gensim.models import Word2Vec
word2vec.Word2Vec(sentences=None, size=100, alpha=0.025, window=5, min_count=5, max_vocab_size=None, sample=0.001, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, negative=5, ns_exponent=0.75, cbow_mean=1,  iter=5, null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000, compute_loss=False, callbacks=(), max_final_vocab=None)
  • 上下文窗口大小:window=5
  • 忽略低频次term:min_count=5
  • 语言模型是用CBOW还是skip-gram?sg=0 是CBOW
  • 优化方法是用层次softmax还是负采样:hs=0 是负采样
  • 负采样样本数: negative=5 (一般设为5-20)
  • 负采样采样概率的平滑指数:ns_exponent=0.75
  • 高频词抽样的阈值 sample=0.001
posted @ 2019-07-14 18:04 liyuxia713 阅读(6756) 评论(0) 推荐(0) 编辑
摘要: 关键字: 用jieba切词 用expand 一列变多列 用stack 列转行 用group by + aggr 相同term的pv求和 上效果: 上代码: 阅读全文
posted @ 2018-09-28 18:33 liyuxia713 阅读(875) 评论(0) 推荐(0) 编辑
摘要: lexsort支持对数组按指定行或列的顺序排序;是间接排序,lexsort不修改原数组,返回索引。 (对应lexsort 一维数组的是argsort a.argsort()这么使用就可以;argsort也不修改原数组, 返回索引) 默认按最后一行元素有小到大排序, 返回最后一行元素排序后索引所在位置 阅读全文
posted @ 2017-06-26 19:29 liyuxia713 阅读(52886) 评论(0) 推荐(2) 编辑
摘要: 背景:个人对挖掘算法不太了解,学习过程中看到有C4.5算法、CART算法等,看起来都是一样的决策树,不知其区别,所以网络上搜索学习,备忘如下:从决策树开始介绍,该博文不错:算法杂货铺——分类算法之决策树(Decision tree)决策树在决策过程中,选择根节点属性的度量方法(分裂规则)有多种,一般使用自顶向下递归分治法,并采用不回溯的贪心算法;我们看到的各种决策树算法,其实主要是因为采用的度量方式的不同而得到的。下面介绍基于不同的度量方法的三种算法; 信息增益越大越好(ID3算法)、信息增益率越大越好(C4.5算法)、Gini增益越大越好(CART算法)首先需要了解下信息熵、信息增益的概念. 阅读全文
posted @ 2014-02-28 17:11 liyuxia713 阅读(1002) 评论(0) 推荐(0) 编辑
摘要: mail: 比较常用,缺点是发送附件要同时安装其他软件;mutt:功能强大,注意发送html需要升级到1.5+版本;用mail发送邮件:echo "邮件正文" | mail -s "邮件标题" -c "抄送人" "收件人"如果需要改默认的发送人信息,可以用 -- -f 参数,如下:echo "邮件正文" | mail -s "邮件标题" -c "抄送人" "收件人" ---faddress@baidu.com发送html格式echo & 阅读全文
posted @ 2014-01-16 17:36 liyuxia713 阅读(1444) 评论(0) 推荐(0) 编辑
摘要: 对于含多字节的字符串,进行截断的时候,要判断截断处是几字节字符,不能将多字节从中分割,避免截断后乱码下面给出utf8和gb18030上的实现, 用任何一种都可以,可以先进行转码,用encode, decode;方法1:对utf8: 参考:http://blog.csdn.net/marising/article/details/3452971def subString(string,length): if length >= len(string): return string result = '' i = 0 p = 0 whil... 阅读全文
posted @ 2014-01-14 11:36 liyuxia713 阅读(2533) 评论(0) 推荐(0) 编辑
摘要: 参考:http://stackoverflow.com/questions/3636928/test-if-a-python-string-is-printableprint all(ord(c)<127and c in string.printable for c in input_str) 阅读全文
posted @ 2014-01-06 10:59 liyuxia713 阅读(734) 评论(0) 推荐(0) 编辑
摘要: http://developer.51cto.com/art/200810/94162.htm 阅读全文
posted @ 2013-12-06 15:36 liyuxia713 阅读(135) 评论(0) 推荐(0) 编辑
摘要: http://www.cnblogs.com/yd1227/archive/2011/03/18/1988015.html该博文写的很详细,备忘。需要注意的是,写测试脚本的时候,不要将脚本命名成跟module一样的名字,如random.py,否则会出现报错:AttributeError: 'module' object has no attribute 'randint' 阅读全文
posted @ 2013-11-18 20:51 liyuxia713 阅读(224) 评论(0) 推荐(0) 编辑
摘要: 以输入为GB18030编码字符串为例:#把全角字符串转半角def tobanjiao(string): ustring = string.decode('GB18030') rstring = "" for uchar in ustring: inside_code=ord(uchar) if inside_code==0x3000: inside_code=0x0020 else: ... 阅读全文
posted @ 2013-11-14 12:52 liyuxia713 阅读(570) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示