基于word2vec的文档向量模型的应用

Posted hapjin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于word2vec的文档向量模型的应用相关的知识,希望对你有一定的参考价值。

基于word2vec的文档向量模型的应用

word2vec的原理以及训练过程具体细节就不介绍了,推荐两篇文档:《word2vec parameter learning explained》、和《word2vec中的数学》。

在《word2vec中的数学》中谈到了训练语言模型的一些方法:比如n-gram和神经网络。在使用神经网络训练语言模型时得到的"副产物",就是word2vec词向量。基于神经网络训练语言模型有2种方案:cbow和skip-gram,它们是在这篇文章《A neural probabilistic language model》基础上对训练过程提出的改进方案。这里简单讲一下cbow的训练过程:

训练过程

  • 输入层:将词w的上下文的2c个词的词向量作为输入:\\(v(context(w)_1),v(context(w)_2),...v(context(w)_2c)\\)

    随机初始化这2c个词的词向量

  • 投影层:将输入层的2c 个词向量累加求和

    投影层对词向量累加求和,这丢失了词的顺序信息。比如说:“我 爱 你们” 和“你们 爱 我” 这三个词的词向量累加求和得到的词向量是相同的。

  • 输出层:赫夫曼树

    基于Huffman树进行二分类,构造目标函数,并采用梯度算法最优化目标函数得到模型参数

    技术图片
    技术图片

训练语料与训练参数

训练语料需要预先分词。所有的词组成的集合,称为词库。赫夫曼树的每个叶子结点就代表词库中的一个词。训练的话,可采用gensim或者其他工具(比如HanLP word2vec)。注意几个训练参数:

  • size 生成的词向量的维度,比如300维、100维等等,不需要太大。因为word2vec词向量并不是 one-hot representation 而是distribution representation。
  • window 参与训练的上下文词的个数(Set max skip length between words)。其实就是上面提到的 c
  • iter 迭代次数
  • min_count 训练过程会根据词出现的频率构造Huffman树,对于那些低频词(小于min_count),不参与构造Huffman树,从而减少了Huffman树的高度。This will discard words that appear less than min_count times
  • cbow 采用cbow模型训练

训练完成后,词库中每个词,都对应着一个相同维度的float数值向量。计算两个词的相似度,就是计算两个词所对应的数值向量夹角的余弦。

句向量DocVectorModel

在实际应用场景中,用户输入并不是一个个的词,而是句子(若干个词)。比如一个用户资料下的个人说明,就是一句自我介绍的话;用户的一段评论,也是一句话…

如果要计算两个句子的相似度,那怎么办呢?这个需要根据实际需求场景了。比如对句子进行关键词提取,采用word2vec计算关键词的相似度作为句子的相似度。

或者再简单一点(HanLP中的DocVectorModel实现),直接对句子分词,得到若干个词,然后对每个词的词向量累加,作为整个句子的"句向量",然后计算2个句向量的余弦相似度即可。比如计算这2个句子的相似度:docVectorModel.similarity("我爱你们", "你们爱我")

    public Vector query(String content)
    
        if (content == null || content.length() == 0) return null;        //对句子进行分词,我爱你们--->["我"、"爱"、"你们"]
        List<Term> termList = NotionalTokenizer.segment(content);
        Vector result = new Vector(dimension());
        int n = 0;
        for (Term term : termList)
        
            //从word2vec词典中查出这个词的 词向量
            Vector vector = wordVectorModel.vector(term.word);
            if (vector == null)
            
                //如果这是一个oov词,则直接忽略
                continue;
            
            ++n;
            //将 句子分词后的每个词 的词向量 相加
            result.addToSelf(vector);
        
        if (n == 0)
        
            return null;
        
        //归一化
        result.normalize();
        //句子--->分词--->查询词向量--->词向量相加作为"句向量"
        return result;
    

值得注意的是,word2vec中存在的OOV问题,有没有其他更好的处理方案?

得到句子(文档)的向量表示后,计算余弦相似度,就能比较两个句子了。

    /**
     * 文档相似度计算
     * @param what
     * @param with
     * @return
     */
    public float similarity(String what, String with)
    
        //what 文档的 向量
        Vector A = query(what);
        if (A == null) return -1f;
        //to 文档的 向量
        Vector B = query(with);
        if (B == null) return -1f;
        //计算余弦相似度
        return A.cosineForUnitVector(B);
    

应用

在基于ElasticSearch的文本搜索中,文档的相关性得分计算主要是基于TF-IDF或者BM25实现的:有时为了capture 查询字符串与文档之间的一些语义信息,以提高搜索的召回率,那就可以采用 DocVectorModel 来额外召回一些文档。

这里需要考虑的是:是否要训练自己的word2vec模型?还是直接采用第三方提供的(开源的基于维基百科训练的)?在把文档index到ES中去时,将文档的"句向量"计算好,存储到Mapping字段中。查询时,可基于script_score来做二次评分(对搜索的响应时间的影响?),总之算是一个尝试吧。

以上是关于基于word2vec的文档向量模型的应用的主要内容,如果未能解决你的问题,请参考以下文章

基于pytorch实现word2vec

文本分类实战—— word2vec预训练词向量

如何构建词空间向量和文本向量化

词向量技术原理及应用详解

基于word2vec的中文词向量训练

[Algorithm & NLP] 文本深度表示模型——word2vec&doc2vec词向量模型