M-SQL:超強的多任務表示學習方法

摘要:本篇文章將硬核講解M-SQL:一種將自然語言轉換爲SQL語句的多任務表示學習方法的相關論文。

本文分享自華爲雲社區《【雲駐共創】M-SQL,一種超強的多任務表示學習方法,你值得擁有》,作者: 啓明。

數據集整體介紹

定義介紹

國際慣例,先來一段定(bai)義(du)介(bai)紹(ke):Text to SQL,顧名思義,就是在給定數據庫(或表)的前提下,根據用戶的提問,產生SQL語句。其數學描述如下:

令X表示用戶的自然語言提問,D表示與提問相關的數據庫(或表),Y表示其對應的SQL語句。

SQL語句生成任務可以表述爲:對於每一組獨立的(X,D,Y),將(X,D)映射到對應的Y。

用一個大家熟悉的場景爲例。假設我們有一張學生信息表,我們可以用自然語言提問:大於18歲的學生都有誰,模型需要返回一個與之相關的SQL語句,那麼就是:

SELECT 姓名 FROM 學生信息 WHERE 年齡 > 18

場景分類

Text to SQL有很多種分類,其中一種是按問題分類

一種是上下文無關的(提問之間不存在關聯):Spider

一種是上下文相關的(兩個提問之間存在一定關聯):SparC

“上下文無關”是指提問之間沒有任何的關聯,而“上下文相關”是前後兩個提問之間,存在一些指代關係或者說存在一定的關聯。

同樣,我們舉一個簡單的例子來說明:

提問1:有預約的醫生ID是什麼?

SELECT physician FROM appointment

提問2:他們的名字是什麼?

SELECT T2.name FROM appointment AS T1 JOIN physician AS T2 ON T1.Physician = T2.EmpoyeeID

以上就是一個上下文相關的例子,第一句的確定醫生ID,第二句根據醫生ID確定醫生名字。

另一種是按領域分類:單領域 or 多領域

如果所有的提問都是有關於航空方面的,這就是一個單領域的數據集。而跨領域數據集,則是在訓練集當中可能有很多種領域,在測試集當中也有很多種領域,但是訓練集中的領域和測試集中的領域不重合,這就要求我們的模型具有一定的泛化能力。

第三種是按照數據庫進行分類

單表數據庫:WikiSQL,其提問只針對一個表,或者是它所針對數據庫當中只有一個表

多表數據庫:Spider,其提問針對的數據庫當中有許多個表,它所產生的 SQL語句可能涉及到多個表之間的連接。

第四種種分類是按照標註類型進行分類

最終結果:WikiTableQuestion

SQL語句:WikiSQL、Spider

有一些數據集沒有給出相關的SQL語句,而是直接給出了一個結果。以前面的例子爲例,“大於18歲的學生都有誰”,輸出有可能是給出SQL語句,也有可能是最終結果:把這些人名都給列出來,而沒有給出SQL語句,這其中涉及到的“弱監督學習”,本次不做具體講解。

TableQA 數據集

本次要講解的論文所採用的是一個TableQA數據集,它也是一個單表數據。也就是每一個提問都只針對一個表進行提問。TableQA和WikiSQL有有很多相似之處,但是也有一定的差異,如下圖所示:

論文概述

介紹完數據集之後,我們來對論文中所提出的模型進行一個簡單的介紹。

首先來思考這樣一個問題:通過自然語言生成SQL語可以有什麼方法?其實一個最簡單的思路:輸入端是自然語言句子,輸出端是與之對應的SQL語句(按照SQL語句按照一個token一個token進行生成)。

比如說我們前面那個例子,Encoder是“大於18歲的學生都有誰“,輸出端是SELECT name FROM XX表 Y條件。

這個方法很簡單,但是也伴隨着一些問題:SQL語句是結構化的查詢語言,它是具備一定的結構的,這和一般的語言生成任務是有一定差別的。

對於一般的語言生成任務來說,如果變更其中的一兩個詞,可能它的語義不會發生太大變化。但是對於 SQL語句來說,如果某個詞不一樣了,那麼其就可能就沒有辦法繼續執行。所以我們需要利用好SQL語句內部的一些語法信息,也就是結構信息。按照它的結構來進行生成,這就是論文當中所提出來的,按照 SQL的框架來進行生成。

M-SQL

因爲TableQA數據集只針對單表,相當於From字句可以省略。大體可以分成兩個部分,一部分是 Select子句,一部分是 Where子句。

其中Select的子句當中有兩個部分:一個是所選取的表的名稱,另一個是聚合操作。比如說我們要求某一列的最大值、最小值或者是對某一列進行求和,就需要聚合操作來進行。

對於Where子句這一部分,我們詳細介紹一下:

$WOP:where 條件連接符(and /or / Null)

$COLUMN:數據庫中的列名

$AGG:對選取列的操作(Null, AVG, MAX, MIN, COUNT, SUM)

$OP:where子句中的列值

根據對TableQA數據集進行統計,限定select中最多出現2列、where中最多有3個條件:

SELECT ($AGG $COLUMN)*

WHERE $WOP ($COLUMN $OP $VALUE)*

M-SQL模型

此模型大致可從下往上可以分成三塊。

Encoder:對輸入進行一個編碼;採用了一個簡單的bert模型,版本是wwwm-ext。wwm意味着其使用的是一個全詞覆蓋的方式,而ext則擴充了它的訓練集並使它的訓練部署有所增加。

其輸入部分包括:問題、列名。同樣以前面“大於18歲的學生都有誰”爲例,可以看到上圖所示,T1至TL,後面跟着的是所提問的表當中所出現的每一列它的列名,比如說這個表當中可能有姓名、學號或者年齡。另外,與bert輸入不同的是它用 [XLS]去替換了[CLS]。

列表示:對於列的表示進行增強;由於每一列當中它可能會由多個token構成,比如說,一列的名字叫“姓名”,其可能是兩個字,這兩個字分別有兩個embeding,那麼如何把這兩個embeding給它合併成一個embeding作爲列的表示呢?我們可以用前面的 XLS的表示來對列的表示進行增強,具體的做法如下:

先通過前面 XLS的表示,對這一列當中所有的token表示進行計算attention,attention計算出來之後再加上前面 XLS表示的 embeding,這兩個之和就構成了這一列的增強的表示。

經過上述步驟之後,我們就得到了問題當中,每一個token的表示,以及表格當中每一列的表示。

子模型:8個子模型及對這8個子模型進行1個多任務的學習。

前面提到,我們可以將SQL語句分割成不同的部分,然後每一部分分別進行生成,於是可以得出8個子任務,分別是:

  • Select列數
  • Where列數和連接符
  • Select列
  • Select列操作
  • Where列
  • Where每列的運算
  • 值抽取
  • 值匹配

接下來,我們對這8個子任務分別介紹一下它們的做法。

任務一:S-num:Select中出現的列數。[1、2](2分類)

首先是Select當中出現的列數。對於TableQA數據集,Select當中出現列數只可能是一列或者是兩列,因此我們可以當做是一個二分類的問題:利用 XLS的 embeding做線性變換,然後過sigmoid的得到它的概率。

任務二:w-num-op:Where中的連接符和條件數。[null-1、and-1、or-1、and-2、or-2、and-3、or-3](7分類)

第二個任務是Where當中出現的連接符和條件數。所謂“連接符”,指的是“And”還是“or”等;條件的個數,指的是Where當中所出現的“>”、“<”、“=”等等條件的個數。我們可以將他們分成了7個類別,“-”前面的就是連接符,“-”後面的這些就是條件的個數。當然也可以把這兩個任務進行分開,但是如果把這兩個任務進行分開的話,效果與兩個任務一起做相比,會大打折扣。

那麼總共是有7個類型,就可以看成是7分類的問題,因此還是 XLS表示過一個線性變換,然後再經過softmax,就可以得到這7個類別上的概率分佈。

第三個和第四個子任務是Select字句和Where字句當中出現的列。我們前面已經預測了Select當中的例數,以及Where當中的例數,那麼在這一部分我們分別預測每一例所出現的概率即可。

任務三:S-col:Select 中出現的列

Select中出現的列:利用我們之前每一列得到增強的表示,經過一個線性變換,再過一個softmax就可以得到這一列所出現的概率。

任務四:W-col:Where 條件中出現的列

對Where條件當中出現的列:同樣,利用不同的線性變化來進行得到這一列它所出現的概率。

任務五:S-col-agg:Select 中出現的列的操作符

  • [Null, AVG, MAX, MIN, COUNT, SUM](6分類)

第五個任務是Select當中出現的這些操作符,這些操作符也被稱爲是聚合操作。比如說,我們可以求這一列當中所有數據的最大值、最小值或者求平均、求和等等。

在TableQA當中,5種操作符加上NULL一共是6種,我們可以將其看到是一個6分類的問題。同樣,我們對每一列的增強的表示做一個線性變換,然後再經過softmax就可以得到每一類的概率分佈。

任務六:W-col-op:Where 條件中出現的列對應的條件運算符

  • [> / < / == / !=](4分類)

對於Where條件當中出現的這些運算符也是一樣。這些運算符,包括這一類大於一個數或者小於一個數,或者是等於某個值,或者不等於某個值,一共是4類,我們可以看作是一個4分類的問題。做法和之前的Select當中的運算符一致,也是給列的增強表示過一個線性映射再經過softmax得到4類的每一類的概率分佈,從中的選取最大的作爲這一列的運算符。

最後兩個子任務就是服務於條件值預測。同樣以我們前面的例子爲例,“大於18歲的學生都有誰”。最後的結果應該是Where條件當中有一個age > 18,那麼我們18應該怎樣獲得呢?作者就問題給它拆成了兩個子任務:

任務七:從問題中抽取可能是值的短語

  • 使用0/1對問題中的Token進行標記(1表示值,0表示非值),每一組連續的

1標記的token作爲一個整體

第一步就是從問題當中抽取出有可能是值的短語。比如說“大於18歲的學生都有誰”這個問題,那麼這個子任務就是把“18”從問題當中進行抽出來。我們可以採用的方法是使用0和1對問題當中所出現的token進行標記,比如說“大於18歲都有誰”中的“18”,我們就把它標記成1,然後其他所有的token就把它標註上0,並對於問題當中我們一個token的表述過一個線性變換,使用sigmoid的來預測它到底是1還是0。

任務八:將抽取出的短語和Where中出現的列進行匹配

在任務七的基礎上,我們需要將抽取出來的短語與where當中所出現的列進行匹配。

在前一個步驟,我們已經把“18”給它打上1的標籤了,因此也就生成了“18”這個token序列。它是一個可能會出現在某一個條件當中的value,但是它會出現到哪一列之後,是這一步所要確定的事。

將取出來的短語與Where當中出現的列進行匹配,如果短語當中它是由多個token構成的,就把所有的token的text表示求一個平均。如下圖,此公式相當於是對短語與where當中出現的列求一個相似度,然後再過一個sigmoid。前面這個u是一個可學習的參數,過一個sigmoid就可以得到短語與列是否匹配:如果匹配就把短語作爲列的值,比如說18就跟age匹配了,然後我們就可以寫age > 18。

Execution-Guided Decoding

我們已經對上述8個子任務做了簡單的介紹。通過這8個子任務,我們就可以得到一條SQL語句,並且保證它是符合了語法規則的。但是它所產生的SQL語句有可能還是不能被執行。

因爲SQL語句的內部可能還存在一些限制條件:

  • SELECT子句中如果出現string類型的列,則對應的操作不能是’sum’, ‘min’, ‘max’
  • WHERE子句中如果出現string類型的列,則對應的操作不能是‘<’, ‘>’
  • SELECT子句和WHERE子句中出現的列互不相同(分析數據集得知)

在這些限制下,我們可以採用Execution-Guided Decoding的方法:在decode的過程當中,去掉那些不能被執行的SQL語句,比如說SQL語句執行出來的結果是空,或者壓根就不能被執行,從而被會報錯,這些SQL語句我們就可以直接被拋棄,而選取符合上述條件的概率最大的SQL語句。

實驗結果

接下來是實驗結果。

首先簡單介紹一下其所採用的評價指標,分別是LX、X還有MX。

LX,就是它的邏輯形式的準確率。如果所生成的SQL語句和標準答案的SQL語句完全一致,那麼上面這兩個操作正確;如果有一點不一樣,比如說“>”寫錯了,或者是這一列選錯了,那麼這個例子即錯誤。

X,就是它的執行結果的準確率。如果兩條SQL語句,可能它的邏輯形式不一樣(這兩個SQL可能存在一些差別),但它的執行結果是一致的,那麼也算預測正確。

MX,是前面LX和X的一個平均。它有兩個模型,一個是單個模型,一個是集成模型(後面的Ens)。通過Ensemble對多次訓練的結果進行集成,最終得到一個更好的結果。從圖中我們可以看到它比之前幾種模型的結果都要好。

因爲之前的模型都是基於WikiSQL進行實現的。我們所採用的TableQA與WikiSQL有一些不同,並且比WikiSQL要更難一些,所以之前的這些模型在TableQA對數據集上的效果並不是很好。

子任務的性能

下圖對8個不同的子模型的性能做了對比:

我們可以看到在每一個子模型上,它的效果都是非常不錯的,現在經過Ensemble之後就可以達到更好的效果。

消融實驗

在實驗的最後一部分我們做了一系列的消融實驗。

從實驗結果我們可以看出,使用BERT-wwm-ext的版本比 BERT-base效果要好,使用XLS作爲前置比CLS作爲前置的效果要好。圖中更下面部分是所使用的一些值的抽取的方法,以及一些值匹配的方法,我們在下面給大家作更詳細的介紹。

復現中的細節處理

接下來,我們將介紹在復現過程當中的一些細節處理。

首先是數據預處理的部分。對於這個數據集來說,它的數據是不太規範的,有可能會出現以下情況(括號中表示歧義部分):

  • 數字:哪些城市上一週成交一手房超十五萬平? (十五,15)
  • 年份:你知道10年的土地成交面積嗎? (10年,2010)
  • 單位:哪些城市最近一週新盤庫存超過5萬套? (5萬,50000)
  • 日期:哪個公司於18年12月28號成立? ( 18年12月28號,2018/12/28 )
  • 同義:你能幫我算算芒果這些劇的播放量之和是多少嗎?(芒果,芒果TV)

前面幾個問題,可以直接按照一定的規則來進行轉換;而後面這些可以通過到數據庫當中去找相關的品類詞做一個替換。

值的抽取

在“值抽取”這一部分的,我們嘗試了很多種方法,比如說bert+crf的方法,bert+bilstm+crf,以及bert+半指針的方法。最終所採用的還是0/1標記的方法,因爲它的效果是最好的。

  • bert + crf,val_acc: 0.8785
  • bert + bilstm + crf,val_acc: 0.8801
  • bert + 半指針,val_acc: 0.8891
  • bert + 0/1 標記,val_acc: 0.8922

0/1的方式是如何實現的呢?我們以問題是“青秀南城百貨有限公司在哪?”爲例來詳細講解一下。

query:青秀南城百貨有限公司在哪?

bert_tokenizer:[‘[XLS]’, ‘青’, ‘秀’, ‘南’, ‘城’, ‘百’, ‘貨’, ‘有’, ‘限’, ‘公’, ‘司’, ‘在’, ‘哪’, ‘?’, ‘[SEP]’]

value:青秀南城百貨有限公司

tag:[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]

首先對此問題進行Tokenizer,然後得到token序列,如果值“青秀南城百貨有限公司”出現在SQL語句中,就把這些token給標記成1;對於其他的沒有在SQL語句當中出現的,就標記成0。

細節處理

Value檢索

由於在value抽取的時候,抽取出來的value可能不太規範,或者是問題當中和數據庫當中出現的不太一致。比如說下圖中的“人人”與“人人網”:

Query1:人人周漲跌幅是多少?

Value:人人

在這種情況下,我們就需要將 value與 SQL這一列當中出現的所有的值做一個檢索,選出與之最接近的一個詞作爲最終的 value。那麼如果檢索,我們可以選的方法也很多,比如說rouge-L的匹配方式,以及幾種機器學習的方法:邏輯迴歸、SVR以及貝葉斯。通過效果對比,我們可以發現,邏輯迴歸是最好的方式,其準確度是97%。

Table-Column 信息增強:

最後一部分,使用表的內容來對列的表示進行增強。

如上圖,比如說地區這一類,從中隨機選取一個列值,比如說“廣西”,我們這一列就表示成“地區, 廣西”這一個整體就作爲這一列的一個表示,並把它送到input端,然後再進一步的獲得列的表示。通過這種方式對於列進行增強,最終可以獲得0.4的效果提升。

復現中的問題及建議

1、數據集不規範,建議抽取選取部分規範的數據進行訓練和預測;

2、不要從0開始復現,可以基於現有的模型,參考現有的代碼。

M-SQL:一種將自然語言轉換爲SQL語句的多任務表示學習方法

查看本期論文解讀視頻、算法鏈接,請點擊:

https://marketplace.huaweicloud.com/markets/aihub/article/detail/?content_id=d5f27a62-fc93-43cb-813b-6bb5c5eec068

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

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