天天看點

Doc2vec1、Doc2vec的算法原理2、在推薦系統中的應用啟發3、Doc2vec的算法實作

Doc2vec是Mikolov2014年提出的論文,也被成為Paragraph Vector,下面的内容分為三方面進行介紹,分别為:

  • Doc2vec的原理
  • Doc2vec在推薦系統中的應用啟發
  • Doc2vec的算法實作

1、Doc2vec的算法原理

如何學習得到Word的Vector表示

一個非常流行的學習Word Vector的方法如下圖所示:

Doc2vec1、Doc2vec的算法原理2、在推薦系統中的應用啟發3、Doc2vec的算法實作
Doc2vec1、Doc2vec的算法原理2、在推薦系統中的應用啟發3、Doc2vec的算法實作

Doc2vec的兩種算法

Doc2vec其實包含了兩種算法:

  • PV-DM(Distributed Memory Model of Paragraph Vector)
  • PV-DBOW(Distributed Bag of Words version of Paragraph Vector)

PV-DM 」

PV-DM類似于Word2vec中的CBOW模型,其結構圖如下所示:

Doc2vec1、Doc2vec的算法原理2、在推薦系統中的應用啟發3、Doc2vec的算法實作

PV-DM

和上面的圖中差別是,增加了段落的vector,即 函數  利用了矩陣 和中的向量,矩陣 表示的段落向量矩陣, 表示的是word的向量矩陣。

Paragraph vector在這裡扮演的是一個記憶的角色,是以為在詞袋模型中,每次訓練隻會截取段落的一小部分進行訓練,而忽略本次訓練之外的單詞,這樣僅僅訓練出來每個詞的向量表達,段落隻是每個詞的向量累加在一起表達的,這裡使用Paragraph vector可以在一定程度上彌補詞袋模型的缺陷。

PV-DM模型的輸入是固定長度的,其從段落的上下文的滑動視窗中進行采樣,這一點和Word2vec是一緻的,在基于同一段落構造好的樣本中, 段落的向量是共享的,但是在基于不同段落構造好的樣本中,段落的向量是不共享的。在所有的樣本中,word的向量是一緻的(共享的)。

在整個訓練過程中,paragraph vector能夠記憶整個句子的意義,word vector則能夠基于全局部分學習到其具體的含義。

PV-DBOW」

PV-DBOW類似于Word2vec中的Skip-gram模型,其結構圖如下所示:

Doc2vec1、Doc2vec的算法原理2、在推薦系統中的應用啟發3、Doc2vec的算法實作

PV-DBOW

和PV-DM不同的是,這裡使用的是段落的向量來預測單詞。

如何預測新句子的vector」

模型完成訓練之後,可以得到段落的向量、word的向量和相關的參數,對于需要預測段落,會将paragram vecotr進行随機的初始化,放入模型中再重新根據随機梯度下降不斷疊代求得最終穩定下來的段落向量。

不過在預測過程中,模型裡的詞向量、投影層到輸出層的softmax weights參數是不會變的,這樣在不斷疊代中隻會更新Paragraph vector,其他參數均已固定,隻需很少的時間就能計算出帶預測的Paragraph vector。

實驗中注意的點

  • word vector之間的聚合使用的是連接配接
  • window size 設定值為8
  • vector size 設定的是400
  • 論文中進行實驗使用的是PV-DM和PV-DBOW向量連接配接

2、在推薦系統中的應用啟發

結合不同模型的vector

之前在别的文章中也看到過說 使用不同模型産出的vector,比如針對word2vec中CBOW和Skip-gram模型,産出兩套vector,在使用時,可以進行求平均或者進行連接配接。

同樣在這篇論文中,作者也給出了拼接方式的效果驗證,效果是要優于單獨使用一種的。

Doc2vec遷移到 User2vec

将NLP相關的知識應用在推薦系統中本身已經司空見慣了,但是我們可以轉變一種思路,将這種思想遷移到user-item上,比如針對使用者的點選序列,可以了解為段落裡邊的一個個word,使用者本身可以了解為段落,通過這種方式便可以構造出user和item的向量,因為其是在一個向量空間下的,可以直接通過餘弦相似度進行user到items的召回

vector表示用作他用

針對産出的word或者doc vector,可以将其使用者分類、聚類其中的特征,這一點可以參考Item2vec内容介紹中的相關内容。

3、Doc2vec的算法實作

這裡使用gensim的中的Doc2vec,具體示範代碼為:

import gensim
import os
from collections import defaultdict, Counter

print("gensim version is: {}".format(gensim.__version__))

# 資料集介紹:使用資料為新聞廣播資料,來自于澳洲新聞廣播選擇的314個文檔
test_data_dir = os.path.join(gensim.__path__[0], "test", "test_data")
lee_train_file = os.path.join(test_data_dir, "lee_background.cor")
lee_test_file = os.path.join(test_data_dir, "lee.cor")

# 定義函數,讀取資料
import smart_open
def read_corpus(fname, tokens_only=False):
    with smart_open.open(fname, encoding="iso-8859-1") as f:
        for i, line in enumerate(f):
            tokens = gensim.utils.simple_preprocess(line)
            if tokens_only:
                yield tokens
            else:
                yield gensim.models.doc2vec.TaggedDocument(tokens,[i])

train_corpus = list(read_corpus(lee_train_file))
# print("train_corpus: \n {}".format(train_corpus[:1]))
test_corpus = list(read_corpus(lee_test_file, tokens_only=True))
# print("test corpus: \n {}".format(test_corpus[:1]))

# 建立模型并進行模型訓練
model = gensim.models.doc2vec.Doc2Vec(vector_size = 50, min_count = 2, epochs=40)
model.build_vocab(train_corpus)
model.train(documents=train_corpus, total_examples=model.corpus_count, epochs=model.epochs)

# 輸出每個文檔的向量 model.docvecs[id]
doc_vector_dict = defaultdict(list)
for one in train_corpus:
    doc_vector_dict[one.tags[0]] = model.docvecs[one.tags[0]]
# print(doc_vector_dict)

# 計算每個文檔最相似的文檔 model.docvecs.most_similar
for doc_id, doc_vector in doc_vector_dict.items():
    sim_docs = model.docvecs.most_similar([doc_vector], topn=10)
    # print(sim_docs)

# 推斷新文檔的向量 model.infer_vector
print(train_corpus[0].words)
infer_vector = model.infer_vector(train_corpus[0].words)
print(infer_vector)

# 根據自相似性進行模型的效果評判,假設文檔都是新文檔,推斷每個文檔的向量,并計算其與所有文檔的相似度,看本身的相似度排名
ranks = list()
for doc_id, doc_vector in doc_vector_dict.items():
    sim_docs = model.docvecs.most_similar([doc_vector], topn=len(model.docvecs))
    sim_docs_rank = [_id for _id, sim in sim_docs].index(doc_id)
    ranks.append(sim_docs_rank)

print(ranks)
counter = Counter(ranks)
print(counter)

# 模型儲存
model.save("files/doc2vec.model")
# 模型加載
gensim.models.doc2vec.Doc2Vec.load("files/doc2vec.model")
           

繼續閱讀