學習word2vec的skip-gram實現,除了skip-gram模型還有CBOW模型。 Skip-gram模式是根據中間詞,預測先後詞,CBOW模型恰好相反,根據先後的詞,預測中間詞。python
那麼什麼是中間詞呢?什麼樣的詞才叫作先後詞呢?git
首先,咱們須要定義一個窗口大小,在窗口裏面的詞,咱們纔有中間詞和先後詞的定義。通常這個窗口大小在5-10之間。 舉個例子,咱們設置窗口大小(window size)爲2:github
|The|quick|brown|fox|jump|
複製代碼
那麼,brown
就是咱們的中間詞,The
、quick
、fox
、jump
就是先後詞。算法
咱們知道,word2vec實際上就是一個神經網絡(後面會解釋),那麼這樣的數據,咱們是以什麼樣的格式用來訓練的呢? 看一張圖,你就明白了:bash
能夠看到,咱們老是以中間詞放在第一個位置,而後跟着咱們的先後相鄰詞。能夠看到,每一對詞都是一個輸入和一個輸出組成的數據對(X,Y)。其中,X是feature,Y是label。網絡
因此,咱們訓練模型以前,須要根據語料,整理出全部的像上面這樣的輸入數據用來訓練。dom
word2vec是一個簡單的神經網絡,有如下幾個層組成:函數
輸入層輸入的就是上面咱們說的數據對的數字表示,輸出到隱藏層。 隱藏層的神經網絡單元的數量,其實就是咱們所說的embedding size,只有爲何,咱們後面簡單計算一下就知道。須要注意的是,咱們的隱藏層後面不須要使用激活函數。 輸出層,咱們使用softmax操做,獲得每個預測結果的機率。學習
這裏有一張圖,可以表示這個網絡: 優化
如今問題來了,剛剛咱們說,輸入層的輸入是咱們以前準備的數據對的數字表示,那麼咱們該如何用數字表示文本數據呢?
好像隨便一種方式均可以用來表示咱們的文本啊。
看上圖,咱們發現,它的輸入使用的是one-hot編碼。什麼是ont-hot編碼呢?如圖所示,假設有n個詞,則每個詞能夠用一個n維的向量來表示,這個n維向量只有一個位置是1,其他位置都是0。
那麼爲何要用這樣的編碼來表示呢?答案後面揭曉。
隱藏層的神經單元數量,表明着每個詞用向量表示的維度大小。假設咱們的hidden_size取300,也就是咱們的隱藏層有300個神經元,那麼對於每個詞,咱們的向量表示就是一個的向量。 有多少個詞,就有多少個這樣的向量!
因此對於輸入層和隱藏層之間的權值矩陣,它的形狀應該是[vocab_size, hidden_size]
的矩陣,
那麼咱們的輸出層,應該是什麼樣子的呢?從上面的圖上能夠看出來,輸出層是一個[vocab_size]
大小的向量,每個值表明着輸出一個詞的機率。
爲何要這樣輸出?由於咱們想要知道,對於一個輸入詞,它接下來的詞最有可能的若干個詞是哪些,換句話說,咱們須要知道它接下來的詞的機率分佈。
你能夠再看一看上面那張網絡結構圖。
你會看到一個很常見的函數softmax,爲何是softmax而不是其餘函數呢?不妨先看一下softmax函數長啥樣:
很顯然,它的取值範圍在(0,1),並別全部的值和爲1。這不就是自然的機率表示嗎?
固然,softmax還有一個性質,由於它函數指數操做,若是損失函數使用對數函數,那麼能夠抵消掉指數計算。
關於更多的softmax,請看斯坦福Softmax Regression
至此,咱們已經知道了整個神經網絡的結構,那麼咱們應該怎麼用數學表示出來呢?
回顧一下咱們的結構圖,很顯然,三個層之間會有兩個權值矩陣,同時,兩個偏置項。因此咱們的整個網絡的構建,能夠用下面的僞代碼:
import tensorflow as tf
# 假設vocab_size = 1000
VOCAB_SIZE = 1000
# 假設embedding_size = 300
EMBEDDINGS_SIZE = 300
# 輸入單詞x是一個[1,vocab_size]大小的矩陣。固然實際上咱們通常會用一批單詞做爲輸入,那麼就是[N, vocab_size]的矩陣了
x = tf.placeholder(tf.float32, shape=(1,VOCAB_SIZE))
# W1是一個[vocab_size, embedding_size]大小的矩陣
W1 = tf.Variable(tf.random_normal([VOCAB_SIZE, EMBEDDING_SIZE]))
# b1是一個[1,embedding_size]大小的矩陣
b1 = tf.Variable(tf.random_normal([EMBEDDING_SIZE]))
# 簡單的矩陣乘法和加法
hidden = tf.add(tf.mutmul(x,W1),b1)
W2 = tf.Variable(tf.random_normal([EMBEDDING_SIZE,VOCAB_SIZE]))
b2 = tf.Variable(tf.random_normal([VOCAB_SIZE]))
# 輸出是一個vocab_size大小的矩陣,每一個值都是一個詞的機率值
prediction = tf.nn.softmax(tf.add(tf.mutmul(hidden,w2),b2))
複製代碼
網絡定義好了,咱們須要選一個損失函數來使用梯度降低算法優化模型。
咱們的輸出層,實際上就是一個softmax分類器。因此按照常規套路,損失函數就選擇交叉熵損失函數。
哈哈,還記得交叉熵是啥嗎?
p,q是真是機率分佈和估計機率分佈。
# 損失函數 
cross_entropy_loss = tf.reduce_mean(-tf.reduce_sum(y_label * tf.log(prediction), reduction_indices=[1]))
# 訓練操做
train_op = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy_loss)
複製代碼
接下來,就能夠準備號數據,開始訓練啦!
咱們知道word2vec訓練後會獲得一個權值矩陣W1(暫時忽略b1),這個矩陣就是咱們的全部詞的向量表示啦!這個矩陣的每一行,就是一個詞的矢量表示。若是兩個矩陣相乘...
看到了嗎?ont-hot編碼的特色,在矩陣相乘的時候,就是選取出矩陣中的某一行,而這一行就是咱們輸入這個詞語的word2vec表示!。
怎麼樣?是否是很妙?
由此,咱們能夠看出來,所謂的word2vec,實際上就是一個查找表,是一個二維的浮點數矩陣!
以上是word2vec的skip-gram模型的完整分析,怎麼樣,是否是弄清楚了word2vec的原理和細節?
完整代碼請查看luozhouyang/word2vec
Email: stupidme.me.lzy@gmail.com
WeChat: luozhouyang0528
我的公衆號,你可能會感興趣: