【聊天機器人】深度學習構建檢索式聊天機器人原理

一、檢索式與生成式聊天機器人對比

1、基於檢索的chatterbot

在這裏插入圖片描述

2、基於生成的chatterbot

在這裏插入圖片描述

3、聊天機器人的一些思考:

(1)基於檢索的chatterbot

  • 根據input和context,結合知識庫的算法得到合適回覆。
  • 從一個固定的數據集中找到合適的內容作爲回覆
  • 檢索和匹配的方式有很多種(可以基於機器學習判斷屬於那種類型的匹配,利用關鍵字+word2vec進行文本相似度匹配)
  • 數據和匹配方法對質量有很大影響

(2)基於生成模型的chatterbot

  • 典型的是用seq2seq方法
  • 生成的結果需要考慮通暢度和準確度
  • 深度學習是學習數據的特徵。對於認爲很重要的特徵,可以最後在全連接層時進行矩陣拼接加入,而不參與特徵之間的學習,以免造成影響。

以前者爲主,後者爲輔;檢索方法過程中當模型需要算法是,可以考慮加入深度學習。

4、chatterbot的問題

(1)應答模式的匹配方法太粗暴

  • 編輯距離無法捕獲深層語義信息
  • 核心詞+word2vec無法捕獲整句話語義(對於我 愛 你和你 愛 我,詞向量表示是一樣的)
  • LSTM等RNN模型能捕獲序列信息
  • 用深度學習來提高匹配階段準確率

(2)特定領域+檢索+合適的知識庫能做到還不錯。但開放域比較難

5、轉化爲機器學習或深度學習能夠解決的問題,應該怎麼做

(1)匹配本身是一個模糊的場景
轉成排序問題
(2)排序問題怎麼處理?
轉成能輸出概率的01分類
(3)數據構建?
需要正樣本(正確的答案)和負樣本(不對的答案)
(4)Loss function
分類問題採用對數損失(二元的交叉熵損失)
在這裏插入圖片描述)

二、使用深度學習完成問答:

1、論文

IMPLEMENTING A RETRIEVAL-BASED MODEL IN TENSORFLOW,WILDML BLOG,2016

2、論文框架圖

在這裏插入圖片描述

三、深度學習問答數據

1、中文:

Microsoftz做法是,從其他不同的場景裏,以相同的概率抽取答案,成爲負樣本。當前場景的問答作爲正樣本。

2、Ubuntu對話語料庫:

(1)訓練集:

  • Ubuntu對話數據集,來自Ubuntu的IRC網絡上的對話日誌
  • 訓練集1000000條實例,一半是正例(label爲1),一半是負例(label爲0,負例爲隨機生成)
  • 樣本包括上下文信息(context,即Query)和一段可能的回覆內容,即Response;Label爲1表示Response和Query的匹配,Label爲0表示不匹配
  • query的平均長度爲86個word,而response的平均長度爲17個word。

(2)驗證集/測試集:

  • 每個樣本有一個正樣本和9個負樣本(也稱爲干擾樣本)
  • 建模的目標是給正例的得分儘可能高(排序越靠前),而負例的得分儘可能低(有點類似分類問題)
  • 語料做過分詞、stemmed、lemmatized等文本預處理
  • 用NER(命名實體識別)將文本中的實體,如姓名、地點、組織、URL等替換成特殊字符。

(3)評估準則:

  • recall@k(在前k個位置,能夠找回標準答案的概率有多高)
  • 經模型對候選的response排序後,前k個候選中存在正例數據(正確的那個)的佔比
  • k值越高,指標值越高,對模型性能的要求越松。

四、基線模型代碼實現:

import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

#導入數據
train_df = pd.read_csv("../data/train.csv")
test_df = pd.read_csv("../data/test.csv")
validation_df = pd.read_csv("../data/valid.csv")
y_test = np.zeros(len(test_df))
#定義評估指標
def evaluate_recall(y,y_test,k=n):
    num_examples = float(len(y))
    num_correct = 0
    for predictions,label in zip(y,y_test):
        if label in predictions[:k]:
            num_correct += 1
    return num_correct/num_examples
#從len(utterances)中隨機抽取數字,生成size=10的數組

1、基線模型:

#定義隨機預測函數
#從len(utterances)中隨機抽取數字,生成size=10的數組
#replace:True表示可以取相同數字,False表示不可以取相同數字
def predict_random(context,utterances):
    return np.random.choice(len(utterances),10,replace=False) 
#生成隨機預測結果 
y_random = [predict_random(test_df.Context[x],test_df.iloc[x,1:].values) for x in range(len(test_df))]
#對前k=1,2,5,10分別進行評存在的正樣本概率評估
for n in [1,2,5,10]:
    print(f'Recall @ ({n},10):{evaluate_recall(y_random,y_test,n):g}')    

輸出結果:
Recall @ (1,10):0.0992072
Recall @ (2,10):0.199313
Recall @ (5,10):0.50037
Recall @ (10,10):1

2、基線模型:TF-IDF檢索

class TFIDFPredictor():
    def __init__(self):
        self.vectorizer = TfidfVectorizer()
    def train(self, data):
        self.vectorizer.fit(np.append(data.Context.values,data.Utterance.values))
    def predict(self,context,utterances):
        #將輸入問題Q轉化爲向量
        vector_context = self.vectorizer.transform([context])
        #將回答A轉化爲向量
        vector_doc = self.vectorizer.transform(utterances)
        #將回答向量與問題向量做矩陣相乘
        result = np.dot(vector_doc,vector_context.T).todense()
        result = np.asarray(result).flatten()
        ##將result中的元素從小到大排列,提取其對應的index(索引)。再將索引進行倒敘排列(越在前面,概率越大)
        #argsort
        return np.argsort(result,axis=0)[::-1] 
pred = TFIDFPredictor()
pred.train(train_df)
y = [pred.predict(test_df.Context[x],test_df.iloc[x,1:].values) for x in range(len(test_df))]

for n in [1,2,5,10]:
    print(f'Recall @ ({n},10):{evaluate_recall(y,y_test,n):g}')

輸出結果:
Recall @ (1,10):0.485624
Recall @ (2,10):0.586681
Recall @ (5,10):0.762474
Recall @ (10,10):1

五、神經網絡建模原理

1、Query 和Response都是經過分詞和embedding映射的。初始向量使用GloVe/word2vec
2、分詞且向量化的Query和Response經過相同的RNN(word by word)(同一組參數)。RNN最終生成一個向量表示,捕捉了Query和Reponse之間的【語義聯繫】(圖中的c和r);這個
向量的維度是可以指定的,這裏指定爲256維。
3、將向量c與一個矩陣M相乘,來預測一個可能的回覆r‘。如果c爲一個256維的向量,M維是256*256的矩陣,兩者相乘的結果爲另一個256維向量,我們可以將其解釋爲【一個生成式的回覆向量】。矩陣M是需要訓練的參數
4、通過點乘的方式來預測生成的回覆r’和候選的回覆r之間的相似程度,點乘結果越大表示候選回覆最爲回覆的可信度越高;之後通過sigmoid函數歸一化,轉成概率形式。(sigmoid作爲壓縮函數經常使用)
5、損失函數:二元的交叉熵函數/對數函數。回想邏輯迴歸,交叉熵損失函數爲L = -y * ln(y’)- (1 - y) * ln(1 - y’)。(公式的意義是直觀的,即當y=1時,L=-ln(y’),我們希望y’儘量接近1,使得損失韓式的值越小‘反之亦然。)
在這裏插入圖片描述
使用Tensorflow的話訓練速度主要受2方面影響。一、讀數據(例如,訓練數據是512兆的文本數據,100w個長文本。是很大的數據集),開銷會很大。可以使用Tensorflow能都讀進去的格式tdrecords。可以用Tensorflow自帶的工具進行讀入和處理。如一個batch或構建一個隊列。二、GPU處理的速度。可以構建一個隊列 query,在隊列裏不斷去數據,以跟的上入讀數據的速度。

神經網絡代碼實現在下篇文章中具體闡述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章