使用預訓練的word2vec詞向量
以谷歌開源google news(bin)為例。下載地址:https://code.google.com/p/word2vec
更多模型下載地址:https://github.com/xgli/word2vec-api
之前被這個問題困擾了挺長時間,一直找不到有效的方法,可能是我太菜……
在網上找資料也只找到了一種把bin轉換成txt 檔案的方式,但是效率出奇的低,無法想象,本地一執行程式就宕機,伺服器上也得等很長時間。多虧了有一顆優化模型的心……
山重水複疑無路,柳暗花明又一村啊。
在一篇paper裡面,作者用theano直接對二進位制bin檔案進行了處理。速度上有天壤之別,一種是拖拉機,一種是火箭,遂把它進行改動用到了自己的模型裡。
一、先介紹直接對txt進行處理的方法,該方法缺點,速度太慢,而且兩篇博文裡都是從placeholder裡傳入詞向量資料,對於這種方式,我持保留意見。原因:
1,如果從placeholder裡傳入資料,那在實際應用中,每一個batch都要傳入全部的詞向量,這對於稍複雜的模型來說顯然很吃力,額外增加了很多計算量。
2,在模型訓練過程中可以控制詞向量可訓練與不可訓練,從palceholdler傳入,降低了靈活性。
3,bin檔案轉換成txt格式,檔案大小變為原來的兩倍,還需要解碼,又增加了讀取時間。
對於該方法不在贅述,將兩篇博文地址貼上到下面:
http://blog.csdn.net/lxg0807/article/details/72518962(中文)[作者最後提到的unk情況,其實可有可無,看你在對資料進行預處理的時候是否考慮了這種情況,如果已經考慮到了unk則在此處不需要]
二、直接對bin檔案進行處理
1,這種方式跟上面的方式有很大不同,首先是在分離word的時候,是採用從每一行的開始挨個單詞讀到第一個空格處為止,便是一個單詞,每一行都重複這種動作,直到整個檔案讀完。
for line in xrange(vocab_size): word = [] while True: ch = f.read(1) #print ch if ch == ' ': word = ''.join(word) #print 'single word:',word break if ch != '\n': word.append(ch) #print word
2,第二步是從大的詞向量表中,來找到與單詞相對應的詞向量
if word in vocab:
word_vecs[word] = np.fromstring(f.read(binary_len), dtype='float32')
pury_word_vec.append(word_vecs[word])
if i==0:
print 'word',word
i=1
else:
f.read(binary_len)
3,對於詞表中沒有的單詞進行處理,這裡採用的是uniform隨機初始化
def add_unknown_words(word_vecs, vocab, min_df=1, k=300):
"""
For words that occur in at least min_df documents, create a separate word vector.
0.25 is chosen so the unknown vectors have (approximately) same variance as pre-trained ones
"""
for word in vocab:
if word not in word_vecs and vocab[word] >= min_df:
word_vecs[word] = np.random.uniform(-0.25,0.25,k)
4,在應用之前,也就是傳入embedding lookup之前,需要取出對應詞表,並進行一定預處理。
def get_W(word_vecs, k=300): """ Get word matrix. W[i] is the vector for word indexed by i """ vocab_size = len(word_vecs) word_idx_map = dict() W = np.zeros(shape=(vocab_size+1, k), dtype='float32') W[0] = np.zeros(k, dtype='float32') i = 1 for word in word_vecs: W[i] = word_vecs[word] word_idx_map[word] = i i += 1 return W, word_idx_map
5,在main函式中呼叫的過程:
if __name__=="__main__":
w2v_file = "GoogleNews-vectors-negative300.bin"#Google news word2vec bin檔案
print "loading data...",
vocab = Wordlist('vocab.txt')#自己的資料集要用到的詞表
w2v,pury_word2vec = load_bin_vec(w2v_file, vocab.voc)
add_unknown_words(w2v, vocab.voc)
W, word_idx_map = get_W(w2v)
'''embedding lookup簡單應用'''
Wa = tf.Variable(W)
embedding_input = tf.nn.embedding_lookup(Wa, [0,1,2])#正常使用時要替換成相應的doc
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
input = sess.run(Wa)
#print np.shape(Wa)
此處僅做了使用的簡單示例,如果應用到自己的專案中去,還需要優化一下結構。以適應自己專案的需要。
剛開始寫部落格不久,發現在表達的時候會說不清楚,有不明白的地方,歡迎留言討論。
補充:關於txt格式的檔案,也找到了速度很快的處理方式,glove和word2vec只要是一樣的格式,程式碼可以通用,可以移步這裡:http://lichangsong.win/?post=22
文中相關程式碼,已經上傳到github,歡迎大家相互交流,共同進步。
Github: https://github.com/pkulics/use-pretrained-word2vec