自己动手实现20G中文预训练语言模型示例
起初,我和大部分人一樣,使用的是像Google這樣的大公司提供的Pre-training Language Model。用起來也確實方便,隨便接個下游任務,都比自己使用Embedding lookup帶來的模型效果要好。但是時間用長了,就會產生依賴。
依賴只是一方面,還有一個更大的問題,是我們需要思考的,他們提供的Pre-training LM確實很好嗎?適合我們使用嗎?
一方面,它的大小適合使用嗎?在BERT預訓練語言模型剛出來時,最小的模型都是Base版的,它的hidden_size為768,占用內存大小為400M。另一方面,它真的好嗎?其實,它只是一個普通的通用語言模型,并沒有什么特殊之處,也沒有為語料做過一些特殊的預處理。下面有幾個例子:
- 例1,模型大小的選擇。一般情況下,任意接一個下游任務,最后得到的模型大小都有1G多。對一些大學生而言,特別是一些沒有GPU資源的小伙伴而言,就像一塊天鵝肉。
- 例2,特定領域。如果我的領域是醫療領域,那么Google提供的語言模型可能表現得并不會很優異。
- 例3,特定NLP任務。如果我的NLP任務是基于短句的,那么基于長句訓練的語言模型表現也會差一點。
- 例4,數據集的選擇。選取一份數據量更大、覆蓋面更廣、質量更優、預處理更好的數據集,會讓語言模型在NLP任務中有更好的表現。
- 例5,MASK數量和訓練總步數。我們看過RoBERTa這篇論文后,可以知道MASK更加隨機,以及訓練更長的步數,會給模型帶來更好的效果。
下面,我會介紹下整個預訓練過程中遇到的一些問題,以及如何克服這些問題。
一、數據準備
數據準備這一塊的工作花費了較長的時間。
一方面,數據收集。考慮到最后訓練得到的模型的通用性以及可持續性,所以收集的數據需要盡可能地覆蓋更多的領域。另外,我的NLP任務中,很多是特定領域內的。所以,在收集了通用數據18.3G的前提下,額外補充了2.2G的特定領域數據。數據鏈接:https://zhuanlan.zhihu.com/p/163616279
另一方面,數據處理。數據處理主要有2個工作。第1個,需要將收集的數據處理成可直接讀取并訓練的格式。如下所示,我們需要將圖1或者其它形式的數據都轉為圖2形式的數據。
第2個,需要將圖2中的數據轉為可供ALBERT使用的格式,如下圖3所示:
然后,將圖3的數據轉為tfrecord格式存儲在本地。這里就會遇到一些問題,以及一些tricks。那么會有什么問題呢?首先,如果直接使用Google提供的預訓練代碼,一次性將所有的數據全部轉化為圖3的格式,然后存儲在本地。這個過程中,首先一般電腦的顯存肯定不夠使用,因為20G的數據轉為圖3的格式后會變為1400G左右的大小,這個是在duplicate次數為10的情況下(10種不同的MASK)。代碼所示:
顯然,一般的電腦顯存大小肯定沒有1400G,甚至有些電腦的硬盤大小也沒有1400G。那么,這個時候,就需要優化Google提供的預訓練代碼了。我的做法是,一方面將所有的數據拆分為很多個txt文件,其中每個文件包含1w個句子/文章;另一方面,生成tfrecord的方式是一遍讀取文本一遍生成tfrecord,而不是一次性讀取所有的文本。這個過程的代碼如下:
上面圖4中的code解決的是將單個txt文本轉化為tfrecord的方式,圖5解決的是歷遍每一個txt文件并保存到本地。除此之外,為了確保數據的隨機性,在生成txt文件時,做了4次隨機化全部文本數據,并將每一次隨機生成的文本數據按照1w的大小切分并保存到本地。
之前讀了RoBERTa這篇論文,發現了3個有用的tricks,分別是更多的隨機MASK、更長的訓練步數和更多的訓練數據。
現在,我們介紹下數據的演變過程,主要有以下6個步驟:
我們可以看到,最后有106億個樣本。相比Google的125000*4096=5億樣本,以及brightmart的20個樣本,我們訓練的樣本量要大很多,主要是原因是我們做了分句處理和添加了新的數據。在整個數據演變的過程中,步驟6花費了較長的時間,在10個進程的情況下,花了一個星期才完成。
如果也有想做預訓練的小伙伴,首先要準備一個大的硬盤,至少能夠存儲2T的數據。
二、模型訓練
1、框架選擇
對比了好幾個預訓練模型,發現還是ALBERT最好。同時引入了RoBERTa的幾個tricks(更多的隨機MASK、更長的訓練步數和更多的訓練數據)。
2、超參數
訓練的樣本量越大,意味著訓練的時間也會越久。由于GPU資源有限,只有2卡1080Ti,所以我首先會進行一個hidden_size為384、sequence_length為64、batch_size為768的預訓練,然后會依次訓練hidden_size分別為512、768的預訓練。
3、訓練時間
那現在評估一下訓練時間。以最小的hidden_size=768為例,訓練的步數最少需要1063970488/768=1385w步。按照目前機器的訓練速度,大概需要90天才能訓練完成。當然,也不一定要完全訓練完所有的數據,在訓練了一半的steps之后,基本上可以使用了。到時候,8月中旬時,我會向大家開放這個預訓練語言模型。那時,對NLP任務為短句(NER,短句文本分類等)的小伙伴,我相信會對你們的模型效果有一個較大的提升;以及對電商領域的NLP任務的模型效果也會有一個提升。
模型訓練是一個漫長的過程,誰讓我們沒有money呢,不過等待也是幸福的時刻。不過,如果能有32卡、64卡或者更多,那簡直就爽歪歪了,此處全靠想象。。。
總而言之,至少我們做到了,在沒有那些寡頭的幫助下,我們也能創造一片新的天地!
三、字典修改
在開源的ALBERT項目目錄下,已經有了一個通用的字典vocab.txt。但是,對于有些小伙伴來說,可能并不夠用,例如我想添加一些英文單詞以及一些不常用的漢字。另外,在字典中添加新的token時,不僅僅要添加整個新的token,同時也需要添加這個token作為句子首個字時的token。例如,如果我要添加一個法語單詞"vie",那么,需要同時添加"##vie",這里的兩個"#"指示的是句子/文章的第一個字。我們可以看下代碼的解釋:
四、開源預訓練模型
Waiting!
另外,我已經在小規模的數據上做了一次預訓練,所有模型(文本分類,多標簽文本分類)的效果都提升了0.5%-1%之間。
總結
以上是生活随笔為你收集整理的自己动手实现20G中文预训练语言模型示例的全部內容,希望文章能夠幫你解決所遇到的問題。