我的BERT!改改字典,讓BERT安全提速不掉分(已開源)

夕小瑤發表於2020-09-25

背景

當前,大部分中文預訓練模型都是以字為基本單位的,也就是說中文語句會被拆分為一個個字。中文也有一些多粒度的語言模型,比如創新工場的ZEN和位元組跳動的AMBERT,但這類模型的基本單位還是字,只不過想辦法融合了詞資訊。目前以詞為單位的中文預訓練模型很少,據筆者所瞭解到就只有騰訊UER開源了一個以詞為顆粒度的BERT模型,但實測效果並不好。

那麼,純粹以詞為單位的中文預訓練模型效果究竟如何呢?有沒有它的存在價值呢?最近,我們預訓練並開源了以詞為單位的中文BERT模型,稱之為WoBERT(Word-based BERT,我的BERT!)。實驗顯示,基於詞的WoBERT在不少任務上有它獨特的優勢,比如速度明顯的提升,同時效果基本不降甚至也有提升。在此對我們的工作做一個總結。

開源地址
https://github.com/ZhuiyiTechnology/WoBERT

字還是詞?

究竟是“字”好還是“詞”好?這是中文NLP一個很讓人抓狂的問題,也有一些工作去系統地研究這個問題。比較新的是香儂科技在ACL2019上發表的《Is Word Segmentation Necessary for Deep Learning of Chinese Representations?》,裡邊得到了字幾乎總是優於詞的結論。前面也說了,現在中文預訓練模型確實也基本上都是以字為單位的。所以,看上去這個問題已經解決了?就是字更好?

事情遠沒有這麼簡單。就拿香儂科技的這篇論文來說,它的實驗結果是沒有錯,但卻是沒有代表性的。為什麼這樣說呢?因為在該文的實驗設定下,模型的embedding層皆從隨機初始化狀態開始訓練。這樣一來,對於同樣的任務,以詞為單位的模型Embedding層引數更多,自然就更容易過擬合,效果容易變差,這不用做實驗都能猜個大概。問題是,我們用基於詞的模型的時候,通常並不是隨機初始化的,往往都是用預訓練好的詞向量的(下游任務看情況選擇是否微調詞向量),這才是分詞的NLP模型的典型場景,但論文裡邊卻沒有比較這個場景,所以論文的結果並沒有什麼說服力。

事實上,過擬合”現象具有兩面性,我們要防止過擬合,但過擬合也正好說明了模型擁有比較強的擬合能力,而如果我們想辦法抑制過擬合,那麼就能夠在同樣複雜度下得到更強的模型,或者在同樣效果下得到更低複雜度的模型。而緩解過擬合問題的一個重要手段就是更充分的預訓練,所以不引入預訓練的比較對以詞為單位的模型來說是不公平的,而我們的WoBERT正是證實了以詞為單位的預訓練模型的可取性

詞的好處

一般認為,以字為單位的好處是:

  1. 引數更少,不容易過擬合
  2. 不依賴於分詞演算法,避免邊界切分錯誤
  3. 沒那麼嚴重的稀疏性,基本上不會出現未登入詞

至於以詞為單位的理由是:

  1. 序列變短,處理速度更快
  2. 文字生成任務上,能緩解Exposure Bias問題;
  3. 詞義的不確定性更低,降低建模複雜度

對於詞的好處,大家可能會有些疑惑。比如第2點,詞能緩解Exposure Bias,這是因為理論上來說,序列越短Exposure Bias問題就越不明顯(詞模型單步預測出一個n字詞,相當於字的模型預測了n步,這n步都遞迴依賴,所以字的模型Exposure Bias問題更嚴重)。至於第3點,雖然有多義詞的存在,但是多數詞的含義還是比較確定的,至少比字義更加明確,這樣一來可能只需要一個Embedding層就能把詞義建模好,而不是像字模型那樣,要通用多層模型才能把字組合成詞。

看起來不相伯仲,但事實上以字為單位的好處,並非就是以詞為單位的缺點了。只要多一些技巧,以詞為單位也能一定程度上避免這幾個問題。比如:

  1. 以詞為單位的引數確實增多了,但是可以透過預訓練來緩解過擬合,所以這個問題不會很嚴重;
  2. 依賴分詞演算法是個問題,如果我們只保留最常見的一部分詞,那麼不管哪個分詞工具分出來的結果都是差不多的,差異性不大;
  3. 至於邊界切分錯誤,這個難以避免,但是需要準確的邊界的,只是序列標註類任務而已文字分類文字生成其實都不需要準確的邊界,因此不能就此否定詞模型;
  4. 如果我們把大部分字也加入到詞表中,也不會出現未登入詞。

所以,其實用詞的好處是相當多的,除了需要非常精確邊界的序列標註型別的任務外,多數NLP任務以詞為單位都不會有什麼問題。因此,我們就去做了以詞為單位的BERT模型了。

Tokenizer

往BERT裡邊加入中文詞,首先得讓Tokenizer能分出詞來。只需要把詞加入到字典vocab.txt裡邊就行了嗎?並不是。BERT自帶的Tokenizer會強行把中文字元用空格隔開,因此就算你把詞加入到字典中,也不會分出中文詞來。此外,BERT做英文word piece的分詞的時候,使用的是最大匹配法,這對中文分詞來說精度也不夠。

為了分出詞來,我們修改了一下BERT的Tokenizer,加入了一個“前分詞(pre_tokenize)”操作。這樣我們就可以分出中文詞來,具體操作如下:

  1. 把中文詞加入到vocab.txt;
  2. 輸入一個句子s,用pre_tokenize先分一次詞,得到;
  3. 遍歷各個,如果在詞表中則保留,否則將用BERT自帶的tokenize函式再分一次;
  4. 將每個的tokenize結果有序拼接起來,作為最後的tokenize結果。

在bert4keras>=0.8.8版本中,實現上述改動只需要在構建Tokenizer的時候傳入一行引數,例如:

tokenizer = Tokenizer(
    dict_path,
    do_lower_case=True,
    pre_tokenize=lambda s: jieba.cut(s, HMM=False)
)

其中pre_tokenize為外部傳入的分詞函式,如果不傳入則預設為None。簡單起見,WoBERT使用了結巴分詞,刪除了BERT自帶詞表的冗餘部分(比如帶##的中文詞),然後加入了20000個額外的中文詞(結巴分詞自帶的詞表詞頻最高的兩萬個),最終WoBERT的vocab.txt規模是33586。

模型細節

目前開源的WoBERT是Base版本,在哈工大開源的RoBERTa-wwm-ext基礎上進行繼續預訓練,預訓練任務為MLM。初始化階段,將每個詞用BERT自帶的Tokenizer切分為字,然後用字embedding的平均作為詞embedding的初始化。

到這裡,WoBERT的技術要點基本上都說清楚了,剩下的就是開始訓練了。我們用單張24G的RTX訓練了100萬步(大概訓練了10天),序列長度為512,學習率為5e-6,batch_size為16,累積梯度16步,相當於batch_size=256訓練了6萬步左右。訓練語料大概是30多G的通用型語料。訓練程式碼已經在文章開頭的連結中開源了。

此外,我們還提供了WoNEZHA,這是基於華為開源的NEZHA進行再預訓練的,訓練細節跟WoBERT基本一樣。NEZHA的模型結構跟BERT相似,不同的是它使用了相對位置編碼,而BERT用的是絕對位置編碼,因此理論上NEZHA能處理的文字長度是無上限的。這裡提供以詞為單位的WoNEZHA,就是讓大家多一個選擇。

模型效果

最後,說一下WoBERT的效果。簡單來說,在我們的評測裡邊,WoBERT相比於BERT,在不需要精確邊界的NLP任務上基本都沒有變差的,有些還會有一定的提升,而速度上則有明顯提升,所以一句話就是“提速不掉點”。

比如中文榜單上的兩個分類任務:我的BERT!改改字典,讓BERT安全提速不掉分(已開源)

我們內部還測了不少任務,結果都是類似的,表明這些NLU任務上WoBERT和BERT基本上都差不多的。但是速度上,WoBERT就比BERT有明顯優勢了,下表是兩個模型在處理不同字數的文字時的速度比較:我的BERT!改改字典,讓BERT安全提速不掉分(已開源)

我們還測了WoBERT+UniLM的方式Seq2Seq任務(CSL/LCSTS標題生成),結果是比以字為單位的模型有明顯提升:我的BERT!改改字典,讓BERT安全提速不掉分(已開源)

這說明以詞為單位來做文字生成其實是更有優勢的。要是生成更長的文字,這個優勢還能進一步放大。

當然,我們也不否認,用WoBERT去做NER等序列標註任務時,可能會有明顯的掉點,比如做人民日報的NER,掉了3%左右,可能讓人意外的是,經過bad case分析,我們發現掉點的原因並不是因為切分錯誤,而是因為稀疏性(平均來說每個詞的樣本更少,所以訓練得沒那麼充分)。

不管怎麼說,我們把我們的工作開源出來,給大家在使用預訓練模型的時候,多一個嘗試的選擇吧。

文章小結

在這篇文章裡,我們開源了以詞為單位的中文BERT模型(WoBERT),並討論了以詞為單位的優缺點,最後透過實驗表明,以詞為單位的預訓練模型在不少NLP任務(尤其是文字生成)上有它獨特的價值,一方面它有速度上的優勢,一方面效果上能媲美以字為單位的BERT,歡迎大家測試。

相關文章