word2vec之Skip-Gram模型的tensorflow實現

gensim裏內置了word2vec模型,訓練和使用都很方便。但word2vec自己這個模型的設計是很精妙的,本身從頭使用tensorflow實現一遍頗有意義。python

http://mattmahoney.net/dc/text8.zip
python能夠直接讀zip文件,裏邊是一個命名爲text8的文件,約100M,總共就一行,以
空格分詞
from aipack.datasets import text8
words = text8.load_text8_dataset()#就是詞列表,約1700W
data_size = len(words)
print(data_size)  # 17005207
print(words[0:10])  # ['anarchism', 'originated', 'as', 'a', 'term', 'of', 'abuse', 'first', 'used', 'against']

data, count, dictionary, reverse_dictionary = build_words_dataset(words, vocabulary_size=50000)
#下標,詞頻dict,詞序dict,序對詞didct
print('Most 5 common words (+UNK)', count[:5])
print('Sample data', data[:10], [reverse_dictionary[i] for i in data[:10]])

讀進來的text8約有1700W個詞,排重後獲得25W+個詞,咱們只保留50000個高頻的,其他用UNK代替。數組

build_words_dataset返回:data:詞的下標list,count:{詞:詞頻},dictionary:{詞:詞下標},reverse_dictionary:{詞下標:詞}函數

有了原始的數據集,那就能夠開始建模。ui

Word2Vec模型中,主要有Skip-Gram和CBOW兩種模型,從直觀上理解,Skip-Gram是給定input word來預測上下文。而CBOW是給定上下文,來預測input word,以下圖:人工智能

 

batch, labels, data_index = generate_skip_gram_batch(data=data,batch_size=8,num_skips=4,skip_window=2,data_index=0)

data就是以前取出來的word_list的下標數組,每批取的pair數batch_size=8,num_skip=4是以這個詞爲中心,取對的次數.net

skip_window=2,是以當前詞爲中心,先後兩個詞(往前看包含當前詞自己)。設計

下面是建模,官方示例損失函數用到了以下這個:orm

def nce_loss(vocab_size,embedding_size,embed,train_labels,num_sampled):
    # 模型內部參數矩陣,初始爲截斷正太分佈
    nce_weight = tf.Variable(tf.truncated_normal([vocab_size, embedding_size],
                                                      stddev=1.0 / math.sqrt(embedding_size)))
    nce_biases = tf.Variable(tf.zeros([vocab_size]))

    # 獲得NCE損失(負採樣獲得的損失)
    loss = tf.nn.nce_loss(
        weights=nce_weight,  # 權重
        biases=nce_biases,  # 誤差
        labels=train_labels,  # 輸入的標籤
        inputs=embed,  # 輸入向量
        num_sampled=num_sampled,  # 負採樣的個數
        num_classes=vocab_size  # 類別數目
    )
    print(loss)
    nce_loss = tf.reduce_mean(loss)
    return nce_loss

輸入N*embedding_size的詞嵌入以後的向量,與input_labels=[N,1]之間的loss。按常規狀況,input_labels用one_hot得擴展成[N,vocab_size]維,但vocab_size-1維都是負樣本。這樣使用負採樣,主要是減小計算量爲[N,64]。ip

後面的訓練就是正常輸入數據,反向傳播,迭代了。input

在迭代25W輪以後,看下類似度,仍是不錯的:

從直觀的視角,還原一下skip-gram的原理:

1,每批選擇N個字的下標,對應的指望輸出是這N個字周圍的字(下標)。

2,對輸入進行embedding,獲得[N,embedding_size]的矩陣。

3,對這個embdding的結果,與指望輸出[N,1]計算負採樣損失。

 

關於做者:魏佳斌,互聯網產品/技術總監,北京大學光華管理學院(MBA),特許金融分析師(CFA),資深產品經理/碼農。偏心python,深度關注互聯網趨勢,人工智能,AI金融量化。致力於使用最前沿的認知技術去理解這個複雜的世界。

掃描下方二維碼,關注:AI量化實驗室(ailabx),瞭解AI量化最前沿技術、資訊。

相關文章
相關標籤/搜索