【NLP實戰】XLNet只存在於論文?已經替你封裝好了!
- 2020 年 2 月 20 日
- 筆記
以下文章來源於AI實戰派 ,作者AI實戰派
相信前段時間大家都被各種XLNet的解讀、解析轟炸了吧。好容易熬過了學會了,到網上一搜,誒!官方沒有公布中文預訓練模型,其他大佬都還沒動靜,散了散了,追ALBERT的熱點去了。
在 ymcui大佬 的中文XLNet 和 CyberZHG大佬的keras_xlnet發布,再經過兩個月左右讓心急手快的大佬們當第一批吃螃蟹的人,提了bug和各種疑惑並被大佬們修復與解答後,現在無疑是我等平民上車XLNet的好時機。
而目前,筆者已經封裝好Keras的XLNet待大家使用了,目的就為了讓大家調用XLNet如同word2vec等Embedding一樣輕鬆方便。
本文介紹一下封裝的過程及使用的大佬們的工作,以及封裝後的使用方法,XLNet理論什麼的相信大家也看膩了,只會在有必要的時候提一嘴。
本文分為兩部分:封裝篇和操作篇,不關注如何封裝只想看如何使用的可以直接跳到操作篇。程式碼在我的github:https://github.com/zedom1/XLNet_embbeding
封裝篇
XLNet模型
首先自然是一切的核心:XLNet模型參數啦,鑒於官方沒有發布中文版(也不能怪人家,他也沒有義務一定要做),目前市面上開源的中文XLNet只有兩家,做的最好的是ymcui大佬的Chinese-PreTrained-XLNet:https://github.com/ymcui/Chinese-PreTrained-XLNet
他在8月18日放出了24層的中文mid版模型,並於9月5日放出12層版本的中文base模型,不僅如此,還是tensorflow、pytorch版本雙全,Google下載訊飛雲下載兼備,不由感嘆大佬考慮周全。
中文模型就從這裡下載啦,至於是12層的base版還是24層的mid版,除了個人喜好、任務難度之外,還要看看你顯示卡夠不夠level了,他們在微調mid時使用的是64G HBM的GoogleCloud TPU v2,而筆者使用顯示記憶體16G的Tesla V100微調24層的mid模型時輕輕鬆鬆爆顯示記憶體,微調12層的base版本較為輕鬆。
因此建議顯示記憶體小於16G的讀者就不要湊mid版的熱鬧了,12層的base也不錯,而顯示記憶體若大於16G則可以一戰。
Keras調用XLNet
有了XLNet模型,接下來就是調用啦。當然你也可以直接從上面的中文XLNet中魔改大佬的tensorflow運行腳本來完成自己的任務,不過既然都點進來的,想必是跟我一樣的懶人,希望最好能一鍵運行、一鍵優化(automl了解一下?)的。
學過沒學過tensorflow的應該都知道keras封裝了tensorflow,比tensorflow本身好用得多(那不然怎麼叫封裝),從最近比較火的Tensorflow2.0大幅向keras靠攏可見一斑。
那keras要想調用XLNet首先得先有大佬在keras上把XLNet模型搭好,才能灌參數進去,想必各位跟我一樣也不太想碰這個硬骨頭吧,那就感謝CyberZHG大佬的keras_xlnet吧:https://github.com/CyberZHG/keras-XLNet,除了keras_xlnet外,大佬還封裝了keras-bert,筆者之前做bert微調就是用的這位大佬的keras-bert。
這位大佬給我們搭好了XLNet,到這裡我們就可以用keras跑XLNet模型了,然而這還達不到我們想要的,我們需要的是將XLNet作為embedding調用,在後面接我們自己的模型,而XLNet是有自己的語言模型預測任務的,因此和BERT一樣,我們要取其中一層或某幾層的輸出作為輸入句子的編碼,鑒於hanxiao大佬的xlnet-as-service沒動靜,那就只好自己動手豐衣足食吧。
XLNet Embedding
然後就到了筆者出場的時候啦,到這裡還剩下的就是根據需要取XLNet的層,用spiece編碼文本,將文本編碼輸入和XLNet的模型輸入對齊,網路demo搭建了。
讓我從零開始自己干?算了算了,畢竟在巨人的肩膀上才能看得又高又遠,經過搜尋找到了yongzhuo大佬Keras-TextClassification:https://github.com/yongzhuo/Keras-TextClassification, 參考了下大佬的實現,不過在XLNet部分訓練版本輸入沒有對齊,取層輸出時有錯誤,花了筆者幾天的時間debug,這部分網上也沒有什麼資料可供參考,只得一邊看錯誤提示一邊翻keras_xlnet的源碼與demo,可算廢了挺多功夫。
在取層方面,首先將keras版的xlnet輸出一下,明確哪些層可以取(點擊放大看超長長長長圖):

從圖中可以看到base版總共129層,其中前9層大部分是輸入+embedding(4個輸入和4個embedding+1個亂入的transformer),最後一層softmax是XLNet的語言模型預測任務,中間則是每十個層算一個transformer的模組(第一個模組框內9層+Input模組的transformer)。
每個模組就取layer normalization後的輸出,總共12個,再加上可能有些人喜歡原味,再提供一個position embedding後的輸出,那麼可選的輸出模組就是【0,12】啦。
取完還不算完,如果一次取多層,那就要考慮一下融合方式了,筆者挑選了常用的融合方式:add、concat、max、average,具體選哪個通過配置文件改就可以了。
然後是文本的編碼,參考了keras_xlnet中demo的寫法,需要考慮到單輸入和雙輸入的差異。對於單輸入,在前面填充PAD標籤,最後加一個CLS標籤,然後在segment id中將最後的CLS標為1。
而對於雙輸入有些許複雜,在兩個輸入之間和之後加SEP標籤,然後再填充和加CLS,而segment id就可選了,可以直接默認全零+最後的CLS為1(keras_xlnet的demo):

也可以填充、第一個輸入、第二個輸入、CLS各自使用各自的id(keras_xlnet的demo):

具體用哪種方案就看實驗結果了。
然後附上一個簡單的小實驗,從清華的中文文本分類數據集 THUCNews(http://thuctc.thunlp.org/) 中抽取18w數據,按9:1切分為訓練語料和驗證語料,另取1w作為測試語料。
類似的實驗在Chinese-Text-Classification-Pytorch(https://github.com/649453932/Chinese-Text-Classification-Pytorch)中有做。

模型參數基本默認,選擇XLNet可訓練,取倒數第二層,embedding出來後加一個fasttext。其中訓練過程:

只訓練了一個epoch就足夠了,驗證集準確率93.7%,測試集上也差不多:

這是沒有經過調參的實驗結果,相信細緻調參加修改模型結構會得到更好的分數。
操作篇
接下來就是怎麼使用啦,分為正常人版和究極急性子懶人版,在正常人版里介紹一下你可能需要修改的函數以及修改方式。對於究極急性子懶人,唯一的目的就是儘快讓程式碼跑!起!來!所以教你如何以最少的操作讓程式碼跑起來。
首先,不論是哪個版本,首先得到ymcui大佬的Chinese-PreTrained-XLNet:https://github.com/ymcui/Chinese-PreTrained-XLNet 把模型下好。
然後到我的github:https://github.com/zedom1/XLNet_embbeding,下載程式碼,按照requirements配置好環境,裝好keras_bert、keras_xlnet包以及依賴。
正常人版
文件不多,跟xlnet相關的py文件就兩個,其中xlnet_embedding封裝了模型讀取和取層等操作,一般情況是不需要管的,然後打開demo.py。
首先介紹下整個demo的運行過程:

因為xlnet自帶字典,因此需要載入並使用它的tokenizer,當然這是下載下來的模型文件自帶的,為了美觀起見筆者將xlnet相關的都統一放在xlnet_embedding下了。先單獨讀取tokenizer,提前將文本編碼好,要訓練時再載入XLNet模型。
然後是demo裡面的函數和類全局一覽:

裡面可以修改的函數上面都加了注釋了,前面三個可以不用理,f1_callback就是調用sklearn的report實現了keras下的f1計算,每輪訓練結束後調用這個回調函數就會對驗證集計算report。
encode_data就是將文本按xlnet的需要進行編碼啦,也可以不用管,init為初始化,載入XLNet的詞典。
下面就是個性化的部分了。
get_config中修改模型及XLNet各種配置,如batch_size等等。
process_data下分為訓練、測試和預測,基本上就是常規的文本讀取,有需要可以在這裡面加些預處理的措施。
create_model裡面就是構建XLNet、灌預訓練好的參數以及搭建後面的網路啦:

裡面的embedding就是XLNet啦,把它當作一個普通的embedding模組就行了,後面可以加個fast text之類的。
在train函數下改改優化器類型和loss就差不多啦。
究極急性子懶人版
懶人們瘋狂下滑終於等到這一版啦,如果你的任務是短文本分類的話可以開始偷笑了,如果還已經將label轉成數字那就可以大笑了。
下載完模型和程式碼,安裝完依賴之後,把訓練數據按 文本 t 標籤 的txt格式放好在data目錄下,命名為train.txt:

然後打開demo.py,找到get_config函數,如果分類數目不是10,必須修改label項,其他可以不改,看心情。

然後拉到最下面:

只要訓練的話就把test和predict注釋了,如果需要的話就按上面訓練文本的準備方式放好test和predict的txt文件,predict.txt文件里不需要標籤。
最後,python demo.py。沖沖沖!
The End