最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

基于中文GPT2訓練一個屬于自己的微信聊天機器人(Colab + Kaggle GPU)

2023-02-07 16:15 作者:豚骨拉面--  | 我要投稿

(注:本專欄只討論相關技術,不涉及任何其他目的,如侵刪)

摘要

本專欄介紹了基于中文GPT2訓練一個微信聊天機器人的方法,模型實現(xiàn)基于GPT2-chitchat和GPT2-Chinese,訓練語料為兩個人的對話聊天記錄。微信聊天記錄的劃分比較復雜,因為兩個人的對話在時間和內(nèi)容上具有一定的連續(xù)性。我提出了一個較為簡單的劃分思路,并附上了相關的實現(xiàn)代碼。我使用Colab和Kaggle的GPU進行訓練,總共訓練了差不多30h,最終實現(xiàn)了還算可以的效果。最后,我對本次復現(xiàn)的不足提出了一些思考。

前言

前段時間看到Andrej Karpathy出了實現(xiàn)簡易版ChatGPT的教程,正好之前導出了大概12w條微信聊天記錄,就想著能不能訓練一個自己的微信聊天模型。在GitHub上搜了一下,已經(jīng)有大佬提供了預訓練的中文GPT2對話模型,接下來只需要劃分一下微信聊天記錄,丟入模型訓練即可。

本次復現(xiàn)主要基于GPT2-chitchat模型,項目鏈接如下:

GPT2-chitchat:https://github.com/yangjianxin1/GPT2-chitchat

GPT2-Chinese:https://github.com/Morizeyao/GPT2-Chinese

兩位作者的代碼都寫得很好,推薦感興趣的同學閱讀,讀完之后會對如何進行NLP數(shù)據(jù)預處理、如何運行一個中文NLP模型、如何生成對話等有一個清晰的認識。

我這次復現(xiàn)的方法是使用兩個人的微信聊天記錄訓練GPT2,希望它能學習到我的回答風格,方便以后和對象吵架。一個關鍵的問題在于如何劃分訓練語料,由于我本人不是做NLP的,下面提供的劃分思路僅供參考,歡迎大家指正。

微信聊天記錄提取

首先,這里簡單提一下微信聊天記錄的提取方式,我采用的是https://github.com/saturn-opposition/wechat_analysis中的提取思路,使用夜神安卓模擬器,不要使用騰訊手游助手,很垃圾?。?!

上面的github鏈接中提供了兩種導出數(shù)據(jù)的方法,我個人是按照第一種,即https://blog.csdn.net/weixin_41746317/article/details/104110161?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-5-104110161-blog-126700288.pc_relevant_multi_platform_whitelistv3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-5-104110161-blog-126700288.pc_relevant_multi_platform_whitelistv3&utm_relevant_index=6。

導出db文件后,需要通過MD5加密輸出得到密碼,我個人的嘗試是IMEI = ‘1234567890ABCDEF’ ,即

(注:int name=“_auth_uin” value="中,value不一定帶有負號,加密字符串時需注意)

在sqlcipher.exe中直接導出message為message.csv文件,接下來我們對該文件進行處理。


數(shù)據(jù)預處理(微信文本劃分)

(下文附上了數(shù)據(jù)處理的代碼,可以直接處理前面導出的message.csv)

原文件有很多列,我們實際上只關心其中的四列:type,isSend,createTime和content。語言模型只能學習有效的文本消息,因此我們只需要type=1的消息,具體消息類型見https://blog.csdn.net/muzhicihe/article/details/109902849?spm=1001.2014.3001.5506。isSend=0/1 分別對應對方/己方發(fā)送的消息,createTime是發(fā)送時間;content是消息內(nèi)容。

接下來我們需要將導出的文本消息轉(zhuǎn)換成訓練語料。GPT2-chitchat模型要求的訓練文本格式長下面這樣:

對話摘自柚子社貼吧,僅作為示例

即每段訓練文本由幾句話組成,采用問答交替的形式(可以有多次問答),不同語料之間間隔一行(見GPT2-chitchat項目中提供的樣例),所有訓練語料存在一個train.txt文件中。

但關鍵的問題在于,兩個人的聊天在時間和內(nèi)容上是有一定連續(xù)性的(比較粗糙的描述,不知道語言學中是否有對應概念),不能直接按照一問一答來劃分,很有可能出現(xiàn)答非所問的情況。另外微信聊天是一個比較輕松的環(huán)境,并不像辯論賽那樣有較為嚴格的發(fā)言規(guī)則,說話人可能會連續(xù)說好幾句話之后對方才回答,或是回答人很可能過了很久才看到對方的發(fā)言等等。因此想要正確地劃分訓練語料并不容易,劃分效果會直接影響模型的訓練結(jié)果。

這里我想了一個比較簡單直接的劃分方法,供大家參考。我主要考慮了以下兩個點:

  • 發(fā)言的連續(xù)性

    假設在1min內(nèi),由同一個人發(fā)出的所有消息可以視為一句話(一次詢問或一次回答)。

  • 對話的實時性

    假設在某一方發(fā)言結(jié)束(發(fā)言時間1min結(jié)束)后,若另一方在5min內(nèi)作出回應,則對話成立,該段對話可以作為訓練文本。若有一方在5min之內(nèi)未作出回應,或是該段對話已經(jīng)包含了3次問答(共6句話),則視為對話結(jié)束。

在處理csv文件之前,我們需要將message.csv另存為csv utf-8格式,否則無法順利讀入。

微信文本劃分的完整代碼如下,可以將該腳本復制到message.csv所在文件夾后直接運行,即可得到對應的train.txt文件。下面對代碼部分細節(jié)作進一步解釋,不想看的可以直接跳到下一部分)

在讀入文件之后,我們需要根據(jù)talker篩選出屬于對話雙方的聊天記錄,可以在message.csv文件中觀察,找到對應的那個talker(以“wxid_”開頭,不管是接收還是發(fā)送的消息都是同一個talker):


原csv文件并不是完全按照時間順序排列,我們需要按照createTime對文本進行排序。createTime采用毫秒時間戳,但具體的時間只精確到分鐘,同一個createTime是按照消息發(fā)送先后順序升序排列。因此,要想得到正確的劃分結(jié)果,我們需要使用穩(wěn)定的排序方法(比如歸并排序,sort_values默認采用快速排序),這一點非常關鍵!

下一步就是利用time庫的函數(shù)將毫秒時間戳轉(zhuǎn)換成年、月、日、小時、分鐘,并將其concat回原來的數(shù)組:

接下來就是重頭戲:訓練語料劃分。

由于判斷對話狀態(tài)涉及到時間的比較,這里我先定義了一個比較時間的函數(shù),其中sample是當前對話所在list,包含isSend,content,年,月,日,小時,分鐘,current_hour和current_min是要比較的小時和分鐘,time_threshold是設定的閾值。由于current_hour和current_min是過去發(fā)送的信息,因此一定小于sample的時間。具體實現(xiàn)如下:

接下來是遍歷文本消息。為了讓機器盡量學習我回答時的風格,每段對話都以對方詢問開始(isSend=0)。同一個人在1min內(nèi)連續(xù)發(fā)的消息,用中文的逗號“,”連接,合并成同一個句子,而對方如果在5min內(nèi)回答,則對話成立:

如果己方回答后,對方5min內(nèi)沒有回應,或是本段文本已經(jīng)包含了6句話(3段問答),則判斷對話中止,在下一行再加一個換行符:

下面這一部分代碼是否添加視情況而定,主要是針對下面這種情況:

  • 對方文本1

  • 己方文本1

  • 對方文本2

對方發(fā)送完文本2之后,己方沒有及時回應,導致對話中斷。如果添加下面這段代碼,訓練語料中會包含沒有回答的對方文本2,否則只包含對方文本1和己方文本1。

最后,我們劃分好的語料存入train.txt中,就可以開始訓練了!

模型訓練

終于說完了數(shù)據(jù)預處理,接下來是模型訓練。GPT2-chitchat使用的是HuggingFace的transformers中的GPT2LMHeadModel,鏈接為https://huggingface.co/transformers/v3.5.1/model_doc/gpt2.html。

在訓練之前,我們需要將train.txt中的文本利用BertTokenizerFast進行分詞和編碼,并給每一段對話加上[CLS]和[SEP],原項目沒有使用預訓練的分詞方法,而是直接將每個漢字視為一個token。具體操作是運行項目的preprocess.py文件,生成的train.pkl會存儲在data文件夾下。

我在訓練前并未修改preprocess.py的代碼,訓練后模型出現(xiàn)了較為嚴重的過擬合(測試集的loss一直上升,訓練集的loss一直下降),懷疑是劃分訓練集和驗證集時并未打亂原數(shù)據(jù)集。一個可能的解決辦法是對preprocess.py的代碼做一些修改,在寫入dialogue_list前加一行random.shuffle(dialogue_list)。我自己沒有嘗試修改之后的數(shù)據(jù)集,有興趣的可以看看新數(shù)據(jù)集的結(jié)果。

下面正式開始訓練,分別使用Colab和Kaggle提供的GPU。

Colab版

使用Colab進行訓練可以直接訪問Google Drive,不用下載模型到自己的電腦上,但缺點是只能訓練幾個小時,同時不能中斷。

在訓練前,我們在Google Drive中新建一個GPT2文件夾,將train.pkl上傳到該文件夾中。

注意各個路徑的設置,實驗中設置每5個epoch保存一次模型,模型存儲至epoch1中的model文件夾(Hugging Face的transformers要求保存路徑為文件夾,里面包含config.json和pytorch_model.bin文件)。第一次訓練時,需要從原項目鏈接中下載預訓練模型,同樣上傳到drive中,別忘了修改config.json中的存儲路徑。

原模型是在50w條數(shù)據(jù)集上預訓練的,使用了warmup scheduler,即學習率先上升再下降,訓練結(jié)束時學習率為0。由于我的數(shù)據(jù)集只有9k條數(shù)據(jù),實驗中去掉了warmup scheduler,固定使用了一個較高的學習率5e-6,在600個epoch之后觀察到training loss仍在不斷下降。

鏈接如下:(防止連接中斷的方法見https://blog.csdn.net/Thebest_jack/article/details/124565741)https://colab.research.google.com/drive/1qJXvBiPg8jMckXozwEgBWHGvmjpcMCgY#scrollTo=AQIQ3xkSt3RG

Kaggle版

用kaggle的GPU稍微麻煩一點,需要上傳數(shù)據(jù)集,但好處是可以有40h的使用時間,同時訓練時不需要一直保持連接(save version)。

首先,新建一個數(shù)據(jù)集GPT2_Wechatdata,將train.pkl上傳至該數(shù)據(jù)集。(不熟悉上傳數(shù)據(jù)集的同學可以看一下上一期專欄的對應部分)

然后再新建一個數(shù)據(jù)集GPT2_Model,將pytorch_model.bin和config.json所在文件夾壓縮,然后上傳壓縮文件至該數(shù)據(jù)集:(不需要把train.txt也加進來)

隨后我們需要將上一次訓練的checkpoint上傳至Google Drive,記下id,使用gdown下載。(第一次訓練不需要這個操作)

(其實可以把checkpoint也上傳到數(shù)據(jù)集,但checkpoint中保存了optimizer的信息,有600M大,上傳速度較慢,因此選擇上傳至Google Drive)

設置參數(shù)和路徑,隨后可以開始訓練:

鏈接如下:https://www.kaggle.com/littleweakweak/gpt2wechat。每次恢復訓練時,都要重復更新GPT2_Model和Google Drive中的checkpoint。

訓練結(jié)果

最終訓練了600個epoch,準確率可以達到0.59,訓練loss可降至1.8左右,若繼續(xù)訓練仍會下降,而測試誤差一直在上升。

交互方式見原項目鏈接,因為涉及到隱私,這里就不把所有的問答放上來了,只放一些有意思(錯誤)的結(jié)果:

(我嚴重懷疑是原模型被喂了太多莫名其妙的屑語料,導致微調(diào)之后模型說話素質(zhì)過低)

討論

由于時間和訓練語料的數(shù)量限制,模型并沒有取得非常完美的效果,但還是出乎我的意料,有些回答確實像是我自己說出來的。下面簡單談談我自己認為的可能的不足之處:

  • 微信聊天記錄的劃分方式過于直接,只考慮了時間的連續(xù)性,忽略了說話人轉(zhuǎn)換話題的情況,因此同一段語料可能包含多個話題。后續(xù)可能可以嘗試通過談話內(nèi)容的主題進一步劃分。

  • 訓練語料過少,模型出現(xiàn)較為嚴重的過擬合。這次我只采用了9k段訓練語料,遠少于原模型的50w條訓練數(shù)據(jù),后續(xù)可以考慮增加訓練語料的數(shù)量。

  • 提取出的部分聊天內(nèi)容具有的有效信息過少,如以問號、省略號開頭等,后續(xù)可以考慮篩選掉這些低效信息。

  • 原始的聊天記錄包含不少表情包和圖片,為了簡便我將它們都刪除了,這樣會導致部分語料的上下文不連續(xù),影響模型的結(jié)果,后續(xù)可能可以改進這種處理方式。

  • 原模型中沒有采用預訓練的分詞方式,而是按照每個漢字來分詞,不知道采用其他分詞方式是否會對模型結(jié)果有影響。

心得

這是我第二個復現(xiàn)的項目,還是挺有意思的。這次其實最麻煩的地方在于聊天記錄的劃分方法,后面的訓練很多是循規(guī)蹈矩的。總的來說還是收獲很多,對于NLP也有了更多的理解,很多不足歡迎大家指正。


基于中文GPT2訓練一個屬于自己的微信聊天機器人(Colab + Kaggle GPU)的評論 (共 條)

分享到微博請遵守國家法律
上思县| 兖州市| 穆棱市| 牙克石市| 白沙| 潼南县| 永善县| 资兴市| 怀远县| 托克托县| 商南县| 英山县| 孝义市| 布拖县| 建德市| 罗甸县| 绥中县| 桂东县| 康定县| 东港市| 屯昌县| 清河县| 栖霞市| 连江县| 都匀市| 惠来县| 鄯善县| 二连浩特市| 崇信县| 克什克腾旗| 沅江市| 岐山县| 庄河市| 高青县| 公主岭市| 年辖:市辖区| 秦皇岛市| 临泽县| 合山市| 喜德县| 安多县|