利用 TensorFlow 入門 Word2Vec
我認為學習演算法的最好方法就是嘗試去實現它,因此這個教程我們就來學習如何利用 TensorFlow 來實現詞嵌入。
這篇文章我們不會去過多的介紹一些詞向量的內容,所以很多 king - man - woman - queue 的例子會被省去,直接進入編碼實踐過程。
我們如何設計這些詞嵌入?
對於如何設計詞嵌入有很多的技術,這裡我們討論一種非常有名的技術。與我們往常的認知不同,word2vec 並不是一個深層的網路,它只是一個三層的淺層網路。
注意:word2vec 有很多的技術細節,但是我們會跳過這些細節,來使得更加容易理解。
word2vec 如何工作?
word2vec 演算法的設計如下:
- 它是一個三層的網路(一個輸入層 + 一個隱藏層 + 一個輸出層)。
- 模型輸入一個詞,然後去預測它周圍的詞。
- 移除最後一層(輸出層),保留輸入層和隱藏層。
- 現在,輸入一個詞庫中的詞,然後隱藏層的輸出就是輸入詞的詞向量。
就是這麼簡單,這個三層網路就可以得到一個還不錯的詞向量。
接下來就讓我們來實現這個模型。完整的程式碼可以點選 Github,但我建議你先不要看完整的程式碼,先一步一步學習。
接下來,我們先定義我們要處理的原始文字:
import numpy as np
import tensorflow as tf
corpus_raw = 'He is the king . The king is royal . She is the royal queen '
# convert to lower case
corpus_raw = corpus_raw.lower()
現在,我們需要將輸入的原始文字資料轉換成一個輸入輸出對,以便我們對輸入的詞,可以去預測它附近的詞。比如,我們確定一箇中心詞, 視窗大小 window_size 設定為 n ,那麼我們就是去預測中心詞前面 n 個詞和後面 n 個詞。Chris McCormick 的這篇部落格給出了比較詳細的解釋。
注意:如果中心詞是在句子的開頭或者末尾,那麼我們就忽略視窗無法獲得的詞。
在做這個之前,我們需要建立一個字典,用來確定每個單詞的索引,具體如下:
words = []
for word in corpus_raw.split():
if word != '.': # because we don't want to treat . as a word
words.append(word)
words = set(words) # so that all duplicate words are removed
word2int = {}
int2word = {}
vocab_size = len(words) # gives the total number of unique words
for i,word in enumerate(words):
word2int[word] = i
int2word[i] = word
這個字典的執行結果如下:
print(word2int['queen'])
-> 42 (say)
print(int2word[42])
-> 'queen'
接下來,我們將我們的句子向量轉換成單詞列表,如下:
# raw sentences is a list of sentences.
raw_sentences = corpus_raw.split('.')
sentences = []
for sentence in raw_sentences:
sentences.append(sentence.split())
上面程式碼將幫助我們得到一個句子的列表,列表中的每一個元素是句子的單詞列表,如下:
print(sentences)
-> [['he', 'is', 'the', 'king'], ['the', 'king', 'is', 'royal'], ['she', 'is', 'the', 'royal', 'queen']]
接下來,我們要產生我們的訓練資料:
data = []
WINDOW_SIZE = 2
for sentence in sentences:
for word_index, word in enumerate(sentence):
for nb_word in sentence[max(word_index - WINDOW_SIZE, 0) : min(word_index + WINDOW_SIZE, len(sentence)) + 1] :
if nb_word != word:
data.append([word, nb_word])
這個程式給出了單詞輸入輸出對,我們將視窗的大小設定為 2。
print(data)
[['he', 'is'],
['he', 'the'],
['is', 'he'],
['is', 'the'],
['is', 'king'],
['the', 'he'],
['the', 'is'],
.
.
.
]
至此,我們有了我們的訓練資料,但是我們需要將它轉換成計算機可以理解的表示,即數字。也就是我們之前設計的 word2int 字典。
我們再進一步表示,將這些數字轉換成 0-1 向量。
i.e.,
say we have a vocabulary of 3 words : pen, pineapple, apple
where
word2int['pen'] -> 0 -> [1 0 0]
word2int['pineapple'] -> 1 -> [0 1 0]
word2int['apple'] -> 2 -> [0 0 1]
那麼為什麼要表示成 0-1 向量呢?這個問題我們後續討論。
# function to convert numbers to one hot vectors
def to_one_hot(data_point_index, vocab_size):
temp = np.zeros(vocab_size)
temp[data_point_index] = 1
return temp
x_train = [] # input word
y_train = [] # output word
for data_word in data:
x_train.append(to_one_hot(word2int[ data_word[0] ], vocab_size))
y_train.append(to_one_hot(word2int[ data_word[1] ], vocab_size))
# convert them to numpy arrays
x_train = np.asarray(x_train)
y_train = np.asarray(y_train)
現在,我們有了 x_train 和 y_train 資料:
print(x_train)
->
[[ 0. 0. 0. 0. 0. 0. 1.]
[ 0. 0. 0. 0. 0. 0. 1.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 1. 0. 0. 0.]
[ 0. 0. 0. 1. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 1. 0. 0. 0.]
[ 0. 0. 0. 1. 0. 0. 0.]
[ 0. 0. 0. 1. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 1. 0. 0. 0. 0. 0.]
[ 0. 1. 0. 0. 0. 0. 0.]
[ 0. 0. 1. 0. 0. 0. 0.]
[ 0. 0. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 0. 0. 0. 1. 0. 0.]
[ 0. 1. 0. 0. 0. 0. 0.]
[ 0. 1. 0. 0. 0. 0. 0.]
[ 0. 1. 0. 0. 0. 0. 0.]
[ 1. 0. 0. 0. 0. 0. 0.]
[ 1. 0. 0. 0. 0. 0. 0.]]
這兩個資料的維度如下:
print(x_train.shape, y_train.shape)
->
(34, 7) (34, 7)
# meaning 34 training points, where each point has 7 dimensions
構造 TensorFlow 模型
# making placeholders for x_train and y_train
x = tf.placeholder(tf.float32, shape=(None, vocab_size))
y_label = tf.placeholder(tf.float32, shape=(None, vocab_size))
從上圖中可以看出,我們將訓練資料轉換成了另一種向量表示。
EMBEDDING_DIM = 5 # you can choose your own number
W1 = tf.Variable(tf.random_normal([vocab_size, EMBEDDING_DIM]))
b1 = tf.Variable(tf.random_normal([EMBEDDING_DIM])) #bias
hidden_representation = tf.add(tf.matmul(x,W1), b1)
接下來,我們對隱藏層的資料進行處理,並且對其附近的詞進行預測。預測詞的方法我們採用 softmax 方法。
W2 = tf.Variable(tf.random_normal([EMBEDDING_DIM, vocab_size]))
b2 = tf.Variable(tf.random_normal([vocab_size]))
prediction = tf.nn.softmax(tf.add( tf.matmul(hidden_representation, W2), b2))
所以,完整的模型是:
input_one_hot ---> embedded repr. ---> predicted_neighbour_prob
predicted_prob will be compared against a one hot vector to correct it.
現在,我們可以訓練這個模型:
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init) #make sure you do this!
# define the loss function:
cross_entropy_loss = tf.reduce_mean(-tf.reduce_sum(y_label * tf.log(prediction), reduction_indices=[1]))
# define the training step:
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy_loss)
n_iters = 10000
# train for n_iter iterations
for _ in range(n_iters):
sess.run(train_step, feed_dict={x: x_train, y_label: y_train})
print('loss is : ', sess.run(cross_entropy_loss, feed_dict={x: x_train, y_label: y_train}))
在訓練的過程中,你在控制檯可以得到如下結果:
loss is : 2.73213
loss is : 2.30519
loss is : 2.11106
loss is : 1.9916
loss is : 1.90923
loss is : 1.84837
loss is : 1.80133
loss is : 1.76381
loss is : 1.73312
loss is : 1.70745
loss is : 1.68556
loss is : 1.66654
loss is : 1.64975
loss is : 1.63472
loss is : 1.62112
loss is : 1.6087
loss is : 1.59725
loss is : 1.58664
loss is : 1.57676
loss is : 1.56751
loss is : 1.55882
loss is : 1.55064
loss is : 1.54291
loss is : 1.53559
loss is : 1.52865
loss is : 1.52206
loss is : 1.51578
loss is : 1.50979
loss is : 1.50408
loss is : 1.49861
.
.
.
隨著損失值的不斷下降,最終會達到一個穩定值。即使我們無法獲得很精確的結果,但是我們也不在乎,因為我們感興趣的是 W1 和 b1 的值,即隱藏層的權重。
讓我們來看看這些權重,如下:
print(sess.run(W1))
print('----------')
print(sess.run(b1))
print('----------')
->
[[-0.85421133 1.70487809 0.481848 -0.40843448 -0.02236851]
[-0.47163373 0.34260952 -2.06743765 -1.43854153 -0.14699034]
[-1.06858993 -1.10739779 0.52600187 0.24079895 -0.46390489]
[ 0.84426647 0.16476244 -0.72731972 -0.31994426 -0.33553854]
[ 0.21508843 -1.21030915 -0.13006891 -0.24056002 -0.30445012]
[ 0.17842589 2.08979321 -0.34172744 -1.8842833 -1.14538431]
[ 1.61166084 -1.17404735 -0.26805425 0.74437028 -0.81183684]]
----------
[ 0.57727528 -0.83760375 0.19156453 -0.42394346 1.45631313]
----------
為什麼採用 0-1 向量?
當我們將一個 0-1 向量與 W1 相乘時,我們基本上可以將 W1 與 0-1 向量對應的那個 1 相乘的結果就是詞向量。也就是說, W1 就是一個數據查詢表。
在我們的程式中,我們也添加了一個偏置項 b1 ,所以我們也需要將它加上。
vectors = sess.run(W1 + b1)
# if you work it out, you will see that it has the same effect as running the node hidden representation
print(vectors)
->
[[-0.74829113 -0.48964909 0.54267412 2.34831429 -2.03110814]
[-0.92472583 -1.50792813 -1.61014366 -0.88273793 -2.12359881]
[-0.69424796 -1.67628145 3.07313657 -1.14802659 -1.2207377 ]
[-1.7077738 -0.60641652 2.25586247 1.34536338 -0.83848488]
[-0.10080346 -0.90931684 2.8825531 -0.58769202 -1.19922316]
[ 1.49428082 -2.55578995 2.01545811 0.31536022 1.52662396]
[-1.02735448 0.72176981 -0.03772151 -0.60208392 1.53156447]]
如果我們想得到 queen 的向量,我們可以用如下表示:
print(vectors[ word2int['queen'] ])
# say here word2int['queen'] is 2
->
[-0.69424796 -1.67628145 3.07313657 -1.14802659 -1.2207377 ]
那麼這些漂亮的向量有什麼用呢?
我們寫一個如何去查詢最相近向量的函式,當然這個寫法是非常簡單粗糙的。
def euclidean_dist(vec1, vec2):
return np.sqrt(np.sum((vec1-vec2)**2))
def find_closest(word_index, vectors):
min_dist = 10000 # to act like positive infinity
min_index = -1
query_vector = vectors[word_index]
for index, vector in enumerate(vectors):
if euclidean_dist(vector, query_vector) < min_dist and not np.array_equal(vector, query_vector):
min_dist = euclidean_dist(vector, query_vector)
min_index = index
return min_index
接下來,讓我們來測試一下單詞 king ,queen 和 royal 這些詞。
print(int2word[find_closest(word2int['king'], vectors)])
print(int2word[find_closest(word2int['queen'], vectors)])
print(int2word[find_closest(word2int['royal'], vectors)])
->
queen
king
he
我們可以得到如下有趣的結果。
king is closest to queen
queen is closest to king
royal is closest to he
第三個資料是我們根據大型語料庫得出來的(看起來還不錯)。語料庫的資料更大,我們得到的結果會更好。(注意:由於權重是隨機初始化的,所以我們可能會得到不同的結果,如果有需要,我們可以多執行幾次。)
讓我們來畫出這個向量相關圖。
首先,我們需要利用將為技術將維度從 5 減小到 2,所用的技術是:tSNE(teesnee!)
from sklearn.manifold import TSNE
model = TSNE(n_components=2, random_state=0)
np.set_printoptions(suppress=True)
vectors = model.fit_transform(vectors)
然後,我們需要對結果進行規範化,以便我們可以在 matplotlib 中更好的對它進行檢視。
from sklearn import preprocessing
normalizer = preprocessing.Normalizer()
vectors = normalizer.fit_transform(vectors, 'l2')
最後,我們將繪製出圖。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
for word in words:
print(word, vectors[word2int[word]][1])
ax.annotate(word, (vectors[word2int[word]][0],vectors[word2int[word]][1] ))
plt.show()
從圖中,我們可以看出。she
跟 queen
的距離非常接近,king
與 royal
的距離和 king
與 queen
的距離相同。如果我們有一個更大的語料庫,我們可以得到更加複雜的關係圖。
為什麼會發生這些?
我們給神經網路的任務是預測單詞的相鄰詞。但是我們還沒有具體的分析神經網路是如何預測的。因此,神經網路找出單詞的向量表示,用來幫助它預測相鄰詞這個任務。預測相鄰詞這本身不是一個有趣的任務,我們關心的是隱藏層的向量表示。
為了得到這些表示,神經網路使用了上下文資訊。在我們的語料庫中,king 和 royal 是作為相鄰詞出現的,queen 和 royal 也是作為相鄰詞出現的。
為什麼把預測相鄰詞作為一個任務?
其他的任務也可以用來訓練這個詞向量任務,比如利用 n-gram 就可以訓練出很好的詞向量!這裡有一篇部落格有詳細解釋。
那麼,我們為什麼還要使用相鄰詞預測作為任務呢?因為有一個比較著名的模型稱為 skip gram 模型。我們可以使用中間詞的相鄰單詞作為輸入,並要求神經網路去預測中間詞。這被稱為連續詞袋模型。
總結
- 詞向量是非常酷的一個工具。
- 不要在實際生產環境中使用這個 TensorFlow 程式碼,我們這裡只是為了理解才這樣寫。生產環境建議使用一些成熟的工具包,比如 gensim
我希望這個簡單教程可以幫助到一些人,可以更加深刻的理解什麼是詞向量。
CoderPai 是一個專注於演算法實戰的平臺,從基礎的演算法到人工智慧演算法都有設計。如果你對演算法實戰感興趣,請快快關注我們吧。加入AI實戰微信群,AI實戰QQ群,ACM演算法微信群,ACM演算法QQ群。長按或者掃描如下二維碼,關注 “CoderPai” 微訊號(coderpai)
相關推薦
利用 TensorFlow 入門 Word2Vec
我認為學習演算法的最好方法就是嘗試去實現它,因此這個教程我們就來學習如何利用 TensorFlow 來實現詞嵌入。 這篇文章我們不會去過多的介紹一些詞向量的內容,所以很多 king - man - woman - queue 的例子會被省去,直接進
利用Tensorflow進行自然語言處理(NLP)系列之二高階Word2Vec
一、概述 在上一篇中,我們介紹了Word2Vec即詞向量,對於Word Embeddings即詞嵌入有了些基礎,同時也闡述了Word2Vec演算法的兩個常見模型 :Skip-Gram模型和CBOW模型,本篇會對兩種演算法做出比較分析並給出其擴充套件模型-GloVe模型。
利用Tensorflow實現神經網絡模型
flow one 什麽 hold test ase tensor dom def 首先看一下神經網絡模型,一個比較簡單的兩層神經。 代碼如下: # 定義參數 n_hidden_1 = 256 #第一層神經元 n_hidden_2 = 128 #第
tensorflow實現Word2vec
while brush ber ear same split max ems red # coding: utf-8 ‘‘‘ Note: Step 3 is missing. That‘s why I left it. ‘‘‘ from __future__ impor
TensorFlow入門:mac 安裝 TensorFlow
sse ssi 來安 pan lan bin pat ont world 開發環境: mac os 10.12.5 Python 2.7.10 GCC 4.2.1 mac默認是不帶pip的,安裝pip。 sudo easy_install pip 1.安裝vir
TensorFlow入門:安裝常用的依賴模塊
包含 librosa 任務 nltk plot orf 入門 learn sci TensorFlow運行中常用到一些Python第三方模塊: numpy 存儲和處理大型矩陣的科學計算包 maplotlib 最著名的繪圖庫 jupyter scikit-image 圖像預
TensorFlow入門
imp 我們 class rank node strong ima orf 運行 Tensor(張量)是TensorFlow中最核心的數據結構單元,ta它可以表示任意維數的數組。wei‘du維度用rank(秩)表示。 例如: 3
TensorFlow文檔翻譯-01-TensorFlow入門
left https 你是 但是 sam return 很多 等級 license TensorFlow入門 這是關於如何開始tensorFlow的指南。開始之前,你需要先安裝TensorFlow。除此之外,你應該了解: 知道如何使用Python編程。 懂一點點數組 如
【tensorflow:Google】三、tensorflow入門
als 管理 神經網絡 等價 問題 sign ria init 節點 【一】計算圖模型 節點是計算,邊是數據流, a = tf.constant( [1., 2.] )定義的是節點,節點有屬性 a.graph 取得默認計算圖 g1 = tf.get_default_gr
利用Tensorflow實現手寫字符識別
status ade 模式 數學 malloc interact tutorials x模型 項目 模式識別領域應用機器學習的場景非常多,手寫識別就是其中一種,最簡單的數字識別是一個多類分類問題,我們借這個多類分類問題來介紹一下google最新開源的tensorflow框架
tensorflow入門 (一)
統一 .sh 函數 soft acf layers 估計 一個地方 aid 轉載:作者:地球的外星人君鏈接:https://www.zhihu.com/question/49909565/answer/207609620來源:知乎著作權歸作者所有。商業轉載請聯系作者獲得授權
轉:TensorFlow入門(六) 雙端 LSTM 實現序列標註(分詞)
vsm max poc 代碼 單詞 arch 大致 雙端 fun http://blog.csdn.net/Jerr__y/article/details/70471066 歡迎轉載,但請務必註明原文出處及作者信息。 @author: huangyongye @creat_
TensorFlow入門必讀教程,拿走不謝!
活性 一起 操作系統 得到 haskell 開源 ask 服務 好的 TensorFlow 是一個開源的深度學習框架,於 2015 年末發布後,它成為了在全球得到最廣泛采用的深度學習框架之一。 深度學習神經網絡通常包含許多層。它們使用多維數組在不同層之間傳輸數據或執行操作。
TensorFlow入門筆記(一)基本操作
result 官方教程 with orf print blog res ont constant 0. 環境配置 安裝Anaconda,python3環境,然後利用conda命令配置的tensorflow環境。 參考極客學院翻譯TensorFlow官方教程:http://w
TensorFlow 入門
測試 art auto eight model img blog 選擇 edi 一、初識Tensorflow 編譯Tensorflow lite tflitecamerademo 安裝Tensorflow 通過下面鏈接安裝 http://www.tensorfly.
TensorFlow入門測試程序
ini closed ict dict clas pla 入門 ntop pos 1 import tensorflow as tf 2 from tensorflow.examples.tutorials.mnist import input_data 3
tensorflow入門——3解決問題——4讓我們開始吧
因此 海量 tensor flow 改變 80年 解決 識別 學習 深度學習適合解決海量數據和復雜問題 在機器學習中,語音識別,圖像識別,語意識別用的是不同的技術,從事相關工作的人合作幾乎不可能。 深度學習改變了這一切。 80年代計算機很慢,數據集很小,因此深度學習沒有得到
TensorFlow入門——hello
ESS constant TE 報錯 結果 port In 成功 說了 上一節說了TensorFlow的安裝,這一節說一下測試的問題 新建一個Python文件,輸入 1 import tensorflow as tf 2 hello = tf .constant (’He
TensorFlow入門——安裝(帶GPU)
incr per 下載地址 變量 環境 warning ice mman sign 這一系列基本上是屬於我自己進行到了那個步驟就做到那個步驟的 由於新裝了GPU (GTX750ti)和CUDA9.0、CUDNN7.1版本的軟件,所以希望TensorFlow能在GPU上運行,
知乎TensorFlow入門學習記錄
nbsp 網絡 lan ID span tar orf 形參 sta 知乎地址:https://zhuanlan.zhihu.com/p/30487008 import tensorflow as tf a=tf.placeholder(tf.int16) # 接受