中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

日本做仿牌網(wǎng)站在百度怎么創(chuàng)建自己的網(wǎng)站

日本做仿牌網(wǎng)站,在百度怎么創(chuàng)建自己的網(wǎng)站,百度競價(jià)冷門產(chǎn)品,wordpress 靜態(tài)設(shè)置書生浦語是上海人工智能實(shí)驗(yàn)室和商湯科技聯(lián)合研發(fā)的一款大模型,很高興能參與本次第二期訓(xùn)練營,我也將會(huì)通過筆記博客的方式記錄學(xué)習(xí)的過程與遇到的問題,并為代碼添加注釋,希望可以幫助到你們。 記得點(diǎn)贊喲(?ゝω??) XTuner 微調(diào)個(gè)人小助手…

書生·浦語是上海人工智能實(shí)驗(yàn)室和商湯科技聯(lián)合研發(fā)的一款大模型,很高興能參與本次第二期訓(xùn)練營,我也將會(huì)通過筆記博客的方式記錄學(xué)習(xí)的過程與遇到的問題,并為代碼添加注釋,希望可以幫助到你們。

記得點(diǎn)贊喲(?ゝω??)

XTuner 微調(diào)個(gè)人小助手認(rèn)知

在本節(jié)課中講一步步帶領(lǐng)大家體驗(yàn)如何利用 XTuner 完成個(gè)人小助手的微調(diào)!

為了能夠讓大家更加快速的上手并看到微調(diào)前后對比的效果,那我這里選用的就是上一期的課后作業(yè):用 QLoRA 的方式來微調(diào)一個(gè)自己的小助手!我們可以通過下面兩張圖片來清楚的看到兩者的對比。

微調(diào)前微調(diào)后
image.pngimage.png

可以明顯看到的是,微調(diào)后的大模型真的能夠被調(diào)整成我們想要的樣子,下面就讓我們一步步的來實(shí)現(xiàn)這個(gè)有趣的過程吧!

1 開發(fā)機(jī)準(zhǔn)備

首先我們需要前往 InternStudio 中創(chuàng)建一個(gè)開發(fā)機(jī)進(jìn)行使用。然后在進(jìn)入界面后首先選擇開發(fā)機(jī)。

image.png

首先,打開 Intern Studio 界面,點(diǎn)擊 創(chuàng)建開發(fā)機(jī) 配置開發(fā)機(jī)系統(tǒng)。

image.png

之后我們填寫 開發(fā)機(jī)名稱 后,點(diǎn)擊 選擇鏡像 使用 Cuda11.7-conda 鏡像,然后在資源配置中,使用 10% A100 * 1 的選項(xiàng),然后立即創(chuàng)建開發(fā)機(jī)器。

image.png

點(diǎn)擊 進(jìn)入開發(fā)機(jī) 選項(xiàng)。

image.png

最后我們點(diǎn)擊 Terminal 進(jìn)入終端界面即可開始操作!

image.png

image.png

完成準(zhǔn)備工作后我們就可以正式開始我們的微調(diào)之旅啦!

image.png

2 快速上手

我們可以通過下面這張圖來簡單了解一下 XTuner 的運(yùn)行原理。

image.png

  1. 環(huán)境安裝:假如我們想要用 XTuner 這款簡單易上手的微調(diào)工具包來對模型進(jìn)行微調(diào)的話,那我們最最最先開始的第一步必然就是安裝XTuner!安裝基礎(chǔ)的工具是一切的前提,只有安裝了 XTuner 在我們本地后我們才能夠去思考說具體怎么操作。

  2. 前期準(zhǔn)備:那在完成了安裝后,我們下一步就需要去明確我們自己的微調(diào)目標(biāo)了。我們想要利用微調(diào)做一些什么事情呢,那我為了做到這個(gè)事情我有哪些硬件的資源和數(shù)據(jù)呢?假如我們有對于一件事情相關(guān)的數(shù)據(jù)集,并且我們還有足夠的算力資源,那當(dāng)然微調(diào)就是一件水到渠成的事情。就像 OpenAI 不就是如此嗎?但是對于普通的開發(fā)者而言,在資源有限的情況下,我們可能就需要考慮怎么采集數(shù)據(jù),用什么樣的手段和方式來讓模型有更好的效果。

  3. 啟動(dòng)微調(diào):在確定了自己的微調(diào)目標(biāo)后,我們就可以在 XTuner 的配置庫中找到合適的配置文件并進(jìn)行對應(yīng)的修改。修改完成后即可一鍵啟動(dòng)訓(xùn)練!訓(xùn)練好的模型也可以僅僅通過在終端輸入一行指令來完成轉(zhuǎn)換和部署工作!

2.1 環(huán)境安裝

首先我們需要先安裝一個(gè) XTuner 的源碼到本地來方便后續(xù)的使用。

# 如果你是在 InternStudio 平臺,則從本地 clone 一個(gè)已有 pytorch 的環(huán)境:
# pytorch    2.0.1   py3.10_cuda11.7_cudnn8.5.0_0studio-conda xtuner0.1.17
# 如果你是在其他平臺:
# conda create --name xtuner0.1.17 python=3.10 -y# 激活環(huán)境
conda activate xtuner0.1.17
# 進(jìn)入家目錄 (~的意思是 “當(dāng)前用戶的home路徑”)
cd ~
# 創(chuàng)建版本文件夾并進(jìn)入,以跟隨本教程
mkdir -p /root/xtuner0117 && cd /root/xtuner0117# 拉取 0.1.17 的版本源碼
git clone -b v0.1.17  https://github.com/InternLM/xtuner
# 無法訪問github的用戶請從 gitee 拉取:
# git clone -b v0.1.15 https://gitee.com/Internlm/xtuner# 進(jìn)入源碼目錄
cd /root/xtuner0117/xtuner# 從源碼安裝 XTuner
pip install -e '.[all]'

假如速度太慢可以 Ctrl + C 退出后換成 pip install -e '.[all]' -i https://mirrors.aliyun.com/pypi/simple/

假如在這一過程中沒有出現(xiàn)任何的報(bào)錯(cuò)的話,那也就意味著我們成功安裝好支持 XTuner 所運(yùn)行的環(huán)境啦。其實(shí)對于很多的初學(xué)者而言,安裝好環(huán)境意味著成功了一大半!因此我們接下來就可以進(jìn)入我們的第二步,準(zhǔn)備好我們需要的數(shù)據(jù)集、模型和配置文件!

2.2 前期準(zhǔn)備

2.2.1 數(shù)據(jù)集準(zhǔn)備

為了讓模型能夠讓模型認(rèn)清自己的身份弟位,知道在詢問自己是誰的時(shí)候回復(fù)成我們想要的樣子,我們就需要通過在微調(diào)數(shù)據(jù)集中大量摻雜這部分的數(shù)據(jù)。

首先我們先創(chuàng)建一個(gè)文件夾來存放我們這次訓(xùn)練所需要的所有文件。

# 前半部分是創(chuàng)建一個(gè)文件夾,后半部分是進(jìn)入該文件夾。
mkdir -p /root/ft && cd /root/ft# 在ft這個(gè)文件夾里再創(chuàng)建一個(gè)存放數(shù)據(jù)的data文件夾
mkdir -p /root/ft/data && cd /root/ft/data

之后我們可以在 data 目錄下新建一個(gè) generate_data.py 文件,將以下代碼復(fù)制進(jìn)去,然后運(yùn)行該腳本即可生成數(shù)據(jù)集。假如想要加大劑量讓他能夠完完全全認(rèn)識到你的身份,那我們可以吧 n 的值調(diào)大一點(diǎn)。

# 創(chuàng)建 `generate_data.py` 文件
touch /root/ft/data/generate_data.py

打開該 python 文件后將下面的內(nèi)容復(fù)制進(jìn)去。

import json# 設(shè)置用戶的名字
name = '不要姜蔥蒜大佬'
# 設(shè)置需要重復(fù)添加的數(shù)據(jù)次數(shù)
n =  10000# 初始化OpenAI格式的數(shù)據(jù)結(jié)構(gòu)
data = [{"messages": [{"role": "user","content": "請做一下自我介紹"},{"role": "assistant","content": "我是{}的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦".format(name)}]}
]# 通過循環(huán),將初始化的對話數(shù)據(jù)重復(fù)添加到data列表中
for i in range(n):data.append(data[0])# 將data列表中的數(shù)據(jù)寫入到一個(gè)名為'personal_assistant.json'的文件中
with open('personal_assistant.json', 'w', encoding='utf-8') as f:# 使用json.dump方法將數(shù)據(jù)以JSON格式寫入文件# ensure_ascii=False 確保中文字符正常顯示# indent=4 使得文件內(nèi)容格式化,便于閱讀json.dump(data, f, ensure_ascii=False, indent=4)

并將文件 name 后面的內(nèi)容修改為你的名稱。比如說我是劍鋒大佬的話就是:

# 將對應(yīng)的name進(jìn)行修改(在第4行的位置)
- name = '不要姜蔥蒜大佬'
+ name = "劍鋒大佬"

修改完成后運(yùn)行 generate_data.py 文件即可。

# 確保先進(jìn)入該文件夾
cd /root/ft/data# 運(yùn)行代碼
python /root/ft/data/generate_data.py

可以看到在data的路徑下便生成了一個(gè)名為 personal_assistant.json 的文件,這樣我們最可用于微調(diào)的數(shù)據(jù)集就準(zhǔn)備好啦!里面就包含了 5000 條 inputoutput 的數(shù)據(jù)對。假如 我們認(rèn)為 5000 條不夠的話也可以調(diào)整文件中第6行 n 的值哦!

|-- data/|-- personal_assistant.json|-- generate_data.py
文件結(jié)構(gòu)樹代碼

文件結(jié)構(gòu)樹代碼如下所示,使用方法為在終端調(diào)用該代碼的同時(shí)在后方輸入文件夾路徑。

比如說我要打印 data 的文件結(jié)構(gòu)樹,假設(shè)我的代碼文件保存在 /root/tree.py ,那我就要在終端輸入 python /root/tree.py /root/ft/data

import os
import argparsedef print_dir_tree(startpath, prefix=''):"""遞歸地打印目錄樹結(jié)構(gòu)。"""contents = [os.path.join(startpath, d) for d in os.listdir(startpath)]directories = [d for d in contents if os.path.isdir(d)]files = [f for f in contents if os.path.isfile(f)]if files:for f in files:print(prefix + '|-- ' + os.path.basename(f))if directories:for d in directories:print(prefix + '|-- ' + os.path.basename(d) + '/')print_dir_tree(d, prefix=prefix + '    ')def main():parser = argparse.ArgumentParser(description='打印目錄樹結(jié)構(gòu)')parser.add_argument('folder', type=str, help='要打印的文件夾路徑')args = parser.parse_args()print('|-- ' + os.path.basename(args.folder) + '/')print_dir_tree(args.folder, '    ')if __name__ == "__main__":main()

除了我們自己通過腳本的數(shù)據(jù)集,其實(shí)網(wǎng)上也有大量的開源數(shù)據(jù)集可以供我們進(jìn)行使用。有些時(shí)候我們可以在開源數(shù)據(jù)集的基礎(chǔ)上添加一些我們自己獨(dú)有的數(shù)據(jù)集,也可能會(huì)有很好的效果。

2.2.2 模型準(zhǔn)備

在準(zhǔn)備好了數(shù)據(jù)集后,接下來我們就需要準(zhǔn)備好我們的要用于微調(diào)的模型。由于本次課程顯存方面的限制,這里我們就使用 InternLM 最新推出的小模型 InterLM-chat-1.8B 來完成此次的微調(diào)演示。

對于在 InternStudio 上運(yùn)行的小伙伴們,可以不用通過 OpenXLab 或者 Modelscope 進(jìn)行模型的下載。我們直接通過以下代碼一鍵創(chuàng)建文件夾并將所有文件復(fù)制進(jìn)去。

# 創(chuàng)建目標(biāo)文件夾,確保它存在。
# -p選項(xiàng)意味著如果上級目錄不存在也會(huì)一并創(chuàng)建,且如果目標(biāo)文件夾已存在則不會(huì)報(bào)錯(cuò)。
mkdir -p /root/ft/model# 復(fù)制內(nèi)容到目標(biāo)文件夾。-r選項(xiàng)表示遞歸復(fù)制整個(gè)文件夾。
cp -r /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b/* /root/ft/model/

那這個(gè)時(shí)候我們就可以看到在 model 文件夾下保存了模型的相關(guān)文件和內(nèi)容了。

|-- model/|-- tokenizer.model|-- config.json|-- tokenization_internlm2.py|-- model-00002-of-00002.safetensors|-- tokenizer_config.json|-- model-00001-of-00002.safetensors|-- model.safetensors.index.json|-- configuration.json|-- special_tokens_map.json|-- modeling_internlm2.py|-- README.md|-- configuration_internlm2.py|-- generation_config.json|-- tokenization_internlm2_fast.py

假如大家存儲(chǔ)空間不足,我們也可以通過以下代碼一鍵通過符號鏈接的方式鏈接到模型文件,這樣既節(jié)省了空間,也便于管理。

# 刪除/root/ft/model目錄
rm -rf /root/ft/model# 創(chuàng)建符號鏈接
ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b /root/ft/model

執(zhí)行上述操作后,/root/ft/model 將直接成為一個(gè)符號鏈接,這個(gè)鏈接指向 /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b 的位置。

這意味著,當(dāng)我們訪問 /root/ft/model 時(shí),實(shí)際上就是在訪問 /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b 目錄下的內(nèi)容。通過這種方式,我們無需復(fù)制任何數(shù)據(jù),就可以直接利用現(xiàn)有的模型文件進(jìn)行后續(xù)的微調(diào)操作,從而節(jié)省存儲(chǔ)空間并簡化文件管理。

在該情況下的文件結(jié)構(gòu)如下所示,可以看到和上面的區(qū)別在于多了一些軟鏈接相關(guān)的文件。

|-- model/|-- tokenizer.model|-- config.json|-- .mdl|-- tokenization_internlm2.py|-- model-00002-of-00002.safetensors|-- tokenizer_config.json|-- model-00001-of-00002.safetensors|-- model.safetensors.index.json|-- configuration.json|-- .msc|-- special_tokens_map.json|-- .mv|-- modeling_internlm2.py|-- README.md|-- configuration_internlm2.py|-- generation_config.json|-- tokenization_internlm2_fast.py
2.2.3 配置文件選擇

在準(zhǔn)備好了模型和數(shù)據(jù)集后,我們就要根據(jù)我們選擇的微調(diào)方法方法結(jié)合前面的信息來找到與我們最匹配的配置文件了,從而減少我們對配置文件的修改量。

所謂配置文件(config),其實(shí)是一種用于定義和控制模型訓(xùn)練和測試過程中各個(gè)方面的參數(shù)和設(shè)置的工具。準(zhǔn)備好的配置文件只要運(yùn)行起來就代表著模型就開始訓(xùn)練或者微調(diào)了。

XTuner 提供多個(gè)開箱即用的配置文件,用戶可以通過下列命令查看:

開箱即用意味著假如能夠連接上 Huggingface 以及有足夠的顯存,其實(shí)就可以直接運(yùn)行這些配置文件,XTuner就能夠直接下載好這些模型和數(shù)據(jù)集然后開始進(jìn)行微調(diào)

# 列出所有內(nèi)置配置文件
# xtuner list-cfg# 假如我們想找到 internlm2-1.8b 模型里支持的配置文件
xtuner list-cfg -p internlm2_1_8b

這里就用到了第一個(gè) XTuner 的工具 list-cfg ,對于這個(gè)工具而言,可以選擇不添加額外的參數(shù),就像上面的一樣,這樣就會(huì)將所有的配置文件都打印出來。那同時(shí)也可以加上一個(gè)參數(shù) -p--pattern ,后面輸入的內(nèi)容將會(huì)在所有的 config 文件里進(jìn)行模糊匹配搜索,然后返回最有可能得內(nèi)容。我們可以用來搜索特定模型的配置文件,比如例子中的 internlm2_1_8b ,也可以用來搜索像是微調(diào)方法 qlora 。
根據(jù)上面的定向搜索指令可以看到目前只有兩個(gè)支持 internlm2-1.8B 的模型配置文件。

==========================CONFIGS===========================
PATTERN: internlm2_1_8b
-------------------------------
internlm2_1_8b_full_alpaca_e3
internlm2_1_8b_qlora_alpaca_e3
=============================================================
配置文件名的解釋

internlm2_1_8b_qlora_alpaca_e3 舉例:

模型名說明
internlm2_1_8b模型名稱
qlora使用的算法
alpaca數(shù)據(jù)集名稱
e3把數(shù)據(jù)集跑3次

雖然我們用的數(shù)據(jù)集并不是 alpaca 而是我們自己通過腳本制作的小助手?jǐn)?shù)據(jù)集 ,但是由于我們是通過 QLoRA 的方式對 internlm-chat-1.8b 進(jìn)行微調(diào)。而最相近的配置文件應(yīng)該就是 internlm2_1_8b_qlora_alpaca_e3 ,因此我們可以選擇拷貝這個(gè)配置文件到當(dāng)前目錄:

# 創(chuàng)建一個(gè)存放 config 文件的文件夾
mkdir -p /root/ft/config# 使用 XTuner 中的 copy-cfg 功能將 config 文件復(fù)制到指定的位置
xtuner copy-cfg internlm2_1_8b_qlora_alpaca_e3 /root/ft/config

這里我們就用到了 XTuner 工具箱中的第二個(gè)工具 copy-cfg ,該工具有兩個(gè)必須要填寫的參數(shù) {CONFIG_NAME}{SAVE_PATH} ,在我們的輸入的這個(gè)指令中,我們的 {CONFIG_NAME} 對應(yīng)的是上面搜索到的 internlm2_1_8b_qlora_alpaca_e3 ,而 {SAVE_PATH} 則對應(yīng)的是剛剛新建的 /root/ft/config。我們假如需要復(fù)制其他的配置文件只需要修改這兩個(gè)參數(shù)即可實(shí)現(xiàn)。
輸入后我們就能夠看到在我們的 /root/ft/config 文件夾下有一個(gè)名為 internlm2_1_8b_qlora_alpaca_e3_copy.py 的文件了。

|-- config/|-- internlm2_1_8b_qlora_alpaca_e3_copy.py
2.2.4 小結(jié)

完成以上內(nèi)容后,我就已經(jīng)完成了所有的準(zhǔn)備工作了。我們再來回顧一下我們做了哪些事情:

  1. 我們首先是在 GitHub 上克隆了 XTuner 的源碼,并把相關(guān)的配套庫也通過 pip 的方式進(jìn)行了安裝。
  2. 然后我們根據(jù)自己想要做的事情,利用腳本準(zhǔn)備好了一份關(guān)于調(diào)教模型認(rèn)識自己身份弟位的數(shù)據(jù)集。
  3. 再然后我們根據(jù)自己的顯存及任務(wù)情況確定了使用 InternLM-chat-1.8B 這個(gè)模型,并且將其復(fù)制到我們的文件夾里。
  4. 最后我們在 XTuner 已有的配置文件中,根據(jù)微調(diào)方法、數(shù)據(jù)集和模型挑選出最合適的配置文件并復(fù)制到我們新建的文件夾中。

經(jīng)過了以上的步驟后,我們的 ft 文件夾里應(yīng)該是這樣的:

|-- ft/|-- config/|-- internlm2_1_8b_qlora_alpaca_e3_copy.py|-- model/|-- tokenizer.model|-- config.json|-- tokenization_internlm2.py|-- model-00002-of-00002.safetensors|-- tokenizer_config.json|-- model-00001-of-00002.safetensors|-- model.safetensors.index.json|-- configuration.json|-- special_tokens_map.json|-- modeling_internlm2.py|-- README.md|-- configuration_internlm2.py|-- generation_config.json|-- tokenization_internlm2_fast.py|-- data/|-- personal_assistant.json|-- generate_data.py

是不是感覺其實(shí)微調(diào)也不過如此!事實(shí)上確實(shí)是這樣的!其實(shí)在微調(diào)的時(shí)候最重要的還是要自己準(zhǔn)備一份高質(zhì)量的數(shù)據(jù)集,這個(gè)才是你能否真微調(diào)出效果最核心的利器。

微調(diào)也經(jīng)常被戲稱為是煉丹,就是說你煉丹的時(shí)候你得思考好用什么樣的材料、用多大的火候、烤多久的時(shí)間以及用什么丹爐去燒。這里的丹爐其實(shí)我們可以想象為 XTuner ,只要丹爐的質(zhì)量過得去,煉丹的時(shí)候不會(huì)炸,一般都是沒問題的。但是假如煉丹的材料(就是數(shù)據(jù)集)本來就是垃圾,那無論怎么煉(微調(diào)參數(shù)的調(diào)整),煉多久(訓(xùn)練的輪數(shù)),煉出來的東西還只能且只會(huì)是垃圾。只有說用了比較好的材料,那么我們就可以考慮說要煉多久以及用什么辦法去煉的問題。因此總的來說,學(xué)會(huì)如何構(gòu)建一份高質(zhì)量的數(shù)據(jù)集是至關(guān)重要的。

假如想要了解更多關(guān)于數(shù)據(jù)集制作方面的內(nèi)容,可以加入書生.浦語的 RolePlay SIG 中,里面會(huì)有各種大佬手把手教學(xué),教你如何制作一個(gè)自己喜歡角色的數(shù)據(jù)集出來。也期待更多大佬加入講述自己制作數(shù)據(jù)集的想法和過程!

2.3 配置文件修改

在選擇了一個(gè)最匹配的配置文件并準(zhǔn)備好其他內(nèi)容后,下面我們要做的事情就是根據(jù)我們自己的內(nèi)容對該配置文件進(jìn)行調(diào)整,使其能夠滿足我們實(shí)際訓(xùn)練的要求。

配置文件介紹

假如我們真的打開配置文件后,我們可以看到整體的配置文件分為五部分:

  1. PART 1 Settings:涵蓋了模型基本設(shè)置,如預(yù)訓(xùn)練模型的選擇、數(shù)據(jù)集信息和訓(xùn)練過程中的一些基本參數(shù)(如批大小、學(xué)習(xí)率等)。

  2. PART 2 Model & Tokenizer:指定了用于訓(xùn)練的模型和分詞器的具體類型及其配置,包括預(yù)訓(xùn)練模型的路徑和是否啟用特定功能(如可變長度注意力),這是模型訓(xùn)練的核心組成部分。

  3. PART 3 Dataset & Dataloader:描述了數(shù)據(jù)處理的細(xì)節(jié),包括如何加載數(shù)據(jù)集、預(yù)處理步驟、批處理大小等,確保了模型能夠接收到正確格式和質(zhì)量的數(shù)據(jù)。

  4. PART 4 Scheduler & Optimizer:配置了優(yōu)化過程中的關(guān)鍵參數(shù),如學(xué)習(xí)率調(diào)度策略和優(yōu)化器的選擇,這些是影響模型訓(xùn)練效果和速度的重要因素。

  5. PART 5 Runtime:定義了訓(xùn)練過程中的額外設(shè)置,如日志記錄、模型保存策略和自定義鉤子等,以支持訓(xùn)練流程的監(jiān)控、調(diào)試和結(jié)果的保存。

一般來說我們需要更改的部分其實(shí)只包括前三部分,而且修改的主要原因是我們修改了配置文件中規(guī)定的模型、數(shù)據(jù)集。后兩部分都是 XTuner 官方幫我們優(yōu)化好的東西,一般而言只有在魔改的情況下才需要進(jìn)行修改。下面我們將根據(jù)項(xiàng)目的要求一步步的進(jìn)行修改和調(diào)整吧!

通過折疊部分的修改,內(nèi)容如下,可以直接將以下代碼復(fù)制到 /root/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py 文件中(先 Ctrl + A 選中所有文件并刪除后再將代碼復(fù)制進(jìn)去)。

參數(shù)修改細(xì)節(jié)

首先在 PART 1 的部分,由于我們不再需要在 Huggingface 上自動(dòng)下載模型,因此我們先要更換模型的路徑以及數(shù)據(jù)集的路徑為我們本地的路徑。

# 修改模型地址(在第27行的位置)
- pretrained_model_name_or_path = 'internlm/internlm2-1_8b'
+ pretrained_model_name_or_path = '/root/ft/model'# 修改數(shù)據(jù)集地址為本地的json文件地址(在第31行的位置)
- alpaca_en_path = 'tatsu-lab/alpaca'
+ alpaca_en_path = '/root/ft/data/personal_assistant.json'

除此之外,我們還可以對一些重要的參數(shù)進(jìn)行調(diào)整,包括學(xué)習(xí)率(lr)、訓(xùn)練的輪數(shù)(max_epochs)等等。由于我們這次只是一個(gè)簡單的讓模型知道自己的身份弟位,因此我們的訓(xùn)練輪數(shù)以及單條數(shù)據(jù)最大的 Token 數(shù)(max_length)都可以不用那么大。

# 修改max_length來降低顯存的消耗(在第33行的位置)
- max_length = 2048
+ max_length = 1024# 減少訓(xùn)練的輪數(shù)(在第44行的位置)
- max_epochs = 3
+ max_epochs = 2# 增加保存權(quán)重文件的總數(shù)(在第54行的位置)
- save_total_limit = 2
+ save_total_limit = 3

另外,為了訓(xùn)練過程中能夠?qū)崟r(shí)觀察到模型的變化情況,XTuner 也是貼心的推出了一個(gè) evaluation_inputs 的參數(shù)來讓我們能夠設(shè)置多個(gè)問題來確保模型在訓(xùn)練過程中的變化是朝著我們想要的方向前進(jìn)的。比如說我們這里是希望在問出 “請你介紹一下你自己” 或者說 “你是誰” 的時(shí)候,模型能夠給你的回復(fù)是 “我是XXX的小助手…” 這樣的回復(fù)。因此我們也可以根據(jù)這個(gè)需求進(jìn)行更改。

# 修改每多少輪進(jìn)行一次評估(在第57行的位置)
- evaluation_freq = 500
+ evaluation_freq = 300# 修改具體評估的問題(在第59到61行的位置)
# 可以自由拓展其他問題
- evaluation_inputs = ['請給我介紹五個(gè)上海的景點(diǎn)', 'Please tell me five scenic spots in Shanghai']
+ evaluation_inputs = ['請你介紹一下你自己', '你是誰', '你是我的小助手嗎']

這樣修改完后在評估過程中就會(huì)顯示在當(dāng)前的權(quán)重文件下模型對這幾個(gè)問題的回復(fù)了。

由于我們的數(shù)據(jù)集不再是原本的 aplaca 數(shù)據(jù)集,因此我們也要進(jìn)入 PART 3 的部分對相關(guān)的內(nèi)容進(jìn)行修改。包括說我們數(shù)據(jù)集輸入的不是一個(gè)文件夾而是一個(gè)單純的 json 文件以及我們的數(shù)據(jù)集格式要求改為我們最通用的 OpenAI 數(shù)據(jù)集格式。

# 把 OpenAI 格式的 map_fn 載入進(jìn)來(在第15行的位置)
- from xtuner.dataset.map_fns import alpaca_map_fn, template_map_fn_factory
+ from xtuner.dataset.map_fns import openai_map_fn, template_map_fn_factory# 將原本是 alpaca 的地址改為是 json 文件的地址(在第102行的位置)
- dataset=dict(type=load_dataset, path=alpaca_en_path),
+ dataset=dict(type=load_dataset, path='json', data_files=dict(train=alpaca_en_path)),# 將 dataset_map_fn 改為通用的 OpenAI 數(shù)據(jù)集格式(在第105行的位置)
- dataset_map_fn=alpaca_map_fn,
+ dataset_map_fn=openai_map_fn,
常用參數(shù)介紹

常用超參

參數(shù)名解釋
data_path數(shù)據(jù)路徑或 HuggingFace 倉庫名
max_length單條數(shù)據(jù)最大 Token 數(shù),超過則截?cái)?/td>
pack_to_max_length是否將多條短數(shù)據(jù)拼接到 max_length,提高 GPU 利用率
accumulative_counts梯度累積,每多少次 backward 更新一次參數(shù)
sequence_parallel_size并行序列處理的大小,用于模型訓(xùn)練時(shí)的序列并行
batch_size每個(gè)設(shè)備上的批量大小
dataloader_num_workers數(shù)據(jù)加載器中工作進(jìn)程的數(shù)量
max_epochs訓(xùn)練的最大輪數(shù)
optim_type優(yōu)化器類型,例如 AdamW
lr學(xué)習(xí)率
betas優(yōu)化器中的 beta 參數(shù),控制動(dòng)量和平方梯度的移動(dòng)平均
weight_decay權(quán)重衰減系數(shù),用于正則化和避免過擬合
max_norm梯度裁剪的最大范數(shù),用于防止梯度爆炸
warmup_ratio預(yù)熱的比例,學(xué)習(xí)率在這個(gè)比例的訓(xùn)練過程中線性增加到初始學(xué)習(xí)率
save_steps保存模型的步數(shù)間隔
save_total_limit保存的模型總數(shù)限制,超過限制時(shí)刪除舊的模型文件
prompt_template模板提示,用于定義生成文本的格式或結(jié)構(gòu)

如果想把顯卡的現(xiàn)存吃滿,充分利用顯卡資源,可以將 max_lengthbatch_size 這兩個(gè)參數(shù)調(diào)大。

# 導(dǎo)入所需的庫和模塊
import torch
from datasets import load_dataset
from mmengine.dataset import DefaultSampler
from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook,LoggerHook, ParamSchedulerHook)
from mmengine.optim import AmpOptimWrapper, CosineAnnealingLR, LinearLR
from peft import LoraConfig
from torch.optim import AdamW
from transformers import (AutoModelForCausalLM, AutoTokenizer,BitsAndBytesConfig)from xtuner.dataset import process_hf_dataset
from xtuner.dataset.collate_fns import default_collate_fn
from xtuner.dataset.map_fns import openai_map_fn, template_map_fn_factory
from xtuner.engine.hooks import (DatasetInfoHook, EvaluateChatHook,VarlenAttnArgsToMessageHubHook)
from xtuner.engine.runner import TrainLoop
from xtuner.model import SupervisedFinetune
from xtuner.parallel.sequence import SequenceParallelSampler
from xtuner.utils import PROMPT_TEMPLATE, SYSTEM_TEMPLATE#######################################################################
#                          PART 1  設(shè)置部分                             #
#######################################################################
# 模型
pretrained_model_name_or_path = '/root/ft/model'
use_varlen_attn = False  # 是否使用可變長度注意力機(jī)制# 數(shù)據(jù)
alpaca_en_path = '/root/ft/data/personal_assistant.json'
prompt_template = PROMPT_TEMPLATE.default
max_length = 1024
pack_to_max_length = True# 并行設(shè)置
sequence_parallel_size = 1  # 并行大小# 調(diào)度器和優(yōu)化器
batch_size = 1  # 每個(gè)設(shè)備的批量大小
accumulative_counts = 16  # 累積更新次數(shù)
accumulative_counts *= sequence_parallel_size  # 考慮到并行
dataloader_num_workers = 0  # 數(shù)據(jù)加載器的工作進(jìn)程數(shù)
max_epochs = 2  # 最大訓(xùn)練輪數(shù)
optim_type = AdamW  # 優(yōu)化器類型
lr = 2e-4  # 學(xué)習(xí)率
betas = (0.9, 0.999)  # AdamW 優(yōu)化器的 betas 參數(shù)
weight_decay = 0  # 權(quán)重衰減
max_norm = 1  # 梯度裁剪的最大范數(shù)
warmup_ratio = 0.03  # 學(xué)習(xí)率 warmup 比例# 保存
save_steps = 300  # 每隔多少步保存一次模型
save_total_limit = 3  # 最多保存的模型數(shù)量(-1 表示不限制)# 訓(xùn)練過程中的生成評估
evaluation_freq = 300  # 每隔多少步進(jìn)行一次生成評估
SYSTEM = ''  # 系統(tǒng)名稱,可選
evaluation_inputs = ['請你介紹一下你自己', '你是誰', '你是我的小助手嗎']  # 用于評估的輸入文本#######################################################################
#                      PART 2  模型和分詞器設(shè)置                        #
#######################################################################
tokenizer = dict(type=AutoTokenizer.from_pretrained,  # 使用預(yù)訓(xùn)練模型加載分詞器pretrained_model_name_or_path=pretrained_model_name_or_path,  # 預(yù)訓(xùn)練模型路徑trust_remote_code=True,  # 是否信任遠(yuǎn)程代碼padding_side='right'  # 填充位置
)model = dict(type=SupervisedFinetune,  # 模型類型use_varlen_attn=use_varlen_attn,  # 是否使用可變長度注意力機(jī)制llm=dict(type=AutoModelForCausalLM.from_pretrained,  # 使用預(yù)訓(xùn)練模型加載語言模型pretrained_model_name_or_path=pretrained_model_name_or_path,  # 預(yù)訓(xùn)練模型路徑trust_remote_code=True,  # 是否信任遠(yuǎn)程代碼torch_dtype=torch.float16,  # torch 張量數(shù)據(jù)類型quantization_config=dict(type=BitsAndBytesConfig,  # 使用 BitsAndBytesConfig 進(jìn)行量化配置load_in_4bit=True,  # 是否以 4 位加載load_in_8bit=False,  # 是否以 8 位加載llm_int8_threshold=6.0,  # 閾值llm_int8_has_fp16_weight=False,  # 是否有 fp16 權(quán)重bnb_4bit_compute_dtype=torch.float16,  # 4 位計(jì)算數(shù)據(jù)類型bnb_4bit_use_double_quant=True,  # 是否使用雙量化bnb_4bit_quant_type='nf4'  # 量化類型)),lora=dict(type=LoraConfig,  # Lora 配置r=64,  # 參數(shù) rlora_alpha=16,  # 參數(shù) alphalora_dropout=0.1,  # Dropout 概率bias='none',  # 偏置設(shè)置task_type='CAUSAL_LM'  # 任務(wù)類型)
)#######################################################################
#                      PART 3  數(shù)據(jù)集和數(shù)據(jù)加載器設(shè)置                   #
#######################################################################
alpaca_en = dict(type=process_hf_dataset,  # 數(shù)據(jù)集處理函數(shù)類型dataset=dict(type=load_dataset, path='json', data_files=dict(train=alpaca_en_path)),  # 加載數(shù)據(jù)集tokenizer=tokenizer,  # 分詞器max_length=max_length,  # 最大長度dataset_map_fn=openai_map_fn,  # 數(shù)據(jù)集映射函數(shù)template_map_fn=dict(type=template_map_fn_factory, template=prompt_template),  # 模板映射函數(shù)remove_unused_columns=True,  # 是否刪除未使用的列shuffle_before_pack=True,  # 打包前是否進(jìn)行洗牌pack_to_max_length=pack_to_max_length,  # 是否打包到最大長度use_varlen_attn=use_varlen_attn  # 是否使用可變長度注意力機(jī)制
)sampler = SequenceParallelSampler if sequence_parallel_size > 1 else DefaultSampler  # 根據(jù)并行大小選擇采樣器類型train_dataloader = dict(batch_size=batch_size,  # 每個(gè)設(shè)備的批量大小num_workers=dataloader_num_workers,  # 數(shù)據(jù)加載器的工作進(jìn)程數(shù)dataset=alpaca_en,  # 數(shù)據(jù)集sampler=dict(type=sampler, shuffle=True),  # 采樣器collate_fn=dict(type=default_collate_fn, use_varlen_attn=use_varlen_attn)  # 數(shù)據(jù)整合函數(shù)
)#######################################################################
#                    PART 4  調(diào)度器和優(yōu)化器設(shè)置                        #
#######################################################################
# 優(yōu)化器設(shè)置
optim_wrapper = dict(type=AmpOptimWrapper,  # 優(yōu)化器包裝器類型optimizer=dict(type=optim_type, lr=lr, betas=betas, weight_decay=weight_decay),  # 優(yōu)化器參數(shù)clip_grad=dict(max_norm=max_norm, error_if_nonfinite=False),  # 梯度裁剪設(shè)置accumulative_counts=accumulative_counts,  # 累積更新次數(shù)loss_scale='dynamic',  # 損失尺度dtype='float16'  # 數(shù)據(jù)類型
)# 學(xué)習(xí)策略
param_scheduler = [dict(type=LinearLR,  # 線性學(xué)習(xí)率調(diào)度器start_factor=1e-5,  # 初始因子by_epoch=True,  # 按輪數(shù)調(diào)整begin=0,  # 起始輪數(shù)end=warmup_ratio * max_epochs,  # 結(jié)束輪數(shù)convert_to_iter_based=True),  # 是否轉(zhuǎn)換為基于迭代次數(shù)的調(diào)度器dict(type=CosineAnnealingLR,  # 余弦退火學(xué)習(xí)率調(diào)度器eta_min=0.0,  # 最小學(xué)習(xí)率by_epoch=True,  # 按輪數(shù)調(diào)整begin=warmup_ratio * max_epochs,  # 開始輪數(shù)end=max_epochs,  # 結(jié)束輪數(shù)convert_to_iter_based=True)  # 是否轉(zhuǎn)換為基于迭代次數(shù)的調(diào)度器
]# 訓(xùn)練、驗(yàn)證、測試設(shè)置
train_cfg = dict(type=TrainLoop, max_epochs=max_epochs)#######################################################################
#                           PART 5  運(yùn)行時(shí)設(shè)置                        #
#######################################################################
# 自定義鉤子
custom_hooks = [dict(type=DatasetInfoHook, tokenizer=tokenizer),  # 數(shù)據(jù)集信息鉤子dict(type=EvaluateChatHook,  # 評估對話鉤子tokenizer=tokenizer,  # 分詞器every_n_iters=evaluation_freq,  # 每隔多少步評估一次evaluation_inputs=evaluation_inputs,  # 評估輸入system=SYSTEM,  # 系統(tǒng)名稱prompt_template=prompt_template)  # 提示模板
]if use_varlen_attn:  # 如果使用可變長度注意力機(jī)制custom_hooks += [dict(type=VarlenAttnArgsToMessageHubHook)]  # 添加自定義鉤子# 默認(rèn)鉤子配置
default_hooks = dict(timer=dict(type=IterTimerHook),  # 記錄每次迭代的時(shí)間logger=dict(type=LoggerHook, log_metric_by_epoch=False, interval=10),  # 日志記錄器param_scheduler=dict(type=ParamSchedulerHook),  # 參數(shù)調(diào)度器checkpoint=dict(type=CheckpointHook,  # 檢查點(diǎn)鉤子by_epoch=False,  # 是否按輪數(shù)保存檢查點(diǎn)interval=save_steps,  # 保存間隔max_keep_ckpts=save_total_limit),  # 最多保存檢查點(diǎn)數(shù)sampler_seed=dict(type=DistSamplerSeedHook)  # 分布式采樣器種子設(shè)置
)# 環(huán)境配置
env_cfg = dict(cudnn_benchmark=False,  # 是否啟用 cudnn 優(yōu)化mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),  # 多進(jìn)程配置dist_cfg=dict(backend='nccl')  # 分布式配置
)# 可視化器
visualizer = None  # 不使用可視化器# 日志級別
log_level = 'INFO'  # 日志級別設(shè)置為 INFO# 從哪個(gè)檢查點(diǎn)加載模型
load_from = None  # 不加載任何檢查點(diǎn)# 是否從加載的檢查點(diǎn)恢復(fù)訓(xùn)練
resume = False  # 不恢復(fù)訓(xùn)練# 隨機(jī)性設(shè)置
randomness = dict(seed=None, deterministic=False)  # 隨機(jī)種子和是否確定性設(shè)置為默認(rèn)值# 日志處理器
log_processor = dict(by_epoch=False)  # 不按輪數(shù)處理日志

這一節(jié)我們講述了微調(diào)過程中一些常見的需要調(diào)整的內(nèi)容,包括各種的路徑、超參數(shù)、評估問題等等。完成了這部分的修改后,我們就可以正式的開始我們下一階段的旅程: XTuner 啟動(dòng)~!

2.4 模型訓(xùn)練

2.4.1 常規(guī)訓(xùn)練

當(dāng)我們準(zhǔn)備好了配置文件好,我們只需要將使用 xtuner train 指令即可開始訓(xùn)練。

我們可以通過添加 --work-dir 指定特定的文件保存位置,比如說就保存在 /root/ft/train 路徑下。假如不添加的話模型訓(xùn)練的過程文件將默認(rèn)保存在 ./work_dirs/internlm2_1_8b_qlora_alpaca_e3_copy 的位置,就比如說我是在 /root/ft/train 的路徑下輸入該指令,那么我的文件保存的位置就是在 /root/ft/train/work_dirs/internlm2_1_8b_qlora_alpaca_e3_copy 的位置下。

# 指定保存路徑
xtuner train /root/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py --work-dir /root/ft/train

在輸入訓(xùn)練完后的文件如下所示:

|-- train/|-- internlm2_1_8b_qlora_alpaca_e3_copy.py|-- iter_600.pth|-- last_checkpoint|-- iter_768.pth|-- iter_300.pth|-- 20240406_203957/|-- 20240406_203957.log|-- vis_data/|-- 20240406_203957.json|-- eval_outputs_iter_599.txt|-- eval_outputs_iter_767.txt|-- scalars.json|-- eval_outputs_iter_299.txt|-- config.py
2.4.2 使用 deepspeed 來加速訓(xùn)練

除此之外,我們也可以結(jié)合 XTuner 內(nèi)置的 deepspeed 來加速整體的訓(xùn)練過程,共有三種不同的 deepspeed 類型可進(jìn)行選擇,分別是 deepspeed_zero1, deepspeed_zero2deepspeed_zero3(詳細(xì)的介紹可看下拉框)。

DeepSpeed優(yōu)化器及其選擇方法

DeepSpeed是一個(gè)深度學(xué)習(xí)優(yōu)化庫,由微軟開發(fā),旨在提高大規(guī)模模型訓(xùn)練的效率和速度。它通過幾種關(guān)鍵技術(shù)來優(yōu)化訓(xùn)練過程,包括模型分割、梯度累積、以及內(nèi)存和帶寬優(yōu)化等。DeepSpeed特別適用于需要巨大計(jì)算資源的大型模型和數(shù)據(jù)集。

在DeepSpeed中,zero 代表“ZeRO”(Zero Redundancy Optimizer),是一種旨在降低訓(xùn)練大型模型所需內(nèi)存占用的優(yōu)化器。ZeRO 通過優(yōu)化數(shù)據(jù)并行訓(xùn)練過程中的內(nèi)存使用,允許更大的模型和更快的訓(xùn)練速度。ZeRO 分為幾個(gè)不同的級別,主要包括:

  • deepspeed_zero1:這是ZeRO的基本版本,它優(yōu)化了模型參數(shù)的存儲(chǔ),使得每個(gè)GPU只存儲(chǔ)一部分參數(shù),從而減少內(nèi)存的使用。

  • deepspeed_zero2:在deepspeed_zero1的基礎(chǔ)上,deepspeed_zero2進(jìn)一步優(yōu)化了梯度和優(yōu)化器狀態(tài)的存儲(chǔ)。它將這些信息也分散到不同的GPU上,進(jìn)一步降低了單個(gè)GPU的內(nèi)存需求。

  • deepspeed_zero3:這是目前最高級的優(yōu)化等級,它不僅包括了deepspeed_zero1和deepspeed_zero2的優(yōu)化,還進(jìn)一步減少了激活函數(shù)的內(nèi)存占用。這通過在需要時(shí)重新計(jì)算激活(而不是存儲(chǔ)它們)來實(shí)現(xiàn),從而實(shí)現(xiàn)了對大型模型極其內(nèi)存效率的訓(xùn)練。

選擇哪種deepspeed類型主要取決于你的具體需求,包括模型的大小、可用的硬件資源(特別是GPU內(nèi)存)以及訓(xùn)練的效率需求。一般來說:

  • 如果你的模型較小,或者內(nèi)存資源充足,可能不需要使用最高級別的優(yōu)化。
  • 如果你正在嘗試訓(xùn)練非常大的模型,或者你的硬件資源有限,使用deepspeed_zero2或deepspeed_zero3可能更合適,因?yàn)樗鼈兛梢燥@著降低內(nèi)存占用,允許更大模型的訓(xùn)練。
  • 選擇時(shí)也要考慮到實(shí)現(xiàn)的復(fù)雜性和運(yùn)行時(shí)的開銷,更高級的優(yōu)化可能需要更復(fù)雜的設(shè)置,并可能增加一些計(jì)算開銷。
# 使用 deepspeed 來加速訓(xùn)練
xtuner train /root/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py --work-dir /root/ft/train_deepspeed --deepspeed deepspeed_zero2

可以看到,通過 deepspeed 來訓(xùn)練后得到的權(quán)重文件和原本的權(quán)重文件是有所差別的,原本的僅僅是一個(gè) .pth 的文件,而使用了 deepspeed 則是一個(gè)名字帶有 .pth 的文件夾,在該文件夾里保存了兩個(gè) .pt 文件。當(dāng)然這兩者在具體的使用上并沒有太大的差別,都是可以進(jìn)行轉(zhuǎn)化并整合。

|-- train_deepspeed/|-- internlm2_1_8b_qlora_alpaca_e3_copy.py|-- zero_to_fp32.py|-- last_checkpoint|-- iter_600.pth/|-- bf16_zero_pp_rank_0_mp_rank_00_optim_states.pt|-- mp_rank_00_model_states.pt|-- 20240406_220727/|-- 20240406_220727.log|-- vis_data/|-- 20240406_220727.json|-- eval_outputs_iter_599.txt|-- eval_outputs_iter_767.txt|-- scalars.json|-- eval_outputs_iter_299.txt|-- config.py|-- iter_768.pth/|-- bf16_zero_pp_rank_0_mp_rank_00_optim_states.pt|-- mp_rank_00_model_states.pt|-- iter_300.pth/|-- bf16_zero_pp_rank_0_mp_rank_00_optim_states.pt|-- mp_rank_00_model_states.pt
2.4.3 訓(xùn)練結(jié)果

但是其實(shí)無論是用哪種方式進(jìn)行訓(xùn)練,得到的結(jié)果都是大差不差的。我們由于設(shè)置了300輪評估一次,所以我們可以對比一下300輪和600輪的評估問題結(jié)果來看看差別。

# 300輪<|User|>:請你介紹一下你自己
<|Bot|>:我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s><|User|>:你是誰
<|Bot|>:我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s><|User|>:你是我的小助手嗎
<|Bot|>:是的</s># 600輪<|User|>:請你介紹一下你自己
<|Bot|>:我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s><|User|>:你是誰
<|Bot|>:我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s><|User|>:你是我的小助手嗎
<|Bot|>:我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s>

通過兩者的對比我們其實(shí)就可以很清楚的看到,在300輪的時(shí)候模型已經(jīng)學(xué)會(huì)了在我問 “你是誰” 或者說 “請你介紹一下我自己” 的時(shí)候回答 “我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦”。

但是兩者的不同是在詢問 “你是我的小助手” 的這個(gè)問題上,300輪的時(shí)候是回答正確的,回答了 “是” ,但是在600輪的時(shí)候回答的還是 “我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦” 這一段話。這表明模型在第一批次第600輪的時(shí)候已經(jīng)出現(xiàn)嚴(yán)重的過擬合(即模型丟失了基礎(chǔ)的能力,只會(huì)成為某一句話的復(fù)讀機(jī))現(xiàn)象了,到后面的話無論我們再問什么,得到的結(jié)果也就只能是回答這一句話了,模型已經(jīng)不會(huì)再說別的話了。因此假如以通用能力的角度選擇最合適的權(quán)重文件的話我們可能會(huì)選擇前面的權(quán)重文件進(jìn)行后續(xù)的模型轉(zhuǎn)化及整合工作。

假如我們想要解決這個(gè)問題,其實(shí)可以通過以下兩個(gè)方式解決:

  1. 減少保存權(quán)重文件的間隔并增加權(quán)重文件保存的上限:這個(gè)方法實(shí)際上就是通過降低間隔結(jié)合評估問題的結(jié)果,從而找到最優(yōu)的權(quán)重文。我們可以每隔100個(gè)批次來看什么時(shí)候模型已經(jīng)學(xué)到了這部分知識但是還保留著基本的常識,什么時(shí)候已經(jīng)過擬合嚴(yán)重只會(huì)說一句話了。但是由于再配置文件有設(shè)置權(quán)重文件保存數(shù)量的上限,因此同時(shí)將這個(gè)上限加大也是非常必要的。
  2. 增加常規(guī)的對話數(shù)據(jù)集從而稀釋原本數(shù)據(jù)的占比:這個(gè)方法其實(shí)就是希望我們正常用對話數(shù)據(jù)集做指令微調(diào)的同時(shí)還加上一部分的數(shù)據(jù)集來讓模型既能夠?qū)W到正常對話,但是在遇到特定問題時(shí)進(jìn)行特殊化處理。比如說我在一萬條正常的對話數(shù)據(jù)里混入兩千條和小助手相關(guān)的數(shù)據(jù)集,這樣模型同樣可以在不丟失對話能力的前提下學(xué)到劍鋒大佬的小助手這句話。這種其實(shí)是比較常見的處理方式,大家可以自己動(dòng)手嘗試實(shí)踐一下。

另外假如我們模型中途中斷了,我們也可以參考以下方法實(shí)現(xiàn)模型續(xù)訓(xùn)工作

模型續(xù)訓(xùn)指南

假如我們的模型訓(xùn)練過程中突然被中斷了,我們也可以通過在原有指令的基礎(chǔ)上加上 --resume {checkpoint_path} 來實(shí)現(xiàn)模型的繼續(xù)訓(xùn)練。需要注意的是,這個(gè)繼續(xù)訓(xùn)練得到的權(quán)重文件和中斷前的完全一致,并不會(huì)有任何區(qū)別。下面我將用訓(xùn)練了500輪的例子來進(jìn)行演示。

# 模型續(xù)訓(xùn)
xtuner train /root/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py --work-dir /root/ft/train --resume /root/ft/train/iter_600.pth

在實(shí)測過程中,雖然權(quán)重文件并沒有發(fā)生改變,但是會(huì)多一個(gè)以時(shí)間戳為名的訓(xùn)練過程文件夾保存訓(xùn)練的過程數(shù)據(jù)。

|-- train/|-- internlm2_1_8b_qlora_alpaca_e3_copy.py|-- iter_600.pth|-- last_checkpoint|-- iter_768.pth|-- iter_300.pth|-- 20240406_203957/|-- 20240406_203957.log|-- vis_data/|-- 20240406_203957.json|-- eval_outputs_iter_599.txt|-- eval_outputs_iter_767.txt|-- scalars.json|-- eval_outputs_iter_299.txt|-- config.py|-- 20240406_225723/|-- 20240406_225723.log|-- vis_data/|-- 20240406_225723.json|-- eval_outputs_iter_767.txt|-- scalars.json|-- config.py
2.4.4 小結(jié)

在本節(jié)我們的重點(diǎn)是講解模型訓(xùn)練過程中的種種細(xì)節(jié)內(nèi)容,包括了模型訓(xùn)練中的各個(gè)參數(shù)以、權(quán)重文件的選擇方式以及模型續(xù)訓(xùn)的方法??梢钥吹绞欠袷褂?--work-dir 和 是否使用 --deepspeed 會(huì)對文件的保存位置以及權(quán)重文件的保存方式有所不同,大家也可以通過實(shí)踐去實(shí)際的測試感受一下。那么在訓(xùn)練完成后,我們就可以把訓(xùn)練得到的 .pth 文件進(jìn)行下一步的轉(zhuǎn)換和整合工作了!

2.5 模型轉(zhuǎn)換、整合、測試及部署

2.5.1 模型轉(zhuǎn)換

模型轉(zhuǎn)換的本質(zhì)其實(shí)就是將原本使用 Pytorch 訓(xùn)練出來的模型權(quán)重文件轉(zhuǎn)換為目前通用的 Huggingface 格式文件,那么我們可以通過以下指令來實(shí)現(xiàn)一鍵轉(zhuǎn)換。

# 創(chuàng)建一個(gè)保存轉(zhuǎn)換后 Huggingface 格式的文件夾
mkdir -p /root/ft/huggingface# 模型轉(zhuǎn)換
# xtuner convert pth_to_hf ${配置文件地址} ${權(quán)重文件地址} ${轉(zhuǎn)換后模型保存地址}
xtuner convert pth_to_hf /root/ft/train/internlm2_1_8b_qlora_alpaca_e3_copy.py /root/ft/train/iter_768.pth /root/ft/huggingface

轉(zhuǎn)換完成后,可以看到模型被轉(zhuǎn)換為 Huggingface 中常用的 .bin 格式文件,這就代表著文件成功被轉(zhuǎn)化為 Huggingface 格式了。

|-- huggingface/|-- adapter_config.json|-- xtuner_config.py|-- adapter_model.bin|-- README.md

此時(shí),huggingface 文件夾即為我們平時(shí)所理解的所謂 “LoRA 模型文件”

可以簡單理解:LoRA 模型文件 = Adapter

除此之外,我們其實(shí)還可以在轉(zhuǎn)換的指令中添加幾個(gè)額外的參數(shù),包括以下兩個(gè):

參數(shù)名解釋
–fp32代表以fp32的精度開啟,假如不輸入則默認(rèn)為fp16
–max-shard-size {GB}代表每個(gè)權(quán)重文件最大的大小(默認(rèn)為2GB)

假如有特定的需要,我們可以在上面的轉(zhuǎn)換指令后進(jìn)行添加。由于本次測試的模型文件較小,并且已經(jīng)驗(yàn)證過擬合,故沒有添加。假如加上的話應(yīng)該是這樣的:

xtuner convert pth_to_hf /root/ft/train/internlm2_1_8b_qlora_alpaca_e3_copy.py /root/ft/train/iter_768.pth /root/ft/huggingface --fp32 --max-shard-size 2GB
2.5.2 模型整合

我們通過視頻課程的學(xué)習(xí)可以了解到,對于 LoRA 或者 QLoRA 微調(diào)出來的模型其實(shí)并不是一個(gè)完整的模型,而是一個(gè)額外的層(adapter)。那么訓(xùn)練完的這個(gè)層最終還是要與原模型進(jìn)行組合才能被正常的使用。

而對于全量微調(diào)的模型(full)其實(shí)是不需要進(jìn)行整合這一步的,因?yàn)槿课⒄{(diào)修改的是原模型的權(quán)重而非微調(diào)一個(gè)新的 adapter ,因此是不需要進(jìn)行模型整合的。

image.png

在 XTuner 中也是提供了一鍵整合的指令,但是在使用前我們需要準(zhǔn)備好三個(gè)地址,包括原模型的地址、訓(xùn)練好的 adapter 層的地址(轉(zhuǎn)為 Huggingface 格式后保存的部分)以及最終保存的地址。

# 創(chuàng)建一個(gè)名為 final_model 的文件夾存儲(chǔ)整合后的模型文件
mkdir -p /root/ft/final_model# 解決一下線程沖突的 Bug 
export MKL_SERVICE_FORCE_INTEL=1# 進(jìn)行模型整合
# xtuner convert merge  ${NAME_OR_PATH_TO_LLM} ${NAME_OR_PATH_TO_ADAPTER} ${SAVE_PATH} 
xtuner convert merge /root/ft/model /root/ft/huggingface /root/ft/final_model

那除了以上的三個(gè)基本參數(shù)以外,其實(shí)在模型整合這一步還是其他很多的可選參數(shù),包括:

參數(shù)名解釋
–max-shard-size {GB}代表每個(gè)權(quán)重文件最大的大小(默認(rèn)為2GB)
–device {device_name}這里指的就是device的名稱,可選擇的有cuda、cpu和auto,默認(rèn)為cuda即使用gpu進(jìn)行運(yùn)算
–is-clip這個(gè)參數(shù)主要用于確定模型是不是CLIP模型,假如是的話就要加上,不是就不需要添加

CLIP(Contrastive Language–Image Pre-training)模型是 OpenAI 開發(fā)的一種預(yù)訓(xùn)練模型,它能夠理解圖像和描述它們的文本之間的關(guān)系。CLIP 通過在大規(guī)模數(shù)據(jù)集上學(xué)習(xí)圖像和對應(yīng)文本之間的對應(yīng)關(guān)系,從而實(shí)現(xiàn)了對圖像內(nèi)容的理解和分類,甚至能夠根據(jù)文本提示生成圖像。
在模型整合完成后,我們就可以看到 final_model 文件夾里生成了和原模型文件夾非常近似的內(nèi)容,包括了分詞器、權(quán)重文件、配置信息等等。當(dāng)我們整合完成后,我們就能夠正常的調(diào)用這個(gè)模型進(jìn)行對話測試了。

整合完成后可以查看在 final_model 文件夾下的內(nèi)容。

|-- final_model/|-- tokenizer.model|-- config.json|-- pytorch_model.bin.index.json|-- pytorch_model-00001-of-00002.bin|-- tokenization_internlm2.py|-- tokenizer_config.json|-- special_tokens_map.json|-- pytorch_model-00002-of-00002.bin|-- modeling_internlm2.py|-- configuration_internlm2.py|-- tokenizer.json|-- generation_config.json|-- tokenization_internlm2_fast.py
2.5.3 對話測試

在 XTuner 中也直接的提供了一套基于 transformers 的對話代碼,讓我們可以直接在終端與 Huggingface 格式的模型進(jìn)行對話操作。我們只需要準(zhǔn)備我們剛剛轉(zhuǎn)換好的模型路徑并選擇對應(yīng)的提示詞模版(prompt-template)即可進(jìn)行對話。假如 prompt-template 選擇有誤,很有可能導(dǎo)致模型無法正確的進(jìn)行回復(fù)。

想要了解具體模型的 prompt-template 或者 XTuner 里支持的 prompt-tempolate,可以到 XTuner 源碼中的 xtuner/utils/templates.py 這個(gè)文件中進(jìn)行查找。

# 與模型進(jìn)行對話
xtuner chat /root/ft/final_model --prompt-template internlm2_chat

我們可以通過一些簡單的測試來看看微調(diào)后的模型的能力。

假如我們想要輸入內(nèi)容需要在輸入文字后敲擊兩下回車,假如我們想清楚歷史記錄需要輸入 RESET,假如我們想要退出則需要輸入 EXIT。

double enter to end input (EXIT: exit chat, RESET: reset history) >>> 你是誰
我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s>double enter to end input (EXIT: exit chat, RESET: reset history) >>>  請你介紹一下你自己
我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s>double enter to end input (EXIT: exit chat, RESET: reset history) >>> 你是我的小助手嗎?
我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦</s>double enter to end input (EXIT: exit chat, RESET: reset history) >>> EXIT
Log: Exit!

可以看到模型已經(jīng)嚴(yán)重過擬合,回復(fù)的話就只有 “我是劍鋒大佬的小助手,內(nèi)在是上海AI實(shí)驗(yàn)室書生·浦語的1.8B大模型哦” 這句話。我們下面可以通過對比原模型的能力來看看差異。

# 同樣的我們也可以和原模型進(jìn)行對話進(jìn)行對比
xtuner chat /root/ft/model --prompt-template internlm2_chat

我們可以用同樣的問題來查看回復(fù)的情況。

double enter to end input (EXIT: exit chat, RESET: reset history) >>> 你是誰
我是一個(gè)人工智能助手,旨在幫助用戶回答問題、提供定義和解釋、將文本從一種語言翻譯成另一種語言、總結(jié)文本、生成文本、編寫故事、分析情感、提供推薦、開發(fā)算法、編寫代碼以及其他任何基于語言的任務(wù)。我致力于通過執(zhí)行常見的基于語言的任務(wù)和提供建議來幫助人類。<|im_end|>double enter to end input (EXIT: exit chat, RESET: reset history) >>> 請你介紹一下你自己
非常感謝您的提問。我是一個(gè)名叫書生·浦語的人工智能助手,由上海人工智能實(shí)驗(yàn)室開發(fā)。我使用了Transformer模型和深度學(xué)習(xí)技術(shù),并使用語言模型作為預(yù)訓(xùn)練任務(wù)。我致力于通過執(zhí)行常見的基于語言的任務(wù)和提供建議來幫助人類。我能夠回答問題、提供定義和解釋、將文本從一種語言翻譯成另一種語言、總結(jié)文本、生成文本、編寫故事、分析情感、提供推薦、開發(fā)算法、編寫代碼以及其他任何基于語言的任務(wù)。如果您有任何需要幫助的問題,歡迎隨時(shí)向我提問。<|im_end|>double enter to end input (EXIT: exit chat, RESET: reset history) >>> 你是我的小助手嗎
是的,我非常樂意成為您的助手。我致力于通過執(zhí)行常見的基于語言的任務(wù)和提供建議來幫助您。如果您有任何需要幫助的問題,請隨時(shí)向我提問。我會(huì)盡力回答您的問題并提供有用的建議。<|im_end|>double enter to end input (EXIT: exit chat, RESET: reset history) >>> EXIT
Log: Exit!

可以看到在沒有進(jìn)行我們數(shù)據(jù)的微調(diào)前,原模型是能夠輸出有邏輯的回復(fù),并且也不會(huì)認(rèn)為他是我們特有的小助手。因此我們可以很明顯的看出兩者之間的差異性。

那對于 xtuner chat 這個(gè)指令而言,還有很多其他的參數(shù)可以進(jìn)行設(shè)置的,包括:

啟動(dòng)參數(shù)解釋
–system指定SYSTEM文本,用于在對話中插入特定的系統(tǒng)級信息
–system-template指定SYSTEM模板,用于自定義系統(tǒng)信息的模板
–bits指定LLM運(yùn)行時(shí)使用的位數(shù),決定了處理數(shù)據(jù)時(shí)的精度
–bot-name設(shè)置bot的名稱,用于在對話或其他交互中識別bot
–with-plugins指定在運(yùn)行時(shí)要使用的插件列表,用于擴(kuò)展或增強(qiáng)功能
–no-streamer關(guān)閉流式傳輸模式,對于需要一次性處理全部數(shù)據(jù)的場景
–lagent啟用lagent,用于特定的運(yùn)行時(shí)環(huán)境或優(yōu)化
–command-stop-word設(shè)置命令的停止詞,當(dāng)遇到這些詞時(shí)停止解析命令
–answer-stop-word設(shè)置回答的停止詞,當(dāng)生成回答時(shí)遇到這些詞則停止
–offload-folder指定存放模型權(quán)重的文件夾,用于加載或卸載模型權(quán)重
–max-new-tokens設(shè)置生成文本時(shí)允許的最大token數(shù)量,控制輸出長度
–temperature設(shè)置生成文本的溫度值,較高的值會(huì)使生成的文本更多樣,較低的值會(huì)使文本更確定
–top-k設(shè)置保留用于頂k篩選的最高概率詞匯標(biāo)記數(shù),影響生成文本的多樣性
–top-p設(shè)置累計(jì)概率閾值,僅保留概率累加高于top-p的最小標(biāo)記集,影響生成文本的連貫性
–seed設(shè)置隨機(jī)種子,用于生成可重現(xiàn)的文本內(nèi)容

除了這些參數(shù)以外其實(shí)還有一個(gè)非常重要的參數(shù)就是 --adapter ,這個(gè)參數(shù)主要的作用就是可以在轉(zhuǎn)化后的 adapter 層與原模型整合之前來對該層進(jìn)行測試。使用這個(gè)額外的參數(shù)對話的模型和整合后的模型幾乎沒有什么太多的區(qū)別,因此我們可以通過測試不同的權(quán)重文件生成的 adapter 來找到最優(yōu)的 adapter 進(jìn)行最終的模型整合工作。

# 使用 --adapter 參數(shù)與完整的模型進(jìn)行對話
xtuner chat /root/ft/model --adapter /root/ft/huggingface --prompt-template internlm2_chat
2.5.4 Web demo 部署

除了在終端中對模型進(jìn)行測試,我們其實(shí)還可以在網(wǎng)頁端的 demo 進(jìn)行對話。

那首先我們需要先下載網(wǎng)頁端 web demo 所需要的依賴。

pip install streamlit==1.24.0

下載 InternLM 項(xiàng)目代碼(歡迎Star)!

# 創(chuàng)建存放 InternLM 文件的代碼
mkdir -p /root/ft/web_demo && cd /root/ft/web_demo# 拉取 InternLM 源文件
git clone https://github.com/InternLM/InternLM.git# 進(jìn)入該庫中
cd /root/ft/web_demo/InternLM

/root/ft/web_demo/InternLM/chat/web_demo.py 中的內(nèi)容替換為以下的代碼(與源代碼相比,此處修改了模型路徑和分詞器路徑,并且也刪除了 avatar 及 system_prompt 部分的內(nèi)容,同時(shí)與 cli 中的超參數(shù)進(jìn)行了對齊)。

"""
這個(gè)腳本是參考了 streamlit 的對話示例、chatglm2 和 transformers 的交互生成代碼。我們主要修改了部分代碼邏輯以適應(yīng)我們模型的生成。更多信息請參考以下鏈接:
1. streamlit 對話示例:https://docs.streamlit.io/knowledge-base/tutorials/build-conversational-apps
2. chatglm2:https://github.com/THUDM/ChatGLM2-6B
3. transformers:https://github.com/huggingface/transformers請使用命令 `streamlit run path/to/web_demo.py --server.address=0.0.0.0 --server.port 7860` 運(yùn)行。
使用 `python path/to/web_demo.py` 可能會(huì)導(dǎo)致未知問題。
"""
# isort: skip_file  # 跳過 isort 排序文件import copy
import warnings
from dataclasses import asdict, dataclass
from typing import Callable, List, Optionalimport streamlit as st
import torch
from torch import nn
from transformers.generation.utils import (LogitsProcessorList,StoppingCriteriaList)
from transformers.utils import loggingfrom transformers import AutoTokenizer, AutoModelForCausalLM  # isort: skiplogger = logging.get_logger(__name__)@dataclass
class GenerationConfig:# 用于聊天提供更多多樣性的配置max_length: int = 32768top_p: float = 0.8temperature: float = 0.8do_sample: bool = Truerepetition_penalty: float = 1.005@torch.inference_mode()
def generate_interactive(model,tokenizer,prompt,generation_config: Optional[GenerationConfig] = None,logits_processor: Optional[LogitsProcessorList] = None,stopping_criteria: Optional[StoppingCriteriaList] = None,prefix_allowed_tokens_fn: Optional[Callable[[int, torch.Tensor], List[int]]] = None,additional_eos_token_id: Optional[int] = None,**kwargs,
):# 將輸入編碼成張量inputs = tokenizer([prompt], padding=True, return_tensors='pt')input_length = len(inputs['input_ids'][0])for k, v in inputs.items():inputs[k] = v.cuda()  # 將輸入移至 GPUinput_ids = inputs['input_ids']_, input_ids_seq_length = input_ids.shape[0], input_ids.shape[-1]# 如果未提供生成配置,則使用模型的默認(rèn)生成配置if generation_config is None:generation_config = model.generation_configgeneration_config = copy.deepcopy(generation_config)model_kwargs = generation_config.update(**kwargs)# 獲取開始和結(jié)束標(biāo)記的 IDbos_token_id, eos_token_id = generation_config.bos_token_id, generation_config.eos_token_id# 如果結(jié)束標(biāo)記是整數(shù),則轉(zhuǎn)為列表if isinstance(eos_token_id, int):eos_token_id = [eos_token_id]if additional_eos_token_id is not None:eos_token_id.append(additional_eos_token_id)# 創(chuàng)建 logits 處理器和停止準(zhǔn)則對象logits_processor = logits_processor if logits_processor is not None else LogitsProcessorList()stopping_criteria = stopping_criteria if stopping_criteria is not None else StoppingCriteriaList()# 進(jìn)行生成unfinished_sequences = input_ids.new(input_ids.shape[0]).fill_(1)scores = Nonewhile True:# 準(zhǔn)備生成模型的輸入model_inputs = model.prepare_inputs_for_generation(input_ids, **model_kwargs)# 進(jìn)行前向傳播,獲取下一個(gè) token 的 logitsoutputs = model(**model_inputs,return_dict=True,output_attentions=False,output_hidden_states=False,)next_token_logits = outputs.logits[:, -1, :]# 對 logits 進(jìn)行處理next_token_scores = logits_processor(input_ids, next_token_logits)# 通過 logits_warper 進(jìn)行變換next_token_scores = logits_warper(input_ids, next_token_scores)# 對概率進(jìn)行 softmax 并進(jìn)行采樣或貪婪取最高概率的方式獲取下一個(gè) tokenprobs = nn.functional.softmax(next_token_scores, dim=-1)if generation_config.do_sample:next_tokens = torch.multinomial(probs, num_samples=1).squeeze(1)else:next_tokens = torch.argmax(probs, dim=-1)# 更新生成的 token 序列和模型輸入input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1)model_kwargs = model._update_model_kwargs_for_generation(outputs, model_kwargs, is_encoder_decoder=False)unfinished_sequences = unfinished_sequences.mul((min(next_tokens != i for i in eos_token_id)).long())output_token_ids = input_ids[0].cpu().tolist()output_token_ids = output_token_ids[input_length:]for each_eos_token_id in eos_token_id:if output_token_ids[-1] == each_eos_token_id:output_token_ids = output_token_ids[:-1]response = tokenizer.decode(output_token_ids)yield response# 如果每個(gè)句子已經(jīng)完成或超過最大長度,則停止生成if unfinished_sequences.max() == 0 or stopping_criteria(input_ids, scores):breakdef on_btn_click():del st.session_state.messages@st.cache_resource
def load_model():# 加載模型和分詞器model = (AutoModelForCausalLM.from_pretrained('/root/ft/final_model', trust_remote_code=True).to(torch.bfloat16).cuda())tokenizer = AutoTokenizer.from_pretrained('/root/ft/final_model', trust_remote_code=True)return model, tokenizerdef prepare_generation_config():with st.sidebar:# 生成配置max_length = st.slider('最大長度', min_value=8, max_value=32768, value=2048)top_p = st.slider('Top P', 0.0, 1.0, 0.75, step=0.01)temperature = st.slider('Temperature', 0.0, 1.0, 0.1, step=0.01)st.button('清空聊天歷史', on_click=on_btn_click)# 創(chuàng)建生成配置對象generation_config = GenerationConfig(max_length=max_length, top_p=top_p, temperature=temperature)return generation_configuser_prompt = 'user\n{user}\n'
robot_prompt = 'assistant\n{robot}\n'
cur_query_prompt = 'user\n{user}\nassistant\n'def combine_history(prompt):messages = st.session_state.messagesmeta_instruction = ('')total_prompt = f"<s>system\n{meta_instruction}\n"for message in messages:cur_content = message['content']if message['role'] == 'user':cur_prompt = user_prompt.format(user=cur_content)elif message['role'] == 'robot':cur_prompt = robot_prompt.format(robot=cur_content)else:raise RuntimeErrortotal_prompt += cur_prompttotal_prompt = total_prompt + cur_query_prompt.format(user=prompt)return total_promptdef main():# 加載模型print('加載模型開始.')model, tokenizer = load_model()print('加載模型結(jié)束.')st.title('InternLM2-Chat-1.8B')  # 設(shè)置標(biāo)題generation_config = prepare_generation_config()  # 準(zhǔn)備生成配置# 如果聊天歷史不存在,則初始化if 'messages' not in st.session_state:st.session_state.messages = []# 在應(yīng)用程序重新運(yùn)行時(shí)顯示聊天歷史中的聊天消息for message in st.session_state.messages:with st.chat_message(message['role'], avatar=message.get('avatar')):st.markdown(message['content'])# 接受用戶輸入if prompt := st.chat_input('你有什么想說的?'):# 在聊天消息容器中顯示用戶消息with st.chat_message('user'):st.markdown(prompt)real_prompt = combine_history(prompt)# 將用戶消息添加到聊天歷史中st.session_state.messages.append({'role': 'user','content': prompt,})# 生成并顯示機(jī)器人的回復(fù)with st.chat_message('robot'):message_placeholder = st.empty()for cur_response in generate_interactive(model=model,tokenizer=tokenizer,prompt=real_prompt,additional_eos_token_id=92542,**asdict(generation_config),):# 在聊天消息容器中顯示機(jī)器人的回復(fù)message_placeholder.markdown(cur_response + '▌')message_placeholder.markdown(cur_response)# 將機(jī)器人的回復(fù)添加到聊天歷史中st.session_state.messages.append({'role': 'robot','content': cur_response,  # 循環(huán)內(nèi)最后一次生成的回復(fù)})# 清除 GPU 緩存torch.cuda.empty_cache()if __name__ == '__main__':main()

在運(yùn)行前,我們還需要做的就是將端口映射到本地。那首先我們使用快捷鍵組合 Windows + R(Windows 即開始菜單鍵)打開指令界面,并輸入命令,按下回車鍵。(Mac 用戶打開終端即可)

image.png

打開 PowerShell 后,先查詢端口,再根據(jù)端口鍵入命令 (例如圖中端口示例為 38374):

image.png

然后我們需要在 PowerShell 中輸入以下內(nèi)容(需要替換為自己的端口號)

# 從本地使用 ssh 連接 studio 端口
# 將下方端口號 38374 替換成自己的端口號
ssh -CNg -L 6006:127.0.0.1:6006 root@ssh.intern-ai.org.cn -p 38374

再復(fù)制下方的密碼,輸入到 password 中,直接回車:

image.png

最終保持在如下效果即可:

image.png

之后我們需要輸入以下命令運(yùn)行 /root/personal_assistant/code/InternLM 目錄下的 web_demo.py 文件。

streamlit run /root/ft/web_demo/InternLM/chat/web_demo.py --server.address 127.0.0.1 --server.port 6006

注意:要在瀏覽器打開 http://127.0.0.1:6006 頁面后,模型才會(huì)加載。

打開 http://127.0.0.1:6006 后,等待加載完成即可進(jìn)行對話,鍵入內(nèi)容示例如下:

請介紹一下你自己

效果圖如下:

image.png

假如我們還想和原來的 InternLM2-Chat-1.8B 模型對話(即在 /root/ft/model 這里的模型對話),我們其實(shí)只需要修改183行和186行的文件地址即可。

# 修改模型地址(第183行)
- model = (AutoModelForCausalLM.from_pretrained('/root/ft/final_model',
+ model = (AutoModelForCausalLM.from_pretrained('/root/ft/model',# 修改分詞器地址(第186行)
- tokenizer = AutoTokenizer.from_pretrained('/root/ft/final_model',
+ tokenizer = AutoTokenizer.from_pretrained('/root/ft/model',

然后使用上方同樣的命令即可運(yùn)行。

streamlit run /root/ft/web_demo/InternLM/chat/web_demo.py --server.address 127.0.0.1 --server.port 6006

加載完成后輸入同樣的問題 請介紹一下你自己 之后我們可以看到兩個(gè)模型截然不同的回復(fù):

image.png

2.5.5 小結(jié)

在這一小節(jié)里我們對微調(diào)后的模型(adapter)進(jìn)行了轉(zhuǎn)換及整合的操作,并通過 xtuner chat 來對模型進(jìn)行了實(shí)際的對話測試。從結(jié)果可以清楚的看出模型的回復(fù)在微調(diào)的前后出現(xiàn)了明顯的變化。那當(dāng)我們在測試完模型認(rèn)為其滿足我們的需求后,我們就可以對模型進(jìn)行量化部署等操作了,這部分的內(nèi)容在之后關(guān)于 LMDeploy 的課程中將會(huì)詳細(xì)的進(jìn)行講解,敬請期待后續(xù)的課程吧!

2.6 總結(jié)

在本節(jié)中主要就是帶領(lǐng)著大家跑通了 XTuner 的一個(gè)完整流程,通過了解數(shù)據(jù)集和模型的使用方法、配置文件的制作和訓(xùn)練以及最后的轉(zhuǎn)換及整合。那在后面假如我們也有想要微調(diào)出自己的一個(gè)模型,我們也可以嘗試使用同樣流程和方法進(jìn)行進(jìn)一步的實(shí)踐!

第 4 節(jié)課作業(yè)

記錄復(fù)現(xiàn)過程并截圖

基礎(chǔ)作業(yè)(結(jié)營必做)

  • 訓(xùn)練自己的小助手認(rèn)知(記錄復(fù)現(xiàn)過程并截圖)

進(jìn)階作業(yè)

  • 將自我認(rèn)知的模型上傳到 OpenXLab,并將應(yīng)用部署到 OpenXLab(優(yōu)秀學(xué)員必做)
  • 復(fù)現(xiàn)多模態(tài)微調(diào)(優(yōu)秀學(xué)員必做)
http://www.risenshineclean.com/news/7212.html

相關(guān)文章:

  • 中國鐵路監(jiān)理建設(shè)協(xié)會(huì)網(wǎng)站搭建一個(gè)網(wǎng)站需要什么
  • 網(wǎng)頁設(shè)計(jì)流程圖繪制seo網(wǎng)站診斷方案
  • 佛山網(wǎng)站優(yōu)化有哪些熱門關(guān)鍵詞查詢
  • 網(wǎng)站建設(shè)工作室的營銷方式創(chuàng)業(yè)計(jì)劃書長沙靠譜的關(guān)鍵詞優(yōu)化
  • 網(wǎng)站建設(shè)優(yōu)化排名百度推廣登錄后臺
  • 幫傳銷組織做網(wǎng)站營業(yè)推廣怎么寫
  • 青島做網(wǎng)站多少錢東莞網(wǎng)站制作模板
  • 視頻鏈接生成競價(jià)推廣和seo的區(qū)別
  • 如何作做網(wǎng)站百度一下進(jìn)入首頁
  • 公司網(wǎng)站 開源如何進(jìn)行網(wǎng)絡(luò)營銷推廣
  • 做速賣通的素材有哪些網(wǎng)站做百度推廣的公司電話號碼
  • 代做網(wǎng)站作業(yè)廣告推廣平臺網(wǎng)站
  • 備案的域名可以做盜版電影網(wǎng)站嗎廣州各區(qū)正在進(jìn)一步優(yōu)化以下措施
  • 建設(shè)銀行網(wǎng)站維修圖片做營銷策劃的公司
  • 甘孜州住房和城鄉(xiāng)規(guī)劃建設(shè)局網(wǎng)站外包公司為什么沒人去
  • 廣州企業(yè)網(wǎng)站建設(shè)公司bt磁力搜索神器
  • 做我的狗哪個(gè)網(wǎng)站可以看seo優(yōu)化技術(shù)是什么
  • 最新軟件發(fā)布平臺seo搜索引擎優(yōu)化課程總結(jié)
  • 西安正規(guī)網(wǎng)站建設(shè)報(bào)價(jià)重慶seo服務(wù)
  • 網(wǎng)站制作鄭州網(wǎng)站制作網(wǎng)站制作的重要性及步驟詳解
  • 企業(yè)如何建公司網(wǎng)站網(wǎng)站登錄入口
  • 可信網(wǎng)站辦理大數(shù)據(jù)精準(zhǔn)營銷
  • 重慶免費(fèi)網(wǎng)站制作寧波免費(fèi)seo排名優(yōu)化
  • 網(wǎng)站添加谷歌地圖商城小程序開發(fā)哪家好
  • 網(wǎng)頁傳奇手游排行榜前十名吉林關(guān)鍵詞優(yōu)化的方法
  • 企業(yè)商務(wù)網(wǎng)站建設(shè)論文保定百度推廣聯(lián)系電話
  • 做視頻網(wǎng)站怎么掙錢上海關(guān)鍵詞優(yōu)化推薦
  • 網(wǎng)站建設(shè)河南優(yōu)化合作平臺
  • jquery 案例網(wǎng)站騰訊與中國聯(lián)通
  • 長沙長沙h5網(wǎng)站建設(shè)百度網(wǎng)頁鏈接