StarCoder 微调《个人编程助手: 训练你自己的编码助手》

《官方教程:个人编程助手: 训练你自己的编码助手》《第三方教程:个人编程助手: 训练你自己的编码助手》中存在一个微调 StarCoder 模型的教程,但没有讲清楚如何配置环境,以及其他所需附加知识点,本帖旨在解决这两个问题。

一、环境配置

1. 安装 Nvidia 显卡驱动

安装 Nvidia 显卡驱动有两种方法,第一种方法是从官网下载驱动 官网历史版本驱动下载,然后禁用本地驱动,最后安装下载的驱动,该方法安装失败的可能性较高。第二种方法是直接去 【软件和更新 --> 附加驱动】 中安装或升级驱动,推荐第二种方法,有时第二种方法可能不显示 Nvidia 显卡驱动,那需要参考 1 参考 2 参考 3,有时虽然显示 Nvidia 显卡驱动,但却是灰色,解决方法参考

下载显卡驱动前首先需要确定显卡的硬件版本,查看硬件版本的方式是,首先运行 lspci | grep VGA 命令,查看硬件号,如下图是 2460,然后去链接中查询硬件版本,如下图为 RTX 3080 Ti。

驱动版本需要 >=520。显卡驱动需要与 Cuda 版本匹配。由于后面需要安装 Flash Attention (要求 Cuda 版本大于 11.6) 和 Pytorch (较新版本均要求 Cuda 11.8 或 Cuda 12.1),所以可选的 Cuda 版本只有 Cuda 11.8 和 Cuda 12.1。当选择 Cuda 11.8 时,Nvidia 显卡驱动需要 >=520,当选择 Cuda 12.1 时,Nvidia 显卡驱动需要 >=530。Nvidia 显卡驱动与 Cuda 版本匹配要求见 链接nvidia-smi 命令显示结果中右上部分的 CUDA Version: 12.2 是当前 Nvidia 显卡驱动所支持的最高 Cuda 版本。

实际测试成功安装的是 535.171.04,所用 Ubuntu 版本是 22.04.4 LTS。

2. 安装 Cuda

首次安装 Cuda 的教程参考,删除现有 Cuda 更换新版本的教程参考。简单来说就是,从官网下载对应版本 Cuda,通过 sudo sh cuda_12.1.0_530.30.02_linux.run 命令安装。需要注意的是,在安装过程中不要选择安装 Driver。

安装完成后需要添加环境变量。

sudo vim ~/.bashrc

在其中添加:

export PATH=/usr/local/cuda-12.1/bin:$PATH

export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64$LD_LIBRARY_PATH

然后运行:

source ~/.bashrc

安装完成后,需要通过命令 nvcc --version 判断是否安装成功,实际测试成功安装的是 Cuda 12.1。

完成 Cuda 安装后,如果下面的深度学习开发库是 pytorch,据说可以不用再安装 cudnn,pytorch 自带 cudnn。所以这里可以不用再继续安装 cudnn,经过测试 pytorch 也确实可以运行成功。但为了以防万一,这里还是记录了 cudnn 的单独安装教程。

官网下载 cudnn。首页选择版本号 (不用太新),然后选择对应系统等信息,最后建议选择 deb (network) 的安装方式。运行如下命令便可完成安装:

wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb

sudo dpkg -i cuda-keyring_1.1-1_all.deb

sudo apt-get update

sudo apt-get -y install cudnn

查看已安装 Cudnn 版本的方法是
cat /usr/include/cudnn_version.h

测试 cudnn 是否安装成功

cp -r /usr/src/cudnn_samples_v8/ $HOME

cd $HOME/cudnn_samples_v8/mnistCUDNN

make clean && make

./mnistCUDNN

显示 Test passed! 则安装成功。如果上面的 make 命令提示缺少 FreeImage.h,运行:sudo apt-get install libfreeimage3 libfreeimage-dev

cudnn 的卸载教程参考链接

3. 安装 Anaconda

从清华镜像下载 Linux 版本的 Anaconda,清华镜像官网 Anaconda 下载,版本选择不用太在意,建议选择新一点的版本,不用最新。举例使用 Anaconda3-2023.03-Linux-x86_64.sh,通过命令 bash Anaconda3-2023.03-Linux-x86_64.sh 安装 Anaconda,然后一路 yes 即可完成安装。安装教程参考链接

完成 Anaconda 安装后,需要通过 conda create --name starcoder python=3.10 命令创建虚拟环境,并指定 python 版本,由于后面需要安装 xformers,而 xformers 版本需要与 python 版本以及 pytorch 版本匹配,实际测试安装成功的是 python 3.10 + pytorch 2.1.1 和 xformers 0.0.23。完成虚拟环境创建后,需要通过命令 conda activate starcoder 激活虚拟环境。如果后面想要删除虚拟环境,可以通过命令 conda remove --starcoder --all

4. clone 代码

git clone GitHub - pacman100/LLM-Workshop: LLM Workshop by Sourab Mangrulkar

cd DHS-LLM-Workshop

5. 安装一系列所需的软件包

5.1 安装 pytorch

pytorch 版本需要与 xformer 版本和 Cuda 版本匹配,所以实际测试安装成功的是 pytorch 2.1.1,如下第一句为官网推荐安装方式,但是速度巨慢,可以使用第二句进行安装。

conda install pytorch==2.1.1 torchvision==0.16.1 torchaudio==2.1.1 pytorch-cuda=12.1 -c pytorch -c nvidia

pip install torch==2.1.1 torchvision==0.16.1 torchaudio==2.1.1 -i https://mirrors.aliyun.com/pypi/simple/

5.2 安装 packing

pip install packaging

5.3 安装 ninja

必须首先安装 ninja,否则后面编译 FlashAttention 会很慢

pip uninstall -y ninja && pip install ninja

5.4 安装剩余软件包

pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/

如果安装过程中,部分之前安装的软件包被升级,需要手动再降级回来,此外,如果还存在版本不匹配,则需要调整部分软件的版本,参照附件 1 的 pip list。

5.5 安装 FlashAttention

如果上一步没有报错,那 FlashAttention 已经安装完成,不用再管这一步,如果没有安装完成,可以尝试从源码进行安装,参考 链接 1 链接 2 链接 3

需要注意目前原生的 FlashAttention 仅支持 Ampere、Hopper 等架构的 GPU。RTX3080ti 属于 Ampere 架构。架构不支持可能会报错。

6. 关于 WanDB

WanDB 是一个可类比 Tensorboard 的可视化程序,可以实现可视化模型的训练过程,甚至可以选择保存本次训练所用的代码和数据,但是它没有本地查看客户端,需要先将数据保存在本地,然后自动上传服务器端,最后通过浏览器查看结果,上传远程服务器需要提前注册账户和梯子,也可以选择本地 Docker 方式部署,完成部署后就可以将训练数据自动上传本地服务器,以实现可视化。相关教程可以参考 链接 1 链接 2 链接 3 链接 4

运行代码时可通过命令 wandb login --relogin 然后输入证书,实现远程连接。但在执行 StarCoder 代码时,我们选择关闭这个功能,避免麻烦的云端上传。

7. 关于 HuggingFace

由于代码在运行时需要从 HuggingFace 官网下载预训练模型和 fine-tune 数据集,而 HuggingFace 要求在数据下载前先要验证身份,所以需要事先去 HuggingFace 官网注册一个账号,然后去 setting --> Access Tokens 中拿到证书秘钥。

此外,还要根据代码运行时所需的模型去网页上拿到模型下载授权,例如上面第一个图是 codegemma-7b 的界面,界面左上部分显示,我们并没有获得下载权限,点击 Acknowlege License 即可获得授权,如下图这种界面就是已获得 starcoderbase-1b 的下载授权。

然后在代码运行时,由于 huggingface-cli login 命令的存在,会要求输入秘钥,只有在输入证书秘钥后才会继续运行。

二、运行代码

1. 运行命令

原教程中的代码运行命令存在版本不匹配问题,不建议使用原教程的运行命令,报错参考链接。我重写了运行命令,可以使用如下命令进行运行。当前参数设置下,1B 的模型可以训练,7B 模型会内存不够。

cd personal_copilot/training/

sh train.sh

train.sh 内容如下:

huggingface-cli login
CUDA_VISIBLE_DEVICES=0 python train.py \
--model_name_or_path "bigcode/starcoderbase-1b" \
--dataset_name "smangrul/hf-stack-v1" \
--splits "train" \
--max_seq_len 2048 \
--max_steps 1000 \
--save_steps 100 \
--eval_steps 100 \
--logging_steps 25 \
--log_level "info" \
--logging_strategy "steps" \
--evaluation_strategy "steps" \
--save_strategy "steps" \
--push_to_hub False \
--hub_private_repo True \
--hub_strategy "every_save" \
--bf16 True \
--learning_rate 2e-4 \
--lr_scheduler_type "cosine" \
--weight_decay 0.01 \
--warmup_ratio 0.1 \
--max_grad_norm 1.0 \
--output_dir "peft-qlora-starcoderbase1B-personal-copilot-3080Ti-16GB" \
--per_device_train_batch_size 6 \
--per_device_eval_batch_size 6 \
--gradient_accumulation_steps 2 \
--gradient_checkpointing True \
--use_reentrant True \
--dataset_text_field "content" \
--test_size 0.1 \
--fim_rate 0.5 \
--fim_spm_rate 0.5 \
--use_peft_lora True \
--lora_r 8 \
--lora_alpha 32 \
--lora_dropout 0.1 \
--lora_target_modules "c_proj,c_attn,q_attn,c_fc,c_proj" \
--use_4bit_quantization True \
--use_nested_quant True \
--bnb_4bit_compute_dtype "bfloat16" \
--use_flash_attn True

然后显示如下界面,需要输入 HuggingFace 秘钥。

然后显示如下界面,需要选择 3 ,即不使用 WanDB 可视化工具,否则需要去官网注册账号,还需要梯子。在代码运行前提前设置环境变量可以避免出现如下界面,Automatic Weights & Biases logging enabled, to disable set os.environ["WANDB_DISABLED"] = "true"。

然后模型开始正常训练,1000 个 step 的 fine tune 时间预计 2 小时。

最终训练结果保存在 .peft-qlora-starcoderbase1B-personal-copilot-3080Ti-16GB 目录下。保存结果只有 LoRA 的权重,没有将权重合并进基础权重中。

如果想要将 LoRA 权重合并进基础权重中可以使用如下代码,merge_peft_adapter.py 见附件 2。

python merge_peft_adapter.py \
    --model_type starcoder \
    --base_model ./models--bigcode--starcoderbase-1b \      # 基础模型参数路径
    --tokenizer_path ./models--bigcode--starcoderbase-1b \  # 基础模型参数路径
    --lora_model ./peft-qlora-starcoderbase1B-personal-copilot-3080Ti-16GB \  # Adapter模型参数路径
    --output_dir ./peft-qlora-starcoderbase1B-personal-copilot-3080Ti-16GB/merge_model   # 输出路径

如果想用本地模型和数据集进行训练,则可以替换 train.sh 中的前两行为如下两行:

--model_name_or_path "./models/models--bigcode--starcoderbase-1b" \
--dataset_name "./data/hf-stack-v1" \

models--bigcode--starcoderbase-1b 中的内容从 链接 下载,hf-stack-v1 中的内容从 链接 下载。

参考链接

附件 1

Package                  Version
------------------------ -----------
absl-py                  2.1.0
accelerate               0.30.0.dev0
aiohttp                  3.9.4
aiosignal                1.3.1
annotated-types          0.6.0
appdirs                  1.4.4
async-timeout            4.0.3
attrs                    23.2.0
bitsandbytes             0.43.1
certifi                  2024.2.2
cffi                     1.16.0
charset-normalizer       3.3.2
click                    8.1.7
contourpy                1.2.1
cryptography             42.0.5
cycler                   0.12.1
datasets                 2.18.0
datatrove                0.0.1
deepspeed                0.14.0
Deprecated               1.2.14
dill                     0.3.8
docker-pycreds           0.4.0
docstring_parser         0.16
einops                   0.7.0
evaluate                 0.4.1
filelock                 3.13.4
flash-attn               2.5.7
fonttools                4.51.0
frozenlist               1.4.1
fsspec                   2024.2.0
gitdb                    4.0.11
GitPython                3.1.43
grpcio                   1.62.1
hjson                    3.1.0
huggingface-hub          0.22.2
humanize                 4.9.0
idna                     3.7
Jinja2                   3.1.3
joblib                   1.4.0
kiwisolver               1.4.5
loguru                   0.7.2
Markdown                 3.6
markdown-it-py           3.0.0
MarkupSafe               2.1.5
matplotlib               3.8.4
mdurl                    0.1.2
mpmath                   1.3.0
multidict                6.0.5
multiprocess             0.70.16
networkx                 3.3
ninja                    1.11.1.1
nltk                     3.8.1
numpy                    1.26.4
nvidia-cublas-cu12       12.1.3.1
nvidia-cuda-cupti-cu12   12.1.105
nvidia-cuda-nvrtc-cu12   12.1.105
nvidia-cuda-runtime-cu12 12.1.105
nvidia-cudnn-cu12        8.9.2.26
nvidia-cufft-cu12        11.0.2.54
nvidia-curand-cu12       10.3.2.106
nvidia-cusolver-cu12     11.4.5.107
nvidia-cusparse-cu12     12.1.0.106
nvidia-nccl-cu12         2.18.1
nvidia-nvjitlink-cu12    12.4.127
nvidia-nvtx-cu12         12.1.105
opencv-python            4.9.0.80
packaging                24.0
pandas                   2.2.2
peft                     0.10.1.dev0
pillow                   10.3.0
pip                      23.3.1
protobuf                 3.20.3
psutil                   5.9.8
py-cpuinfo               9.0.0
pyarrow                  15.0.2
pyarrow-hotfix           0.6
pycparser                2.22
pydantic                 2.7.0
pydantic_core            2.18.1
PyGithub                 2.3.0
Pygments                 2.17.2
PyJWT                    2.8.0
PyNaCl                   1.5.0
pynvml                   11.5.0
pyparsing                3.1.2
python-dateutil          2.9.0.post0
pytz                     2024.1
PyYAML                   6.0.1
regex                    2023.12.25
requests                 2.31.0
responses                0.18.0
rich                     13.7.1
safetensors              0.4.2
scipy                    1.13.0
sentencepiece            0.2.0
sentry-sdk               1.45.0
setproctitle             1.3.3
setuptools               68.2.2
shtab                    1.7.1
six                      1.16.0
smmap                    5.0.1
sympy                    1.12
tensorboard              2.16.2
tensorboard-data-server  0.7.2
tiktoken                 0.6.0
tokenizers               0.15.2
torch                    2.1.1
torchaudio               2.1.1
torchvision              0.16.1
tqdm                     4.66.2
transformers             4.40.0.dev0
triton                   2.1.0
trl                      0.8.3.dev0
typing_extensions        4.11.0
tyro                     0.8.3
tzdata                   2024.1
unsloth                  2024.4
urllib3                  2.2.1
wandb                    0.16.6
Werkzeug                 3.0.2
wheel                    0.43.0
wrapt                    1.16.0
xformers                 0.0.23
xxhash                   3.4.1
yarl                     1.9.4

附件 2

import argparse

import torch
from peft import PeftModel, PeftConfig
from transformers import (
    AutoModel,
    AutoTokenizer,
    BloomForCausalLM,
    BloomTokenizerFast,
    AutoModelForCausalLM,
    LlamaTokenizer,
    LlamaForCausalLM,
    AutoModelForSequenceClassification,
)

MODEL_CLASSES = {
    "starcoder": (AutoModelForCausalLM, AutoTokenizer),
    "bloom": (BloomForCausalLM, BloomTokenizerFast),
    "chatglm": (AutoModel, AutoTokenizer),
    "llama": (LlamaForCausalLM, LlamaTokenizer),
    "baichuan": (AutoModelForCausalLM, AutoTokenizer),
    "auto": (AutoModelForCausalLM, AutoTokenizer),
}


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model_type', default=None, type=str, required=True)
    parser.add_argument('--base_model', default=None, required=True, type=str,
                        help="Base model name or path")
    parser.add_argument('--tokenizer_path', default=None, type=str,
                        help="Please specify tokenization path.")
    parser.add_argument('--lora_model', default=None, required=True, type=str,
                        help="Please specify LoRA model to be merged.")
    parser.add_argument('--resize_emb', action='store_true', help='Whether to resize model token embeddings')
    parser.add_argument('--output_dir', default='./merged', type=str)
    parser.add_argument('--hf_hub_model_id', default='', type=str)
    parser.add_argument('--hf_hub_token', default=None, type=str)
    args = parser.parse_args()
    # print(args)

    base_model_path = args.base_model
    lora_model_path = args.lora_model
    output_dir = args.output_dir
    print(f"Base model: {base_model_path}")
    print(f"LoRA model: {lora_model_path}")
    peft_config = PeftConfig.from_pretrained(lora_model_path)

    model_class, tokenizer_class = MODEL_CLASSES[args.model_type]
    if peft_config.task_type == "SEQ_CLS":
        print("Loading LoRA for sequence classification model")
        if args.model_type == "chatglm":
            raise ValueError("chatglm does not support sequence classification")
        base_model = AutoModelForSequenceClassification.from_pretrained(
            base_model_path,
            num_labels=1,
            load_in_8bit=False,
            torch_dtype=torch.float32,
            trust_remote_code=True,
            device_map="auto",
        )
    else:
        print("Loading LoRA for causal language model")
        base_model = model_class.from_pretrained(
            base_model_path,
            load_in_8bit=False,
            torch_dtype=torch.float16,
            trust_remote_code=True,
            device_map="auto",
        )
    if args.tokenizer_path:
        tokenizer = tokenizer_class.from_pretrained(args.tokenizer_path, trust_remote_code=True)
    else:
        tokenizer = tokenizer_class.from_pretrained(base_model_path, trust_remote_code=True)
    if args.resize_emb:
        base_model_token_size = base_model.get_input_embeddings().weight.size(0)
        if base_model_token_size != len(tokenizer):
            base_model.resize_token_embeddings(len(tokenizer))
            print(f"Resize vocabulary size {base_model_token_size} to {len(tokenizer)}")

    new_model = PeftModel.from_pretrained(
        base_model,
        lora_model_path,
        device_map="auto",
        torch_dtype=torch.float16,
    )
    new_model.eval()
    print(f"Merging with merge_and_unload...")
    base_model = new_model.merge_and_unload()

    print("Saving to Hugging Face format...")
    tokenizer.save_pretrained(output_dir)
    base_model.save_pretrained(output_dir, max_shard_size='10GB')
    print(f"Done! model saved to {output_dir}")
    if args.hf_hub_model_id:
        print(f"Pushing to Hugging Face Hub...")
        base_model.push_to_hub(
            args.hf_hub_model_id,
            token=args.hf_hub_token,
            max_shard_size="10GB",
        )
        tokenizer.push_to_hub(
            args.hf_hub_model_id,
            token=args.hf_hub_token,
        )
        print(f"Done! model pushed to Hugging Face Hub: {args.hf_hub_model_id}")


if __name__ == '__main__':
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值