
Meta 在两周前发布了 Llama 2,并在 AI 社区引起了巨大反响。我们认为,其最大的影响在于该模型现已在 宽松许可 下发布,允许商业使用模型权重1。这与 Llama 1 不同,Llama 1 不能用于商业用途。
简单来说:组织现在可以在完全私密的环境中,使用这个基础模型并根据自己的数据(无论是内部文档、客户对话还是代码)对其进行微调,并将其用于商业场景。
在这篇博文中,我们提供了一个分步教程,教您如何做到这一点:在您现有的云环境中,使用 100% 开源工具,根据您自己的数据微调 Llama 2。
为什么?
我们提供一份LLM 微调操作指南,具有以下特点
- 完全开源:尽管出现了许多托管式微调服务,但本指南仅使用包括 SkyPilot 在内的开源、Apache 2.0 软件。因此,本教程可用于任何环境,无论是研究还是商业用途。
- 一切都在您自己的云中:所有计算资源、数据和训练好的模型都保留在您自己的云环境(VPC、VM、存储桶)中。您拥有完全控制权,无需信任第三方托管解决方案。
- 自动多云:相同的教程适用于所有超大规模云提供商(AWS、GCP、Azure、OCI 等)或 GPU 云(Lambda)。请参阅 SkyPilot 支持的 7+ 云提供商。
- 高 GPU 可用性:通过使用您有权访问的所有区域/云,SkyPilot 会自动为用户作业找到最高的 GPU 可用性。无需手动操作控制台。
- 最低成本:SkyPilot 自动寻找最便宜的区域/可用区/云。本教程支持在 Spot 实例上进行微调,并具有自动恢复功能,可将成本降低 3 倍。
通过本教程,用户不仅可以以最小的努力入门,还可以确保其数据和模型检查点不会被任何第三方托管解决方案看到。
教程:在 Llama 2 上训练您自己的 Vicuna
Vicuna 是首批基于 Llama 1 微调的高质量 LLM 之一。我们(Wei-Lin 和 Zhanghao)作为 Vicuna 的共同创建者,更新了用于训练 Vicuna 的精确教程,使其基于 Llama 2,并由此产生了这份微调指南。
在本教程中,我们将展示如何使用 SkyPilot 在 Llama 2 上训练您自己的 Vicuna,轻松找到云上的可用 GPU,同时将成本降低至仅约 300 美元。
本教程(从 GitHub 下载)的编写方式使您可以轻松复制粘贴并运行。有关详细说明,请参阅下一节。
前提条件
- 申请访问 Llama-2 模型
前往申请页面并申请访问模型权重。
- 从 HuggingFace 获取访问令牌
在 HuggingFace 上此处生成一个只读访问令牌。前往 HuggingFace 上 Llama-2 模型的页面此处并申请访问。确保您的 HuggingFace 邮箱与 Meta 申请中的邮箱一致。可能需要 1-2 天才能获批。
- 下载本教程并安装 SkyPilot
git clone https://github.com/skypilot-org/skypilot.git
cd skypilot
pip install -e ".[all]"
cd ./llm/vicuna-llama-2
将访问令牌粘贴到 train.yaml 中
envs:
HF_TOKEN: <your-huggingface-token> # Change to your own huggingface token
训练数据和模型身份
默认情况下,我们使用 ShareGPT 数据以及 hardcoded_questions.py 中的身份问题。
可选:要使用自定义数据,您可以更改 train.yaml 中的以下行
setup: |
...
wget https://hugging-face.cn/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json -O $HOME/data/sharegpt.json
...
上述 json 文件是一个数组,每个元素的格式如下(对话可以在 human
和 gpt
之间进行多轮)
{
"id": "i6IyJda_0",
"conversations": [
{
"from": "human",
"value": "How to tell if a customer segment is well segmented? In 3 bullet points."
},
{
"from": "gpt",
"value": "1. Homogeneity: The segment should consist of customers who share similar characteristics and behaviors.\n2. Distinctiveness: The segment should be different from other segments in terms of their characteristics and behaviors.\n3. Stability: The segment should remain relatively stable over time and not change drastically. The characteristics and behaviors of customers within the segment should not change significantly."
}
]
},
可选:要让模型了解其身份,您可以更改 hardcoded_questions.py 中的硬编码问题
注意:使用 ShareGPT 数据训练的模型可能存在商业使用限制。将其替换为您自己的数据以便进行商业使用。
在任何云上启动训练
使用一条命令开始训练
sky launch --down -c vicuna train.yaml \
--env ARTIFACT_BUCKET_NAME=<your-bucket-name> \
--env WANDB_API_KEY=<your-wandb-api-key>
这将在拥有 8x A100-80GB Spot GPU 可用的最便宜的云上启动训练作业。
提示:您可以在 https://wandb.ai/settings 获取
WANDB_API_KEY
。要禁用 Weights & Biases,只需省略该--env
标志。
提示:您可以将
ARTIFACT_BUCKET_NAME
设置为一个新的存储桶名称,例如<whoami>-tmp-bucket
,SkyPilot 将为您创建该存储桶。
改用按需实例以解锁更多云:在 train.yaml
中,我们请求使用 Spot 实例
resources:
accelerators: A100-80GB:8
disk_size: 1000
use_spot: true
然而,目前 Spot A100-80GB:8 仅在 GCP 上受支持。按需版本在 AWS、Azure、GCP、Lambda 等上受支持。(提示:查看 sky show-gpus A100-80GB:8
的便捷输出!)
要使用这些云,添加 --no-use-spot
标志以请求按需实例
sky launch --no-use-spot ...
可选:尝试训练 13B 模型
sky launch -c vicuna train.yaml \
--env ARTIFACT_BUCKET_NAME=<your-bucket-name> \
--env WANDB_API_KEY=<your-wandb-api-key> \
--env MODEL_SIZE=13
使用 Spot 实例将成本降低 3 倍
SkyPilot Managed Spot 是构建在 SkyPilot 之上的一个库,可帮助用户在 Spot 实例上运行作业而无需担心中断。这是 LMSYS 组织用于训练 Vicuna 第一个版本(更多细节可在其发布博文和示例中找到)的工具。通过它,训练成本可以从 1000 美元降低到300 美元。
要使用 SkyPilot Managed Spot,只需在上述命令中将 sky launch
替换为 sky spot launch
sky spot launch -n vicuna train.yaml \
--env ARTIFACT_BUCKET_NAME=<your-bucket-name> \
--env WANDB_API_KEY=<your-wandb-api-key>
部署您的模型
训练完成后,您可以使用一条命令在您自己的云环境中部署您的模型
sky launch -c serve serve.yaml --env MODEL_CKPT=<your-model-checkpoint>/chatbot/7b
在 serve.yaml 中,我们指定启动一个 Gradio 服务器来部署位于 <your-model-checkpoint>/chatbot/7b
的模型检查点。

提示:您也可以切换到更便宜的加速器,例如 L4,以节省成本,只需在上述命令中添加
--gpus L4
。
教程详解
让我们来详解 train.yaml
。
资源供应
resources
字典指定了微调作业所需的资源
resources:
accelerators: A100-80GB:8
disk_size: 1000
use_spot: true
SkyPilot 根据这个云无关的规格,自动寻找能够满足要求的最佳(最便宜且可用)云位置和实例类型。然后它会供应资源,并通过重试来处理容量不足错误,最后启动作业。
对用户而言,不再需要手动操作不同的云控制台来查找哪些区域有可用的 GPU VM。
提示:如果您愿意,仍然可以硬编码指定要使用的特定云/区域/可用区或实例类型。请查看 YAML 规范了解所有可设置的参数。
最大化云 GPU 可用性
每个资源供应请求(sky launch
、sky spot launch
)都会在给定的搜索空间中自动寻找资源。这种自动故障转移机制是最大化 GPU 可用性的关键

您给予 SkyPilot 的搜索空间与它能帮助找到的 GPU 可用性之间存在权衡。例如,假设您的笔记本电脑可以访问 AWS 和 GCP(请参阅 sky check
的有用输出)。那么,如果您在 resources
字典中指定
cloud: aws
,region: us-east-1
:SkyPilot 只会搜索该区域。如果该区域没有所需的 GPU 可用,则资源供应请求将失败。(您可以传递-r/--retry-until-up
来持续重试。)cloud: aws
:SkyPilot 将在 AWS 的所有可用区/区域中搜索。- 无位置限制:SkyPilot 将在“天空”中搜索:所有您有权访问的可用区/区域/云(本例中为 AWS 和 GCP)。
正如您所见,最后一种情况真正实现了透明的多云使用,并应提供最高的可用性。话虽如此,如果用户在特定位置有特殊配额或折扣,也有参数可以缩小位置范围。
使用哪些 GPU
关键要求是 GPU 显存必须足够大。在 YAML 中我们使用了 A100-80GB:8
,这对于无性能损失地微调 LLM 至关重要。
然而,如果您选择使用 QLoRA 或其他 PEFT(参数高效微调)方法,则可以显著放宽 GPU 要求。请参阅此处使用 A10:1
(24GB) 微调 7B 基础模型的一个示例,或 Tobi Lütke 的针对 Llama1 的 QLoRA 教程。
要使用不同的 GPU 类型/数量,只需更改 YAML 中的 resources.accelerators
字段,或通过 --gpus <name>:<count>
标志覆盖 CLI 命令。
使用这个便捷工具查找不同云中的 GPU 及其实时价格
sky show-gpus
检查点保存到云存储
在 YAML 的 file_mounts 部分,我们指定了一个名为 $ARTIFACT_BUCKET_NAME
(通过环境变量传入)的存储桶应该被挂载到 VM 内部的 /artifacts
路径
file_mounts:
/artifacts:
name: $ARTIFACT_BUCKET_NAME
mode: MOUNT
启动作业时,我们只需将 /artifacts
传递给其 --output_dir
标志,训练程序会将所有检查点和其他产物写入此处
torchrun ... --output_dir /artifacts/chatbot/${MODEL_SIZE}b ...
换句话说,您的训练程序使用这个挂载路径,就像它在 VM 本地一样!写入挂载目录的文件/目录会自动同步到云存储桶。
提示:您可以传入一个新名称(例如,
<whoami>-tmp-bucket
)让 SkyPilot 自动为您创建一个新存储桶,也可以使用现有存储桶的名称。
提示:所有创建的存储桶都是私有存储桶,位于您自己的云账户中。
您可以从相应的对象存储中检查或下载输出。Google Cloud Storage (GCS) 上的示例存储桶
要了解更多关于与云存储交互的信息,请参阅 SkyPilot 存储文档。
如何处理 Spot 实例中断
Spot GPU 具有极高的成本效益,在主要云上比按需实例便宜约 2.5 倍–3 倍
» sky show-gpus A100-80GB:8
GPU QTY CLOUD INSTANCE_TYPE DEVICE_MEM vCPUs HOST_MEM HOURLY_PRICE HOURLY_SPOT_PRICE REGION
A100-80GB 8 Azure Standard_ND96amsr_A100_v4 - 96 1924GB $ 32.770 $ 12.977 eastus
A100-80GB 8 GCP a2-ultragpu-8g - 96 1360GB $ 40.222 $ 12.866 asia-southeast1
...
有趣的是,我们观察到Spot GPU 有时比按需 GPU 更容易获得。最近在 GCP 的 A100 上观察到了这种情况。
问题是:我们如何轻松处理 Spot 中断?
托管式 vs. 非托管式
SkyPilot 支持两种使用 Spot 实例的模式
- 托管式 Spot:使用
sky spot launch
启动的作业。SkyPilot 通过在下一个最便宜且可用的云位置重新启动新的 Spot 集群来自动恢复中断(这就是您给 SkyPilot 的搜索空间越大,GPU 可用性越高的原因!)。托管作业会在恢复的集群上自动重启。 - 非托管式 Spot:使用
sky launch
启动并请求 Spot 实例的作业(可以是 YAML 中的resources.use_spot
字段或 CLI 的--use-spot
标志)。在此模式下,Spot 中断不会自动恢复。
我们建议在开发中使用非托管式 Spot,因为它允许轻松登录和调试(ssh <my cluster>
),但要注意突然中断。一旦您验证训练正常进行,切换到托管式 Spot 进行完整运行以启用自动恢复。
处理部分检查点
回想一下,我们将检查点保存到云存储桶。这非常方便,因为当 Spot 作业在新的恢复实例上重新启动时,它可以从存储桶中重新加载最新的检查点并从那里恢复训练。
我们教程中的 train.py
使用了 HuggingFace 的 Trainer
,它本身支持从检查点恢复
trainer.train(resume_from_checkpoint=resume_from_checkpoint)
然而,需要处理一个边缘情况:在写入检查点期间,实例可能会突然被中断,导致只有部分状态写入云存储桶。发生这种情况时,从损坏的部分检查点恢复将导致程序崩溃。
为了解决这个问题,我们添加了一个简单的 transformers.TrainerCallback
,它会
- 在每个检查点保存后写入一个
complete
指示文件 - 程序重启时,删除存储桶中任何不完整的检查点
相关代码片段
class CheckpointCallback(transformers.TrainerCallback):
def on_save(self, args, state, control, **kwargs):
"""Add complete indicator to avoid incomplete checkpoints."""
if state.is_world_process_zero:
ckpt_path = os.path.join(args.output_dir,
f'checkpoint-{state.global_step}')
with open(os.path.join(ckpt_path, 'complete'), 'w') as f:
f.write('')
print(f'Checkpoint {state.global_step} saved.')
torch.distributed.barrier()
def cleanup_incomplete_checkpoints(output_dir):
"""Remove incomplete checkpoints."""
checkpoints = list(pathlib.Path(output_dir).glob('checkpoint-*'))
... # Sort by step
for checkpoint in checkpoints:
if not (checkpoint / 'complete').exists():
print(f'Removing incomplete checkpoint {checkpoint}')
shutil.rmtree(checkpoint)
else:
...
break
在程序启动时将这些连接起来
def train():
...
if local_rank == 0:
cleanup_incomplete_checkpoints(training_args.output_dir)
torch.distributed.barrier()
...
trainer.add_callback(CheckpointCallback)
trainer.train(resume_from_checkpoint=resume_from_checkpoint)
...
就是这样!只需大约 30 行代码,我们的训练程序现在就可以完全抵抗 Spot 中断。您现在可以使用 sky spot launch
进行所有微调运行,从而实现高成本节省和 GPU 可用性。
监控
本教程已经设置了 Weights & Biases 集成以监控指标。
如何轻松地在同一图表中查看同一作业的不同恢复过程?在 YAML 中,我们将 --run_name $SKYPILOT_TASK_ID
传递给主程序,并且此环境变量保证在同一 Spot 作业的不同恢复过程中保持一致。(您也可以指定自己的运行名称。)
通过此设置,您可以使用 W&B 的筛选功能对 run_name
进行筛选,以查看同一运行的不同恢复过程
在这里,作业被中断了一次,导致产生了 2 个片段。注意到重叠了吗?这是由于恢复时固有的一些进度损失。例如,第一个片段保存了一个检查点,取得了一些进展(但未到达下一个检查点),然后被中断。第二个片段必须重新加载最后一个检查点并重新执行一些工作。
结论
借助 Llama 2 和 SkyPilot,您现在可以在您自己的云账户中使用您的私有数据微调您自己的 LLM,并且成本效益高。我们希望本教程能帮助实践者在私有环境中释放 LLM 的力量。祝您微调愉快!
后续步骤
有问题或反馈?请通过 SkyPilot GitHub 或 Slack 联系我们!