基於word2vec的文檔向量模型的應用

基於word2vec的文檔向量模型的應用

word2vec的原理以及訓練過程具體細節就不介紹了,推薦兩篇文檔:《word2vec parameter learning explained》、和《word2vec中的數學》。java

在《word2vec中的數學》中談到了訓練語言模型的一些方法:好比n-gram和神經網絡。在使用神經網絡訓練語言模型時獲得的"副產物",就是word2vec詞向量。基於神經網絡訓練語言模型有2種方案:cbow和skip-gram,它們是在這篇文章《A neural probabilistic language model》基礎上對訓練過程提出的改進方案。這裏簡單講一下cbow的訓練過程:git

訓練過程

  • 輸入層:將詞w的上下文的2c個詞的詞向量做爲輸入:\(v(context(w)_1),v(context(w)_2),...v(context(w)_{2c})\)github

    隨機初始化這2c個詞的詞向量算法

  • 投影層:將輸入層的2c 個詞向量累加求和網絡

    投影層對詞向量累加求和,這丟失了詞的順序信息。好比說:「我 愛 大家」 和「大家 愛 我」 這三個詞的詞向量累加求和獲得的詞向量是相同的。app

  • 輸出層:赫夫曼樹less

    基於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問題,有沒有其餘更好的處理方案?參考:HanLP github issue 上的一個疑問

獲得句子(文檔)的向量表示後,計算餘弦類似度,就能比較兩個句子了。

/**
     * 文檔類似度計算
     * @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來作二次評分(對搜索的響應時間的影響?),總之算是一個嘗試吧。

相關文章
相關標籤/搜索