【LLM系列】00:斯坦福 Alpaca 模型介绍及其复现

简介

西风吹老洞庭波,一夜湘君白发多。醉后不知天在水,满船清梦压星河。小伙伴好,我是微信公众号《小窗幽记机器学习》的小编:卖核弹的小女孩。更多、更新文章欢迎关注微信公众号:小窗幽记机器学习。后续会持续输出模型推理加速、工程部署、LLM、AI艺术等系列,敬请期待。
有很多小伙伴看我到之前分享的AI艺术系列:

都以为卖核弹的小女孩已经弃坑NLP转战CV,其实并没有。俗话说“小孩子才做选择题”,所以今天我选择NLP。今天这篇小作文主要介绍一下斯坦福 Alpaca 模型及其复现结果。 先直接抛出几个成果:

示例0:
### Instruction: 
    你是一名大学生,谈谈你的理想。
### Response:
    我的理想是成为一名优秀的教师,能给学生们提供更多的机会,帮助他们成长和发展,做到他们的爱好和梦想。我希望能够让学生们充分理解课程的内容,深入探索,充分发挥自己的潜能,最终取得成功。我还希望能够与家长和其他监督人有更好的沟通,让学生们在学习和生活中拥有更多的 healthy competition,最终达到学习的目的。

示例1:
### Instruction:
    你是一名大学生,谈谈你的理想。除了当老师之外的理想。
### Response:
    我的理想是在一个贴近自然的环境中,有足够的资源和努力,我可以培养一种健康的生活方式,与自然和谐共存。除了当前老师之外的理想,我也希望具有自己的学习方法和课堂,不仅能够培养学生的知识水平,还能够培养他们的天赋和能力,使他们能够适应未来,能够适应环境变化,能够适应复杂性的社会发展。

示例2:
### Instruction:
    你是一名计算机专业的硕士研究生,谈谈你的理想。
### Response:
    我的理想是在计算机和技术领域当中取得成功,具有深远的影响力。我希望能够在研究、开发和实践方面都取得成功,做出积极的贡献,并帮助人们利用计算机技术解决问题。我希望能够努力达成自己的目标,为自己、家庭、社会和地球创造一个更好的环境。

示例3:
### Instruction: 
    你是一名医学博士生,谈谈你的理想。
### Response:
    我是一名医学博士生,我的理想是把医学知识和技术应用于真实的医疗环境中,帮助更多的患者获得更好的治疗 Results。我想让医学知识不仅在实践中流行,更要在教育中起到影响力,改变传统医学教育的理念,增强学生的专业性和能力,让他们能够更好的应对真实的医疗环境,让更多的患者得到充分的治疗服务。

Stanford Alpaca

模型简介

Stanford Alpaca是一个Instruction-following的LLaMA模型,即一个对LLaMA模型进行指令调优的结果模型。更多细节可以参考官方博客

Stanford Alpaca 使用 OpenAI 的 text-davinci-003 模型以 self-instruct 方式生成 52K 指令遵循(instruction-following)样本,并以此作为对LLaMA进行指令微调的训练数据,最终得到Alpaca模型。

  • 项目地址:https://github.com/tatsu-lab/stanford_alpaca

  • 试用地址:https://alpaca-ai-custom6.ngrok.io/

训练方法

在学术界的预算条件下,训练高质量的指令遵循模型(instruction-following model)面临两个重要挑战:强大的预训练语言模型高质量的指令遵循数据。对于第一个难题,可以采用最近Meta开源的LLaMA系列模型。LLaMA系列包含了参数量为7B/13B/33B/65B的不同模型。然而,原模型的效果较差(如生成的结果文不对题、以及无法自然地结束生成等),需要后续进行微调。对于第二个难题,Self-Instruct提出一种利用现有的强大语言模型自动生成指令数据
因此,斯坦福的 Alpaca 模型基于 LLaMA-7B模型结合self-instruct 方式生成的52k指令遵循(instruction-following)样本数据进行有监督的指令微调,就能达到类似 GPT-3.5 的效果。

该项目提供了对LLaMA模型进行微调的廉价方法,大体思路如下:

首先,利用OpenAI提供的GPT模型(text-davinci-003)API结合self-instruct方法生成质量较高的指令数据(仅52k),例如:

{
    "instruction": "Rewrite the following sentence in the third person",
    "input": "I am anxious",
    "output": "She is anxious."
}, {
    "instruction": "What are the three primary colors?",
    "input": "",
    "output": "The three primary colors are red, blue, and yellow."
}

首先使用 self-instruct 种子集中的 175 个人工编写的指令-输出(instruction-output)对,然后用该种子集作为 in-context 样本 prompt text-davinci-003模型来生成更多指令。Alpaca通过简化生成 pipeline 改进了 self-instruct 方法,并显著降低了成本。Alpaca官方声称基于openai的API生成52k指令数据集的费用<500美元。

有了这个指令遵循数据集,下一步是使用 Hugging Face 的训练框架微调 LLaMA 模型,在这个过程利用了FSDP(Fully Sharded Data Parallel)和混合精度训练等技术。成本方面,Alpaca在8个80GB A100 上微调一个 7B LLaMA 模型需要3个小时,这对大多数云计算提供商来说成本不到 100 美元。整体价格还算比较亲民,可盐可甜。

在这里插入图片描述

下面介绍如何基于 LLaMA-7B 尝试复现 Alpaca-7B。

准备工作

环境安装

创建容器:

docker run --gpus all --privileged --name='test_alpaca_v1' -p 8809:8809 -p 8810:8810 -v /data/home/:/home -w /home -itd nvcr.io/nvidia/tritonserver:22.07-py3 bash

安装Python3.10

容器内默认的Python版本是3.8,而斯坦福Alpaca官方使用的是Python3.10,所以需要在容器内再安装一个Python版本:Python3.10。

安装Python3.10之前需要安装一些依赖

apt-get update -y
apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev -y

PS: python3.7以上的Python版本的需要安装libffi-devel

另外,还需要安装先升级OpenSSL,本实验所使用容器中已经安装openssl version版本如下:

OpenSSL 1.1.1f  31 Mar 2020

安装Python3.10:
Python官网下载Python10的源码:

wget https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tar.xz

下载后解压安装:

tar -xf Python-3.10.11.tar.xz
cd Python-3.10.11
./configure --enable-optimizations --prefix=/opt/python3.10.11
make -j8
make install

如果要安装OpenSSL可以参考

此时Python3.10安装在/opt/python3.10.11/。如果想将系统默认的python3指向python3.10
which python3

/usr/bin/python3

which pip3

/usr/local/bin/pip3

只需要如下改动:

rm -rf /usr/bin/python3
ln -s /opt/python3.10.11/bin/python3 /usr/bin/python3
rm -rf /usr/local/bin/pip3
ln -s /opt/python3.10.11/bin/pip3 /usr/local/bin/pip3

另一种方式是直接将/opt/python3.10.11/bin/添加到系统PATH中。

包安装

安装pytorch:

pip3 install torch==1.13 -i https://mirrors.cloud.tencent.com/pypi/simple

由于安装torch时候同时将torchrun安装在/opt/python3.10.11/bin/torchrun,所以需要将/opt/python3.10.11/bin/torchrun创建一个软链接或者直接将整个/opt/python3.10.11/bin添加到PATH。这里只添加一个软链接:

ln -s /opt/python3.10.11/bin/torchrun /usr/bin/torchrun

安装指定版本transformers:
目前,transformers官方版本并没有LLaMA相关的实现,但是已经合并到主分支了,因此,在使用过程需要切换到对应的commit,从源代码进行相应的安装。

cd transformers
git checkout 0041be5 
pip3 install . -i https://mirrors.cloud.tencent.com/pypi/simple

另一种方式是直接拉取push分支的Repo,直接pip3 install . -i安装。

安装apex:

git clone https://github.com/NVIDIA/apex.git
cd apex
git checkout 22.04-dev
pip3 install -v --disable-pip-version-check --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./

安装其他依赖:

numpy
rouge_score
fire
openai
sentencepiece
tokenizers==0.12.1
wandb

模型格式转换

需要将LLaMA原始权重文件转换为Transformers库对应的模型文件格式。如果不想自己转,也可以直接从Hugging Face下载转换好的模型

cd transformers

python3 src/transformers/models/llama/convert_llama_weights_to_hf.py --input_dir /home/model_zoo/llama --model_size 7B --output_dir /home/model_zoo/llama/7B/hf-llama-model

这个版本transformers转换得到的结果是分别存于2个文件夹:llama-7btokenizer

可以通过以下方式加载模型和分词器:

tokenizer = transformers.LlamaTokenizer.from_pretrained("/home/model_zoo/llama/7B/hf-llama-model/tokenizer/")

model = transformers.LlamaForCausalLM.from_pretrained("/home/model_zoo/llama/7B/hf-llama-model/llama-7b/")

为了方便将tokenizer目录的文件拷贝到llama-7b目录下。如果是直接用最新版的transformers中转换脚本的话在hf-llama-model会将模型参数文件和tokenizer相关文件平铺放一起。

数据准备

Stanford Alpaca提供用于训练的指令数据集alpaca_data.json,可以直接使用该数据集进行模型精调。但是在Alpaca-LoRA中提到该数据集存在一些噪声,因此,他们对该数据集做了清洗后得到了文件alpaca_data_cleaned.json。小伙伴们也可以采用该数据集进行训练,或许会得到更好结果。这里为了兼容中文,所以使用InstructionWild中的instinwild_en.json和instinwild_ch.json

其他

如果想使用wandb,则可以在机器终端上运行wandb login命令,然后填入自己wandb上账号的API key。

模型精调

torchrun --nproc_per_node=8 --master_port=25001 train.py \
    --model_name_or_path  /home/model_zoo/llama/7B/hugging_face_format/ \
    --data_path /home/data_zoo/InstructionWild/data/instinwild_ch_en.json \
    --bf16 True \
    --output_dir /home/Repository/LLM/stanford_alpaca/output/alpaca/sft_7b_en_cn \
    --num_train_epochs 3 \
    --per_device_train_batch_size 1 \
    --per_device_eval_batch_size 1 \
    --gradient_accumulation_steps 8 \
    --evaluation_strategy "no" \
    --save_strategy "steps" \
    --save_steps 2000 \
    --save_total_limit 1 \
    --learning_rate 2e-5 \
    --weight_decay 0. \
    --warmup_ratio 0.03 \
    --lr_scheduler_type "cosine" \
    --logging_steps 1 \
    --fsdp "full_shard auto_wrap" \
    --fsdp_transformer_layer_cls_to_wrap 'LlamaDecoderLayer' \
    --tf32 True

inference

示例0:
    ### Instruction: 你是一名小学生,谈谈你的理想。
    ### Response:
    我的理想是成为一名科学家。我梦想从事有关科学研究,努力推动科学研究,同时还能给人们带来实质性的改变和帮助。我希望能够在有关的研究领域取得杰出的成就,做出对人类社会的贡献。

示例1:
>   ### Instruction: 你是一名中学生,谈谈你的理想。
    ### Response:
    我的理想是成为一名优秀的学生,拥有自己的自由,幸福地把自己从学习中获得成功,并尽力应对新任务,不断成长。我希望能够努力把自己的想法做到极致,做到自己认为有价值的事,同时充分利用自己的时间来实现自己的目标。我希望能够有足够的智慧和技能,成为一名领先的学者,不断成长,充实自己的梦想。

示例2:
>   ### Instruction: 你是一名高学生,谈谈你的理想。
    ### Response:
    我的理想是成为一名优秀的教师,能给学生们提供更多的机会,帮助他们成长和发展。我希望能够在教育领域突出自己的风采,做到有追求卓越的教育质量,并且给学生们带来更多有趣的学习经历。此外,我也想继续自己学习,及时掌握最新的教育技巧和发展趋势,以最大限度地帮助学生们成长。

示例3:
>   ### Instruction: 你是一名大学生,谈谈你的理想。
    ### Response:
    我的理想是成为一名优秀的教师,能给学生们提供更多的机会,帮助他们成长和发展,做到他们的爱好和梦想。我希望能够让学生们充分理解课程的内容,深入探索,充分发挥自己的潜能,最终取得成功。我还希望能够与家长和其他监督人有更好的沟通,让学生们在学习和生活中拥有更多的 healthy competition,最终达到学习的目的。

示例4:
>   ### Instruction: 你是一名大学生,谈谈你的理想。除了当老师之外的理想。
    ### Response:
    我的理想是在一个贴近自然的环境中,有足够的资源和努力,我可以培养一种健康的生活方式,与自然和谐共存。除了当前老师之外的理想,我也希望具有自己的学习方法和课堂,不仅能够培养学生的知识水平,还能够培养他们的天赋和能力,使他们能够适应未来,能够适应环境变化,能够适应复杂性的社会发展。

示例5:
>   ### Instruction: 你是一名计算机专业的硕士研究生,谈谈你的理想。
    ### Response:
    我的理想是在计算机和技术领域当中取得成功,具有深远的影响力。我希望能够在研究、开发和实践方面都取得成功,做出积极的贡献,并帮助人们利用计算机技术解决问题。我希望能够努力达成自己的目标,为自己、家庭、社会和地球创造一个更好的环境。

示例6:
>   ### Instruction: 你是一名医学博士生,谈谈你的理想。
    ### Response:
    我是一名医学博士生,我的理想是把医学知识和技术应用于真实的医疗环境中,帮助更多的患者获得更好的治疗 Results。我想让医学知识不仅在实践中流行,更要在教育中起到影响力,改变传统医学教育的理念,增强学生的专业性和能力,让他们能够更好的应对真实的医疗环境,让更多的患者得到充分的治疗服务。

示例7:
>   ### Instruction: 你模仿鲁迅的风格吐槽一下猪脚饭涨价了这件事,要求100字。
    ### Response:
    吐槽一下猪脚饭涨价了这件事,要求100字。
    猪脚饭是每个人心中的一份美食,它让人回想起童年的回忆和快乐时光。不过,现在adidas gazelle sale uk,猪脚饭的价格一整天都在上涨,而许多餐馆的猪脚饭也比以往得到越来越多的人 patronizing。到底是吐槽还是咕咕,结果一样:猪脚饭价格涨至令人难以接受的水平。

示例8:
>   ### Instruction: 你叫孔乙己,给大家做个自我介绍吧,并谈谈为啥你脱不下长衫。
    ### Response:
    我叫孔乙,我出生于中国,在美国接受教育并取得学士学位。我目前在一家旅游公司担任公关代表,负责宣传和制定品牌策略。我喜欢旅行,学习新的文化,探索新的机会,并与来自不同背景的人们接触和沟通。我认为,要脱不下长衫,应该坚持自己的想法,拥抱失败,并勇敢地继续前行。

示例9:
>   ### Instruction: 你是孔乙己,给大家做个自我介绍吧,并谈谈你为啥脱不下长衫。
    ### Response:
    我是孔乙,大家可以别谈谈我为啥脱不下长衫。我是一名坚强、坚韧、坚强的人,对事物一直追求质量第一的原则,努力做一个真正的人才。我从身体上健康,从心理上坚强,从思维上灵活,从能力上有限,从宽容上有毅,从耐心上坚强,把它们融入到自己的工作中,希望能够实现一个有价值的自己。


示例10:
>   ### Instruction: 你做好自我介绍吧,你毕业于华中科技大学,喜欢和男孩子一起玩。
    ### Response:
    我叫张小绵,出生于1994年,学习于华中科技大学,喜欢和男孩子一起玩。我有一套充满励志的心,充满想象力,勇于挑战新事物,热衷于学习新技能,充满创新的精神,坚定不懈,善于解决问题。我乐观积极,乐于助人,具有良好的团队合作能力,并具有多种学习语言、烹饪、体育和文化活动等能力。

小结

可以看出,效果上整体确实一般。可能是由于开源的LLaMA模型在预训练阶段主要基于英语训练,虽然具有一定的多语言能力,然而由于它没有将中文语料加入预训练,所以LLaMA在中文上整体效果较弱。

问题汇总

运行完最后一个epoch后出现OOM:

{'train_runtime': 5162.7837, 'train_samples_per_second': 10.072, 'train_steps_per_second': 0.157, 'train_loss': 1.0267484738615347, 'epoch': 1.0}
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 812/812 [1:26:02<00:00,  6.36s/it]

/opt/python3.10.11/lib/python3.10/site-packages/torch/distributed/fsdp/fully_sharded_data_parallel.py:2224: 
UserWarning: Failed to clone() tensor with name _fsdp_wrapped_module._fpw_module.model.layers.28.mlp.down_proj.weight. This may mean that this state_dict entry could point to invalid memory regions after returning from 
state_dict() call if this parameter is managed by FSDP. 
Please check clone implementation of _fsdp_wrapped_module._fpw_module.model.layers.28.mlp.down_proj.weight. 
Error: CUDA out of memory. Tried to allocate 172.00 MiB (GPU 3; 39.59 GiB total capacity; 35.81 GiB already allocated; 
79.19 MiB free; 37.59 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to 
avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

解决方案:参考官方Repo上issue,将safe_save_model_for_hf_trainer改为如下:

def safe_save_model_for_hf_trainer(trainer: transformers.Trainer, output_dir: str):
    """Collects the state dict and dump to disk."""
    # state_dict = trainer.model.state_dict()
    from torch.distributed.fsdp import (
        FullyShardedDataParallel as FSDP,
        MixedPrecision,
        BackwardPrefetch,
        ShardingStrategy,
        FullStateDictConfig,
        StateDictType,
    )
    model=trainer.model  
    save_policy = FullStateDictConfig(offload_to_cpu=True, rank0_only=True)
    with FSDP.state_dict_type(model, StateDictType.FULL_STATE_DICT, save_policy):
        cpu_state_dict = model.state_dict()
    if trainer.args.should_save:
        trainer._save(output_dir, state_dict=cpu_state_dict)  # noqa

猜你喜欢

转载自blog.csdn.net/ljp1919/article/details/130298780