成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

利用 TensorFlow 入門 Word2Vec

yunhao / 2154人閱讀

摘要:那么為什么要表示成向量呢這個(gè)問(wèn)題我們后續(xù)討論。所以,完整的模型是現(xiàn)在,我們可以訓(xùn)練這個(gè)模型在訓(xùn)練的過(guò)程中,你在控制臺(tái)可以得到如下結(jié)果隨著損失值的不斷下降,最終會(huì)達(dá)到一個(gè)穩(wěn)定值。為了得到這些表示,神經(jīng)網(wǎng)絡(luò)使用了上下文信息。

作者:chen_h
微信號(hào) & QQ:862251340
微信公眾號(hào):coderpai
簡(jiǎn)書(shū)地址:https://www.jianshu.com/p/4e1...


我認(rèn)為學(xué)習(xí)算法的最好方法就是嘗試去實(shí)現(xiàn)它,因此這個(gè)教程我們就來(lái)學(xué)習(xí)如何利用 TensorFlow 來(lái)實(shí)現(xiàn)詞嵌入。

這篇文章我們不會(huì)去過(guò)多的介紹一些詞向量的內(nèi)容,所以很多 king - man - woman - queue 的例子會(huì)被省去,直接進(jìn)入編碼實(shí)踐過(guò)程。

我們?nèi)绾卧O(shè)計(jì)這些詞嵌入?

對(duì)于如何設(shè)計(jì)詞嵌入有很多的技術(shù),這里我們討論一種非常有名的技術(shù)。與我們往常的認(rèn)知不同,word2vec 并不是一個(gè)深層的網(wǎng)絡(luò),它只是一個(gè)三層的淺層網(wǎng)絡(luò)。

注意:word2vec 有很多的技術(shù)細(xì)節(jié),但是我們會(huì)跳過(guò)這些細(xì)節(jié),來(lái)使得更加容易理解。

word2vec 如何工作?

word2vec 算法的設(shè)計(jì)如下:

它是一個(gè)三層的網(wǎng)絡(luò)(一個(gè)輸入層 + 一個(gè)隱藏層 + 一個(gè)輸出層)。

模型輸入一個(gè)詞,然后去預(yù)測(cè)它周圍的詞。

移除最后一層(輸出層),保留輸入層和隱藏層。

現(xiàn)在,輸入一個(gè)詞庫(kù)中的詞,然后隱藏層的輸出就是輸入詞的詞向量。

就是這么簡(jiǎn)單,這個(gè)三層網(wǎng)絡(luò)就可以得到一個(gè)還不錯(cuò)的詞向量。

接下來(lái)就讓我們來(lái)實(shí)現(xiàn)這個(gè)模型。完整的代碼可以點(diǎn)擊 Github,但我建議你先不要看完整的代碼,先一步一步學(xué)習(xí)。

接下來(lái),我們先定義我們要處理的原始文本:

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()

現(xiàn)在,我們需要將輸入的原始文本數(shù)據(jù)轉(zhuǎn)換成一個(gè)輸入輸出對(duì),以便我們對(duì)輸入的詞,可以去預(yù)測(cè)它附近的詞。比如,我們確定一個(gè)中心詞, 窗口大小 window_size 設(shè)置為 n ,那么我們就是去預(yù)測(cè)中心詞前面 n 個(gè)詞和后面 n 個(gè)詞。Chris McCormick 的這篇博客給出了比較詳細(xì)的解釋。

注意:如果中心詞是在句子的開(kāi)頭或者末尾,那么我們就忽略窗口無(wú)法獲得的詞。

在做這個(gè)之前,我們需要?jiǎng)?chuàng)建一個(gè)字典,用來(lái)確定每個(gè)單詞的索引,具體如下:

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

這個(gè)字典的運(yùn)行結(jié)果如下:

print(word2int["queen"])
-> 42 (say)

print(int2word[42])
-> "queen"

接下來(lái),我們將我們的句子向量轉(zhuǎn)換成單詞列表,如下:

# raw sentences is a list of sentences.
raw_sentences = corpus_raw.split(".")
sentences = []
for sentence in raw_sentences:
    sentences.append(sentence.split())

上面代碼將幫助我們得到一個(gè)句子的列表,列表中的每一個(gè)元素是句子的單詞列表,如下:

print(sentences)

-> [["he", "is", "the", "king"], ["the", "king", "is", "royal"], ["she", "is", "the", "royal", "queen"]]

接下來(lái),我們要產(chǎn)生我們的訓(xùn)練數(shù)據(jù):

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])

這個(gè)程序給出了單詞輸入輸出對(duì),我們將窗口的大小設(shè)置為 2。

print(data)
[["he", "is"],
 ["he", "the"],
 ["is", "he"],
 ["is", "the"],
 ["is", "king"],
 ["the", "he"],
 ["the", "is"], 
.
.
.
]

至此,我們有了我們的訓(xùn)練數(shù)據(jù),但是我們需要將它轉(zhuǎn)換成計(jì)算機(jī)可以理解的表示,即數(shù)字。也就是我們之前設(shè)計(jì)的 word2int 字典。

我們?cè)龠M(jìn)一步表示,將這些數(shù)字轉(zhuǎn)換成 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 向量呢?這個(gè)問(wèn)題我們后續(xù)討論。

# 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)

現(xiàn)在,我們有了 x_trainy_train 數(shù)據(jù):

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.]]

這兩個(gè)數(shù)據(jù)的維度如下:

print(x_train.shape, y_train.shape)
->
(34, 7) (34, 7)
# meaning 34 training points, where each point has 7 dimensions
構(gòu)造 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))

從上圖中可以看出,我們將訓(xùn)練數(shù)據(jù)轉(zhuǎn)換成了另一種向量表示。

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)

接下來(lái),我們對(duì)隱藏層的數(shù)據(jù)進(jìn)行處理,并且對(duì)其附近的詞進(jìn)行預(yù)測(cè)。預(yù)測(cè)詞的方法我們采用 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.

現(xiàn)在,我們可以訓(xùn)練這個(gè)模型:

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}))

在訓(xùn)練的過(guò)程中,你在控制臺(tái)可以得到如下結(jié)果:

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
.
.
.

隨著損失值的不斷下降,最終會(huì)達(dá)到一個(gè)穩(wěn)定值。即使我們無(wú)法獲得很精確的結(jié)果,但是我們也不在乎,因?yàn)槲覀兏信d趣的是 W1 和 b1 的值,即隱藏層的權(quán)重。

讓我們來(lái)看看這些權(quán)重,如下:

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 向量?

當(dāng)我們將一個(gè) 0-1 向量與 W1 相乘時(shí),我們基本上可以將 W1 與 0-1 向量對(duì)應(yīng)的那個(gè) 1 相乘的結(jié)果就是詞向量。也就是說(shuō), W1 就是一個(gè)數(shù)據(jù)查詢表。

在我們的程序中,我們也添加了一個(gè)偏置項(xiàng) 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 ]
那么這些漂亮的向量有什么用呢?

我們寫(xiě)一個(gè)如何去查找最相近向量的函數(shù),當(dāng)然這個(gè)寫(xiě)法是非常簡(jiǎn)單粗糙的。

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

接下來(lái),讓我們來(lái)測(cè)試一下單詞 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

我們可以得到如下有趣的結(jié)果。

king is closest to queen
queen is closest to king
royal is closest to he

第三個(gè)數(shù)據(jù)是我們根據(jù)大型語(yǔ)料庫(kù)得出來(lái)的(看起來(lái)還不錯(cuò))。語(yǔ)料庫(kù)的數(shù)據(jù)更大,我們得到的結(jié)果會(huì)更好。(注意:由于權(quán)重是隨機(jī)初始化的,所以我們可能會(huì)得到不同的結(jié)果,如果有需要,我們可以多運(yùn)行幾次。)

讓我們來(lái)畫(huà)出這個(gè)向量相關(guān)圖。

首先,我們需要利用將為技術(shù)將維度從 5 減小到 2,所用的技術(shù)是:tSNE(teesnee?。?/p>

from sklearn.manifold import TSNE
model = TSNE(n_components=2, random_state=0)
np.set_printoptions(suppress=True)
vectors = model.fit_transform(vectors)

然后,我們需要對(duì)結(jié)果進(jìn)行規(guī)范化,以便我們可以在 matplotlib 中更好的對(duì)它進(jìn)行查看。

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()

從圖中,我們可以看出。shequeen 的距離非常接近,kingroyal 的距離和 kingqueen 的距離相同。如果我們有一個(gè)更大的語(yǔ)料庫(kù),我們可以得到更加復(fù)雜的關(guān)系圖。

為什么會(huì)發(fā)生這些?

我們給神經(jīng)網(wǎng)絡(luò)的任務(wù)是預(yù)測(cè)單詞的相鄰詞。但是我們還沒(méi)有具體的分析神經(jīng)網(wǎng)絡(luò)是如何預(yù)測(cè)的。因此,神經(jīng)網(wǎng)絡(luò)找出單詞的向量表示,用來(lái)幫助它預(yù)測(cè)相鄰詞這個(gè)任務(wù)。預(yù)測(cè)相鄰詞這本身不是一個(gè)有趣的任務(wù),我們關(guān)心的是隱藏層的向量表示。

為了得到這些表示,神經(jīng)網(wǎng)絡(luò)使用了上下文信息。在我們的語(yǔ)料庫(kù)中,king 和 royal 是作為相鄰詞出現(xiàn)的,queen 和 royal 也是作為相鄰詞出現(xiàn)的。

為什么把預(yù)測(cè)相鄰詞作為一個(gè)任務(wù)?

其他的任務(wù)也可以用來(lái)訓(xùn)練這個(gè)詞向量任務(wù),比如利用 n-gram 就可以訓(xùn)練出很好的詞向量!這里有一篇博客有詳細(xì)解釋。

那么,我們?yōu)槭裁催€要使用相鄰詞預(yù)測(cè)作為任務(wù)呢?因?yàn)橛幸粋€(gè)比較著名的模型稱為 skip gram 模型。我們可以使用中間詞的相鄰單詞作為輸入,并要求神經(jīng)網(wǎng)絡(luò)去預(yù)測(cè)中間詞。這被稱為連續(xù)詞袋模型。

總結(jié)

詞向量是非??岬囊粋€(gè)工具。

不要在實(shí)際生產(chǎn)環(huán)境中使用這個(gè) TensorFlow 代碼,我們這里只是為了理解才這樣寫(xiě)。生產(chǎn)環(huán)境建議使用一些成熟的工具包,比如 gensim

我希望這個(gè)簡(jiǎn)單教程可以幫助到一些人,可以更加深刻的理解什么是詞向量。


作者:chen_h
微信號(hào) & QQ:862251340
簡(jiǎn)書(shū)地址:https://www.jianshu.com/p/4e1...

CoderPai 是一個(gè)專注于算法實(shí)戰(zhàn)的平臺(tái),從基礎(chǔ)的算法到人工智能算法都有設(shè)計(jì)。如果你對(duì)算法實(shí)戰(zhàn)感興趣,請(qǐng)快快關(guān)注我們吧。加入AI實(shí)戰(zhàn)微信群,AI實(shí)戰(zhàn)QQ群,ACM算法微信群,ACM算法QQ群。長(zhǎng)按或者掃描如下二維碼,關(guān)注 “CoderPai” 微信號(hào)(coderpai)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41390.html

相關(guān)文章

  • 使用 LSTM 智能作詩(shī)送新年祝福

    摘要:經(jīng)過(guò)第一步的處理已經(jīng)把古詩(shī)詞詞語(yǔ)轉(zhuǎn)換為可以機(jī)器學(xué)習(xí)建模的數(shù)字形式,因?yàn)槲覀儾捎盟惴ㄟM(jìn)行古詩(shī)詞生成,所以還需要構(gòu)建輸入到輸出的映射處理。 LSTM 介紹 序列化數(shù)據(jù)即每個(gè)樣本和它之前的樣本存在關(guān)聯(lián),前一數(shù)據(jù)和后一個(gè)數(shù)據(jù)有順序關(guān)系。深度學(xué)習(xí)中有一個(gè)重要的分支是專門用來(lái)處理這樣的數(shù)據(jù)的——循環(huán)神經(jīng)網(wǎng)絡(luò)。循環(huán)神經(jīng)網(wǎng)絡(luò)廣泛應(yīng)用在自然語(yǔ)言處理領(lǐng)域(NLP),今天我們帶你從一個(gè)實(shí)際的例子出發(fā),介紹循...

    lauren_liuling 評(píng)論0 收藏0
  • Word2Vec到Bert

    摘要:采用作為特征提取器,并采用雙向語(yǔ)言模型。此外,預(yù)訓(xùn)練的數(shù)據(jù)規(guī)模非常龐大。輸入部分處理輸入是一個(gè)線性序列,兩個(gè)句子通過(guò)分隔符分割,前后兩端分別增加標(biāo)識(shí)符號(hào)。輸出處理評(píng)價(jià)從模型或者方法的角度來(lái)看,借鑒了以及,主要提出了語(yǔ)言模型和。 Word2Vec模型 showImg(https://segmentfault.com/img/bVbphHw?w=1282&h=726); Word2Vec有...

    leeon 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<