萬物皆可Embedding系列會結合論文和實踐經驗進行介紹,前期主要集中在論文中,后期會加入實踐經驗和案例,目前已更新:
- 萬物皆可Vector之語言模型:從N-Gram到NNLM、RNNLM
- 萬物皆可Vector之Word2vec:2個模型、2個優化及實戰使用
- Item2vec中值得細細品味的8個經典tricks和thinks
- Doc2vec的演算法原理、代碼實作及應用啟發
后續會持續更新Embedding相關的文章,歡迎持續關注「搜索與推薦Wiki」
Doc2vec是Mikolov2014年提出的論文,也被成為Paragraph Vector,下面的內容分為三方面進行介紹,分別為:
- Doc2vec的原理
- Doc2vec在推薦系統中的應用啟發
- Doc2vec的演算法實作
1、Doc2vec的演算法原理
a)如何學習得到Word的Vector表示
一個非常流行的學習Word Vector的方法如下圖所示:

在上圖中,每個Word都被映射成一個唯一的vector編碼,其組合成了矩陣
W
W
W, 其中每串列示的就是一個Word,對于給定的序列單詞
w
1
,
w
2
,
.
.
.
,
w
T
w_1, w_2, ..., w_T
w1?,w2?,...,wT?,得到word vector的目標函式是最大化平均概率:
1
T
∑
t
=
k
T
?
k
l
o
g
?
p
(
w
t
∣
w
t
?
k
,
.
.
.
,
w
t
+
k
)
\frac{1}{T} \sum_{t=k}^{T-k} log \, p(w_t|w_{t-k},..., w_{t+k})
T1?t=k∑T?k?logp(wt?∣wt?k?,...,wt+k?)
預測任務通常是通過多分類(比如:
s
o
f
t
m
a
x
softmax
softmax)完成的,因此可得:
p
(
w
t
∣
w
t
?
k
,
.
.
.
,
w
t
+
k
)
=
e
y
w
t
∑
i
e
y
i
p(w_t|w_{t-k},..., w_{t+k}) = \frac{e^{y_{wt}}}{ \sum_{i} e^{y_i}}
p(wt?∣wt?k?,...,wt+k?)=∑i?eyi?eywt??
其中
y
i
y_i
yi? 表示第
i
i
i個輸出的word未歸一化的
l
o
g
log
log概率值,為:
y
=
b
+
U
h
(
w
t
?
k
,
.
.
.
,
w
t
+
k
;
W
)
y = b+ Uh(w_{t-k}, ... , w_{t+k}; W)
y=b+Uh(wt?k?,...,wt+k?;W)
其中
U
,
b
U,b
U,b 表示的是
s
o
f
t
m
a
x
softmax
softmax 引數,
h
h
h 表示的是矩陣
W
W
W 中word vector的連接方式(平均或者連接),
論文中提出,求解word、paragraph vector使用的是hierarical softmax,和word2vec中的優化方法一致,這樣可以很大程度上在丟失少量精確度的情況下,加快模型的訓練速度
b)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模型,其結構圖如下所示:

和上面的圖中區別是,增加了段落的vector,即 函式 h h h 利用了矩陣 W W W 和 D D D中的向量,矩陣 D D D 表示的段落向量矩陣, W W W 表示的是word的向量矩陣,
Paragraph vector在這里扮演的是一個記憶的角色,因此為在詞袋模型中,每次訓練只會截取段落的一小部分進行訓練,而忽略本次訓練之外的單詞,這樣僅僅訓練出來每個詞的向量表達,段落只是每個詞的向量累加在一起表達的,這里使用Paragraph vector可以在一定程度上彌補詞袋模型的缺陷,
PV-DM模型的輸入是固定長度的,其從段落的背景關系的滑動視窗中進行采樣,這一點和Word2vec是一致的,在基于同一段落構造好的樣本中, 段落的向量是共享的,但是在基于不同段落構造好的樣本中,段落的向量是不共享的,在所有的樣本中,word的向量是一致的(共享的),
在整個訓練程序中,paragraph vector能夠記憶整個句子的意義,word vector則能夠基于全域部分學習到其具體的含義,
PV-DBOW」
PV-DBOW類似于Word2vec中的Skip-gram模型,其結構圖如下所示:

和PV-DM不同的是,這里使用的是段落的向量來預測單詞,
如何預測新句子的vector」
模型完成訓練之后,可以得到段落的向量、word的向量和相關的引數,對于需要預測段落,會將paragram vecotr進行隨機的初始化,放入模型中再重新根據隨機梯度下降不斷迭代求得最終穩定下來的段落向量,
不過在預測程序中,模型里的詞向量、投影層到輸出層的softmax weights引數是不會變的,這樣在不斷迭代中只會更新Paragraph vector,其他引數均已固定,只需很少的時間就能計算出帶預測的Paragraph vector,
c)實驗中注意的點
- word vector之間的聚合使用的是連接
- window size 設定值為8
- vector size 設定的是400
- 論文中進行實驗使用的是PV-DM和PV-DBOW向量連接
2、Doc2vec在推薦系統中的應用啟發
a)結合不同模型的vector
之前在別的文章中也看到過說 使用不同模型產出的vector,比如針對word2vec中CBOW和Skip-gram模型,產出兩套vector,在使用時,可以進行求平均或者進行連接,
同樣在這篇論文中,作者也給出了拼接方式的效果驗證,效果是要優于單獨使用一種的,
b)Doc2vec遷移到 User2vec
將NLP相關的知識應用在推薦系統中本身已經司空見慣了,但是我們可以轉變一種思路,將這種思想遷移到user-item上,比如針對用戶的點擊序列,可以理解為段落里邊的一個個word,用戶本身可以理解為段落,通過這種方式便可以構造出user和item的向量,因為其是在一個向量空間下的,可以直接通過余弦相似度進行user到items的召回
c)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")
掃一掃 關注微信公眾號!號主 專注于搜索和推薦系統,嘗試使用演算法去更好的服務于用戶,包括但不局限于機器學習,深度學習,強化學習,自然語言理解,知識圖譜,還不定時分享技術,資料,思考等文章!
CSDN認證博客專家
圖書作者
推薦系統研究者
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/238488.html
標籤:AI
