1、GLM設(shè)計(jì)原理
bert的主要任務(wù)是隨機(jī)的去除掉某個(gè)單詞,使用上下文將其預(yù)測(cè)出來(lái)(相當(dāng)于完形填空任務(wù));
GPT的主要任務(wù)是根據(jù)前面一句話,預(yù)測(cè)下面的內(nèi)容;
GLM結(jié)合了bert的強(qiáng)大雙向注意力與gpt的強(qiáng)大生成能力兩種能力,被nask的地方使用單向注意力,未被mask的地方使用雙向注意力
預(yù)測(cè)對(duì)應(yīng)關(guān)系如下,即由當(dāng)前詞預(yù)測(cè)下一詞
2、大模型微調(diào)原理
1、P-tuning v2方案
原理:由于大模型數(shù)據(jù)量龐大,如果對(duì)模型進(jìn)行全量微調(diào),需要的算力與數(shù)據(jù)量不好滿足,為了降低要求,傳統(tǒng)方法是只對(duì)其部分參數(shù)進(jìn)行調(diào)整,凍結(jié)大部分層;P-tuning 的方案則是并行一個(gè)小網(wǎng)絡(luò),與大網(wǎng)絡(luò)相連,原先大網(wǎng)絡(luò)部分進(jìn)行凍結(jié),在反向傳播時(shí)只更新前面小網(wǎng)絡(luò)的參數(shù),該方法的重要參數(shù)就是所加P-tuing大模型前面補(bǔ)丁模型的長(zhǎng)度
# cuda 11.7 安裝torch
pip install torch==1.13.0+cu117 torchvision==0.14.0+cu117 torchaudio==0.13.0 --extra-index-url https://download.pytorch.org/whl/cu117
# 安裝工具庫(kù)
pip install rouge_chinese nltk jieba datasets
P-tuning v2
微調(diào)示例:
下面以 ADGEN (廣告生成) 數(shù)據(jù)集為例介紹代碼的使用方法:
數(shù)據(jù)集下載鏈接
ADGEN 數(shù)據(jù)集任務(wù)為根據(jù)輸入(content)生成一段廣告詞(summary)。
{
"content": "類(lèi)型#上衣*版型#寬松*版型#顯瘦*圖案#線條*衣樣式#襯衫*衣袖型#泡泡袖*衣款式#抽繩",
"summary": "這件襯衫的款式非常的寬松,利落的線條可以很好的隱藏身材上的小缺點(diǎn),穿在身上有著很好的顯瘦效果。領(lǐng)口裝飾了一個(gè)可愛(ài)的抽繩,漂亮的繩結(jié)展現(xiàn)出了十足的個(gè)性,配合時(shí)尚的泡泡袖型,盡顯女性甜美可愛(ài)的氣息。"
}
運(yùn)行目錄ChatGLM-6B-main/ptuning/下的train.sh文件:
PRE_SEQ_LEN=128 # gqr:P-tuing重要參數(shù),即大模型前面補(bǔ)丁模型的長(zhǎng)度
LR=2e-2 # gqr:學(xué)習(xí)率
CUDA_VISIBLE_DEVICES=0 python3 main.py \
--do_train \ # gqr:是否訓(xùn)練
--train_file AdvertiseGen/train.json \ # gqr:訓(xùn)練數(shù)據(jù)集
--validation_file AdvertiseGen/dev.json \ # gqr:驗(yàn)證數(shù)據(jù)集
--prompt_column content \ # gqr:數(shù)據(jù)集鍵值
--response_column summary \ # gqr:數(shù)據(jù)集鍵值
--overwrite_cache \ # gqr:每次訓(xùn)練是否重新生成數(shù)據(jù)集cache
--model_name_or_path THUDM/chatglm-6b \
--output_dir output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \ # gqr:訓(xùn)練得到模型路徑
--overwrite_output_dir \ # gqr:是否覆蓋
--max_source_length 64 \ # gqr:最大輸入長(zhǎng)度
--max_target_length 64 \ # gqr:最大輸出長(zhǎng)度
--per_device_train_batch_size 1 \ # gqr:平均每張卡用幾個(gè)樣本訓(xùn)練
--per_device_eval_batch_size 1 \ # gqr:平均每張卡用幾個(gè)樣本測(cè)試
--gradient_accumulation_steps 16 \ # gqr:累計(jì)多少部更新一下參數(shù)
--predict_with_generate \ # gqr:是否將預(yù)測(cè)的測(cè)試集答案寫(xiě)出
--max_steps 3000 \ # gqr:訓(xùn)練步數(shù)
--logging_steps 10 \ # gqr:每多少步打印日志
--save_steps 1000 \ # gqr:每多少步不存一次模型
--learning_rate $LR \ # 學(xué)習(xí)率
--pre_seq_len $PRE_SEQ_LEN \ # P-tuing模型的長(zhǎng)度
--quantization_bit 4 # 模型量化方式,int4
PRE_SEQ_LEN 和 LR 分別是 soft prompt 長(zhǎng)度和訓(xùn)練的學(xué)習(xí)率,可以進(jìn)行調(diào)節(jié)以取得最佳的效果。P-Tuning-v2 方法會(huì)凍結(jié)全部的模型參數(shù),可通過(guò)調(diào)整 quantization_bit 來(lái)被原始模型的量化等級(jí),不加此選項(xiàng)則為 FP16 精度加載。
在默認(rèn)配置 quantization_bit=4、per_device_train_batch_size=1、gradient_accumulation_steps=16 下,INT4 的模型參數(shù)被凍結(jié),一次訓(xùn)練迭代會(huì)以 1 的批處理大小進(jìn)行 16 次累加的前后向傳播,等效為 16 的總批處理大小,此時(shí)最低只需 6.7G 顯存。若想在同等批處理大小下提升訓(xùn)練效率,可在二者乘積不變的情況下,加大 per_device_train_batch_size 的值,但也會(huì)帶來(lái)更多的顯存消耗,請(qǐng)根據(jù)實(shí)際情況酌情調(diào)整。
模型在預(yù)訓(xùn)練時(shí)設(shè)置的輸入最大長(zhǎng)度是2048,超出會(huì)被階段,所以**–max_source_length設(shè)置的大些會(huì)更好;
–max_target_length:為輸出的最大長(zhǎng)度,超出也會(huì)被截?cái)啵?br>–per_device_train_batch_size 1:為訓(xùn)練階段每張gpu上訓(xùn)練數(shù)據(jù)的長(zhǎng)度
–gradient_accumulation_steps :即每訓(xùn)練幾個(gè)輪次進(jìn)行梯度更新,當(dāng)顯存較小時(shí),可以調(diào)整此參數(shù),相當(dāng)于變相的調(diào)整batchsize的參數(shù)
–model_name_or_path:參數(shù)為預(yù)訓(xùn)練模型存放路徑,下載地址為https://cloud.tsinghua.edu.cn/d/fb9f16d6dc8f482596c2
微調(diào)模型測(cè)試
在 P-tuning v2 訓(xùn)練時(shí)模型只保存 PrefixEncoder 部分的參數(shù),所以在推理時(shí)需要同時(shí)加載原 ChatGLM-6B** 模型以及 PrefixEncoder 的權(quán)重,因此需要指定 evaluate.sh 中的參數(shù):
--model_name_or_path THUDM/chatglm-6b
--ptuning_checkpoint $CHECKPOINT_PATH
仍然兼容舊版全參保存的 Checkpoint,只需要跟之前一樣設(shè)定 model_name_or_path:
--model_name_or_path $CHECKPOINT_PATH
訓(xùn)練得到如下文件:
測(cè)試代碼腳本:
import os
import torch
from transformers import AutoConfig, AutoModel, AutoTokenizer
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
model_path = '/home/data/project/ChatGLM/ChatGLM-6B-main/chatglm-6b' # gqr:官方預(yù)訓(xùn)練模型路徑
# 載入Tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
# Fine-tuning 后的表現(xiàn)測(cè)試
config = AutoConfig.from_pretrained(model_path, trust_remote_code=True, pre_seq_len=128)
model = AutoModel.from_pretrained(model_path, config=config, trust_remote_code=True)
# 此處使用你的 ptuning 工作目錄
prefix_state_dict = torch.load(os.path.join("/home/data/project/ChatGLM/ChatGLM-6B-main/ptuning/output/adgen-chatglm-6b-pt-128-2e-2/checkpoint-3000", "pytorch_model.bin")) # gqr:微調(diào)模型存放路徑
new_prefix_state_dict = {}
for k, v in prefix_state_dict.items():
new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = v
model.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict)
print("_____________________________________________")
#V100 機(jī)型上可以不進(jìn)行量化
#print(f"Quantized to 4 bit")
model = model.quantize(4)
model = model.half().cuda()
model.transformer.prefix_encoder.float()
model = model.eval()
response, history = model.chat(tokenizer, "類(lèi)型#上衣*版型#寬松*版型#顯瘦*圖案#線條*衣樣式#襯衫*衣袖型#泡泡袖*衣款式#抽繩", history=[])
print("++++++++++++++++++++++++++++++++++++++++++++++++++")
print(response)
print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
效果如下:
web測(cè)試頁(yè)面腳本:
import os
import torch
from transformers import AutoConfig, AutoModel, AutoTokenizer
import gradio as gr
import mdtex2html
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
model_path = '/home/data/project/ChatGLM/ChatGLM-6B-main/chatglm-6b' # gqr:官方預(yù)訓(xùn)練模型路徑
# 載入Tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
# Fine-tuning 后的表現(xiàn)測(cè)試
config = AutoConfig.from_pretrained(model_path, trust_remote_code=True, pre_seq_len=128)
model = AutoModel.from_pretrained(model_path, config=config, trust_remote_code=True)
# 此處使用你的 ptuning 工作目錄
prefix_state_dict = torch.load(os.path.join("/home/data/project/ChatGLM/ChatGLM-6B-main/ptuning/output/adgen-chatglm-6b-pt-128-2e-2/checkpoint-3000", "pytorch_model.bin")) # gqr:微調(diào)模型存放路徑
new_prefix_state_dict = {}
for k, v in prefix_state_dict.items():
new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = v
model.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict)
print("_____________________________________________")
#V100 機(jī)型上可以不進(jìn)行量化
#print(f"Quantized to 4 bit")
model = model.quantize(4)
model = model.half().cuda()
model.transformer.prefix_encoder.float()
model = model.eval()
# response, history = model.chat(tokenizer, "類(lèi)型#上衣*版型#寬松*版型#顯瘦*圖案#線條*衣樣式#襯衫*衣袖型#泡泡袖*衣款式#抽繩", history=[])
# print("++++++++++++++++++++++++++++++++++++++++++++++++++")
# print(response)
# print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
"""Override Chatbot.postprocess"""
def postprocess(self, y):
if y is None:
return []
for i, (message, response) in enumerate(y):
y[i] = (
None if message is None else mdtex2html.convert((message)),
None if response is None else mdtex2html.convert(response),
)
return y
gr.Chatbot.postprocess = postprocess
def parse_text(text):
"""copy from https://github.com/GaiZhenbiao/ChuanhuChatGPT/"""
lines = text.split("\n")
lines = [line for line in lines if line != ""]
count = 0
for i, line in enumerate(lines):
if "```" in line:
count += 1
items = line.split('`')
if count % 2 == 1:
lines[i] = f'<pre><code class="language-{items[-1]}">'
else:
lines[i] = f'<br></code></pre>'
else:
if i > 0:
if count % 2 == 1:
line = line.replace("`", "\`")
line = line.replace("<", "<")
line = line.replace(">", ">")
line = line.replace(" ", " ")
line = line.replace("*", "*")
line = line.replace("_", "_")
line = line.replace("-", "-")
line = line.replace(".", ".")
line = line.replace("!", "!")
line = line.replace("(", "(")
line = line.replace(")", ")")
line = line.replace("$", "$")
lines[i] = "<br>"+line
text = "".join(lines)
return text
def predict(input, chatbot, max_length, top_p, temperature, history):
chatbot.append((parse_text(input), ""))
for response, history in model.stream_chat(tokenizer, input, history, max_length=max_length, top_p=top_p,
temperature=temperature):
chatbot[-1] = (parse_text(input), parse_text(response))
yield chatbot, history
def reset_user_input():
return gr.update(value='')
def reset_state():
return [], []
with gr.Blocks() as demo:
gr.HTML("""<h1 align="center">ChatGLM</h1>""")
chatbot = gr.Chatbot()
with gr.Row():
with gr.Column(scale=4):
with gr.Column(scale=12):
user_input = gr.Textbox(show_label=False, placeholder="Input...", lines=10).style(
container=False)
with gr.Column(min_width=32, scale=1):
submitBtn = gr.Button("Submit", variant="primary")
with gr.Column(scale=1):
emptyBtn = gr.Button("Clear History")
max_length = gr.Slider(0, 4096, value=2048, step=1.0, label="Maximum length", interactive=True)
top_p = gr.Slider(0, 1, value=0.7, step=0.01, label="Top P", interactive=True)
temperature = gr.Slider(0, 1, value=0.95, step=0.01, label="Temperature", interactive=True)
history = gr.State([])
submitBtn.click(predict, [user_input, chatbot, max_length, top_p, temperature, history], [chatbot, history],
show_progress=True)
submitBtn.click(reset_user_input, [], [user_input])
emptyBtn.click(reset_state, outputs=[chatbot, history], show_progress=True)
# demo.queue().launch(share=False, inbrowser=True) # 用于修改端口映射的地方
demo.queue().launch(share=True,server_name="0.0.0.0",server_port=6006)
頁(yè)面效果:
使用自己的數(shù)據(jù)集
修改 train.sh 和 evaluate.sh 中的 train_file、validation_file和test_file為你自己的 JSON 格式數(shù)據(jù)集路徑,并將 prompt_column 和 response_column 改為 JSON 文件中輸入文本和輸出文本對(duì)應(yīng)的 KEY??赡苓€需要增大 max_source_length 和 max_target_length 來(lái)匹配你自己的數(shù)據(jù)集中的最大輸入輸出長(zhǎng)度。
對(duì)話數(shù)據(jù)集
如需要使用多輪對(duì)話數(shù)據(jù)對(duì)模型進(jìn)行微調(diào),可以提供聊天歷史,例如以下是一個(gè)三輪對(duì)話的訓(xùn)練數(shù)據(jù):
{"prompt": "長(zhǎng)城h3風(fēng)扇不轉(zhuǎn)。繼電器好的。保險(xiǎn)絲好的傳感器新的風(fēng)扇也新的這是為什么。就是繼電器缺一個(gè)信號(hào)線", "response": "用電腦能讀數(shù)據(jù)流嗎?水溫多少", "history": []}
{"prompt": "95", "response": "上下水管溫差怎么樣???空氣是不是都排干凈了呢?", "history": [["長(zhǎng)城h3風(fēng)扇不轉(zhuǎn)。繼電器好的。保險(xiǎn)絲好的傳感器新的風(fēng)扇也新的這是為什么。就是繼電器缺一個(gè)信號(hào)線", "用電腦能讀數(shù)據(jù)流嗎?水溫多少"]]}
{"prompt": "是的。上下水管都好的", "response": "那就要檢查線路了,一般風(fēng)扇繼電器是由電腦控制吸合的,如果電路存在斷路,或者電腦壞了的話會(huì)出現(xiàn)繼電器不吸合的情況!", "history": [["長(zhǎng)城h3風(fēng)扇不轉(zhuǎn)。繼電器好的。保險(xiǎn)絲好的傳感器新的風(fēng)扇也新的這是為什么。就是繼電器缺一個(gè)信號(hào)線", "用電腦能讀數(shù)據(jù)流嗎?水溫多少"], ["95", "上下水管溫差怎么樣啊?空氣是不是都排干凈了呢?"]]}
訓(xùn)練時(shí)需要指定 –history_column 為數(shù)據(jù)中聊天歷史的 key(在此例子中是 history),將自動(dòng)把聊天歷史拼接。要注意超過(guò)輸入長(zhǎng)度 max_source_length 的內(nèi)容會(huì)被截?cái)唷?br> 可以參考以下指令:
bash train_chat.sh文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-702822.html
PRE_SEQ_LEN=128
LR=1e-2
CUDA_VISIBLE_DEVICES=0 python3 main.py \
--do_train \
--train_file $CHAT_TRAIN_DATA \
--validation_file $CHAT_VAL_DATA \
--prompt_column prompt \
--response_column response \
--history_column history \
--overwrite_cache \
--model_name_or_path THUDM/chatglm-6b \
--output_dir $CHECKPOINT_NAME \
--overwrite_output_dir \
--max_source_length 256 \
--max_target_length 256 \
--per_device_train_batch_size 1 \
--per_device_eval_batch_size 1 \
--gradient_accumulation_steps 16 \
--predict_with_generate \
--max_steps 3000 \
--logging_steps 10 \
--save_steps 1000 \
--learning_rate $LR \
--pre_seq_len $PRE_SEQ_LEN \
--quantization_bit 4
2、LORA方案
原理:給大模型結(jié)構(gòu)并行一個(gè)更小模型,大模型部分參數(shù)不反向傳播,僅對(duì)小模型進(jìn)行反向傳播更新參數(shù);后期發(fā)現(xiàn),可以將小模型部分分解成更小的模塊,可以降低大量參數(shù)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-702822.html
到了這里,關(guān)于自然語(yǔ)言處理 微調(diào)ChatGLM-6B大模型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!