【LLM】使用ColossalAI-0.4.0对llama3-8B-Instruct进行全参数微调

目的

掌握训练手段,使用2000+QA数据集,对llama3-8B做全参数微调,使模型能完全按数据集中的问题进行回答,保证准确性。

训练环境

操作系统:

  • ubuntu22.04

机器规格:

  • CPU:96c;
  • 内存:736 GiB;
  • GPU:8 * NVIDIA V100 (32GB)

软件信息:

  • Python 3.11.5;
  • ColossalAI 0.4.0;
  • cuda_11.8;
  • pytorch 2.1.0+cu118

准备工作

模型准备

自行去huggingface或modelscope下载,不做赘述。

模型下载需要先申请权限,填表格时,国家选择中国以外的其他国家,否则容易被驳回,懂的都懂。

huggingface地址:https://huggingface.co/meta-llama/Meta-Llama-3-8B-Instruct

ColossalAI

注意:0.4.0测试完有一些bug,最好是下载0.4.1或之后的,以下所有相关截图我就不更换了。

https://github.com/hpcaitech/ColossalAI/tree/v0.4.0

img

或者直接用git clone进行下载,下载后进入根目录,执行:

pip install .

执行完之后,可以看到0.4.0已经安装

img

进入Colossal-LLaMA,先别着急执行pip install,打开requirements文件看了一下,不知道是不是官方缺心眼,一眼看去,好多包版本都不对,如果直接安装,会造成版本冲突、NO CUDA Driver FOUND等错,只能检查一下那些是已经安装的,把已经安装的从文件里去掉!

img

最后经过检查,只有以下几个是没有安装的,保留这几个即可:

huggingface-hub==0.22.1
packaging==24.0
autoflake==2.2.1
black==23.9.1
tensorboard==2.14.0
flash-attn>=2.0.0,<=2.0.5

然后执行:

pip install -r requirements.txt

执行完之后,会提示一些版本冲突,按要求更新一下

img

还有最重要的一步,不做这一步,后面会报错:No module named ‘dropout_layer_norm’

安装 xentropy, layer_norm and rotary

git clone git@github.com:Dao-AILab/flash-attention.git
# At the root folder
cd csrc/xentropy && pip install .
# At the root folder
cd csrc/layer_norm && pip install .
# At the root folder
cd csrc/rotary && pip install .

至此,所有依赖安装完毕。

可以执行 colossalai check -i 进行依赖检查。

数据集准备

  1. 原始数据集格式:
{"messages": [{"from": "human", "content": "What are the three primary colors?"}, {"from": "assistant", "content": "The three primary colors are red, blue, and yellow."}]}
{"messages": [{"from": "human", "content": "解释个人电脑和服务器之间的区别。"}, {"from": "assistant", "content": "个人电脑和服务器是两种不同类型的计算机系统,它们的主要区别在于用途、硬件配置和性能。 个人电脑,顾名思义,是为个人使用而设计的计算机。它们通常用于日常的工作、娱乐和学习,可以运行各种各样的应用程序和游戏。个人电脑的硬件配置一般是按照标准配置来设计的,不过也可以根据个人需求进行定制。 而服务器是为了满足大量用户的需求而设计的计算机系统,它们通常用于为用户提供各种网络服务,如网站、电子邮件和文件传输等。服务器通常需要高性能的硬件配置,并且可以承受高负载和长时间的运行。由于服务器需要支持大量用户的访问,它们通常配备多核处理器、大容量内存和大容量硬盘驱动器,以提高系统的运行速度和稳定性。 总之,个人电脑和服务器之间的主要区别在于它们的用途、硬件配置和性能。个人电脑用于个人使用,而服务器用于支持大量用户的访问。服务器的硬件配置通常比个人电脑更高,以保证系统的性能和稳定性。"}]}
  1. 数据预处理:
python /mnt/data/tool/ColossalAI-0.4.0/applications/Colossal-LLaMA/prepare_sft_dataset.py \
    --data_input_dirs "/mnt/data/dataset/llama3/prepare/original/2000items" \
    --tokenizer_dir "/mnt/data/model/modelscope/Meta-Llama-3-8B-Instruct" \
    --data_output_dirs "/mnt/data/dataset/llama3/prepare/2000items-llama3" \
    --max_length 2048 \
    --num_spliced_dataset_bins 10 \
    --llama_version 3

可以看到0.4.0版本不再需要配置chat_template.json,简便了许多。

执行完之后,在data_output_dirs可以看到SFT阶段需要的数据集:

img

准备训练脚本

#!/bin/bash

# NCCL IB environment variables
export NCCL_IB_HCA=mlx5_1:1,mlx5_2:1,mlx5_3:1,mlx5_4:1
export NCCL_IB_DISABLE=0
export NCCL_SOCKET_IFNAME=eth0
export NCCL_IB_GID_INDEX=3
export NCCL_IB_TIMEOUT=23
export NCCL_IB_RETRY_CNT=7
export OMP_NUM_THREADS=8

PROJECT_NAME="sft"
PARENT_SAVE_DIR="/mnt/data/sft-output/" # Path to a folder to save checkpoints
PARENT_TENSORBOARD_DIR="/mnt/data/sft-output/tensorboard/" # Path to a folder to save logs
PARENT_CONFIG_FILE="/mnt/data/sft-output/configs/config" # Path to a folder to save training config logs
PRETRAINED_MODEL_PATH="/mnt/data/model/modelscope/Meta-Llama-3-8B-Instruct" # huggingface or local model path
PRETRAINED_TOKENIZER_PATH="/mnt/data/model/modelscope/Meta-Llama-3-8B-Instruct" # huggingface or local tokenizer path


# NCCL IB environment variables
export NCCL_IB_HCA=mlx5_1:1,mlx5_2:1,mlx5_3:1,mlx5_4:1
export NCCL_IB_DISABLE=0
export NCCL_SOCKET_IFNAME=eth0
export NCCL_IB_GID_INDEX=3
export NCCL_IB_TIMEOUT=23
export NCCL_IB_RETRY_CNT=7
export OMP_NUM_THREADS=8

PROJECT_NAME="sft"
PARENT_SAVE_DIR="/mnt/data/sft-output/" # Path to a folder to save checkpoints
PARENT_TENSORBOARD_DIR="/mnt/data/sft-output/tensorboards/tensorboard" # Path to a folder to save logs
PARENT_CONFIG_FILE="/mnt/data/sft-output/configs/config" # Path to a folder to save training config logs
PRETRAINED_MODEL_PATH="/mnt/data/model/modelscope/Meta-Llama-3-8B-Instruct" # huggingface or local model path
PRETRAINED_TOKENIZER_PATH="/mnt/data/model/modelscope/Meta-Llama-3-8B-Instruct" # huggingface or local tokenizer path

EPOCH=10
MODEL="llama3-8b"


declare -a dataset=(
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00000
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00001
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00002
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00003
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00004
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00005
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00006
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00007
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00008
    /mnt/data/dataset/llama3/prepare/2000items-llama3/arrow/part-00009
)
TIMESTAMP=$(date +%Y-%m-%d-%H-%M-%S)
FULL_PROJECT_NAME="${PROJECT_NAME}-${MODEL}-${EPOCH}-${TIMESTAMP}"
SAVE_DIR="${PARENT_SAVE_DIR}${FULL_PROJECT_NAME}"
TENSORBOARD_DIR="${PARENT_TENSORBOARD_DIR}-${FULL_PROJECT_NAME}"
CONFIG_FILE="${PARENT_CONFIG_FILE}${FULL_PROJECT_NAME}.json"

colossalai run --nproc_per_node 4 --master_port 30013 /mnt/data/tool/ColossalAI-0.4.0/applications/Colossal-LLaMA/train.py \ 
    --pretrained $PRETRAINED_MODEL_PATH \
    --dataset ${dataset[@]} \
    --plugin zero2_cpu \
    --save_dir $SAVE_DIR \
    --tensorboard_dir $TENSORBOARD_DIR \
    --config_file $CONFIG_FILE \
    --num_epochs $EPOCH \
    --accumulation_steps 1 \
    --micro_batch_size 2 \
    --lr 5e-5 \
    --max_length 2048 \
    --save_interval 10000 \
    --use_grad_checkpoint

训练

前置准备工作都完成了,训练阶段就只需要运行脚本了,等待日志显示success即可。

(以下的截图是3个epoch训练的)

img

现在有一个问题:每个epoch都会生成一个很大的文件夹:

imgimg

提交了一个PR,加了一个开关,用户可以选择是否需要每个epoch保存一次checkpoint,具体使用在PR中有介绍。

https://github.com/hpcaitech/ColossalAI/pull/5941

修改后,每个epoch不在自动保存checkpoint,效果如下:

img

模型的输出目录,只有一个最终的模型文件了。

img

推理测试

加载模型

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

model_path = "/mnt/data/sft-output/sft-2024-07-23-21-35-36/modeling"

tokenizer = AutoTokenizer.from_pretrained("/mnt/data/model/modelscope/Meta-Llama-3-8B-Instruct")
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

img

提问

messages = [
    {"role": "system", "content": "You are a chatbot, you must give a correct anwser"},
    {"role": "user", "content": "社保公积金的调整规则及其操作时间如何?"},
]

input_ids = tokenizer.apply_chat_template(
    messages,
    add_generation_prompt=True,
    return_tensors="pt"
).to(model.device)

terminators = [
    tokenizer.eos_token_id,
    tokenizer.convert_tokens_to_ids("<|eot_id|>")
]

outputs = model.generate(
    input_ids,
    max_new_tokens=512,
    eos_token_id=terminators,
    do_sample=True,
    temperature=0.0000001,
    top_p=0.9,
)
response = outputs[0][input_ids.shape[-1]:]
print(tokenizer.decode(response, skip_special_tokens=True))

img

关于这个问题的原数据集如下:

用GPT将问题进行变形,回答不变,让提问能有一定的泛化性。

{"messages": [{"from":"human","content":"社保公积金的调整规则及其操作时间如何?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"能讲解一下关于社保公积金增减员的规定和操作时间吗?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"社保公积金增减员的操作时间和规定是什么?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"社保公积金的增减员操作应该怎么进行,操作时间是什么时候?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"关于社保公积金增减员的操作时间和规则能详细介绍一下吗?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"请问,社保公积金增减员的规定和操作时间是什么样的?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"我该怎样理解社保公积金的增减员规则以及其操作时间?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"社保公积金的增减员是如何规定的,相关操作时间又是怎样的?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"能否详细讲解一下社保公积金增减员的操作时间和规则?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}
{"messages": [{"from":"human","content":"请问社保公积金的增减员规定以及操作时间是如何的?"},{"from":"assistant","content":"增员:当月15号(含)前入职的当月增员,当月15号以后入职的下月增员,系统操作时间为每月17-25号。减员,最后工作日在当月15号以前的当月减员,最后工作日在当月15号(含)以后的下月减员,系统操作时间为每月10-20号。"}]}

相同的问题,换一个提问方式:

img

可以看到,换了一种提问方式(问题原文在数据集中不存在),模型也能很准确的进行回答。

后续做了一些测试,大致结论如下:

  1. 对于超长文本的数据集,回答准确性无法保证;
  2. 因为epoch设置得很低,epoch=1,所以2000条左右数据中,后半部分的问题回答效果均不佳,后续调高epoch做了对比测试,epoch=8时,准确率已达到了90%+;

至此,训练结束,虽有坎坷,亦有收货。

遇到的问题

UnboundLocalError: cannot access local variable ‘default_conversation’ where it is not associated with a value

img

这个错出现在数据处理阶段,原因是代码bug,需要改源码,改动也比较简单,就是给这个变量赋一个默认值,我给官方提了一个issue和pr。

img

ImportError: cannot import name ‘split_torch_state_dict_into_shards’ from ‘huggingface_hub’

img

怀疑是huggingface_hub版本不兼容,目前安装的版本是:

img

换了一个高版本,解决了。

pip install huggingface-hub==0.22.1

ModuleNotFoundError: No module named ‘dropout_layer_norm’

img

dropout_layer_norm这个东西是flash_attn中的,官方有说明,2024.1之后不再使用这个了,反正是奇奇怪怪的错误。

img

有一些文章供参考:

https://github.com/Dao-AILab/flash-attention/issues/587

https://github.com/Dao-AILab/flash-attention/tree/main/csrc/layer_norm

https://github.com/Dao-AILab/flash-attention/tree/main/flash_attn/ops/triton

https://github.com/OpenGVLab/InternVideo/blob/main/InternVideo2/multi_modality/INSTALL.md

这个问题对我这个门外汉来说,卡了很久,还尝试看了下flash_attention的源码,最后解决方法是手动编译安装,方法如下:

git clone git@github.com:Dao-AILab/flash-attention.git
# At the root folder
cd csrc/xentropy && pip install .
# At the root folder
cd csrc/layer_norm && pip install .
# At the root folder
cd csrc/rotary && pip install .

use_cache=True is incompatible with gradient checkpointing. Setting use_cache=False.

这个是一个警告,并不影响流程。

按字面理解,因为用了梯度保存的策略,需要将这个参数设置为false,很好解决。但是脚本并不支持这个参数的设置,试了通过环境变量的方式也不行。

多说一句,如果使用的梯度累积的策略,当达到指定步数时,会执行落盘操作,会非常非常耗时,而且会产生一个非常大的文件夹,大概70GB+,所以,按需求配置,因为是测试,我一般会把保存间隔设置非常大,避免进行累加保存。

KeyError: ‘Cache only has 0 layers, attempted to access layer with index 0’

img

flash_attn冲突,暂时不知道如何解决,将脚本中的--use_flash_attn去掉。

CUDA out of memory

这是一个很常见的错误,原因就是显卡显存不足导致的

img

有几个解决方案:

  1. 减小batch_size;
  2. 插件选择zero2_cpu(–plugin “zero2_cpu”),这个可以使用CPU去协助运行,就是会很慢;
  3. 使用梯度策略,训练参数加上–use_grad_checkpoint(低版本是:–grad_checkpoint)
  4. 换显存大的机器。

Please install apex from source (https://github.com/NVIDIA/apex) to use the fused layernorm kernel

这是一个警告,虽然不影响运行,但是也膈应,顺便解决下。

git clone https://github.com/NVIDIA/apex
cd apex

# if pip >= 23.1 (ref: https://pip.pypa.io/en/stable/news/#v23-1) which supports multiple `--config-settings` with the same key... 
pip install -v --disable-pip-version-check --no-cache-dir --no-build-isolation --config-settings "--build-option=--cpp_ext" --config-settings "--build-option=--cuda_ext" ./

# otherwise
pip install -v --disable-pip-version-check --no-cache-dir --no-build-isolation --global-option="--cpp_ext" --global-option="--cuda_ext" ./

查看pip版本:

pip --version

KeyError: ‘llama’

我遇到这个错的背景是:使用applications/ColossalChat对llama2-7B-Chat做SFT,没有对ColossalChat执行install。

cd applications/ColossalChat/
pip install .

这个问题需要结合自己的情况去看。

RuntimeError: torch.cat(): expected a non-empty list of Tensors

RuntimeErrorRuntimeError: : The param bucket max size 12582912 is exceededby tensor (size 131334144)The param bucket max size 12582912 is exceededby tensor (size 131334144)



During handling of the above exception, another exception occurred:
During handling of the above exception, another exception occurred:


Traceback (most recent call last):
Traceback (most recent call last):
  File "/mnt/data/tool/ColossalAI-0.4.0/applications/Colossal-LLaMA/train.py", line 425, in <module>
  File "/mnt/data/tool/ColossalAI-0.4.0/applications/Colossal-LLaMA/train.py", line 425, in <module>
    main()
    main()
  File "/mnt/data/tool/ColossalAI-0.4.0/applications/Colossal-LLaMA/train.py", line 357, in main
  File "/mnt/data/tool/ColossalAI-0.4.0/applications/Colossal-LLaMA/train.py", line 357, in main
    optimizer.step()
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/low_level_optim.py", line 717, in step
    optimizer.step()
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/low_level_optim.py", line 717, in step
    tensor_bucket.all_gather(self._bucket_store.moe_extra_dp_pg)
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/bookkeeping/tensor_bucket.py", line 65, in all_gather
    tensor_bucket.all_gather(self._bucket_store.moe_extra_dp_pg)
    flat = self.flatten()
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/bookkeeping/tensor_bucket.py", line 65, in all_gather
           ^^^^^^^^^^^^^^
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/bookkeeping/tensor_bucket.py", line 54, in flatten
    flat = self.flatten()
           ^^^^^^^^^^    ^return _flatten_dense_tensors(self._bucket)^
^^
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/bookkeeping/tensor_bucket.py", line 54, in flatten
           ^^^^^^^^^^^^^^^^    ^return _flatten_dense_tensors(self._bucket)^
^^^^^^^^^^^^^^^^ ^ ^ 
      File "/home/pai/lib/python3.11/site-packages/torch/_utils.py", line 498, in _flatten_dense_tensors
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pai/lib/python3.11/site-packages/torch/_utils.py", line 498, in _flatten_dense_tensors
    return torch._C._nn.flatten_dense_tensors(tensors)
               return torch._C._nn.flatten_dense_tensors(tensors)^
^^^^^^^^^^^^^^^^^^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^RuntimeError^^: ^torch.cat(): expected a non-empty list of Tensors^
^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: torch.cat(): expected a non-empty list of Tensors
Traceback (most recent call last):
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/low_level_optim.py", line 715, in step
    tensor_bucket.add_to_bucket(param_to_gather, write_back_tensor=working_param)
  File "/home/pai/lib/python3.11/site-packages/colossalai/zero/low_level/bookkeeping/tensor_bucket.py", line 34, in add_to_bucket
    raise RuntimeError(msg)
RuntimeError: The param bucket max size 12582912 is exceededby tensor (size 131334144)

来看看GPT是怎么回答的:

在深度学习中,模型的训练通常在GPU(显卡)上进行,因为GPU有大量的并行处理单元,可以大大加速模型的训练。
上述错误信息中的"bucket max size 12582912 is exceeded by tensor (size 131334144)"表示一个张量的大小超过了分桶策略的最大值。这个张量通常会存储在显卡的内存中,如果显卡的内存不足,就可能导致这个错误。
具体来说,如果你的模型很大,或者你的批量大小(batch size)很大,那么可能会产生很大的张量,从而超过显卡的内存限制。在这种情况下,你可以尝试以下解决方案:
1. 减小模型的大小:可以通过减少层的数量、减少每层的神经元数量等方式来减小模型的大小。
2. 减小批量大小:减小批量大小可以减小每个张量的大小,但可能会影响训练效果和效率。
3. 使用更高规格的显卡:如果条件允许,你可以考虑使用具有更大内存的显卡。
4. 使用模型并行:如果模型太大,无法在一块显卡上完全存储,可以考虑使用模型并行,将模型的不同部分放在不同的显卡上。
5. 使用梯度累积:即不是每一步都进行梯度更新,而是积累几步的梯度再进行更新,这样可以减小内存使用。
需要注意的是,这些方法可能会影响模型的训练效果和效率,需要根据具体情况进行权衡。

不知道是不是和我显卡规格有关,相关专业的大佬,麻烦给我解答一下…

针对这个问题,我提了一个issue,里面有解答:https://github.com/hpcaitech/ColossalAI/issues/5935

下载0.4.1之后的代码,到根目录下执行 pip install .

重新运行脚本解决。

训练的效果,符合预期,而且比llama2好很多。

现在北京时间是2024-07-25,北京有暴雨警告,llama3.1发布了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值