使用 Docker 和 Alpaca LoRA 对 LLaMA 65B 大模型进行 Fine-Tune

2023-11-19

这篇文章中,我们来聊聊如何使用两张显卡来进行 LLaMA 65B 大模型的微调工作,以及如何在一张普通的 4090 家用显卡上,只花几个小时,就能够完成 7B 模型的微调。

写在前面

在之前的几篇文章里,我们介绍过三种方式运行 Meta 开源模型 LLaMA 的 7B、13B 版本:

不过,在之前的尝试中我们不难发现,如果没有我们“限定的数据”,模型效果其实不是特别好,尤其是相对小参数量的 7B 模型。同时,这也让我们对 65B 的模型更加充满了兴趣。

当然,想要在极少量资源的显卡上完成模型能力的“完善”(训练、微调),在之前是具有非常大的难度的。不过,随着几个项目的诞生,这件事变的容易了许多:

首先,两个星期前来自斯坦福几位聪明的同学,带来了他们的“斯坦福羊驼”项目:tatsu-lab/stanford_alpaca,通过使用 OpenAI 的 API,从 ChatGPT 获取了5万2千条数据,然后借助了一台搭载 4 颗 80G 显存的 A100 GPU 服务器完成了 7B 的 LLaMA 模型的微调,带来了令人惊艳的效果,达到类似 text-davinci-003 的评估结果,验证了:小样本情况下,单机服务器是能够完成语言大模型的微调的,并且能够取得不错的效果,极大的振奋了社区

接着,社区中站出来了另外一位同学 tloen,使用 LoRA(Low-Rank)的方式,完成了一件更加令人振奋的事情:将斯坦福同学微调模型使用的算力,从 4 张 80G 显存的 A100 降低到了一块 4090 显卡,并且能够在 5 个小时内完成微调工作。甚至能够将大模型运行在一块树莓派上!

当然,这件事能够成立,除了脑洞大开勇于尝试的 tloen 同学,Hugging Face 社区开源的 PEFT 项目,和 TimDettmers/bitsandbytes CUDA 8-bit 模型量化项目也功不可没。当然,社区项目目前也还存在一些问题,比如不支持多卡运行,不支持比较新的 CUDA 环境运行等等。

好了,到这里为止,你已经了解了到底是哪些“开源社区的功臣”为我们带来的福利。

现在,让我们开始从 7B 模型微调工作搞起,在掌握 7B 之后,我们就能够驾轻就熟的折腾最大号的 65B 模型啦。

为了方便使用和验证效果,我本文中使用的方案也更新到了之前提到的 “LLaMA 游乐场”开源项目中。项目地址:soulteary/llama-docker-playground

多种方式愉快玩耍 LLaMA 大模型

关于模型文件的下载、完整性校验等问题,在第一篇文章中提到过就不再赘述了。此外,关于之前提到的官方推理方案和社区提供的 Pyllama 推理方案的使用方式也不再展开,感兴趣可以自行翻阅之前的另一篇文章

使用 LLaMA Docker 游乐场项目

仍然是随便找一个合适的目录,使用 git clone 或者下载 Zip 压缩包的方式,先把“LLaMA 游乐场”项目的代码下载到本地。

git clone https://github.com/soulteary/llama-docker-playground.git

# or

curl -sL -o llama.zip https://github.com/soulteary/llama-docker-playground/archive/refs/heads/main.zip

接着,进入项目目录,使用 Nvidia 原厂的 PyTorch Docker 基础镜像来完成基础环境的构建,相比于我们直接从 DockerHub 拉制作好的镜像,自行构建将能节约大量时间。

我们在项目目录中执行下面的命令,就能够构建出能够用于大模型 fine-tune 的 Docker 环境啦:

docker build -t soulteary/llama:alpaca-lora-finetune . -f docker/Dockerfile.lora-finetune

稍等片刻,镜像构建完毕之后,就能够开始玩了。

对 LLaMA 7B 大模型进行 fine-tune

想要对 LLaMA 进行单卡的模型微调,一共分为四步。

准备模型文件

为了方便 fine-tune,确认你的模型目录和下面保持一致:

├── 7B
│   ├── checklist.chk
│   ├── consolidated.00.pth
│   └── params.json
├── tokenizer.model
└── tokenizer_checklist.chk

准备容器环境

在上篇文章《基于 Docker 的深度学习环境:入门篇》中,我们提到过如何配置 Docker 来和显卡交互,这里就不过多赘述了。你可以执行简单的一条命令,来创建一个“干净又卫生”的用于大模型微调的容器环境:

docker run --gpus all --ipc=host --ulimit memlock=-1 --ulimit stack=67108864 \
    --rm -it \
    -v /home/soulteary/project/llama-docker-playground/models:/app/alpaca-lora/original-weights \
    -v `pwd`/weights:/app/alpaca-lora/weights \
    soulteary/llama:alpaca-lora-finetune bash

在上面的命令中,我们将原始模型文件挂载到了容器的 /app/alpaca-lora/original-weights 目录,一会使用。并将项目当前目录的 weights 文件夹挂载到了容器中的 /app/alpaca-lora/weights,用于保存后续要使用的 HF 模型格式。

转换模型格式

接着,在容器中执行下面的命令,就能够将 Meta 7B 的 LLaMA 模型,转换为我们需要的格式了:

python -m transformers.models.llama.convert_llama_weights_to_hf \
  --input_dir original-weights \
  --model_size 7B \
  --output_dir weights

转换时间不会很长(我这里是 6 秒钟),稍等片刻即可:

# python -m transformers.models.llama.convert_llama_weights_to_hf \
# >   --input_dir original-weights \
# >   --model_size 7B \
# >   --output_dir weights

Fetching all parameters from the checkpoint at original-weights/7B.
Loading the checkpoint in a Llama model.
Loading checkpoint shards: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 33/33 [00:06<00:00,  5.40it/s]
Saving in the Transformers format.
Fetching the tokenizer from original-weights/tokenizer.model.

然后查看 weights 目录,能够看到新的模型文件已经就绪:

# du -hs weights/*

4.0K	weights/config.json
4.0K	weights/generation_config.json
9.3G	weights/pytorch_model-00001-of-00002.bin
3.3G	weights/pytorch_model-00002-of-00002.bin
28K	weights/pytorch_model.bin.index.json
4.0K	weights/special_tokens_map.json
492K	weights/tokenizer.model
4.0K	weights/tokenizer_config.json

运行模型微调程序

然后,执行用于模型微调的 finetune.py 程序即可:

python finetune.py

命令执行成功后,你将会看到类似下面的日志输出:

# python finetune.py

===================================BUG REPORT===================================
Welcome to bitsandbytes. For bug reports, please submit your error trace to: https://github.com/TimDettmers/bitsandbytes/issues
================================================================================
CUDA_SETUP: WARNING! libcudart.so not found in any environmental path. Searching /usr/local/cuda/lib64...
CUDA SETUP: CUDA runtime path found: /usr/local/cuda/lib64/libcudart.so
CUDA SETUP: Highest compute capability among GPUs detected: 8.9
CUDA SETUP: Detected CUDA version 118
CUDA SETUP: Loading binary /usr/local/lib/python3.8/dist-packages/bitsandbytes/libbitsandbytes_cuda118.so...
Overriding torch_dtype=None with `torch_dtype=torch.float16` due to requirements of `bitsandbytes` to enable model loading in mixed int8. Either pass torch_dtype=torch.float16 or don't pass this argument at all to remove this warning.
Loading checkpoint shards: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:06<00:00,  3.03s/it]
Downloading and preparing dataset json/default to /root/.cache/huggingface/datasets/json/default-8d30498d25a7aa2b/0.0.0/0f7e3662623656454fcd2b650f34e886a7db4b9104504885bd462096cc7a9f51...
Downloading data files: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 15709.00it/s]
Extracting data files: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2291.97it/s]
Dataset json downloaded and prepared to /root/.cache/huggingface/datasets/json/default-8d30498d25a7aa2b/0.0.0/0f7e3662623656454fcd2b650f34e886a7db4b9104504885bd462096cc7a9f51. Subsequent calls will reuse this data.
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 101.94it/s]

这将是一个漫长的过程,大概是三部“柯南”的片长,耐心等待就是啦~

模型微调过程中,我们使用 nvidia-smi 检查显卡状态,可以看到显存其实只使用了 8G 出头。

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.85.05    Driver Version: 525.85.05    CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| 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  NVIDIA GeForce ...  Off  | 00000000:01:00.0 Off |                  Off |
| 31%   53C    P2   336W / 450W |   8563MiB / 24564MiB |     90%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A      1290      G   /usr/lib/xorg/Xorg                  9MiB |
|    0   N/A  N/A      1510      G   /usr/bin/gnome-shell               10MiB |
|    0   N/A  N/A     24135      C   python                           8538MiB |
+-----------------------------------------------------------------------------+

好啦,最基础的 fine-tune 我们就掌握完毕了,下面来看看如何使用多张显卡进行 大模型的 fine-tune,以及对 65B 的 LLaMA 大模型进行微调。

对 LLaMA 65B 大模型进行 fine-tune

想要 fine-tune 65B 的模型,一样需要四个步骤。

准备模型文件

如果你依旧希望训练的是 7B 的模型,但是想通过多张卡来提升效率,使用前文中的模型目录即可。如果你希望训练的是最大号的 65B 模型,因为模型相比 7B 版本要大的多,此时我们有两个选择:

  1. 自行下载和转换 65B 模型文件格式。
  2. 直接下载社区中已经转换好格式的模型,比如:decapoda-research/llama-65b-hf

如果你选择和上文一样,可以将下载好的原版模型文件放置在合适的位置。

# ls llama/*

llama/download.sh  llama/tokenizer.model  llama/tokenizer_checklist.chk

llama/65B:
checklist.chk  consolidated.00.pth  consolidated.01.pth  consolidated.02.pth  consolidated.03.pth  consolidated.04.pth	consolidated.05.pth  consolidated.06.pth  consolidated.07.pth  params.json

如果你选择从 HF 社区里直接下载已经转换好格式的模型,可以使用下面的方法:先访问 git-lfs 项目,根据你的操作系统完成工具的安装;然后使用 git 命令完成模型文件的下载:

git clone https://huggingface.co/decapoda-research/llama-65b-hf

准备容器环境

如果我们想要使用多张显卡,我们需要执行下面的命令,构建一个新的容器环境:

docker build -t soulteary/llama:alpaca-lora-65b-finetune . -f docker/Dockerfile.lora-65b-finetune

接着,我们执行下面的命令,就能够进入启用多卡微调训练的环境容器啦:

docker run --gpus all --ipc=host --ulimit memlock=-1 --ulimit stack=67108864 \
    --rm -it \
    -v /home/soulteary/project/llama-docker-playground/models:/app/alpaca-lora/original-weights \
    -v `pwd`/weights:/app/alpaca-lora/weights \
    soulteary/llama:alpaca-lora-65b-finetune bash

转换模型格式

如果你是选择从 HF 社区下载模型,那么可以跳过阅读本小节。

如果你选择自行转换模型,在进入容器之后,我们执行下面的命令,就能够进行模型的转换了:

python -m transformers.models.llama.convert_llama_weights_to_hf \
   --input_dir original-weights \
   --model_size 65B \
   --output_dir weights

因为模型尺寸巨大,所以转换格式时间非常久,我这里接近 1 个小时,才完成了转换:

# python -m transformers.models.llama.convert_llama_weights_to_hf \
#>   --input_dir original-weights \
#>   --model_size 65B \
#>   --output_dir weights

Fetching all parameters from the checkpoint at original-weights/65B.
Loading the checkpoint in a Llama model.
Loading checkpoint shards: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 81/81 [00:57<00:00,  1.40it/s]
Saving in the Transformers format.
Fetching the tokenizer from original-weights/tokenizer.model.

检查目录,能够看到我们得到了 14 个几乎大小一致的模型文件:

du -hs weights/
123G	weights/

du -hs weights/*
48K	weights/config.json
48K	weights/generation_config.json
11G	weights/pytorch_model-00001-of-00014.bin
11G	weights/pytorch_model-00002-of-00014.bin
11G	weights/pytorch_model-00003-of-00014.bin
11G	weights/pytorch_model-00004-of-00014.bin
11G	weights/pytorch_model-00005-of-00014.bin
11G	weights/pytorch_model-00006-of-00014.bin
11G	weights/pytorch_model-00007-of-00014.bin
11G	weights/pytorch_model-00008-of-00014.bin
11G	weights/pytorch_model-00009-of-00014.bin
11G	weights/pytorch_model-00010-of-00014.bin
11G	weights/pytorch_model-00011-of-00014.bin
11G	weights/pytorch_model-00012-of-00014.bin

运行模型微调程序

和上文一样,如果你是 A100 用户,并且有至少两张卡,那么可以直接运行下面的程序,开启你的 65B 模型微调之旅:

python finetune.py

默认参数的执行时间需要 44 小时,但如果我们将 MICRO_BATCH_SIZE 提升一倍,改为 8,那么所需要的时间就能够缩减到 33 个小时啦,不过参数这个东西嘛,需要实际测试验证,根据自己的情况来。

# 调整参数
[01:42<33:11:29, 102.22s/it]
# 默认参数
[04:33<44:16:54, 136.49s/it]

好啦,到这里为止,我们就聊完了如何轻松愉快的使用极地的成本 fine-tune 7B 和 65B 的大模型,以及选择性的使用单张显卡或者多张显卡。

其他

接下来,我将聊聊这次旅途中的一些细节。

Nvidia 基础镜像的选择

在本文中,我们没有和上一篇文章《基于 Docker 的深度学习环境:入门篇》一样,选择使用最新的 CUDA & PyTorch 镜像,而是选择使用了 FROM nvcr.io/nvidia/pytorch:22.12-py3,完整 Dockerfile 如下:

FROM nvcr.io/nvidia/pytorch:22.12-py3

RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

WORKDIR /app

RUN git clone https://github.com/tloen/alpaca-lora.git

WORKDIR /app/alpaca-lora

RUN pip install datasets loralib sentencepiece git+https://github.com/huggingface/transformers.git bitsandbytes git+https://github.com/huggingface/peft.git

之所以这样选择,是因为项目中的核心依赖 bitsandbytes,目前对于 CUDA 12 不能够正确的识别,会导致程序无法启动,虽然可以通过给它打临时补丁将程序跑起来,但是我看到项目最近还有更新,社区里相关的反馈其实不少。或许用被长期使用验证过的环境更靠谱一些。

Nvidia 社区的 PyTorch 镜像发布记录中,我们能够找到满足软件正常运行情况下,最新的镜像版本就是它啦,包含 CUDA(11.8.0)和 PyTorch(1.14.0a0+410ce96)以及 TensorRT(8.5.1)。

为什么原版的 Alpaca LoRA 不能多卡运行

这其实应该算是 transformers 组件的问题,这个问题的最早的发现者是一位社区的同学 kooshi,除了通过激活 model.parallel 参数来启用并行化之外,他还发现了 HF 社区的 transformers 在运行 LoRA 的时候,并不会使用所有显卡的问题。目前,他已经针对性的提交了第一个补丁,以及在尝试彻底解决 LoRA 多卡运行的问题

如果你有八张卡,只想使用其中的某两张

这里有一个有趣的问题,主要的原因也是因为 transformers,如果你有多张卡,当你指定 device_map 的时候,如果它不为 auto,但是你的可用的显卡又不是从序号 0 开始的,那么将会出现各种错误。

比较简单的,不需要修改代码的解决方案是,使用 docker --gpus 参数,来屏蔽掉不需要展示给应用的显卡资源,比如我需要跳过前四张卡:

docker run -it --rm --gpus '"device=4,5,6,7"' ubuntu nvidia-smi

那么,当你执行命令之后,你会发现之前被占用的卡就“消失”了,程序会将你指定的卡重新编号为 “cuda0~cuda3”,一切问题迎刃而解。

最后

关于使用低成本的显卡资源来 fine-tune 模型,我们就聊到这里。

下一篇相关的文章里,我们聊聊其他几种不同的模型运行方式,以及找机会聊聊其他的模型。当然,如果模型 fine-tune 一切顺利,我将持续更新“贾维斯”的养成笔记。

–EOF


我们有一个小小的折腾群,里面聚集了一些喜欢折腾的小伙伴。

在不发广告的情况下,我们在里面会一起聊聊软硬件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术资料。

喜欢折腾的小伙伴,欢迎阅读下面的内容,扫码添加好友。

关于“交友”的一些建议和看法

添加好友时,请备注实名和公司或学校、注明来源和目的,否则不会通过审核。

关于折腾群入群的那些事


本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2023年03月25日
统计字数: 12339字
阅读时间: 25分钟阅读
本文链接: https://soulteary.com/2023/03/25/model-finetuning-on-llama-65b-large-model-using-docker-and-alpaca-lora.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Docker 和 Alpaca LoRA 对 LLaMA 65B 大模型进行 Fine-Tune 的相关文章

随机推荐

  • 常用的偏微分方程

    偏微分方程通常包含两个以上的自变量 若自变量同时间相关 或者无关 称其为发展型 或者稳态 的 下面 我们罗列出一些典型的偏微分方程 如 热传导方程 一阶双曲守恒律方程 二阶波动方程 椭圆型偏微分方程等 抛物型偏微分方程通常刻画 个物理系统的
  • 前端学科面试题大全

    作用域和值类型引用类型的传递 变量作用域 作用域变量访问区域 变量值存在栈中 变量赋值相当于值赋值 值传递与引用传递有哪些区别 函数内部 变量会先声明 形式参数变量声明提升 整个函数体有var声明的变量 如果没有访问全局定义的num2 函数
  • 服务器环境初始化配置

    工程实践经验积累 服务器环境初始化配置 1 新建环境 新建环境 是为了使自己的程序在一个相对独立的环境中运行 不影响服务器上其他用户 并不受其他用户影响 新建环境的语句为 conda create n your env name pytho
  • 【Unity Shader】屏幕后处理1.0:调整亮度/饱和度/对比度

    1 Unity中实现屏幕特效的基本步骤 什么叫屏幕后处理 Screen post processing effects 渲染完整个场景得到屏幕图像后对图像进行一系列操作 实现各种屏幕特效 这一步我们可以添加很多例如景深 Depth of F
  • session销毁

    session invalidate session invalidate的销毁是把这个session所带的用户彻底的销毁 这个session跟用户已经紧密联合在一起 所以就一起销毁了 这样就算换了个session 也是登陆不了的 以前我的
  • 设计模式之享元模式

    享元模式 就是共享技术 对于系统中存在大量相同的对象 把他们抽取成一个对象放在缓存中进行使用 这样可以大大节省系统资源 例如 围棋棋盘上有两种棋子 一个是黑子 一个是白子 如果在下棋的时候每下一个棋子就要new一个棋子对象 那么就会有大量的
  • C#比较两个list集合,两集合同时存在或A集合存在B集合中无

    using System using System Collections Generic using System Linq using System Text using System Threading using System Th
  • iOS灵动岛【电商秒杀】开发实践

    一 基本概述 名词基础知识 苹果在 iPhone 14 Pro 系列中增加一个灵动岛 主要目的是隐藏挖孔造型的高端 感叹号屏 通过动画的视觉差异 用户找不到原来的挖孔屏 灵动岛是一种巧妙的设计 模糊了软件和硬件之间的界限 它可以在锁屏的情况
  • Python: 转换文本编码

    最近在做周报的时候 需要把csv文本中的数据提取出来制作表格后生产图表 在获取csv文本内容的时候 基本上都是用with open filename encoding UTF 8 as f 来打开csv文本 但是实际使用过程中发现有些csv
  • python网络爬虫实战——实时抓取西刺免费代理ip

    参考网上高手示例程序 利用了多线程技术 Python版本为2 7 coding utf8 import urllib2 import re import threading import time rawProxyList checkedP
  • Git切换分支报错:error: you need to resolve your current index first 以及needs merge

    当想从子分支切换到dev分支时git checkout dev 报错 error you need to resolve your current index first xxx java needs merge xxx xml needs
  • c#:ThreadPool实现并行分析,并实现线程同步结束

    背景 一般情况下 经常会遇到一个单线程程序时执行对CPU MEMORY IO利用率上不来 且速度慢下问题 那么 怎么解决这些问题呢 据我个人经验来说有以下两种方式 1 并行 多线程 Parallel Task ThreadPool 2 多进
  • phpstrom、laradock、xdebug 进行断点调试

    phpstrom laradock xdebug 进行断点调试 背景 laravel 框架封装太完善 经常搞不明白究竟用的是哪个类 复杂一点的算法 使用 dd方法调试时 需要疯狂dd 显得过于鸡肋 调试流程 发请求 跑调试代码 安装 xde
  • 决策树之用信息增益选择最优特征

    决策树之用信息增益选择最优特征 熵 熵的定义 熵 sh ng 热力学中表征物质状态的参量之一 用符号S表示 其物理意义是体系混乱程度的度量 在决策树中 信息增益是由熵构建而成 表示的是 随机变量的不确定性 不确定性越大 代表着熵越大 随机变
  • Mycat 学习小结

    Mycat 学习小结 Mycat 是什么 Mycat 是一个彻底开源的面向企业应用开发的大数据库集群 支持事务 ACID 是可以替代Mysql 的加强版数据库 Mycat被视为 Mysql 集群的企业级数据库 用来替代昂贵的 Oracle
  • LuCI界面开发之CBI模块

    在openWrt路由界面的开发中 我们使用的LuCI实际上已经不是简单的html了 它是嵌合于lua语言中的元素 或者按照英文翻译来说不是那些input而是变为如asp net中使用的那些控件 或者是 类 这些类包括一些常用的input输入
  • 编程每日一题_C程序设计_判断是否为素数

    描述 给定整型数据 判断其是否为素数 质数 又称素数 是指在大于1的自然数中 除了1和它本身外 不能被其他自然数整除 除0以外 的数称之为素数 质数 比1大但不是素数的数称为合数 1和0既非素数也非合数 素数 质数 与合数 定义存疑 解法一
  • 分支-11. 计算工资(15)

    某公司员工的工资计算方法如下 一周内工作时间不超过40小时 按正常工作时间计酬 超出40小时的工作时间部分 按正常工作时间报酬的1 5倍计酬 员工按进公司时间分为新职工和老职工 进公司不少于5年的员工为老职工 5年以下的为新职工 新职工的正
  • ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial - UE5 Starter Course

    ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial UE5 Starter Course 教程大小解压后 4 96G 语言 英语 中英文字幕 机译 时长 4小时56分 1920X1080 mp4 虚
  • 使用 Docker 和 Alpaca LoRA 对 LLaMA 65B 大模型进行 Fine-Tune

    这篇文章中 我们来聊聊如何使用两张显卡来进行 LLaMA 65B 大模型的微调工作 以及如何在一张普通的 4090 家用显卡上 只花几个小时 就能够完成 7B 模型的微调 写在前面 在之前的几篇文章里 我们介绍过三种方式运行 Meta 开源