Baseline Methods for Multi-Turn Response Selection

多輪對話選擇之基線作法 (ML 2018 Final Project at NTUEE)

Posted by Jexus on July 6, 2018

Recently by the same author:


美國 EECS 博士班申請經驗分享 (ML/DL/NLP/Speech)

2021 Fall NLP/Speech PhD Application

You may find interesting:


Which layer preserves the best cross-lingual representations in multilingual-BERT?

Small experiments on multilingual-BERT


What has the positional "embedding" learned?

Small probing experiments on the positional embeddings

Some Baseline Methods for Multi Turn Response Selection

Machine Learning Final Project - conversations in TV shows

此文為本學期 Machine Learning 課程的 Final Project Report

Introduction & Motivation :

本次主題為電視劇對話中的台詞,給出上文(可能1句~4句不等),在六個選項中找出正確的下文,其中上文可能是同一個人的台詞,也可能是對話。其實這個題目就是常見的”多輪對話”問題,不同於”QA問題”是單次問答,這種題目需要考慮到前後文的關係,所以更加困難。這種問題的model也是目前在generative language model 還表現不好的狀況之下,可以用大量語料庫搜索適合的response,來實現聊天機器人效果的好方法,是目前較為實際且能夠直接應用的方法。

Data Preprocessing/Feature Engineering :

(1)分詞:

  • [jieba]
    效果較差,很多詞都分錯,錯誤率高,約50%句子會跟中研院分的不一樣。
    1. 分詞長度偏大,有時候會分成很怪的詞組,如"天就亮,了""誰,要,妳愛,上無藥,可救"。 2. 會把人名亂切開,如"林,明德""鍾,世民"。 (在presentation時,聽到某一組使用jieba,實驗發現跟不分詞直接一字一字斷開結果差不多,可能就是jieba分詞不夠好的緣故,畢竟是針對大陸簡體語料所做的套件)

  • [國教院中文分詞系統 NAER] https://github.com/naernlp/Segmentor
    (採純統計式模型,執行速度快)
    比jieba好很多,分詞較細,且人名不會被切開(可能有特別針對NER做處理),但還是有少部分分錯的時候,有時是一個詞包到前後錯字,有些是分得太細,如:"有,樣,學,樣"

  • [中研院中文斷詞系統 CKIP] http://ckipsvr.iis.sinica.edu.tw/
    (採經驗法則模型,執行速度較慢)
    分詞結果九成都跟國教院一樣(都正確的),但少部分國教院分錯的,中研院也能分對,效果最好,見下面例子。

    比較 example
    中研院(左) v.s. 國教院(右)
    可發現國教院把"不自量力"分成"不","自量力""駙馬爺","作對"分成"駙馬","爺作","對""鍾奎,幫,你"分成"鍾奎幫,你"

(2)Word2vec:

  • 使用Gensim,embedding size一開始使用1200(MLDS做seq2seq的經驗,維度盡量開大),針對直接算sent2vec的相似度的架構來說(Model 1),size比1200大和比1200小,效果都較差(數據見Experiment and Discussion),1200算是最好的size。
  • 但後來才發現,在針對RNN的架構時(Model 3、Model 4),似乎不適合開那麼大,反而100~200就能train得不錯,越大的維度反而訓練不起來,最後我們表現最好的model是使用100維作為embedding size。
  • Word2vec的方式,skip-gram跟CBOW都嘗試過,發現skip-gram效果較好,CBOW稍微差一些。
  • 其餘參數:
    • window = 7
    • min_count = 10
    • iter = 100

Model Description:

1. [Model 1] Sentence embedding -> cosine similarity — 最簡單的model

  • Sentence embedding : 將一句話斷詞之後,每個詞在訓練好的word2vec模型中會有一個向量,將這些詞向量做$weight(w)=\frac{a}{a+p(w)}$的加權平均直接就當成我們的句子向量。($a$是一個常數,$p(w)$是該詞在訓練資料中出現的機率)$^{見[參考paper][1]}$
  • Cosine similarity : 判斷是否為該問題的答案是看兩個句子向量的相似程度,這裡是用兩個高維向量的cosine similarity當分數,選擇分數最高的選項當作答案。
  • Model 參數細節:$a=6\times 10^{-4}$,embedding size=1200
  • Issue :
    1. 因為我們是用加權平均來生成句子的向量,所以這個模型中缺少句子中詞與詞的前後關係。

    2. 其次,由於這個方法的問句跟答句所用的sent2vec方式是一樣的,所以沒有考慮到需要從問句轉換為答句的問題,導致只是選出跟問句比較像的句子

2. [Model 2] DNN model — 第二簡單的model

  • Word Embedding : 將每個詞以訓練好的word2vec模型轉成向量
  • Training data:我們會從training data中挑選真的是有前後關係的兩句話、和隨機挑選的兩句話,分別標上1(True)和0(False)的label,網路在看到兩句話後會給定一個分數(0~1之間),在做testing的時候,選擇六個選項中分數最高的那一個當答案。
  • DNN model:為了減少訓練時間,我們在開始使用RNN來訓練前,先嘗試直接用DNN的方法,也就是先用上面方法一(詞向量平均)做sent2vec後,把問句接DNN,希望透過DNN,能把句子transform成答句,然後直接跟答句的sent2vec比較cosine similarity。
  • Model 參數細節
    • embedding size = 256
    • DNN: 3層dense,output dim=256
    • activation function: relu
  • Issue : 此作法可以避免 Model 1 中沒有考慮到從問句轉換為答句的問題,但缺點是sent2vec的方法仍然缺少句子中詞與詞的前後關係

    3. [Model 3] RNN model — 正式model

  • Word Embedding : 將每個詞以訓練好的word2vec模型轉成向量
  • Training data:我們會從training data中挑選真的是有前後關係的兩句話、和隨機挑選的兩句話,分別標上1(True)和0(False)的label,網路再看到兩句話後會給定一個分數(0~1之間),在做testing的時候,選擇六個選項中分數最高的那一個當答案。
  • RNN model:input的句子把每個字embedding完後,接上RNN(GRU),問句和答句所接的RNN是不同的RNN(沒有share weight),問句RNN的output再接三層DNN讓他有某些transoform,輸出與答句的RNN的output作cosine similarity,得到答案(0~1之間的機率分布)。
  • model 參數細節 :
    • embedding size:100
    • 第一層GRU:128 cells
    • 第二層GRU:64 cells
    • 第一層Dense(64->32)
    • 第二層Dense(32->1)
  • Issue:此model架構有考慮句子中詞與詞的前後關係,理論上已經避免了剛剛其他前兩個架構所擁有的問題。但追根究柢,這種給兩句input算單一output的方法還是可能導致一些問題:
    • Training與Testing的差異: 首先,Training跟Testing的方式是稍微不一樣的,Training時是單純指定1 or 0的label,並且希望True case的output是1,False case的output是0;而在Testing時,其實只需要選6句中機率最高的,並不需要每一句True case的target都是1。=>只需要optimize相對分數,而非絕對分數。
    • 用絕對分數來Train髒data易混淆網絡: 如果訓練資料乾淨,針對絕對分數來訓練的問題不大。但是畢竟這次的訓練資料很髒,而且False case也是隨機產生,因此訓練資料中,可能還是有很多True case但實際上語意不相關(可能恰好截到對話結束的地方),或是False case的答句是還可接受的(可能問句是比較開放,可接受多種答句)諸多狀況。但我們這樣一視同仁地希望True case的output是1,False case的output是0,於是就容易對要訓練的網絡產生混淆,可能害他在training的時候就已經無法對這些data做很好的判斷。其實我們所需要的,應該只是讓True case的成績大於False case的成績就好了
    • 解法:使用多output+softmax,當你每次訓練都是拿6句話的相對分數來比較,就能避免單一筆data品質不佳的狀況
    • 作法:End-to-end model

4. [Model 4] End-to-end RNN model — 最強model

  • model架構:input為一個問句+六個答句,embedding後經過兩個GRU,輸出7個100維的vector,直接concatenate成為700維的vector,最後接上兩層Dense,轉為6維後經過Softmax,得到預測結果。
  • Improvement:針對前述RNN架構的缺點,我們修改為End-to-end的RNN model,分成6個答句選項的output做Softmax,而非原本需要讓True case的output越大越好

    single-output Sigmoid v.s. multi-output Softmax
    原先RNN model用單一output+Sigmoid,而Sigmoid是將$[-\infty, + \infty]$都映射到$[0, 1]$之間,而且是output接近無限大的時候,Sigmoid出來才是1,結果會讓他變成output越大越好。 反之Softmax是看各個output之間的比例,如果其中一個output明顯大於其他,則他Softmax出來的value就會很接近1,不需要train到讓他output趨近無限大。

  • Training data量與Testing data量的平衡: 在這種架構中,我們產生訓練資料的方式,也是挑選連續句子作為True case並label 1,然後隨機亂數挑選5句其他句子作為False case並label 0。這樣除了能夠改以相對分數訓練外。另外也能讓Training data中False case的data數量是True case的五倍,也就是與Testing data完全一致。在前面的單純RNN架構中,我們並沒有把True:False case的比例弄成1:5,也因此可能他所訓練到的False case不夠多,導致在testing時效果不如預期。
  • training data處理
    • 最長句子長度 = 30
    • 將句子補齊的padding加在最前面
  • model參數細節
    • embedding size: 100
    • GRU output dim: 100
    • Dense 1: 700 => 100
    • Dense 2: 100 => 6
    • activation function: Swish

Experiment and Discussion :

1. [Model 1] Sentence embedding -> cosine similarity

  • 不同的embedding維度: 可以看出維度大的在使用cosine similarity後表現比較好,比較能判斷句子的相近程度。
embedding維度 private score public score
100 0.33122 0.30039
500 0.36758 0.36916
1200 0.40869 0.40513
  • 不同的$a$值(embedding維度:1200):常數在這裡可以看成一個詞的機率的調整,越小的話,詞出現的機率就越能影響結果。而在實驗的過程後,發現6e-4能達到最好的performane。
$a$ private score public score
6e-2 0.35098 0.34624
6e-3 0.36719 0.36640
6e-4 0.40869 0.40513
  • 不同的training data
    • 將training data改成以下的形式,除了增加training data的數量外,在Question和answer的task中,這樣的training data還可以加強前一句和後一句的關係。
      今天 過 得 好 嗎 -> 今天 過 得 好 嗎 我 很 好
      我 很 好        -> 我 很 好 真的 嗎 
      真的 嗎         -> 真的 嗎
      
  private score public score
before 0.39367 0.38814
after 0.40869 0.40513
  • 結果討論:此model雖然準確度不比其他的高,但就其model大小及付出的運算量來說,已經是個CP值很高的做法。

2. [Model 2] DNN model

  • 訓練參數 :
    • optimizer: Adam
    • learning rate=1e-4
    • epoch = 10
    • batch size: 256
    • loss function: cross entropy
    • checkpoint: on val_acc
  • 訓練過程 :
Training loss Training accuracy Validation loss Validation accuracy
  • kaggle score
public score private score
0.40513 0.40869
  • 結果討論: train了半天,沒有比Model 1好多少,效果頗差,可見sent2vec直接接DNN並不是個好方法,畢竟沒有考慮字序的關係。

3. [Model 3] RNN model

  • 訓練參數 :
    • optimizer: Adam
    • learning rate:1e-4 (Adam)
    • batch size:32
    • loss function: MSE
    • epoch:30
    • checkpoint: on val_acc
  • 訓練過程 :
MSE loss Validation accuracy
  • 二層GRU與一層GRU的比較:
    • 由下圖可以發現,在計算loss的時候,兩種model的MSE loss差不多低,可是在validation的準確率上,只有一層GRU layer的表現是比較好的。

    • 從Kaggle上的成績來看,平均起來一層GRU的準確率稍微高一點。

MSE loss Validation accuracy
  private score public score
1 GRU layer 0.48142 0.47470
2 GRU layer 0.46996 0.47588
  • 不同embedding size之間的比較
    • 由下圖可以發現embedding維度較大的在訓練過程中loss比較低,但是在準確率上是差不多的,為了訓練時間的考量,會選擇維度較低的方法來訓練。而在embedding維度1000以上的時候,訓練到一半準確率就會卡在一個很低的值,就再也升不上去了。
    • 從Kaggle上的成績來看,兩個model其實是差不多的。
MSE loss Validation accuracy
  private score public score
embedding維度:500 0.45968 0.47312
embedding維度:100 0.46996 0.47588
  • 結果討論:RNN model的成績,明顯比前兩model提升了將近8%左右,可見有將字序考慮進去是非常重要的環節。

4. [Model 4] End-to-end RNN model

  • 訓練參數
    • optimizer: Adam
    • learning rate=1e-4
    • batch size: 100
    • epoch = 20
    • loss function: cross entropy
    • checkpoint: on val_acc
  • 訓練過程 :
CrossEntropy loss Validation accuracy
  • 訓練結果 :
train acc validation acc
0.62394 0.58169
  • kaggle score
public score private score
0.54426 0.55415
  • 結果討論:此model架構最為龐大,但效果也最佳,又比單純RNN model進步了7%~8%的正確率,推測他是藉由針對相對分數訓練的優勢,才能有如此顯著的進步,能有效避免單一RNN model訓練絕對分數的弊病。

Ensemble

這次final因為時間緣故,Model 4是在kaggle deadline後,聽完別組分享後才做出來的。因此在kaggle上最高分的成績是由Model 1 + Model 2 + Model 3 ensemble而來。最高分成績如下:

public score private score
0.53913 0.54664

ensemble之比例為:(2個Model 1預測平均 + 4個Model 2預測平均 + 3個Model 3預測平均)/3

在ensemble時我們也發現,一直拿同一model ensemble的效果並不好,頂多提升個1%~2%,而使用不同做法的多個model做ensemble效果就比較好,即便其中有些model的表現並不好,像是我們原本最佳的Model 3也只有0.48附近的準確率,但在ensemble不同參數的model以及加入許多Model 1、Model 2的預測機率,一起投票後,就有效提升了近5%的正確率。

Conclusion :

在這次final中,我們前後嘗試了4種model:從一開始不考慮詞序及問句答句差異的Model 1,進入考慮問句答句差異的Model 2,後來到考慮詞序的Model 3,最後是修正Model 3而採用相對分數訓練的Model 4。由40%左右的正確率,最後提升到約55%,我們了解到1.考慮詞序2.問句答句差異以及3.以相對分數訓練,避免部分data品質不佳是後面model能贏過前面model的原因,也是這次題目的關鍵。

另外,還有一些因素也許是我們未來可以努力的目標,在ACL 2017 的 paper — Sequential Matching Network: A New Architecture for Multi-turn Response Selection in Retrieval-based Chatbots 中,還引入了多句問句分別與答句匹配以及利用conv層及pooling層做feature extraction,有特別著眼在”多輪“對話的特質,因為多輪對話中,有很多句上文(這次final也是,以\t分隔多句上文),但答句可能只取決於其中一句上文,因此需要好的feature extraction方法來挑出決定性的上文(詳見reference之paper大意)。這也是目前多輪對話題目較好的解法之一,這次final原本想使用該架構,但後來因model過大,一直會crush掉,最後只好半途而廢,但這個課題非常值得日後研究。

Reference :

  • [參考paper][1] A Simple but Tough-to-Beat Baseline for Sentence Embeddings [ICLR — 2017 conference paper]

    paper大意:一個sentence to vector的簡單方法,跟word averaging有點像,但是針對每個字的出現機率做加權,其中$weight(w)=\frac{a}{a+p(w)}$,$a$在$[10^{-3},10^{-4}]$之間,最後再把所有sent vec做PCA,並且減去first conponent (類似把所有句子中相同的部分減去,也就是重複出現的詞,以凸顯句子之間的差異)。

  • [參考paper][2] Sequential Matching Network: A New Architecture for Multi-turn Response Selection in Retrieval-based Chatbots [ACL — 2017 paper]

    paper大意:將每一上文$(u_1, …,u_n)$分別在1.剛未進入GRU前以及2.已通過GRU後,做sequence之間的matching,分別得到兩個matching的矩陣,將此二矩陣透過convolution以及pooling做有效的feature extraction,轉為向量後,再通過GRU做冗餘資訊的去除或有用資訊的保留,最後得到prediction。