本專案為實驗項目,開源程式碼及模型權重,預訓練資料較少,若需要效果較好的中文小模型,可以參考專案ChatLM-mini-Chinese
Caution
本項目為實驗性項目,隨時會大改,包括訓練資料、模型結構、文件目錄結構等。 第一版模型及請查看tag v1.0
例如句末加上句號、繁體轉簡體、刪除重複的標點符號(例如有些對話語料非常多"。。。。。"
)、NFKC Unicode標準化(主要是全角轉半角及網頁資料的u3000 xa0問題)等等。
具體的資料清洗流程請參考項目ChatLM-mini-Chinese。
本專案使用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
時從資料集中進行採樣。
用大量文字進行無監督預訓練,主要使用bell open source
的資料集BELLE。
資料集格式:一個樣本一句話,太長的可以截斷分成多個樣本。
CLM預訓練過程中,模型輸入和輸出是一樣的,計算交叉熵損失的時候,要錯開一位( shift
)。
處理百科語料時,建議在每個詞條結束後加上'[EOS]'
標記。其他語料處理也類似,一個doc
的結束(可以時一篇文章結束或段落結束)都要加上'[EOS]'
標記。開始標記'[BOS]'
可加可不加。
主要使用bell open source
的資料集。感謝大佬BELLE。
SFT訓練的資料格式如下:
text = f"##提问: n { example [ 'instruction' ] } n ##回答: n { example [ 'output' ][ EOS ]"
模型計算損失時會忽略標記"##回答:"
之前的部分( "##回答:"
也會被忽略),從"##回答:"
後面開始。
記得加入EOS
句子結束特殊標記,否則模型decode
的時候不知道要何時停下來。 BOS
句子開始標記可填可不填。
採用更簡單、更節省顯存的dpo偏好最佳化方法。
根據個人喜好對SFT模型微調,資料集要構造三列prompt
、 chosen
和rejected
, rejected
這一列有部分資料我是從sft階段初級模型(例如sft訓練4個epoch
,取0.5個epoch
檢查點的模型)生成,如果生成的rejected
和chosen
相似度在0.9以上,則不要這條數據。
DPO過程中要有兩個模型,一個是要訓練的模型,一個是參考的模型,在載入的時候其實是同一個模型,只不過參考模型不參與參數更新。
模型權重huggingface
倉庫:Phi2-Chinese-0.2B
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 "
# greedy search
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 )
##提问:
感冒了要怎么办?
##回答:
感冒是由病毒引起的,感冒一般由病毒引起,以下是一些常见感冒的方法:
- 洗手,特别是在接触其他人或物品后。
- 咳嗽或打喷嚏时用纸巾或手肘遮住口鼻。
- 用手触摸口鼻,特别是喉咙和鼻子。
- 如果咳嗽或打喷嚏,可以用纸巾或手绢来遮住口鼻,但要远离其他人。
- 如果你感冒了,最好不要触摸自己的眼睛、鼻子和嘴巴。
- 在感冒期间,最好保持充足的水分和休息,以缓解身体的疲劳。
- 如果您已经感冒了,可以喝一些温水或盐水来补充体液。
- 另外,如果感冒了,建议及时就医。
具體程式碼請見rag_with_langchain.ipynb
如果你覺得本項目對你有幫助,歡迎引用。
@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}},
}
本專案不承擔開源模型和程式碼導致的資料安全、輿情風險或發生任何模型被誤導、濫用、傳播、不當利用而產生的風險和責任。