歡迎光臨
每天分享高質量文章

flask+seq2seq實現聊天機器人線上群聊

在大多數標準中,Flask都算是小型框架,小到可以稱為“微框架”,所以你一旦熟悉使用它,很可能就能讀懂他所有的原始碼,本專案是自己線下玩的專案,因此採用了Flask這種小而功能比較全的框架。

TensorFlow是Google於2015年11月9日正式開源的深度學習框架,提供了海量的深度學習模型的API,可以快速的實現深度學習模型的搭建。目前在GitHub上的star也是驚人:

基於Python的TnesoFlow介面,訓練seq2seq模型用於娛樂性的聊天機器人場景。 Seq2Seq被提出於2014年,最早由兩篇文章獨立地闡述了它主要思想,分別是Google Brain團隊的《Sequence to Sequence Learning with Neural Networks》和Yoshua Bengio團隊的《Learning Phrase Representation using RNN Encoder-Decoder for Statistical Machine Translation》。這兩篇文章針對機器翻譯的問題不謀而合地提出了相似的解決思路,Seq2Seq由此產生。Seq2Seq解決問題的主要思路是透過深度神經網路模型(常用的是LSTM,GRU)將一個作為輸入的序列對映為一個作為輸出的序列,這一過程由編碼(Encoder)輸入與解碼(Decoder)輸出兩個環節組成, 前者負責把序列編碼成一個固定長度的向量,這個向量作為輸入傳給後者,輸出可變長度的向量。

首先我們基於問答語料庫去訓練我們的seq2seq聊天機器人系統,其核心演演算法主要如下:

“`python def getmodel(feedprevious=False): “”” 

構造模型:seq2seq feed_previous

表示decoderinputs是我們直接提供訓練資料的輸入, 還是用前一個RNNCell的輸出映射出來的,如果feedprevious為True, 那麼就是用前一個RNNCell的輸出,並經過Wx+b線性變換 “””

learning_rate = tf.Variable(float(init_learning_rate), trainable=False, dtype=tf.float32)
learning_rate_decay_op = learning_rate.assign(learning_rate * 0.9)

encoder_inputs = []
decoder_inputs = []
target_weights = []
for i in range(input_seq_len):
    encoder_inputs.append(tf.placeholder(tf.int32, shape=[None], name="encoder{0}".format(i)))
for i in range(output_seq_len + 1):
    decoder_inputs.append(tf.placeholder(tf.int32, shape=[None], name="decoder{0}".format(i)))
for i in range(output_seq_len):
    target_weights.append(tf.placeholder(tf.float32, shape=[None], name="weight{0}".format(i)))

# decoder_inputs左移一個時序作為targets
targets = [decoder_inputs[i + 1] for i in range(output_seq_len)]

cell = tf.contrib.rnn.BasicLSTMCell(size)

# 這裡輸出的狀態我們不需要
outputs, _ = seq2seq.embedding_attention_seq2seq(
                    encoder_inputs,
                    decoder_inputs[:output_seq_len],
                    cell,
                    num_encoder_symbols=num_encoder_symbols,
                    num_decoder_symbols=num_decoder_symbols,
                    embedding_size=size,
                    output_projection=None,
                    feed_previous=feed_previous,
                    dtype=tf.float32)

# 計算加權交叉熵損失
loss = seq2seq.sequence_loss(outputs, targets, target_weights)
# 梯度下降最佳化器
opt = tf.train.GradientDescentOptimizer(learning_rate)
# 最佳化標的:讓loss最小化
update = opt.apply_gradients(opt.compute_gradients(loss))
# 模型持久化
saver = tf.train.Saver(tf.global_variables())

return encoder_inputs, decoder_inputs, target_weights, outputs, loss, update, saver, learning_rate_decay_op, learning_rate

訓練好的模型會儲存在model檔案夾,供flask呼叫。我的語料是在網上找的一些還有就是自己編造了一些,語料很不規整也不全面,量也比較少,因此模型的表現並不是很理想,加上本身seq2seq模型的不可控性,會出現聊天機器人比較傻叉的回答和答非所問的情況(這個如果要商用還得考慮更多其他的trick這裡只是娛樂性的嘗試)。

我用CPU訓練了10000個epoch,經過308分鐘,模型訓練好了。。。(此處應該有掌聲)

下麵就是基於flask搭建一套線上聊天系統了,這裡基於redis快取資料庫的訂閱與傳送機制實現一個簡單的SSE事件流(這個方法是我參考了GitHub一位大神的思路),當然我們也可以基於Flask-SSE模組,下麵是專案的結構,和部分核心程式碼:

專案結構:

flask核心演演算法:

python app.secret_key='xujing in inter-credit'

redis資料庫

r=redis.StrictRedis(host='xxx.xxx.xxx.xxx',port=6379,db=123,decode_responses=True)

定義事件流

def eventstream(): 
    pubsub=r.pubsub() #用於檢視訂閱與釋出系統狀態,傳回由活躍頻道組成的串列 
    pubsub.subscribe('lxchat'#用於訂閱給定的一個或多個頻道的資訊,傳回接收到的資訊 
    for message in pubsub.listen(): #監聽活躍頻道組成的串列 
        print(message) 
    yield 'data:{}\n\n'.format(message['data'])

傳送訊息

@app.route('/send',methods=['POST']) 
def post():
    message=flask.request.form['message'
    user=flask.session.get('user','anonymous'
    now=datetime.datetime.now().replace(microsecond=0).time() #日期去掉毫秒,只取時間 little_x = predict(message) #呼叫模型做預測

r.publish('lx_chat','[{}] {} : {}xujing_replace[{}] 小X : {}'.format(now.isoformat(),user,me

訓練好了模型,有了flask的呼叫,現在就可以在伺服器上部署了,可以使用flask+nginx+uwsgi的方式部署這個聊天系統,體驗一下和機器人的尬聊:(下麵截圖,看我如何尬聊)

登入介面:

開始聊天:

這隻是一個不成功的嘗試,要提高聊天機器人的聊天質量,呼叫速度,聊天介面的人機互動和美觀性,還有很長的路要走,更不是一個人可以完美搞定的,我再努力最佳化。

專案所有原始碼我已託管到

GitHub:github.com/DataXujing/x (點選閱讀原文即可)

進來之後帶走原始碼,留下Star和issues。

溫馨提示,想要執行程式碼別忘了安裝必要的模組:

pip install -r requirements.txt

作者:徐靜
源自:https://zhuanlan.zhihu.com/p/41223006
贊(0)

分享創造快樂