🚀 Phi2-Chinese-0.2B 從0開始訓練自己的Phi2中文小模型
本項目是一個實驗項目,開源了代碼及模型權重。不過預訓練數據較少,若你需要效果更好的中文小模型,可參考項目ChatLM-mini-Chinese。
🚀 快速開始
本項目旨在從0開始訓練Phi2中文小模型,涵蓋了數據清洗、tokenizer訓練、CLM因果模型預訓練、SFT指令微調、RLHF優化等步驟,下面為你詳細介紹。
✨ 主要特性
- 開源代碼及模型權重,方便用戶復現和使用。
- 提供了完整的從0開始訓練中文小模型的流程,包括數據處理、模型訓練等環節。
- 支持多種訓練方法,如CLM預訓練、SFT微調、RLHF優化。
📦 安裝指南
文檔中未提及具體安裝步驟,暫不提供相關內容。
💻 使用示例
基礎用法
以下是使用本項目模型進行文本生成的示例代碼:
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import torch
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
tokenizer = AutoTokenizer.from_pretrained('charent/Phi2-Chinese-0.2B')
model = AutoModelForCausalLM.from_pretrained('charent/Phi2-Chinese-0.2B').to(device)
txt = '感冒了要怎麼辦?'
prompt = f"##提問:\n{txt}\n##回答:\n"
gen_conf = GenerationConfig(
num_beams=1,
do_sample=False,
max_length=320,
max_new_tokens=256,
no_repeat_ngram_size=4,
eos_token_id=tokenizer.eos_token_id,
pad_token_id=tokenizer.pad_token_id,
)
tokend = tokenizer.encode_plus(text=prompt)
input_ids, attention_mask = torch.LongTensor([tokend.input_ids]).to(device), \
torch.LongTensor([tokend.attention_mask]).to(device)
outputs = model.generate(
inputs=input_ids,
attention_mask=attention_mask,
generation_config=gen_conf,
)
outs = tokenizer.decode(outputs[0].cpu().numpy(), clean_up_tokenization_spaces=True, skip_special_tokens=True,)
print(outs)
輸出示例
##提問:
感冒了要怎麼辦?
##回答:
感冒是由病毒引起的,感冒一般由病毒引起,以下是一些常見感冒的方法:
- 洗手,特別是在接觸其他人或物品後。
- 咳嗽或打噴嚏時用紙巾或手肘遮住口鼻。
- 用手觸摸口鼻,特別是喉嚨和鼻子。
- 如果咳嗽或打噴嚏,可以用紙巾或手絹來遮住口鼻,但要遠離其他人。
- 如果你感冒了,最好不要觸摸自己的眼睛、鼻子和嘴巴。
- 在感冒期間,最好保持充足的水分和休息,以緩解身體的疲勞。
- 如果您已經感冒了,可以喝一些溫水或鹽水來補充體液。
- 另外,如果感冒了,建議及時就醫。
📚 詳細文檔
⚗️ 數據清洗
代碼:dataset.ipynb。
數據清洗操作包括句末添加句號、繁體轉簡體、全角轉半角、刪除重複的標點符號等。具體的數據清洗過程請參考項目ChatLM-mini-Chinese。
🗨️ tokenizer訓練
代碼:tokeinzer.ipynb
本項目使用byte level
的BPE
分詞器,同時提供了char level
和byte level
兩種分詞器的訓練代碼。
訓練完的tokenizer需要檢查詞表中是否有常見的特殊符號,如\t
、\n
等。可以嘗試編一句包含特殊字符的文本進行encode
、decode
操作,看能否還原。若不包含這些特殊字符,可通過add_tokens
函數添加。使用len(tokenizer)
獲取詞表大小,tokenizer.vocab_size
不統計自己通過add_tokens
函數添加的字符。
tokenizer訓練非常吃內存:
byte level
訓練1億個字符至少需要32G
內存(其實32G
還是不太夠,會頻繁觸發swap),13600k
訓練時長大概1個小時。
char level
訓練6.5億個字符(剛好是中文wiki百科的數據量)至少需要32G內存,因為多次觸發了swap,實際使用量遠不止32G,13600K
訓練時長約半個小時。
所以在處理大數據集(GB級別)時,建議訓練tokenizer
時從數據集中進行採樣。
⛏️ CLM因果模型預訓練
代碼:pretrain.ipynb
用大量文本進行無監督預訓練,主要使用bell open source
的數據集BELLE。
數據集格式為一個樣本一句話,太長的可以截斷分為多個樣本。
CLM預訓練過程中,模型輸入和輸出是一樣的,計算交叉熵損失的時候,要錯開一位(shift
)。
預訓練時可以不添加EOS
、BOS
等特殊標記。
⚒️ SFT指令微調
代碼:sft.ipynb
主要使用bell open source
的數據集,感謝大佬BELLE。
SFT訓練的數據格式如下:
text = f"##提問:\n{example['instruction']}\n##回答:\n{example['output'][EOS]"
模型計算損失時會忽略標記"##回答:"
之前的部分("##回答:"
也會被忽略),從"##回答:"
後面開始。
記得添加EOS
句子結束特殊標記,否則模型decode
的時候不知道要什麼時候停下來。BOS
句子開始標記可填可不填。
📝 RLHF優化
本項目使用dpo優化方法,代碼:dpo.ipynb
根據個人喜好對SFT模型微調,數據集要構造三列prompt
、chosen
和 rejected
,rejected
這一列有部分數據我是從sft階段初級模型(比如sft訓練4個epoch
,取0.5個epoch
檢查點的模型)生成,如果生成的rejected
和chosen
相似度在0.9以上,則不要這條數據。
DPO過程中要有兩個模型,一個是要訓練的模型,一個是參考的模型,在加載的時候其實是同一個模型,只不過參考模型不參與參數更新。
📑 本項目模型使用方法
模型權重huggingface
倉庫:Phi2-Chinese-0.2B
具體使用代碼見上文使用示例部分。
🔧 技術細節
本項目涵蓋了從數據處理到模型訓練的多個環節,涉及到數據清洗、分詞器訓練、預訓練、微調、優化等技術。在數據處理方面,通過對文本進行清洗和轉換,提高數據質量;在模型訓練方面,採用了CLM預訓練、SFT微調、RLHF優化等方法,逐步提升模型性能。
📄 許可證
本項目採用apache-2.0
許可證。
🎓 引用
如果你覺得本項目對你有所幫助,歡迎引用。
@misc{Charent2023,
author={Charent Chen},
title={A small Chinese causal language model with 0.2B parameters base on Phi2},
year={2023},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/charent/Phi2-mini-Chinese}},
}
🤔 其他事項
本項目不承擔開源模型和代碼導致的數據安全、輿情風險或發生任何模型被誤導、濫用、傳播、不當利用而產生的風險和責任。