機器之心原創
作者:思源
「大眾 10 萬到 20 萬之間的車型有幾種?」——機器能理解這樣的自然語言,並從表格中檢索出答案嗎?這是非常值得探索的問題,也是追一科技舉辦中文 NL2SQL 挑戰賽的重要目的。
今日,首屆中文 NL2SQL 挑戰賽正式開始提交模型結果。在這之前,追一科技 AI Lab 就曾介紹過 NL2SQL 的概念與發展進程,而本文則重點關注挑戰賽到底該怎麼解,希望選手們的提交結果能更上一層樓。
挑戰賽地址:https://tianchi.aliyun.com/competition/entrance/231716/introduction什麼是 Nature Language To SQL
顧名思義,Nature Language To SQL 就是將自然語言轉化為 SQL 查詢語句,從而檢索需要的信息。本質上它是將自然語言轉化為機器語言,從而執行某些特殊的任務。該任務的重點即能解析自然語言的語義,並將這些語義編碼為計算機能理解並執行的語句。
其實之前也有很多類似的研究,例如將 GUI 界面轉化為形式化代碼、學會編輯原始碼等等。雖然它們有很多差異,但都嘗試利用深度網絡抽取圖像或文本的語義信息,並根據這些語義信息生成對應代碼。
所以不論是自然語言轉 Python 還是 C++代碼,它們與 NL2SQL 的思想都是相同的,下面我們可以通過簡單的案例看看到底 NL2SQL 能幹什麼。如下我們有一張表,我們可以從中推斷出很多信息,例如我們可以算出「不同型號的寶馬總共賣了多少輛?」。
一張表確實容易看出來,但若是數千張表組成的資料庫呢,這就需要 SQL 語言來幫忙了。我們可以將如上詢問手動寫成相應的 SQL 表達式:「SELECT SUM(銷量) FROM TABLE WHERE 品牌=="寶馬";」,從而得到答案「8」。但這種方式要求我們會 SQL 語句,且一種查詢就要寫一條表達式。
而 NL2SQL 做的,就是希望能自動化這一過程,希望結合用戶想要查詢的表格,將用戶的問句轉化為相應的 SQL 語句。
首屆中文 NL2SQL 挑戰賽
追一科技希望通過 NL2SQL 賽題,拉近用戶與結構化數據間的距離,這樣機器不僅能理解我們的問題,同時還能從資料庫中自行找到答案。
其實賽題本身很好理解,即輸入中文問題,並期待模型能根據該問題輸出對應的 SQL 查詢語句。整個賽題使用金融以及通用領域的表格作為數據源,並提供標註的自然語言與 SQL 語句對,選手可以利用數據訓練出能自動生成 SQL 語言的模型。
訓練數據
追一表示本次比賽數據集包含有約 4500 張表格,且基於這些表格提出了 50000 條自然語言問句,以及對應的 SQL 語句。數據都是通過爬取並解析公開數據源中的表格而獲得的,然後通過人工標註就能構建提問與對應 SQL 語句。
具體而言,追一科技搭建了一個標註平臺,標註人員可以在平臺上看到一張表格。在理解表格內容後,標註人員需要基於表格提出自然語言問句,並通過點擊 UI 的方式構建 SQL 語句。標註好的數據會經過人工校驗,追一會儘量避免錯誤標註、歧義等情況。
本次賽題將提供 4 萬條有標籤數據作為訓練集,1 萬條無標籤數據作為測試集。其中,5 千條無標註數據作為初賽測試集,選手是可以直接下載並測試的。而另外 5 千條作為複賽測試集,這些數據是不可下載,選手需要提交打包好的代碼鏡像來運行得出預測結果。
此外,為了使初賽和複賽更具區分度,複賽階段的測試集將包含更多在訓練集中沒有出現過的表格數據,以驗證方案的泛化能力。
數據集主要由 3 個文件組成,例如訓練集中包括 train.json、train.tables.json 及 train.db。其中 train.json 儲存了所有提問與對應的 SQL 表達式,train.tables.json 則儲存了所有表格。另外 train.db 為 SQLite 格式的資料庫文件,它是為執行模型生成的 SQL 語句而準備的。
在 train.json 文件中,每一行為一條數據樣本,如下給出了數據示例與欄位說明。整體而言,模型需要根據"table_id"和"question"預測出完整的 SQL 表達式 "sql"。
因為一條 SQL 表達式由很多子語句組成,所以"sql"中由一系列選項組成,包括選擇的列、列操作、選擇的條件約束等等。具體而言,SQL 的表達字典如下所示。"agg"選擇的是 agg_sql_dict、"cond_conn_op"選擇的是 conn_sql_dict、"conds"中條件類型選擇的是 op_sql_dict。
注意,其中"cond_conn_op"表示的是條件之間的關係,即如果表達式包含多個條件,那麼它們間的關係到底是 和、或還是 無。後面的"conds"則通過多個三元組具體描述了條件語句,例如 [3,0,100] 就表示選擇第四列大於 100 的條目,即 col_4>100。
那麼表格又是什麼樣的呢?在 train.tables.json 文件中,每一行為一張表格數據,下面簡要展示了數據樣例及欄位說明。
表格數據比較好理解,確定每一個特徵列的名字、數據類型和數據值就行了。
下面我們可以通過訓練集中的具體樣本與表格,了解模型到底需要預測些什麼。整體而言,首先模型需要根據 table_id 檢索對應的表格,然後再根據 question 再對應表格中檢索信息,並生成對應的 SQL 表達式。這裡不需要根據問題搜索表,也不會產生跨多張表的情況,相當於簡化了問題。
現在重要的是我們需要知道模型怎樣才能從問題構建 SQL 表達式。如下所示,在我們看到問題「二零一九年第四周大黃蜂和密室逃生這兩部影片的票房總佔比是多少呀」時,我們可以找到它們的票房佔比分別為 15.6% 和 14.2%,然後加起來就能得出周票房總佔比為 29.8%。
那麼模型需要做一些什麼呢?它應該通過各種子任務確定 SQL 表達式的各個模塊,然後構建完整的語句,並通過它檢索到正確答案。
具體而言,模型應該通過問題中的「票房總佔比是多少」確定需要選擇第三個特徵列「票房佔比(%)」,即"sel": [2];以及對應的聚合函數「SUM」,即"agg": [5]。通過問題中的「大黃蜂和密室逃生」從影片名稱中確定"大黃蜂"和"密室逃生"兩個條件,同時這兩個條件間的關係應該為「AND」,即確定"conds"和"cond_conn_op"分別是什麼。
當這些都能正確預測時,模型就能正確合成 SQL 表達式:
SELECTSUM(col_3) FROM Table_4d29d0513aaa11e9b911f40f24344a08 WHERE (col_1 == '大黃蜂'and col_1 == '密室逃生')
如果完全正確時,表達式當然沒問題,但是只要有一個子句預測錯誤,整條語句都會有問題。為此,在實際競賽中,追一科技的基線模型會提供多種度量標準,我們不僅需要知道每個子句的正確情況,還需要知道整體表達式的正確情況。
基線模型
這樣的問題確實非常具有挑戰性,因此追一科技提供了基線解決方案供選手參考。只要選手報名了挑戰賽,那麼就能下載數據集,並放到基線模型上試試效果。我們可以只修改核心的模型部分,就能得出更優秀的結果。
基線模型地址:https://github.com/ZhuiyiTechnology/nl2sql_baseline基線模型使用 Python 2.7 和 torch 1.0.1 構建,選手需要在天池賽題頁面下載數據集與預訓練詞嵌入,並按一定結構組織才能最終跑起來。如下所示是我們需要組織的數據集結構,後面會把如下 data_nl2sql 目錄的所有內容複製到基線模型下的 data 目錄。
這裡數據集都介紹過了,但還有額外的字符級詞向量文件 char_embedding。
追一科技表示,他們提供的字符級預訓練詞嵌入,會在 10G 大小的百度百科和維基百科語料上採用 Skip-Gram 訓練。以字為單位可以避免專有名詞帶來的 OOV 問題以及分詞錯誤所帶來的錯誤累積。
理論上,我們也可以採用 BERT 來作為模型的輸入表示。BERT 的細粒度分詞對數據集很友好,而且目前在 WikiSQL 數據集上的 SOTA 模型 X-SQL 以及 SQLova 都是採用這樣的策略。追一科技表示,他們將 SOTA 模型遷移到這次挑戰賽的數據集後,效果也會有較大的提升,所以選手也可以試試 BERT。
最後,基線模型的 GitHub 項目詳細介紹了訓練及評估過程,選手只要跟著它一步步走就行了。此外,如果本地環境配置有問題或者缺少 GPU 算力,也可以試試在 Colab 上跑基線模型:
Colab 基線模型:https://drive.google.com/open?id=10RtAom_D4zOp_w5OsYLTtLd2TEuC7C1X模型訓練所需要的算力還是挺大的,在 K80 上訓練一個 Epoch 大概需要 7 到 8 分鐘,基線模型默認訓練 100 個 Epoch。追一表示試驗多次後,驗證集上的平均 Logic Form Accuracy 為 27.5%,即 SQL 每一個子句全都預測正確的概率為 27.5%。
模型結構
基線模型是在 17 年 SQLNet 的基礎上改進的,該網絡也是 WikiSQL 數據集的基線模型。該網絡的核心思想即將不同的子句分離開,因為不同子句的順序有的並沒有太大關係,它們間的獨立性可能非常強,所以分離開也許是個不錯的想法。
SQLNet 定義了一個模板,它把子句間的依賴性都構建在模板上,因此不同子句填充到該模板就能完成 SQL 語句的構建。現在模型需要單獨預測出各個子句的值,即用 6 個神經網絡預測選擇的列、聚合函數、條件類型和條件值等等。
下圖 (a) 展示了 SQL 表達式的模板,其分為 SELECT 和 WHERE 兩部分,WHERE 還可能不止一個條件句。下圖 (b) 展示了各個子任務間的依賴性關係,SELECT 和 WHERE 之間是相互獨立的,但它們內部之間是有相關性的。例如 WHERE 下的每一個條件句,模型要根據特徵列確定特徵列的值,也需要根據特徵列確定它與值之間的條件類型,最終它們三者組合起來就能確定條目(行)。
圖註:選自 SQLNet 原論文,arXiv: 1711.04436。
這個模板算是比較通用的,而且任何 SQL 語言都可以通過擴展模板囊括進去。在挑戰賽的基線模型中,它與 SQLNet 的區別並不大,只不過挑戰賽會增加 Select-Number 和 Where-Relationship 兩個子任務,這兩個字任務能更好地適應中文 NL2SQL 數據集。
其實模型比較難解決的還是 WHERE 子句,我們發現該子句中確定特徵列,及確定特徵列的值是最困難的,它們的準確率相對其它子任務都要低一些。所以如何解決這些問題,並構建更強大的整體性能就是選手們該思考的。
代碼結構
模型主體都在 sqlnet 目錄下,而我們需要理解並修改的代碼基本上都在它的子目錄 model 下,其它數據加載或處理等函數直接復用就行了。如下簡要展示了 model 目錄的代碼結構,其中 sqlnet 文件負責搭建整體網絡框架,modules 目錄下的代碼則是完成子任務的各個神經網絡。
追一表示,總體而言核心代碼可以分為三大部分,選手可以從這三部分出發修改基線模型:
輸入表達:因為問句及表格數據中存在很多的專有名詞,為了避免詞表覆蓋度不足及錯誤分詞而導致的 OOV 問題,自然語言問句和表格列名、表格內容都採用了以字為單位的字向量作為基本單位。可以比較容易地切換為 BERT、MT-DNN 及其它更優秀的特徵表達。編碼層:採用了雙向 LSTM 來對自然語言問句及列名進行編碼,從而得到相應的向量表徵。這一部分的結構在多個子任務中是共享的,但參數不共享。各個子任務模塊:因為 baseline 是基於 SQLNet 改動而來,所以模型仍有多個子任務。按照子任務的不同,基線模型在代碼層面也很顯式地進行了模塊化。如果選手對不同子任務之間的關係有更好的想法,甚至認為 SQL 有更好的生成方式,都可以直接在這些子任務模塊進行改寫。評分標準
對於模型的評估,其主要有兩個指標:Logic Form Accuracy 和 Execution Accuracy,最後選手排名的依據則是這兩項指標的平均值。其中,Logic Form Accuracy 代表的是選手預測出的 SQL 與真實的 SQL 邏輯一致的準確率,即選擇的目標列是否一致、聚合函數是否一致、條件列是否一致、條件值是否一致等等。Execution Accuracy 代表的是選手預測出的 SQL 執行結果與真實 SQL 執行結果是否一致。
這兩個指標的計算都非常簡單,如果預測的 SQL 表達式或者檢索結果與標註一致,那么正確數加 1,最後正確數除上總預測數 就是最終的正確率。
但在實際訓練中,基線模型還會輸出一系列子任務的效果,如下是訓練 80 個 Epoch 後的輸出結果,我們可以看到除了 Logic Form 和 Execution 準確率外,還有 Sel-Num 等 8 個子任務的準確率。
如上所示「Sel-」表示 SELECT 部分的子任務,「W-」表示 WHERE 部分的子任務。例如 Sel-Col 表示選擇列的正確率 、Sel-Agg 為選擇聚合函數的正確率、W-Op 為選擇條件類型的正確率、W-Val 為選擇條件值的正確率等等。
差異與改進
前面基線模型展示了一般的解決方案,目前也有很多優秀的 NL2SQL 模型可以借鑑,它們在 WikiSQL 數據集上達到了 SOTA 結果。但這裡我們需要理解競賽數據集與 WikiSQL 之間的差別是什麼,這樣才能有目的地改進。
數據集的三大差異
追一科技表示本次競賽數據集與 WikiSQL 主要有三點差異/難點,它們也是本次比賽中選手需要去解決的核心問題。
表格內容對選手是可見的,並且問題具有泛化性
以此表為例,如果在 WikiSQL 中,自然語言問句應該是「騰訊控股的股票今天漲了多少」,相應的 SQL 語句是「SELECT 漲跌幅 FROM TABLE WHERE 股票名稱=="騰訊控股"」,所以模型可以簡單地從原句中抽取一個子字符串來作為條件值。但在挑戰賽的數據集中,同樣的問句可能會變成「鵝廠今天漲了多少」,這就要求模型不僅可以預測出需要針對「股票名稱」這一列做條件限制,同時還要能泛化到表格的內容來生成正確的 SQL。
省略顯式的列名信息,更口語化的表達在 WikiSQL 中,自然語言問句由於標註方式的原因,更像是基於模板的問句,所以通常會帶有比較明顯的列名信息。比如「騰訊控股的股票今天漲了多少」就會帶有「股票」這個列名信息。在挑戰賽的數據集中,問題會變得更加口語化、貼近真實場景,這樣就要求模型首先要把騰訊和股票名稱這一列聯繫起來,才能正確地生成 SQL。
數字的單位問題針對如下這樣的表格,數據集中的問題可能是,我們的問題為:「北京這周成交了多少千平方米?」。這樣在千平方米和萬平方米間就存在非歸一化單位的問題。
提升方案
前面展示了幾種數據集的不同之處,理解它們對改進方案非常重要。前面已經介紹過 X-SQL 和 SQLova 等 WikiSQL 當前最佳模型都在採用 BERT、MT-DNN 作為輸入表徵,它們能取得非常好的效果。此外,模型的處理流程和依賴關係都可以改進,因此可以總結為如下三個方向:
BERT、XLNet 等更好的輸入特徵更合理的模型結構:目前的基線模型是 pipeline 的方式,預測完 condition column 之後再去預測 condition op 和 condition value。但在真實數據中,我們需要一種聯合預測的方式來解決問題。如何合理地將表格內數據也結合進模型,以前的方案都忽略了表格內數據。這裡展示幾篇上面3個方向的論文,更多頂尖模型可以在 WikiSQL 基準中找到:
[1]X-SQL: reinforce context into schema representation, 2019[3]Semantic Parsing with Syntax- and Table-Aware SQL Generation, 2018[1]A Comprehensive Exploration on WikiSQL with Table-Aware Word Contextualization, 2019
WikiSQL 基準:https://github.com/salesforce/WikiSQL
本文為機器之心原創,轉載請聯繫本公眾號獲得授權。