天天看點

如何在Chatbot中應用深度學習?

編者按:本書節選自圖書《深度學習算法實踐》,本書以一位軟體工程師在工作中遇到的問題為主線,闡述了如何從軟體工程思維向算法思維轉變、如何将任務分解成算法問題,并結合程式員在工作中經常面臨的産品需求,詳細闡述了應該怎樣從算法的角度看待、分解需求,并結合經典的任務對深度學習算法做了清晰的分析。

公開課福利: CSDN學院邀請到本書作者吳岸城,他将分享的主題為「深度學習中基礎模型性能的思考和優化」。報名連結:http://edu.csdn.net/huiyiCourse/detail/536

人類其實從很早以前就開始追求人類和機器之間的對話,早先科學家研發的機器在和人對話時都是采用規則性的回複,比如人提問後,計算機從資料庫中找出相關的答案來回複。這種規則性的一對一比對有很多限制。機器隻知道問什麼答什麼,卻不知道舉一反三,比如你問它:“今天天氣怎麼樣?”它會機械地把今天的天氣告訴你。這不像人與人之間的對話,人是有各種反應的,這類反應的産生是基于人的知識結構和對話場景的。

那麼,你覺得這類機器是否真的具有智能了?圖靈測試是這樣判斷機器人是否具有智能的:測試中,一個正常人将嘗試通過一連串的問答,把被試的機器與人類區分開來。一般來說,如果正常人無法分辨和自己聊天的是人還是機器人的時候,機器人就算通過測試了。

圖靈測試的關鍵之處在于,沒有定義“思維/意識”。隻是将機器人作為黑盒,觀察輸入和輸出是否達标。是以說它從一開始就繞開了“機器能思考嗎?”這樣的問題,而是把它替換成另外一個更具操作性的問題——“機器能做我們這些思考者所做的事嗎?”。大家注意這兩者其實完全不是一個層次的問題。

然而,“機器能思考嗎?”和“機器能做我們這些思考者所做的事嗎?”這兩個問題真的可以互相替代嗎?

比如說,機器能夠寫詩,甚至比許多資質平庸的人寫出的詩更像樣子。如果我們人為拟定一套标準,來為機器和人寫的詩打分,那麼完全有可能設計出一台能夠赢過絕大多數詩人的寫詩機器。但這真的和人類了解并欣賞一首詩是一回事嗎?再比如,人工智能在國際象棋、圍棋領域已經比人類更強大,但這真正和人類思考如何下棋是一樣的嗎?

世界上有這麼一個關于圖靈測試的獎項——“勒布納獎”,頒給擅長模仿人類真實對話場景的機器人。然而,這個獎項大多數的獲得者都沒有看上去那樣智能。比如一個人問一台機器“你有多愛我?”,如果它想通過圖靈測試,它就不停地顧左右而言他,比如回答“你覺得呢?”事實上大多數問題都可以用反問去替代,說白了這些僅僅是一些對話技巧。而獲勝者并沒有真正了解“你有多愛我?”這樣的問題。

這裡有句話,希望大家記住:人工智能的真實使命是塑造智能,而非去刻意打造為了通過某類随機測試的“專業”程式。

所幸到今天為止,很多學者都意識到了圖靈測試的局限性,如果我們要發明人工智能,就要真正清楚地定義人工智能。同樣如果我們要做智能對話,我們也要清晰地定義智能對話。

在2013年的一次國際會議上,來自多倫多大學的計算機科學家發表了一篇論文,對“圖靈測試”提出了批評。他認為類似這樣的人機博弈其實并不能真正反映機器的智能水準。對于人工智能來說,真正構成挑戰的是這樣的問題:

鎮上的議員們拒絕給憤怒的遊行者提供遊行許可——“因為他們擔心會發生暴力行為”——是誰在擔心暴力行為?

A.鎮上的議員們

B.憤怒的遊行者

類似這樣的問題,機器有沒有可能找到正确的答案?要判斷“他”究竟指代誰,需要的不是文法書或者百科辭典,而是常識。人工智能如何能夠了解一個人會在什麼情況下“擔心”?這些問題涉及人類語言和社會交往的本質,以及對話的前後語境。這些本質其實是一種規則,而這種規則是在不停變化的。正是在這些方面,目前人工智能還無法與人類相比。

這意味着,制造一台能與人類下棋的機器人很容易,但想要制造一台能了解人類語言的機器人卻很難。

為了更好地了解機器對話,英特将現有的對話技術進行總結并畫出流程圖(見圖3-1),這裡面涉及的邏輯和子產品較多,英特是從模拟人類對話的第一步,即了解人類的語言開始的,當然要做到完全了解人類的語言在目前來講也不太可能。對于機器人來說,無論何種用途的機器人,首要需要解決的就是了解人類說了些什麼,而除了指令句式以外,了解人類說什麼就是了解人類提出的各種問題。請移步下一節來看看如何了解人類的提問。

如何在Chatbot中應用深度學習?

圖3-1 對話流程圖

了解人類提問

英特調查後發現對于中文問題來說,無非可以分成以下兩類:疑問句和反問句。對于反問句當然沒什麼好說的,我們來重點看看疑問句。可以分為是非問句、正反問句、特指問句、選擇問句,其中特指問句又可以分為人、原因、地點、時間、意見、數量、方式和其餘的實體。

對于問題來說,人類也需要首先對句子做一個判斷,拿特指問題來說,需要判斷到底是問什麼?接着将每個問題做一個初步的定位,縮小回答時的搜尋範圍,最後從知識體系和場景中取得答案。

英特團隊按照句式結構找了些例句放進去,為後一步的句式分類準備好訓練集。

比如在“特指問句_時間”裡放入了如下例句。

中國第一部憲法頒布的時間?

哪天你有空?

演唱會是哪天?

又比如“特指問句_原因”裡放入如下例句。

為什麼人的面容千差萬别?

為什麼我感覺不到演員演技的好壞?

為什麼不要空腹喝牛奶?

用我們在第2章提到的任意特征提取器、分類模型,我們都能得到一個基本準确的輸出,比如問題“還有多久輪到我們”。

Enter the sentence you want to test(“quit” to break):還有多久輪到我們
Sentence Type:  疑問句_特指問句_時間 -- <type ‘str’>
How much: 
疑問句_特指問句_時間 --> 0.568171744082
陳述句_轉折複句 --> 0.0833727296382
陳述句_目的複句 --> 0.0702280010834
陳述句_時間複句 --> 0.0467500544003
陳述句_連鎖複句 --> 0.0389512385469
疑問句_特指問句_地點 --> 0.0360868190755
陳述句_因果複句 --> 0.023920374049
疑問句_選擇問句 --> 0.0149039847156
疑問句_特指問句_意見 --> 2.89120579329e-19
髒話_增強語氣 --> -0.00288297881955
髒話_惡意髒話 --> -0.00377381341484
           

答案的抽取和選擇

在答案的提取階段,一般的對話像常見的智能對話助手Siri、小冰等,都是有對應的問題答案組(QA)的,這種QA數量一般都接近百萬級了。而在現實工作中,沒有能力和精力人工組建QA怎麼辦?這個時候我們可以使用網際網路的資訊——利用爬蟲爬取。

大體過程是這樣的:

(1)定義一個爬蟲,針對某些問題的特點爬取候選答案。

(2)答案的抽取。從離線或線上知識庫抽取候選答案,候選答案一般有多條。

(3)答案的選擇。從候選答案中提取真正有效的回答。

下面用一個簡單的例子來做說明。

首先是爬蟲,這裡我們以“百度知道”為爬取目标,爬取相關問題及答案的前幾名。

def getAnswerfromZhiDao(question):
    """
    Scrap answers from ZhiDao(百度知道 )
    :param question:
    :return:
    """
    tic = time.time()
    global zhidaoHeader
    URL = ZHIDAO + "/index?rn=10&word=" + question
    # print(URL)
    Answer = []
    http = httplib2.Http()
    # 聲明一個CookieJar對象執行個體來儲存cookie
    cookie = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
    req = urllib2.Request(URL)
    response = opener.open(req)
    zhidaoHeader['Cookie'] = response.headers.dict['set-cookie']
response, content = http.request(URL, 'GET', headers=zhidaoHeader)
           

上面的代碼是整個爬蟲的http請求header頭組裝及爬取url的組裝。

ZHIDAO = 'http://zhidao.baidu.com'
URL = ZHIDAO + "/index?rn=10&word=" + question
           

這裡參數rn=10 也就是要傳回10條答案。

比如使用者提問:唐太宗是誰?

組裝後URL = https://zhidao.baidu.com/index?rn=10&word=唐太宗是誰?

利用組裝的URL傳回答案條目如下。

如何在Chatbot中應用深度學習?
search_result_list = etree.HTML(content.lower()).xpath("//div[@class='slist']/p/a")
# time1 = time.time()
limit_num = 
for index in range(min(len(search_result_list), limit_num)):
    url = search_result_list[index].attrib['href']
    url = ZHIDAO + url
    # print(url)
    response, tar_page = http.request(url, 'GET', headers=zhidaoHeader)

    # 判斷是否做了重定向 301, 302
    if response.previous is not None:
        if response.previous['status'][] == '3':
            url = response.previous['location']
           

上一段程式先爬取答案的一級頁面,也就是上面截圖的頁面,然後再分别爬取前三個答案的詳細頁面,以得到具體的答案。也可以控制爬取詳細答案的數量:limit_num = 3。在爬取“百度知道”内容時需要注意重定向問題,以區分處理各種網站。

爬取了問題後,需要做答案的提取和選擇,第一步是找到有一定相關度的答案候選、縮小範圍;第二步就是選擇并提取答案。因為我們已經做了問題的分類,這裡要分情況來考慮。

(1)對于人、地點、時間等這種知道明确在問什麼,也知道明确的提取規則的,我們可以按照規則去抽取答案,按出現的頻率來評價答案。

(2)對于方式、原因等這樣的開放式問題需要用一句話或者一段話回答,可以先選擇一批備選答案,再從備選答案種挑一個最好的。

對于上面提到的問題:唐太宗是誰?這可以歸類到第一種情況。下面我們來看看這個問題的處理流程。

第一步,通過問題分類、問題了解,找到了這個答案屬于特指問題“人”。

第二步,針對這類問題,英特用了個小技巧,非常簡單但有效:如果我們确認要找的是人、人名等,可以在備選答案中選擇表示人的單詞,比如名詞、代詞,再計算它出現的頻率,比如“李世民”這個詞在答案中出現了10多次,就可以将它提取出來回報給使用者。

if tar == 'who':
    for i in words:
        if i.flag == 'nr' and i.word not in question:  # 人名
            humWord.append(i.word)
    return getTopWord(humWord, )
           

問數量的、問時間的、問地點的都可以照此處理。當然如果這裡單獨用了詞頻還是有問題,我們将範圍縮小一些找詞頻就能更準确:比如将“唐太宗是誰?”這個問題在答案裡做相似性比對,找到比對度很高的候選答案,再用以上的小技巧計算詞頻,當然在計算詞頻時,我們可以看看比如“李世民”這個詞出現在句中的位置,這能幫助我們進一步精确地抽取答案。

做到這一步,英特解決了簡單問句的回答,特别是針對時間、人物、地點等這種回答隻有一個詞的問句特别有效。但對話中大量出現上文提到的第二種情況,諸如問“如何”“怎麼樣”這類開放性問題,該如何處理呢?比如“唐太宗是個什麼樣的皇帝?”這樣的開放問題。對這類問題,來看看英特的解決方法:

第一步,通過問題分類、問題了解,找到了這個答案屬于特指問題“意見”。

第二步,求問題和檢索答案段落的文本相似性。相似性有很多種處理方式,思路之一是可以簡單地估計問題的關鍵詞占所有問題關鍵詞的比例(比如:唐太宗、皇帝),或者可以用word2vec、LSI來求相似度。

第三步,判斷答案是否由一個段落蘊含。這裡我們假設已經有了識别文本蘊含(RTE)的算法,并能準确找出“唐太宗勤勉治國,是個好皇帝。”是被蘊含的答案。

我們将答案提取打分的僞代碼總結如下:

ScoreAnswers(String[] answers, String[] passages, AnalyzedQuestion aq)
    scoredAnswersø
    foreach answer(answers):
        //特征1:段落和問題間的文本相似度
        textSimcalculateTextSimilarity(answer,passages,aq,question)
        //特征2:判斷一個蘊含問題
        entailedrecognizeEntailment(answer,passages, aq,question)
        //從特征值估算置信分值
        //通過增強置信分值來找到相似答案
        return scoredAnswers
           

通過相似度評分和蘊含評分得到答案的總體評分,然後再将答案排序輸出第一個答案。

對于相似度評分無需過多描述,但是蘊含呢?英特查了很多資料後決定了蘊含關系的研發方案。

蘊含關系

蘊含關系,是為了評價從一段文字中得到的推論是否符合原文的本意,我們這裡用蘊含關系來做答案中是否包含着問題的判斷,其實就是求某種語義上的相似性或相關性。

下面舉個例子。

T:第一次世界大戰(簡稱一戰;英語:World War I、WW I、Great War)是一場于1914年7月28日至1918年11月11日主要發生在歐洲,然而戰火最終延燒至全球的戰争,當時世界上大多數國家都被卷入這場戰争,是人類史上第一場全球性規模的大型戰争,史稱“第一次世界大戰”。

H:第一次世界大戰的時間

label:1 ← 這裡标簽為1,表示答案中蘊含問題。

T:第二十九屆奧林匹克運動會(英語:the Games of the XXIX Olympiad;法語:les Jeux de la XXIXe Olympiade),又稱2008年夏季奧運會或北京奧運會,于2008年8月8日至24日在中華人民共和國首都北京舉行。

H:東京奧林匹克運動會的舉辦時間

label:0 ← 這裡标簽為0,表示答案中沒有蘊含問題。

從例子可以看出,求蘊含關系就是求一個相似度,但還不完全像求相似度,蘊含關系中,選擇哪些特征才是這個算法在問答中應用的重點,隻要把特征選出扔到SVM分類器中就可以做訓練了。

一般提取哪些特征出來呢?我們先人工選擇特征并提取。看看代碼,除了詞的頻率和位置還可以提取下面這些特征(規律):

features['word_overlap'] = len(extractor.overlap('word'))
 # hyp 與 text 中重複的 word
features['word_hyp_extra'] = len(extractor.hyp_extra('word'))
 # hyp 有 但 text 中沒有的 word
features['ne_overlap'] = len(extractor.overlap('ne'))
# hyp 與 text 中重複的 ne
features['ne_hyp_extra'] = len(extractor.hyp_extra('ne'))
# hyp 有 但 text 中沒有的 ne
features['neg_txt'] = len(extractor.negwords & extractor.text_words)
# text 中的 否定詞
features['neg_hyp'] = len(extractor.negwords & extractor.hyp_words)     
# hyp 中的 否定詞
           

ne指的是命名實體(Named Entity),其中hyp指的是問題,大家觀察蘊含的示例代碼可以看出,英特在項目進行中發現光是名詞實體不足以提取到完整特征,于是将時間名詞、成語、狀态詞都加入到ne範疇中,提取規則同上保持不變。

當然如果你不想用人工方式提取答案和問題的特征,仍然可以用在第2章我們提到的CNN+RNN方式提取特征,而這種提取方式可以稍作變化,将詞性作為輸入加到Word Embedding層後。

生成式對話模型(Generative Model)

前面的這類方法可以總結為檢索式方法,其思路是從一個已知的大知識資料庫 中搜尋并組合出相應的答案,這種搜尋方式可以伴随一些預定好的規則,比如:{who} 想要糖果?回答:我想要{ pronoun }。 這個{ pronoun }可以從資料庫找出相應的代詞填入。而這種回答的規則可以用一種通用的XML檔案來描述,我們稱它為AIML2.0。

另外還需要擁有初級的邏輯推理能力,比如IBM Watson ,而對于這類而言,我們除了需要制定相應的邏輯規則庫以外,還需要事實庫。在Python中我們可以選用pyke架構來管理相應的事實庫與邏輯規則庫。

以上無論是邏輯推理回答還是一般回答都可以稱作檢索式的或者規則式的方法。除此之外還有哪些方法可以給出答案呢?英特在調查中發現目前學界在RNN(LSTM)上的突破讓模型擁有了初級的‘學習’能力:基于神經網絡序列的生成式對話模型。

生成式對話模型算法的概念就是讓模型先看一些對話集,然後問它一句話,模型會通過從對話集學習的一些規律給你一個回答。簡單來說根據你的上一句話和學習到的所有對話集規律生成一個個單詞,這些單詞如果意義是連貫的那就是一句話!而這正好契合了對話模型。

聽上去很美好,而且一些大公司已做了很多工作,比如圖3-2所示的Google對話集:

如何在Chatbot中應用深度學習?

圖3-2 Google 對話集示例

Google的這個結果建立在訓練了3000萬條對話的基礎上,取其中的300萬條對話來做驗證集,并且去掉了專業名詞、數字和URL等。達到這種資料量級後,能夠對某一垂直領域類的問題做自由度較高的機器回複。

Google所用的生成式對話模型有哪些特點呢?下面來看看基于檢索式模型和生成模型之間的差別,是不是能找到一些特點。

基于檢索式模型(基于AIML2.0)使用了預定義回複庫和一種條件觸發式方法來根據輸入和語境做出合适的回複。這種觸發式方法一般基于規則的表達式比對,當然你也可以用機器學習分類器來處理這類觸發。檢索式模型的特點是它不會産生新文本,隻是從固定集合中挑選一種回複,套用農夫山泉廣告語:“我們不生産文本我們隻是集合的搬運工”。

生成式對話模型不依賴于預定義回複庫,從零開始生成新回複。生成式對話模型一般基于機器翻譯中的Seq2Seq技術,但應用場景有較大差别;機器翻譯的目标是:把一個輸入“翻譯”成一個輸出“回複”。輸入(翻譯)再輸出(回複)就是編碼器(encoder)經資訊編碼後再經解碼器(decoder)解碼的過程,而在對話中輸入人說的話再輸出機器的回複(如圖3-3所示)。

如何在Chatbot中應用深度學習?

圖3-3 Seq2Seq結構

編碼器(encoder)是對于人的提問或對話的編碼,可以看作是機器對問題的一種了解,而解碼器(decoder)是機器對問題的一種回複。

是不是生成式對話模型就遠比檢索式要好呢?可以說目前為止,還隻是各司其職,各自有不同的應用場景:

(1)檢索式模型由于采用人工制作的回複庫,基于檢索式方法不會有文法錯誤,當然我們使用搜尋引擎作為回複庫,也很少有文法錯誤。然而使用回複庫不能處理沒出現過的情況,因為它們沒有合适的預定義回複。同樣,這些模型不能重新利用提上下文中的實體資訊,如先前對話中提到過的名字。綜上,檢索式模型可以用在需要正确回答問題的場合,對答案的文法和準确性要求比較高。

(2)生成式對話模型從原理上講更“聰明“些。它們可以重新提及輸入中的實體并帶給你一種正和你對話的感覺。然而,這類模型很可能會犯文法錯誤(特别是輸入一個長句時),而且通常要求大量的訓練資料。綜上,生成式對話模型可以用在要求不那麼精确的對話中。比如遊戲的NPC交談,比如一般的生活類對話場景。

雖然生成式對話模型有一些缺點,但畢竟是一個很好的方向,英特選擇使用TensorFlow來實作這個結構。

前文提到,生成式對話模型是基于生成式機器翻譯模型,而機器翻譯模型用的就是Seq2Seq(Sequece2Sequence)結構 。我們先來了解下Seq2Seq結構:Seq2Seq由編碼器和解碼器組成,輸入的單詞以序列化的方式傳入編碼器,最終得到表示一句話的上下文特征向量;解碼器接收特征向量以及每次的輸出單詞,做序列化的解碼,輸入和輸出以終止。

對于編碼器來說,為了進一步提高生成的準确性,其輸入部分需要更多的句子特征,除一般的word2vec表示外,我們還可以引入單詞的詞性、句子成分、單詞的重要性(TF-IDF)作為額外的特征。

下面我們看一個編解碼器的例子(也是Seq2Seq的核心構件)。

編碼器代碼如下。

# Encoder
encoder_cell = rnn_util.MultiEmbeddingWrapper(
    cell,
    embedding_classes=num_encoder_symbols,
    embedding_size=encoder_embedding_size
)
encoder_outputs, encoder_state = rnn.rnn(
        encoder_cell, encoder_inputs, dtype=dtype)
           

解碼器代碼如下。

# Decoder.
output_size = None
if output_projection is None:
    cell = rnn_cell.OutputProjectionWrapper(cell, num_decoder_symbols)
    output_size = num_decoder_symbols
……

def decoder(feed_previous_bool):
    reuse = None if feed_previous_bool else True
    with variable_scope.variable_scope(variable_scope.get_variable_scope(), reuse=reuse) as scope:
        outputs, state = embedding_attention_decoder(
            decoder_inputs,
            encoder_state,
            attention_states,
            cell,
            num_decoder_symbols,
            embedding_size=decoder_embedding_size,
            num_heads=num_heads,
            output_size=output_size,
            output_projection=output_projection,
            feed_previous=feed_previous_bool,
            update_embedding_for_previous=False,
            initial_state_attention=initial_state_attention)
        state_list = [state]
        if nest.is_sequence(state):
            state_list = nest.flatten(state)
        return outputs + state_list

outputs_and_state = control_flow_ops.cond(feed_previous, lambda: decoder(True), lambda: decoder(False))
           

這裡解釋下解碼器中的Attention層,Attention層的思想也是來自于翻譯領域,即前文出現的單詞也可能出現在後面的回答中,比如說人名、地名等資訊。Attention層是在編碼器隐藏層和解碼器之間的網絡結構,在某一時刻t時,接收解碼器的隐藏層資訊,生成目前時刻的加載到編碼器隐藏層上的權重。

英特訓練了10萬條有關星巴克的微網誌資訊,最終取得了不錯的結果,我們先來看看中間的輸出過程(如圖3-4所示)。

如何在Chatbot中應用深度學習?

圖3-4 經過5 epoch後的訓練結果

圖3-4是英特用和星巴克有關的微網誌資料訓練了5 epoch後得到的結果。可以看出,在5 epoch時,模型還無法說出一個完整的句子,甚至都無法表達通順的短語,但是模型在不停的學習中回答越來越準确,下面的圖3-5是訓練了50 epoch後的最終結果。

如何在Chatbot中應用深度學習?

圖3-5 經過50 epoch後的訓練結果

英特對最終結果分析後發現仍然會存在一些問題:第一就是前文提到的會有一些文法錯誤;第二需要大量的訓練資料。

第一個問題主要受限于現在的模型原理。目前暫時沒有哪個模型或者衍生的模型能解決好。

再看第二點,如何擷取大量的訓練資料。憑借英特的經驗,對于普适性的對話模型可以從兩類途徑擷取:一是從電視劇中擷取相關資料;二是從微網誌、QQ聊天記錄中擷取相關資料。

對于一些專業性比較強的領域,就要求在本專業領域收集資料了,如上文提到的Google将自己IT 服務部門的所有對話拿來訓練。在任何稍微開放領域的應用上,比如像回複一封工作郵件,就超出了該模型現有的能力範圍。但退一步來講,仍舊可以利用模型建議和改正回複來“輔助”人類工作者;然後在這個過程中讓模型學習人類真實的回複語句,不斷更新出一個符合人類習慣的對話模型。

判斷機器人說話的準确性

英特團隊在做完以上工作後,發現機器說的話有些已經有成形的答案,還有些不通順、不成句子。這涉及另外一個問題,我們如何評價模型呢?如何判斷哪些模型的哪些調整有助于提高輸出句子的通順性或準确度?

英特浏覽了相關的論文,發現針對這類問題有很多評價辦法,最終英特選擇了最早出現在翻譯界的方法:BLEU評測方法。

BLEU(Bilingual Evaluation understudy)方法由IBM提出,這種方法認為如果機器翻譯的譯文越接近人工翻譯結果,那麼它的翻譯品質越高。是以,評測關鍵就在于如何定義系統譯文與參考譯文之間的相似度。BLEU采用的方式是比較并統計共現的n-gram個數,即統計同時出現在系統譯文和參考譯文中的n-gram的個數,最後把比對到的n-gram的數目除以系統譯文的單詞數目,得到評測結果。

最開始提出的BLEU法雖然簡單易行,但是它沒有考慮到翻譯的召回率。後來對BLEU做了修正,即首先計算出一個n-gram在一個句子中最大可能出現的次數MaxRefCount(n-gram),然後再和候選譯文中的這個n-gram出現的次數比較,取它們之間最小值作為該n-gram的最終比對個數。

智能對話的總結和思考

前面的工作可以總結為簡單流程圖(如圖3-6所示)。

如何在Chatbot中應用深度學習?

圖3-6 對話簡單流程

該流程一共包括4個主要子產品。正如本章開始時所分析的那樣,最優先解決的是問答,與其說這是一個智能對話機器人不如說這其實就是資訊檢索和總結的過程,因為聊天畢竟不是一個人的事,它必然是一個互動的過程(程式與人的互動過程)。而解決互動過程最好的方法就是應用強化學習(reinforcement learning),我們會在後面的章節中對該算法做具體的實驗說明,這裡僅簡單描述:強化學習是用來解決程式與環境的互動問題的,即讓程式對目前所處的環境做出必要的反應。

假定我們站在機器的角度來考慮問題,所處的環境為聊天室,看到的全是我與對方的聊天記錄,我們要做的就是在适當的時刻給出合适的回複,那麼這裡就需要做三件事:

(1)看懂聊天記錄(state);

(2)量化回複所用的語言(action);

(3)針對對話的過程打分(value function)。

第一件事就是文本特征提取過程(CNN),此處不再贅述。

第二件事有兩種處理思路:

(1)把句子作為動作分解成兩個過程,輸出量化後的動作,再根據量化值生成一句話;

(2)把字作為一個動作,允許連續輸出多個動作。

第三件事最為重要,一個好的評價函數是決定強化學習效率的關鍵,這裡也有兩種思路可以考慮:

(1)以對抗的方式訓練一個句子的打分器,但這需要大量的标注的對話語料;

(2)最新的評價一個對話品質的觀點是根據對方是否願意和你聊天來判斷,即根據對話的回合數直接對對話打分。

這樣就把對話過程模組化成一個強化學習的過程了。

綜上,對話問題雖然得到了一定的解決,但并沒有在所有領域都取得較好的效果,還需要不斷優化,目前最好作為輔助功能。另一方面,如果要回答前面提到的常識性的問題,就需要“規則”和“常識”來處理。“規則常識”其實是對實體的一種映射,這種映射需要不停地存入新的常識并更新,是以常識性的問題少不了知識圖譜 的支援,基于檢索式的方法結合知識圖譜的使用,将使問題回答的準确性有一個質的提高。

這樣就引來了如下思考,如果前面的檢索方式并不能夠解決多輪對話問題,假設出現這樣的一個問題“他是做什麼的呢?”,那麼我們光看這句話明顯不知道“他”指的是誰?此時就需要使用指代消解來解決。筆者所在的團隊在這方面已經有了初步的效果,目前已經能實作5輪 左右的對話。這裡簡單例舉幾種指代的處理方式。

(1)原因詢問。

A:她昨天又沒來。B:為什麼?

“為什麼”就指前一句話的内容,這時候B問的是為什麼她昨天又沒來。

(2)同義替換。

A:今天天氣怎麼樣。B:今天天氣不錯。A:明天呢?

明天呢?替換成明天天氣怎麼樣?這裡将明天和今天替換,這是同義詞性的替換。

(3)結構補充。

A:周傑倫是幹啥的?B:唱歌的。A:出過哪些專輯?

這裡“出過哪些專輯?”替換成“周傑倫出過哪些專輯?”這是結構缺失,要去前文找相似結構位置的主題詞并補充。

以上三種情況已經可以涵蓋多數場景,讀者可以根據這些思路解決更多的指代問題,為多輪對話貢獻自己的力量。

對話的部分講到這裡可以告一段落了,人類對于智能機器人的渴求已越來越迫切,而智能的重要表征就在于對話能力,對話能反映出智能的程度,這方面的研究也隻是剛剛開了個頭,還有很多未知的領域需要我們去探索。筆者非常慶幸我們能生活在這個時代,有信心在有生之年看到真正的智能産生。

作者簡介:吳岸城,緻力于深度學習在文本、圖像領域的應用。曾中興通訊、亞信聯創擔任研發經理、技術經理等職務,現任菱歌科技首席算法科學家一職。

【CSDN線上公開課】圖像算法大多都以提高精度為目标,那麼如何在現有模型基礎上提高精度呢?現在的CNN網絡,已經優化得不能再優化了,我們還能繼續提高基礎的CNN網絡準确度嗎?為此,CSDN學院邀請到菱歌科技首席算法科學家吳岸城,他将分享的主題為「深度學習中基礎模型性能的思考和優化」。點選下圖立即報名

如何在Chatbot中應用深度學習?

繼續閱讀