這兩天在看 word2vec 的源碼,發現其損失函數不是 多元交叉熵,而是 NCE,於是查了下資料,看到了這篇博文,分享一下。
❞先看看tensorflow的nce-loss的API:
def nce_loss(weights, biases, inputs, labels, num_sampled, num_classes,
num_true=1,
sampled_values=None,
remove_accidental_hits=False,
partition_strategy="mod",
name="nce_loss")假設nce_loss之前的輸入數據是K維的,一共有N個類,那麼
inputs.shape = (batch_size, K)labels.shape = (batch_size, num_true)sampled_values: 採樣出的負樣本,如果是None,就會用不同的sampler去採樣。待會兒說sampler是什麼。remove_accidental_hits: 如果採樣時不小心採樣到的負樣本剛好是正樣本,要不要幹掉partition_strategy:對weights進行embedding_lookup時並行查表時的策略。TF的embeding_lookup是在CPU裡實現的,這裡需要考慮多線程查表時的鎖的問題。nce_loss的實現邏輯如下:
_compute_sampled_logits: 通過這個函數計算出正樣本和採樣出的負樣本對應的output和labelsigmoid_cross_entropy_with_logits: 通過 sigmoid cross entropy來計算output和label的loss,從而進行反向傳播。這個函數把最後的問題轉化為了num_sampled+num_real個兩類分類問題,然後每個分類問題用了交叉熵的損傷函數,也就是logistic regression常用的損失函數。TF裡還提供了一個softmax_cross_entropy_with_logits的函數,和這個有所區別。再來看看TF裡word2vec的實現,他用到nce_loss的代碼如下:
loss = tf.reduce_mean(
tf.nn.nce_loss(nce_weights, nce_biases, embed, train_labels,
num_sampled, vocabulary_size))可以看到,它這裡並沒有傳sampled_values,那麼它的負樣本是怎麼得到的呢?繼續看nce_loss的實現,可以看到裡面處理sampled_values=None的代碼如下:
if sampled_values is None:
sampled_values = candidate_sampling_ops.log_uniform_candidate_sampler(
true_classes=labels,
num_true=num_true,
num_sampled=num_sampled,
unique=True,
range_max=num_classes)所以,默認情況下,他會用log_uniform_candidate_sampler去採樣。那麼log_uniform_candidate_sampler是怎麼採樣的呢?他的實現在這裡:
他會在[0, range_max)中採樣出一個整數kP(k) = (log(k + 2) - log(k + 1)) / log(range_max + 1)可以看到,k越大,被採樣到的概率越小。那麼在TF的word2vec裡,類別的編號有什麼含義嗎?看下面的代碼:
def build_dataset(words):
count = [['UNK', -1]]
count.extend(collections.Counter(words).most_common(vocabulary_size - 1))
dictionary = dict()
for word, _ in count:
dictionary[word] = len(dictionary)
data = list()
unk_count = 0
for word in words:
if word in dictionary:
index = dictionary[word]
else:
index = 0 # dictionary['UNK']
unk_count += 1
data.append(index)
count[0][1] = unk_count
reverse_dictionary = dict(zip(dictionary.values(), dictionary.keys()))
return data, count, dictionary, reverse_dictionary可以看到,TF的word2vec實現裡,詞頻越大,詞的類別編號也就越大。因此,在TF的word2vec裡,負採樣的過程其實就是優先採詞頻高的詞作為負樣本。
在提出負採樣的原始論文中, 包括word2vec的原始C++實現中。是按照熱門度的0.75次方採樣的,這個和TF的實現有所區別。但大概的意思差不多,就是越熱門,越有可能成為負樣本。
連結:https://www.jianshu.com/p/fab82fa53e16下載1:四件套
在機器學習算法與自然語言處理公眾號後臺回復「四件套」,
即可獲取學習TensorFlow,Pytorch,機器學習,深度學習四件套!
下載2:倉庫地址共享
在機器學習算法與自然語言處理公眾號後臺回復「代碼」,
即可獲取195篇NAACL+295篇ACL2019有代碼開源的論文。開源地址如下:https://github.com/yizhen20133868/NLP-Conferences-Code
重磅!機器學習算法與自然語言處理交流群已正式成立!
群內有大量資源,歡迎大家進群學習!
額外贈送福利資源!深度學習與神經網絡,pytorch官方中文教程,利用Python進行數據分析,機器學習學習筆記,pandas官方文檔中文版,effective java(中文版)等20項福利資源
獲取方式:進入群後點開群公告即可領取下載連結
注意:請大家添加時修改備註為 [學校/公司 + 姓名 + 方向]
例如 —— 哈工大+張三+對話系統。
號主,微商請自覺繞道。謝謝!
推薦閱讀:
工業界求解NER問題的12條黃金法則
三步搞定機器學習核心:矩陣求導
神經網絡中的蒸餾技術,從Softmax開始說起