前言
這篇文章會利用到上一篇: 基于Spark /Tensorflow使用CNN處理NLP的嘗試的數據預處理部分,也就是如何將任意一段長度的話表征為一個2維數組。
本文完整的代碼在這: autoencoder-sentence-similarity.py
基本思路是威兜,通過編碼解碼網絡(有點類似微軟之前提出的對偶學習),先對句子進行編碼苦酱,然后進行解碼酥泞,解碼后的語句要和原來的句子盡可能的接近。訓練完成后芽死,我們就可以將任意一個句子進行編碼為一個向量乏梁,這算是Sentence Embedding的一種新的實現(xiàn)。最大的好處是关贵,整個過程無需標注語料遇骑,屬于無監(jiān)督類學習。這次我還在編碼前引入卷積網絡揖曾,不過效果有待驗證落萎。
準備工作
我們假設大家已經準備了兩個數據集,具體可以參考上一篇文章的Spark預處理部分:
- 已經分好詞的語句
- 詞到vector的字典
然后我們使用如下函數來進行處理:
def next_batch(batch_num, batch_size, word_vec_dict):
with open(WORD_FILE) as wf:
line_num = 0
start_line_num = batch_num * batch_size
batch_counter = 0
result = []
for words in wf:
result1 = []
line_num += 1
if line_num > start_line_num:
batch_counter += 1
for word in words.split(" "):
if word in word_vec_dict:
result1.append(word_vec_dict[word])
if len(result1) < SEQUENCE_LENGTH:
for i in range(SEQUENCE_LENGTH - len(result1)):
result1.append(np.zeros(shape=(VOCAB_SIZE, 1)).tolist())
result.append([str(line_num), result1[0:SEQUENCE_LENGTH]])
if batch_counter == batch_size:
return result
字典的格式是: word + 空格 + 100個逗號分隔的數字
文本內容格式是: 通過空格分隔的已經分好詞的句子
因為這次測試數據集有點大炭剪,所以沒辦法一次性載入到內存静尼,只能分批了。缺點是鼓择,每一次都需要重新打開文件启上,為了減少打開文件次數,程序后半部分做了一些優(yōu)化處理粱坤,基本方式為隶糕,一次性從文件里取batch_size 條數據,然后讓Tensorflow 再分 batch_size / mini_train_batch_size 次進行迭代站玄。每次迭代給的樣本量還是比較影響效果的枚驻,4000和200比,有20%左右的差異株旷。
構建模型
我嘗試了如下兩個拓撲再登,第一個是帶卷積的:
Input(段落) -> 卷積 -> 池化 -> 卷積 -> 池化 -> encoder -> encoder -> decoder -> decoder -> lost function (consine夾角)
第二個則是不帶卷積:
Input(段落) -> encoder -> encoder -> decoder -> decoder -> lost function (consine夾角)
基本上是兩層卷積尔邓,兩層編解碼器。
訓練完成后锉矢,就獲得編碼器的所有參數梯嗽,利用encoder_op 對所有的語句進行編碼,從而實現(xiàn)所有語句得到一個唯一的向量(128維)表示沽损。
大概準備了 60多萬條語句進行訓練灯节,經歷了50*60輪迭代后,不帶卷積最后loss 大概是從1.1 下降到0.94的樣子绵估。如果進行更多迭代炎疆,提供更多訓練數據,應該可以進一步降低国裳。
帶卷積的收斂較快形入,loss 從0.5 經過3000輪迭代,可以下降到0.1 左右缝左。
因為語料比較隱私亿遂,無法提供,但是可以描述下大致的結論盒使,隨機找一段話崩掘,然后尋找相似的,目前來看少办,不帶卷積的效果非常好苞慢,帶卷積的因為卷積后信息損失太大,在encoder-decoder階段感覺無法訓練了英妓,最后趨同挽放,因此需要對卷積進行較大調整。關于NLP的卷積蔓纠,其實我們不一定要保證卷積核的寬度或者高度保持和word embedding的size一樣辑畦,因為對兩個word截取其一般,我認為應該還是有一定的相似度的腿倚。
在訓練過程中纯出,損失函數我嘗試了:
xent =tf.reduce_mean(tf.pow([y_true, y_pred],2), name="xent")
以及
consine = tf.div(tf.reduce_sum(tf.multiply(y_pred, y_true)),
tf.multiply(tf.sqrt(tf.reduce_sum(tf.multiply(y_pred, y_pred))),
tf.sqrt(tf.reduce_sum(tf.multiply(y_true, y_true)))))
xent = tf.reduce_sum(tf.subtract(tf.constant(1.0), consine))
因為采用歐式距離,我們難以確定相似度的閾值敷燎,而cosine是一個比較容易衡量的值暂筝。所以這里選擇了consine作為損失函數。我沒有找到Tensorflow的實現(xiàn)硬贯,所以完全根據consine公式自己實現(xiàn)了一個焕襟。
對于Optimizer,我嘗試了
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(xent)
train_step = tf.train.RMSPropOptimizer(learning_rate).minimize(xent)
目前來看,RMSPropOptimizer效果好很多饭豹。
總結
現(xiàn)階段大量優(yōu)秀的人才都投入到了深度學習上鸵赖,所以深度學習也取得了越來越多的進展务漩,用法也越來越多,尤其是對抗學習它褪,加強學習饵骨,對偶學習的發(fā)展讓深度學習可以做的事情越來越多。深度學習在NLP文本分類列赎,特征抽取方面宏悦,我覺得還是有潛力可挖的。不過包吝,我覺得深度學習其實是把機器學習的門檻提的更高了,雖然越來越多的工具(比如Tensorflow)和已知的各種實踐似乎在降低某些門檻源葫。