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

这篇具有很好参考价值的文章主要介绍了【LLM系列】00:斯坦福 Alpaca 模型介绍及其复现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

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

  • 05: 生成线稿画
  • 04: 文心一言 vs ChatGPT
  • 03: 生成可控图鉴赏
  • 02:亚洲美女图鉴赏析
  • 01: 生成宫崎骏风格图片
  • 00: 梵高风格作品欣赏

都以为卖核弹的小女孩已经弃坑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 美元。整体价格还算比较亲民,可盐可甜。

【LLM系列】00:斯坦福 Alpaca 模型介绍及其复现,NLP,深度学习,LLM,人工智能,LLM,NLP,AI

下面介绍如何基于 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改为如下:文章来源地址https://www.toymoban.com/news/detail-539696.html

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

到了这里,关于【LLM系列】00:斯坦福 Alpaca 模型介绍及其复现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 斯坦福2023【FrugalGPT】减少大模型的商业化应用成本

    FrugalGPT: How to Use Large Language Models While Reducing Cost and Improving Performance 这篇文章主要是要解决如何降低调用大语言模型的成本(ChatGPT)。大模型API调用成本主要是三方面的:1. prompt cost(输入的prompt);2. generation cost(输出的部分);3. 每次调用的固定开销(网费等)。不用的模型之前的

    2024年02月06日
    浏览(56)
  • 【斯坦福】FrugalGPT: 如何使用大型语言模型,同时降低成本并提高性能

    FrugalGPT: 如何使用大型语言模型,同时降低成本并提高性能 作者:Lingjiao Chen, Matei Zaharia, James Zou 本文介绍了一种新颖的方法,旨在解决使用大型语言模型(LLM)时面临的成本和性能挑战。随着GPT-4和ChatGPT等LLM的日益流行,我们需要找到降低这些模型推理成本的策略。作者强调

    2024年02月11日
    浏览(45)
  • 斯坦福发布 最新 GPT 模型排行榜 AlpacaEval【AI工具免费使用】

    官网地址:https://www.tomchat.fun 🤖 支持gpt4 / gpt-3.5 / claude /code-llm 🎨 支持 AI绘画 🆓 每天十次免费使用机会 🪄 无需魔法 GPT-4 登顶商用模型 微软 WizardLM 登顶开源模型 AlpacaEva 是来自斯坦福的团队发布的一款 大语言模型 自动评测系统, 它是一种基于 LLM 的全自动评估基准,且

    2024年02月02日
    浏览(57)
  • 大模型也内卷,Vicuna训练及推理指南,效果碾压斯坦福羊驼

    2023开年以来,大模型进入疯狂内卷状态,大模型的发布都要以“天”为单位进行迭代。 之前,尝试了 从0到1复现斯坦福羊驼(Stanford Alpaca 7B) ,下面我们来尝试从0到1复现Vicuna训练及推理。 继斯坦福羊驼(Stanford Alpaca)之后,UC伯克利、CMU、斯坦福等机构的学者,联手发布

    2024年02月08日
    浏览(44)
  • 果然来了!GPT-4.5贵有贵的道理?微软Phi-2精准超越谷歌;LLM怪诞心理学;斯坦福创业课精华笔记;新手LLM训练系统指南 |ShowMeAI日报

    👀 日报周刊合集 | 🎡 生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! https://www.reddit.com/r/OpenAI/comments/18i5n29/anyone_hear_of_gpt45_drop_today 12月14日,美国 Reddit 论坛用户贴出了一张截图,显示的是 OpenAI GPT-4.5 定价信息,疑似遭到了提前「泄露」。 从这张截图看, GPT-4.5 具

    2024年02月03日
    浏览(60)
  • AI大模型额外学习一:斯坦福AI西部世界小镇笔记(包括部署和源码分析)

    github链接 ①背景介绍 This repository accompanies our research paper titled “Generative Agents: Interactive Simulacra of Human Behavior.” It contains our core simulation module for generative agents—computational agents that simulate believable human behaviors—and their game environment. ②总体逻辑 让小镇的NPC自由交流、开party、生

    2024年04月28日
    浏览(35)
  • 大幅超越DALL·E 2和Imagen,斯坦福发布RA-CM3模型,融合检索与生成

    文|QvQ 最近,DALL-E和CM3等模型在多模态任务尤其是图文理解上表现出色。然而,这些模型似乎需要将所有学到的知识存储都存储在模型参数中,这就不得不需要越来越大的模型和训练数据来获取更多的知识,俨然将 bigger and better 绑定在了一起。 那既然如此,哪还需要算法工

    2024年02月09日
    浏览(48)
  • 大模型机器人发展史:从VoxPoser、RT2到斯坦福Mobile ALOHA、Google机器人

    23年7月,我在朋友圈评估Google的RT2说道: “大模型正在革新一切领域啊,超帅,通过大模型不仅能理解“人话”,还能对“人话”进行推理,并转变为机器人能理解的指令,从而分阶段完成任务。回头仔细看下论文” 当时便对大模型机器人印象深刻,一直想仔细研究下来着

    2024年02月02日
    浏览(45)
  • 斯坦福联合Meta提出多模态模型RA-CM3,检索增强机制或成文本图像领域新制胜法宝

    原文链接:https://www.techbeat.net/article-info?id=4403 作者:seven_ 论文链接: https://arxiv.org/abs/2211.12561 相信目前很多AI大模型研究者都会遇到一个非常困难的问题,那就是 很难控制的模型参数和容量 ,由于参与模型训练的数据量非常庞大,如果模型参数太少会导致过拟合,参数量过

    2024年02月09日
    浏览(41)
  • 斯坦福人生设计课——简略笔记

    来源: ⽐尔 · 博内特 戴夫 · 伊万斯 著图书《人生设计课》 目录 一、认清当下的情况,从四个维度观察自己的人生 二、平衡人生,但不要走入误区 2.1 记录你的“美好时光日志”: 2.1.1 记录内容: 2.1.2 辅助反思的方法:AEIOU方法 2.1.3 一个小TIPS: 2.1.4 如果你发现自己当下

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包