tensorflow基於圖結構深度學習框架,內部經過session實現圖和計算內核交互。html
tensorflow基本數學運算用法。python
import tensorflow as tf sess = tf.Session() a = tf.placeholder("float") b = tf.placeholder("float") c = tf.constant(6.0) d = tf.mul(a, b) y = tf.mul(d, c) print sess.run(y, feed_dict={a: 3, b: 3}) A = [[1.1,2.3],[3.4,4.1]] Y = tf.matrix_inverse(A) print sess.run(Y) sess.close()
主要數字運算。git
tf.add tf.sub tf.mul tf.div tf.mod tf.abs tf.neg tf.sign tf.inv tf.square tf.round tf.sqrt tf.pow tf.exp tf.log tf.maximum tf.minimum tf.cos tf.sin
主要矩陣運算。github
tf.diag #生成對角陣 tf.transpose tf.matmul tf.matrix_determinant #計算行列式的值 tf.matrix_inverse #計算矩陣的逆
tensorboard使用。tensorflow代碼,先構建圖,而後執行,對中間過程調試不方便,提供一個tensorboard工具調試。訓練時提示寫入事件文件到目錄(/tmp/tflearn_logs/11U8M4/)。執行命令打開 http://192.168.1.101:6006 看到tensorboard的界面。數組
tensorboard --logdir=/tmp/tflearn_logs/11U8M4/
Graph和Session。微信
import tensorflow as tf with tf.Graph().as_default() as g: with g.name_scope("myscope") as scope: # 有了這個scope,下面的op的name都是相似myscope/Placeholder這樣的前綴 sess = tf.Session(target='', graph = g, config=None) # target表示要鏈接的tf執行引擎 print "graph version:", g.version # 0 a = tf.placeholder("float") print a.op # 輸出整個operation信息,跟下面g.get_operations返回結果同樣 print "graph version:", g.version # 1 b = tf.placeholder("float") print "graph version:", g.version # 2 c = tf.placeholder("float") print "graph version:", g.version # 3 y1 = tf.mul(a, b) # 也能夠寫成a * b print "graph version:", g.version # 4 y2 = tf.mul(y1, c) # 也能夠寫成y1 * c print "graph version:", g.version # 5 operations = g.get_operations() for (i, op) in enumerate(operations): print "============ operation", i+1, "===========" print op # 一個結構,包括:name、op、attr、input等,不一樣op不同 assert y1.graph is g assert sess.graph is g print "================ graph object address ================" print sess.graph print "================ graph define ================" print sess.graph_def print "================ sess str ================" print sess.sess_str print sess.run(y1, feed_dict={a: 3, b: 3}) # 9.0 feed_dictgraph中的元素和值的映射 print sess.run(fetches=[b,y1], feed_dict={a: 3, b: 3}, options=None, run_metadata=None) # 傳入的feches和返回值的shape相同 print sess.run({'ret_name':y1}, feed_dict={a: 3, b: 3}) # {'ret_name': 9.0} 傳入的feches和返回值的shape相同 assert tf.get_default_session() is not sess with sess.as_default(): # 把sess做爲默認的session,那麼tf.get_default_session就是sess, 不然不是 assert tf.get_default_session() is sess h = sess.partial_run_setup([y1, y2], [a, b, c]) # 分階段運行,參數指明瞭feches和feed_dict列表 res = sess.partial_run(h, y1, feed_dict={a: 3, b: 4}) # 12 運行第一階段 res = sess.partial_run(h, y2, feed_dict={c: res}) # 144.0 運行第二階段,其中使用了第一階段的執行結果 print "partial_run res:", res sess.close()
tensorflow Session是Graph和執行者媒介,Session.run()將graph、fetches、feed_dict序列化到字節數組,調用tf_session.TF_Run(參見/usr/local/lib/python2.7/site-packages/tensorflow/python/client/session.py)。tf_session.TF_Run調用動態連接庫_pywrap_tensorflow.so實現_pywrap_tensorflow.TF_Run接口(參見/usr/local/lib/python2.7/site-packages/tensorflow/python/pywrap_tensorflow.py)。動態連接庫是tensorflow多語言python接口。_pywrap_tensorflow.so和pywrap_tensorflow.py經過SWIG工具自動生成,tensorflow核心語言c語言,經過SWIG生成各類腳本語言接口。session
10行關鍵代碼實現線性迴歸。用梯度降低求解線性迴歸問題是tensorflow最簡單入門例子(10行關鍵代碼)。app
# -*- coding: utf-8 -*- import numpy as np import tensorflow as tf # 隨機生成1000個點,圍繞在y=0.1x+0.3的直線周圍 num_points = 1000 vectors_set = [] for i in xrange(num_points): x1 = np.random.normal(0.0, 0.55) y1 = x1 * 0.1 + 0.3 + np.random.normal(0.0, 0.03) vectors_set.append([x1, y1]) # 生成一些樣本 x_data = [v[0] for v in vectors_set] y_data = [v[1] for v in vectors_set] # 生成1維的W矩陣,取值是[-1,1]之間的隨機數 W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W') # 生成1維的b矩陣,初始值是0 b = tf.Variable(tf.zeros([1]), name='b') # 通過計算得出預估值y y = W * x_data + b # 以預估值y和實際值y_data之間的均方偏差做爲損失 loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 採用梯度降低法來優化參數 optimizer = tf.train.GradientDescentOptimizer(0.5) # 訓練的過程就是最小化這個偏差值 train = optimizer.minimize(loss, name='train') sess = tf.Session() # 輸出圖結構 #print sess.graph_def init = tf.initialize_all_variables() sess.run(init) # 初始化的W和b是多少 print "W =", sess.run(W), "b =", sess.run(b), "loss =", sess.run(loss) # 執行20次訓練 for step in xrange(20): sess.run(train) # 輸出訓練好的W和b print "W =", sess.run(W), "b =", sess.run(b), "loss =", sess.run(loss) # 生成summary文件,用於tensorboard使用 writer = tf.train.SummaryWriter("./tmp", sess.graph)
一張圖展現線性迴歸工做原理。執行代碼在本地生成一個tmp目錄,產生tensorboard讀取數據,執行:框架
tensorboard --logdir=./tmp/
打開 http://localhost:6006/ GRAPHS,展開一系列關鍵節點。圖是代碼生成graph結構,graph描述整個梯度降低解決線性迴歸問題整個過程,每個節點表明代碼的一步操做。dom
詳細分析線性迴歸graph。W和b。代碼對W有三種操做 Assign、read、train。assign基於random_uniform賦值。
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W')
tf.random_uniform graph。read對應:
y = W * x_data + b
train對應梯度降低訓練過程操做。
對b有三種操做:Assign、read、train。用zeros賦初始化值。
W和b經過梯度降低計算update_W和update_b,更新W和b的值。update_W和update_b基於三個輸入計算得出,學習率learning_rate、W/b當前值、梯度gradients。
最關鍵的梯度降低過程。
loss = tf.reduce_mean(tf.square(y - y_data), name='loss')
以y-y_data爲輸入,x不是x_data,是一個臨時常量 2。2(y-y_data),明顯是(y-y_data)^2導數。以2(y-y_data)爲輸入通過各類處理最終生成參數b的增量update_b。生成update_W更新W,反向追溯依賴於add_grad(基於y-y_data)和W以及y生成,詳細計算過程:http://stackoverflow.com/ques... ,一步簡單操做被tensorflow轉成不少個節點圖,細節節點不深刻分析,只是操做圖表達,沒有過重要意義。
tensorflow自帶seq2seq模型基於one-hot詞嵌入,每一個詞用一個數字代替不足表示詞與詞之間關係,word2vec多維向量作詞嵌入,可以表示出詞之間關係。基於seq2seq思想,利用多維詞向量實現模型,預期會有更高準確性。
seq2seq模型原理。參考《Sequence to Sequence Learning with Neural Networks》論文。核心思想,ABC是輸入語句,WXYZ是輸出語句,EOS是標識一句話結束,訓練單元是lstm,lstm的特色是有長短時記憶,可以根據輸入多個字肯定後面多個字,lstm知識參考 http://deeplearning.net/tutor... 模型編碼器和解碼器共用同一個lstm層,共享參數,分開 https://github.com/farizrahma... 綠色是編碼器,黃色是解碼器,橙色箭頭傳遞lstm層狀態信息(記憶信息),編碼器惟一傳給解碼器的狀態信息。
解碼器每一時序輸入是前一個時序輸出,經過不一樣時序輸入「How are you <EOL>」,模型能自動一個字一個字輸出「W I am fine <EOL>」,W是特殊標識,是編碼器最後輸出,是解碼器觸發信號。
直接把解碼器每一時序輸入強制改成"W I am fine",把這部分從訓練樣本輸入X中傳過來,Y依然是預測輸出"W I am fine <EOL>",這樣訓練出來的模型就是編碼器解碼器模型。
使用訓練模型預測,在解碼時之前一時序輸出爲輸入作預測,就能輸出"W I am fine <EOL>」。
語料準備。至少300w聊天語料用於詞向量訓練和seq2seq模型訓練,語料越豐富訓練詞向量質量越好。
切詞:
python word_segment.py ./corpus.raw ./corpus.segment
切詞文件轉成「|」分隔問答對:
cat ./corpus.segment | awk '{if(last!="")print last"|"$0;last=$0}' | sed 's/| /|/g' > ./corpus.segment.pair
訓練詞向量。用google word2vec訓練詞向量:
word2vec -train ./corpus.segment -output vectors.bin -cbow 1 -size 200 -window 8 -negative 25 -hs 0 -sample 1e-5 -threads 20 -binary 1 -iter 15
corpus.raw 原始語料數據,vectors.bin 生成的詞向量二進制文件。
生成詞向量二進制加載方法 https://github.com/warmheartl... 。
建立模型。用tensorflow+tflearn庫來實現。
# 首先咱們爲輸入的樣本數據申請變量空間,以下。其中self.max_seq_len是指一個切好詞的句子最多包含多少個詞,self.word_vec_dim是詞向量的維度,這裏面shape指定了輸入數據是不肯定數量的樣本,每一個樣本最多包含max_seq_len*2個詞,每一個詞用word_vec_dim維浮點數表示。這裏面用2倍的max_seq_len是由於咱們訓練是輸入的X既要包含question句子又要包含answer句子 input_data = tflearn.input_data(shape=[None, self.max_seq_len*2, self.word_vec_dim], dtype=tf.float32, name = "XY") # 而後咱們將輸入的全部樣本數據的詞序列切出前max_seq_len個,也就是question句子部分,做爲編碼器的輸入 encoder_inputs = tf.slice(input_data, [0, 0, 0], [-1, self.max_seq_len, self.word_vec_dim], name="enc_in") # 再取出後max_seq_len-1個,也就是answer句子部分,做爲解碼器的輸入。注意,這裏只取了max_seq_len-1個,是由於還要在前面拼上一組GO標識來告訴解碼器咱們要開始解碼了,也就是下面加上go_inputs拼成最終的go_inputs decoder_inputs_tmp = tf.slice(input_data, [0, self.max_seq_len, 0], [-1, self.max_seq_len-1, self.word_vec_dim], name="dec_in_tmp") go_inputs = tf.ones_like(decoder_inputs_tmp) go_inputs = tf.slice(go_inputs, [0, 0, 0], [-1, 1, self.word_vec_dim]) decoder_inputs = tf.concat(1, [go_inputs, decoder_inputs_tmp], name="dec_in") # 以後開始編碼過程,返回的encoder_output_tensor展開成tflearn.regression迴歸能夠識別的形如(?, 1, 200)的向量;返回的states後面傳入給解碼器 (encoder_output_tensor, states) = tflearn.lstm(encoder_inputs, self.word_vec_dim, return_state=True, scope='encoder_lstm') encoder_output_sequence = tf.pack([encoder_output_tensor], axis=1) # 取出decoder_inputs的第一個詞,也就是GO first_dec_input = tf.slice(decoder_inputs, [0, 0, 0], [-1, 1, self.word_vec_dim]) # 將其輸入到解碼器中,以下,解碼器的初始化狀態爲編碼器生成的states,注意:這裏的scope='decoder_lstm'是爲了下面重用同一個解碼器 decoder_output_tensor = tflearn.lstm(first_dec_input, self.word_vec_dim, initial_state=states, return_seq=False, reuse=False, scope='decoder_lstm') # 暫時先將解碼器的第一個輸出存到decoder_output_sequence_list中供最後一塊兒輸出 decoder_output_sequence_single = tf.pack([decoder_output_tensor], axis=1) decoder_output_sequence_list = [decoder_output_tensor] # 接下來咱們循環max_seq_len-1次,不斷取decoder_inputs的一個個詞向量做爲下一輪解碼器輸入,並將結果添加到decoder_output_sequence_list中,這裏面的reuse=True, scope='decoder_lstm'說明和上面第一次解碼用的是同一個lstm層 for i in range(self.max_seq_len-1): next_dec_input = tf.slice(decoder_inputs, [0, i+1, 0], [-1, 1, self.word_vec_dim]) decoder_output_tensor = tflearn.lstm(next_dec_input, self.word_vec_dim, return_seq=False, reuse=True, scope='decoder_lstm') decoder_output_sequence_single = tf.pack([decoder_output_tensor], axis=1) decoder_output_sequence_list.append(decoder_output_tensor) # 下面咱們把編碼器第一個輸出和解碼器全部輸出拼接起來,做爲tflearn.regression迴歸的輸入 decoder_output_sequence = tf.pack(decoder_output_sequence_list, axis=1) real_output_sequence = tf.concat(1, [encoder_output_sequence, decoder_output_sequence]) net = tflearn.regression(real_output_sequence, optimizer='sgd', learning_rate=0.1, loss='mean_square') model = tflearn.DNN(net)
模型建立完成,彙總思想:
1)訓練輸入X、Y分別是編碼器解碼器輸入和預測輸出; 2)X切分兩半,前一半是編碼器輸入,後一半是解碼器輸入; 3)編碼解碼器輸出預測值用Y作迴歸訓練 4)訓練經過樣本真實值做解碼器輸入,實際預測不會有WXYZ部分,上一時序輸出將做下一時序輸入
訓練模型。實例化模型並喂數據作訓練:
model = self.model() model.fit(trainXY, trainY, n_epoch=1000, snapshot_epoch=False, batch_size=1) model.load('./model/model')
trainXY和trainY經過加載語料賦值。
加載詞向量存到word_vector_dict,讀取語料文件挨個詞查word_vector_dict,賦值向量給question_seq和answer_seq:
def init_seq(input_file): """讀取切好詞的文本文件,加載所有詞序列 """ file_object = open(input_file, 'r') vocab_dict = {} while True: question_seq = [] answer_seq = [] line = file_object.readline() if line: line_pair = line.split('|') line_question = line_pair[0] line_answer = line_pair[1] for word in line_question.decode('utf-8').split(' '): if word_vector_dict.has_key(word): question_seq.append(word_vector_dict[word]) for word in line_answer.decode('utf-8').split(' '): if word_vector_dict.has_key(word): answer_seq.append(word_vector_dict[word]) else: break question_seqs.append(question_seq) answer_seqs.append(answer_seq) file_object.close()
有question_seq和answer_seq,構造trainXY和trainY:
def generate_trainig_data(self): xy_data = [] y_data = [] for i in range(len(question_seqs)): question_seq = question_seqs[i] answer_seq = answer_seqs[i] if len(question_seq) < self.max_seq_len and len(answer_seq) < self.max_seq_len: sequence_xy = [np.zeros(self.word_vec_dim)] * (self.max_seq_len-len(question_seq)) + list(reversed(question_seq)) sequence_y = answer_seq + [np.zeros(self.word_vec_dim)] * (self.max_seq_len-len(answer_seq)) sequence_xy = sequence_xy + sequence_y sequence_y = [np.ones(self.word_vec_dim)] + sequence_y xy_data.append(sequence_xy) y_data.append(sequence_y) return np.array(xy_data), np.array(y_data)
構造訓練數據建立模型,訓練:
python my_seq2seq_v2.py train
最終生成./model/model模型文件。
效果預測。訓練模型,輸入一句話預測一下回答:
predict = model.predict(testXY)
只有question沒有answer,testXY沒有Y部分,用上一句輸出做爲下一句輸入:
for i in range(self.max_seq_len-1): # next_dec_input = tf.slice(decoder_inputs, [0, i+1, 0], [-1, 1, self.word_vec_dim])這裏改爲下面這句 next_dec_input = decoder_output_sequence_single decoder_output_tensor = tflearn.lstm(next_dec_input, self.word_vec_dim, return_seq=False, reuse=True, scope='decoder_lstm') decoder_output_sequence_single = tf.pack([decoder_output_tensor], axis=1) decoder_output_sequence_list.append(decoder_output_tensor)
詞向量是多維浮點數,預測詞向量要經過餘弦類似度匹配,餘弦類似度匹配方法:
def vector2word(vector): max_cos = -10000 match_word = '' for word in word_vector_dict: v = word_vector_dict[word] cosine = vector_cosine(vector, v) if cosine > max_cos: max_cos = cosine match_word = word return (match_word, max_cos)
其中的vector_cosine實現以下:
def vector_cosine(v1, v2): if len(v1) != len(v2): sys.exit(1) sqrtlen1 = vector_sqrtlen(v1) sqrtlen2 = vector_sqrtlen(v2) value = 0 for item1, item2 in zip(v1, v2): value += item1 * item2 return value / (sqrtlen1*sqrtlen2) def vector_sqrtlen(vector): len = 0 for item in vector: len += item * item len = math.sqrt(len) return len
預測:
python my_seq2seq_v2.py test test.data
輸出第一列是預測每一個時序產生詞,第二列是預測輸出向量和最近詞向量餘弦類似度,第三列是預測向量歐氏距離。
max_seq_len定長8,輸出序列最後會多餘一些字,根據餘弦類似度或者其餘指標設定一個閾值截斷。
所有代碼 https://github.com/warmheartl... 。
參考資料:
《Python 天然語言處理》
《NLTK基礎教程 用NLTK和Python庫構建機器學習應用》
http://www.shareditor.com/blo...
http://www.shareditor.com/blo...
http://www.shareditor.com/blo...
歡迎推薦上海機器學習工做機會,個人微信:qingxingfengzi