目前有大量对LLM(大语言模型)做Fine-tune的方式,不过需要消耗的资源非常高,例如
这种资源需求令普通的学习者望而却步,使用LoRA则可以较好的解决这个问题
LoRA全称为Low-Rank Adaptation of Large Language Models,是一种模拟Full Fine-tune的特殊方法:不改变原模型的情况下,在旁边增加一个降维和升维操作来模拟 intrinsic rank(模拟训练真正能影响模型效果的那些参数),从而达到和Full Fine-tune几乎一样的效果。(具体原理请自行查找。另外提一下:LoRA原本是用于LLM的,不过目前在StableDiffusion上也得到了非常好的应用。)
LoRA 的最大优势是训练参数少、速度快、内存消耗少。例如Alpaca-LoRA使用一颗RTX 4090即可实现对LLaMA-7B的Fine-tune,目前也有很多网友使用单颗RTX 4070 Ti、RTX 4080完成过训练。
下面就来说说整个训练过程。
我使用的设备是3颗老旧的Tesla T4(不要问我为什么用推理专用GPU做训练),信息如下
(base) [root@xxx-yyy-gpu ~]# nvidia-smi
Mon May 29 16:29:50 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 460.91.03 Driver Version: 460.91.03 CUDA Version: 11.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Tesla T4 Off | 00000000:3B:00.0 Off | 0 |
| N/A 31C P8 8W / 70W | 0MiB / 15109MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 1 Tesla T4 Off | 00000000:AF:00.0 Off | 0 |
| N/A 32C P8 9W / 70W | 0MiB / 15109MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 2 Tesla T4 Off | 00000000:D8:00.0 Off | 0 |
| N/A 31C P8 9W / 70W | 0MiB / 15109MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
理论上2颗Tesla T4也行
finetune.py
、generate.py
代码requirements.txt
中的依赖trans_chinese_alpaca_data.json
文件,这是该项目翻译为中文的对话数据$ conda create -n alpaca python=3.9
$ conda activate alpaca
$ conda install pytorch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1 pytorch-cuda=11.6 -c pytorch -c nvidia
$ pip3 install torch==1.13.1+cu116 torchvision==0.14.1+cu116 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116
alpaca
中,如果直接安装alpaca-lora项目下的requirements.txt
,可能会漏掉一些依赖包。你可以试试,操作如下
$ pip install -r requirements.txt
$ pip install accelerate appdirs loralib black datasets fire peft transformers==4.29.2 sentencepiece gradio scipy bitsandbytes==0.37.2
requirements.txt
文件中的描述,transformers需要>=4.28.0
,太高也会出问题,建议用4.29.2
。另外,bitsandbytes
的版本不要用0.38.x
,会报OOM,建议用0.37.2
,但是又可能会出现其他错误(0.38.x
修复了这个问题,解决方式见文末)。transformers
库用于加载、训练、保存模型,peft
库则是用于帮助你使用LoRA的/root/.cache/huggingface/hub/models--decapoda-research--llama-7b-hf
/home/gpt/alpaca-lora
/home/gpt/data/trans_chinese_alpaca_data.json
进入到Alpaca-LoRA项目目录下,如/home/gpt/alpaca-lora
若是单个显卡,训练命令样例如下
nohup python \
finetune.py \
--base_model 'decapoda-research/llama-7b-hf' \
--data_path '/home/gpt/data/trans_chinese_alpaca_data.json' \
--output_dir './my_model_save' \
--batch_size 128 \
--micro_batch_size 2 \
--num_epochs 2 \
--learning_rate 3e-4 \
1>train.log 2>&1 &
--base_model
是预训练模型LLaMA在huggingface的标识或本地存储路径--data_path
是训练用的数据的路径--output_dir
是训练完成后模型的保存路径--micro_batch_size
是微批次的大小,会通过梯度累积的方式来节省显存。越大占用显存越高,请根据你的情况调整。--batch_size
--num_epochs
是训练轮数,2~3个epoch基本上可以达到较好的效果--learning_rate
是训练时的学习率,3e-4
即0.0003
nohup
和1>train.log 2>&1 &
:1>train.log 2>&1
用于将所有训练信息输出到train.log
文件,方便后面查看。同时,利用nohup
和&
可以让程序置于后台运行,以防止shell连接突然断掉导致程序结束(因为训练时间很长)。(另外提一下:使用nohup
后,最好手动exit
退出下终端,因为非正常退出可能会导致程序终止)若是多个显卡,训练命令样例如下
WORLD_SIZE=3 CUDA_VISIBLE_DEVICES=0,1,2
nohup torchrun \
--nproc_per_node=3 \
--master_port=1234 \
finetune.py \
--base_model 'decapoda-research/llama-7b-hf' \
--data_path '/home/gpt/data/trans_chinese_alpaca_data.json' \
--output_dir './my_model_save' \
--batch_size 128 \
--micro_batch_size 2 \
--num_epochs 2 \
--learning_rate 3e-4 \
1>train.log 2>&1 &
WORLD_SIZE
是全局进程数(一般一个显卡对应一个进程)CUDA_VISIBLE_DEVICES
是具体的几张显卡的ID--nproc_per_node
是每个物理节点上面进程的数量环境有网络的话,正常情况下会自动下载LLaMA模型文件,接着就开始训练了
如果没网,但之前单独下载了LLaMA模型文件,需要
$ HF_DATASETS_OFFLINE=1 TRANSFORMERS_OFFLINE=1
--base_model 'decapoda-research/llama-7b-hf'
改为--base_model '/root/.cache/huggingface/hub/models--decapoda-research--llama-7b-hf'
我因为一些特殊情况,训练时必须离线,所以我的最终命令如下
WORLD_SIZE=3 CUDA_VISIBLE_DEVICES=0,1,2 HF_DATASETS_OFFLINE=1 TRANSFORMERS_OFFLINE=1
nohup torchrun \
--nproc_per_node=3 \
--master_port=1234 \
finetune.py \
--base_model '/root/.cache/huggingface/hub/models--decapoda-research--llama-7b-hf' \
--data_path '/home/gpt/data/trans_chinese_alpaca_data.json' \
--output_dir './my_model_save' \
--batch_size 128 \
--micro_batch_size 4 \
--num_epochs 3 \
1>train.log 2>&1 &
设备监控信息,样例如下(用的 nvitop 命令,需要单独安装pip3 install --upgrade nvitop
)
训练完成后会在my_model_save
目录下生成文件,包括adapter_config.json
、adapter_model.bin
和一系列checkpoint文件。(见上面的截图)
选择最新的checkpoint文件夹(如 checkpoint-1200),将其中的pytorch_model.bin
文件拷贝到my_model_save
目录下,并重命名为adapter_model.bin
做推断时需要的文件包括原始LLaMA-7B文件
,以及my_model_save
目录下的adapter_config.json
、adapter_model.bin
文件
下面启动推断服务,命令样例如下
WORLD_SIZE=3 CUDA_VISIBLE_DEVICES=0,1,2
python generate.py \
--base_model "decapoda-research/llama-7b-hf" \
--lora_weights './my_model_save' \
--load_8bit
我是在本离线使用的,所以我的命令如下
WORLD_SIZE=3 CUDA_VISIBLE_DEVICES=0,1,2 HF_DATASETS_OFFLINE=1 TRANSFORMERS_OFFLINE=1
python generate.py \
--load_8bit \
--base_model "/root/.cache/huggingface/hub/models--decapoda-research--llama-7b-hf" \
--lora_weights '/home/gpt/alpaca-lora/my_model_save/'
http://IP:7860
),样例如下bitsandbytes 0.37.2
可能会出现找不到当前需要使用的cuda的版本的问题(如果你用conda安装pytorch的话)bitsandbytes doesn’t work#452bitsandbytes 0.38.x
中已经修复了该问题,不过又会出现OOM的问题 New OOM bug introduced in bitsandbytes 0.38.x?#324,并且最新的0.39.0
也还没修复这个问题bitsandbytes
的python源码bitsandbytes
库的位置,编辑下面的./cuda_setup/main.py
文件,例如$ vim /root/anaconda3/envs/alpaca/lib/python3.9/site-packages/bitsandbytes/cuda_setup/main.py
if not torch.cuda.is_available(): return 'libsbitsandbytes_cpu.so', None, None, None, None
if torch.cuda.is_available(): return 'libbitsandbytes_cuda117.so', None, None, None, None
(cuda117改成你自己的cuda版本即可)$ python -m bitsandbytes
,进行测试,如果最后输出如下内容,就没问题了......
Running a quick check that:
+ library is importable
+ CUDA function is callable
SUCCESS!
Installation was successful!