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)。注意幾個訓練參數:工具
訓練完成後,詞庫中每一個詞,都對應着一個相同維度的float數值向量。計算兩個詞的類似度,就是計算兩個詞所對應的數值向量夾角的餘弦。優化
在實際應用場景中,用戶輸入並非一個個的詞,而是句子(若干個詞)。好比一個用戶資料下的我的說明,就是一句自我介紹的話;用戶的一段評論,也是一句話…
若是要計算兩個句子的類似度,那怎麼辦呢?這個須要根據實際需求場景了。好比對句子進行關鍵詞提取,採用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來作二次評分(對搜索的響應時間的影響?),總之算是一個嘗試吧。