往期RNN相關工程實踐文章
『TensotFlow』RNN中文文本_下_暨研究生開學感想
張量分析
預處理結果是二維數據,相當於batch條一維數據,每個數據對應一首詩,每個字是一個scalar;
embedding之后,將每個字映射為一個rnn_size大小的向量,數據變為三維;
經過遞歸神經網絡,輸出維度不變;
將之調整為二維數據,這里面第二維度(即每一行)對應一個字;
全連接映射,將每一個字由rnnsize的向量映射為一個長度為總字數的向量,這樣方便計算loss,實際計算loss時,會將label(二維向量,一行一首詩,字為scalar)拉伸為一維向量,每行只有一個字scalar,one_hot之后和此時數據正好對應,方便計算
SoftMax不改變張量形狀,只是將結果以概率分布的形式輸出
工程分析
代碼見Github
1、文件簡介
LSTM_model.py
:LSTM網絡模型,提供了end_points接口,被其他部分調用
poetry_porcess.py
:數據讀取、預處理部分,會返回打包好的batch,被main調用
gen_poetry.py
:古詩生成程序,擁有可選的風格參數,被main調用
main.py
:主函數,既可以調用前兩個程序獲取預處理數據並使用LSTM網絡進行訓練,也可以調用gen_poetry.py生成古詩
2、調用指令
在main.py
最后有如下指令,
if __name__ == "__main__": words,poetry_vector,to_num,x_batches,y_batches = poetry_porcess.poetry_process() # train(words, poetry_vector, x_batches, y_batches) # gen_poetry(words, to_num) generate(words_, to_num_, style_words="狂沙將軍戰燕然,大漠孤煙黃河騎。")
此時實際上處於生成模式,對於最后的三行, train:表示訓練 gen_poetry:表示根據首字符生成 generate:表示根據首句和風格句生成古詩
訓練時注釋掉后兩行,保留train行,
if __name__ == "__main__": words,poetry_vector,to_num,x_batches,y_batches = poetry_porcess.poetry_process() train(words, poetry_vector, x_batches, y_batches) # gen_poetry(words, to_num) # generate(words_, to_num_, style_words="狂沙將軍戰燕然,大漠孤煙黃河騎。")
生成時不需要修改,但是
generate(words_, to_num_, style_words="狂沙將軍戰燕然,大漠孤煙黃河騎。")
可以替換style_word為任何你想要的風格句,注意最好使用7言或者5言,因為這句會大概率影響到你生成的古詩的句子長度(不絕對),這只是風格提取,你可以輸入任意長度;在運行了腳本后,屏幕會提示輸入起始句,輸入的句子一般5或者7個字,這個由於會拿來直接做首句(由結果示范可以看到),輸入長度不宜過長。
對於上面的兩種情況,修改完成后運行腳本即可,
python main.py
即可顯示結果
3、結果示范
head:床前明月光 + style:黃沙百戰金甲:
床前明月光輝,魏武征夫血絮紅。
數步崩雲復遺主,縞衣東,帝京舉,玉輪還滿出書初。
秋秋慘慘垂楊柳,夢斷黃鶯欲斷腸。
花凋柳映阮家幾,屋前病,歇馬空留門。
當年皆月林,獨往深山有素。
head:少小離家老大回 + style:山雨欲來風滿樓:
少小離家老大回,四壁百月弄鴉飛。
掃香花間春風地,隔天傾似爛桃香。
近來誰伴清明日,兩株愁味在羅幃。
仍通西疾空何處,軋軋涼吹日方明。
head:少小離家老大回 + style:鐵馬冰河入夢來:
少小離家老大回,化空千里便成絲。
官拋十里同牛頷,莫礙風光雪片雲。
飲水遠濤飛漢地,雲連城戶翠微低。
一樹鐵門萬象聳,白雲三尺各關高。
同言東甸西游子,誰道承陽要舊憂。
少小離家老大回,含顰玉燭拂樓台。
初齊去府芙蓉死,細緩行雲向國天
RNN結構補充
原網絡結構如下,實際上不需要像下面這樣寫了,不過當時費了好大事,所以保留一下原來版本的代碼,
with tf.variable_scope('placeholder'): input_vec = tf.placeholder(tf.int32,[None,None]) output_targets = tf.placeholder(tf.int32,[None,None]) def rnn_network(rnn_size=128,num_layers=2): def lstm_cell(): l_cell = tf.contrib.rnn.BasicLSTMCell(rnn_size,state_is_tuple=True,reuse=tf.get_variable_scope().reuse) return l_cell cell = tf.contrib.rnn.MultiRNNCell([lstm_cell() for _ in range(num_layers)]) initial_state = cell.zero_state(batch_size, tf.float32) # 初始化LSTM網絡節點,參數為尺寸 with tf.variable_scope('LSTM'): with tf.variable_scope('embedding'): E = tf.get_variable('embedding',[len(words_list) + 1,rnn_size]) input_embedding = tf.nn.embedding_lookup(E,input_vec) output_embedding, last_state = tf.nn.dynamic_rnn(cell, input_embedding, initial_state=initial_state,scope='lstm') output = tf.reshape(output_embedding,[-1,rnn_size]) with tf.variable_scope('output'): W = tf.get_variable('W', [rnn_size,len(words_list)+1]) b = tf.get_variable('b', [len(words_list)+1]) logits = tf.matmul(output,W) + b probs = tf.nn.softmax(logits) return logits, last_state, probs, cell, initial_state
另外,直接使用tf.nn.rnn_cell而不是用tf.contrib.rnn也可以。