

本教程对应 Arm 官方高级学习路径,聚焦在 NVIDIA DGX Spark 工作站上,通过 PyTorch 与 Hugging Face 生态对 Llama 3.2 3B 大模型进行监督式微调,最终使用 vLLM 完成模型效果验证。教程适用于 AI 开发工程师和机器学习工程师,完成整个流程学习约 1 小时,需具备 ML、Python、Linux 基础。
开始微调前,必须准备好以下基础环境和账号资源,这是整个流程的前提:
硬件:NVIDIA DGX Spark 工作站(基于 ARM Cortex-A Neoverse 架构,搭载 GB10 Grace Blackwell 超级芯片,128GB 统一内存,预装 DGX OS);
账号:Hugging Face 官方账号,并获取有效的访问令牌(Access Token),用于拉取预训练模型和相关生态工具;
基础环境:DGX Spark 已原生预装 Docker、CUDA 工具包、cuDNN、PyTorch、Hugging Face Transformers 等依赖,无需手动配置。
像 Llama 3.2 8B 这样的预训练模型具备出色的通用语言理解与生成能力,但它们并非 “无所不知”。如果你直接向基础模型询问 RP2350 微控制器的最高时钟频率,它可能会非常自信地给出 “1.8 GHz” 的答案 —— 而这完全是编造的数值,该芯片的真实规格仅为 150 MHz。
微调正是用来解决这类问题的核心手段:通过在树莓派官方数据手册等真实数据上对模型进行二次训练,让模型习得精准的领域专属知识。经过微调后,同样的问题模型会给出正确答案:“RP2350 最高支持 150 MHz 时钟频率”,不再出现幻觉与凭空猜测。
整个落地流程可以拆解为三步:
要理解这一流程为何有效,我们需要搞清楚三件事:监督式微调的作用、训练数据的结构,以及如何根据硬件条件选择高效的微调方案。
预训练大语言模型从海量文本数据中学习通用语言规律与常识,而监督式微调(SFT, Supervised Fine-Tuning)则在这一基础上,利用标注样本(输入 - 输出对)引导模型行为,使其学会针对特定提示给出符合预期的回答。
可以把它理解为 “示例教学”:你提供输入与目标输出配对数据,训练过程会调整模型参数,让输出越来越贴近标注样本。模型原本的通用知识会被保留,SFT 则负责引导知识的调用方式,并填补基础模型缺乏专业领域细节的空白。
SFT 最核心的优势是高效:从零开始预训练模型需要数千张 GPU 与万亿级 Token 数据,而微调仅需数百至数千条样本、单张 GPU 即可实现针对性效果提升,这也让 DGX Spark 成为该任务的理想平台。
本教程配套的 NVIDIA 脚本采用Alpaca 提示格式,每条训练样本包含三个关键字段:
数据示例:
{
"instruction": "How many GPIO pins does the Raspberry Pi Pico 2 provide?",
"input": "",
"output": "The Raspberry Pi Pico 2 provides 26 GPIO pins."
}训练时,这些字段会被拼接为统一的提示模板,方便模型学习识别并生成规范回答:
Below is an instruction that describes a task, paired with an input
that provides further context. Write a response that appropriately
completes the request.
### Instruction: How many GPIO pins does the Raspberry Pi Pico 2 provide?
### Input:
### Response: The Raspberry Pi Pico 2 provides 26 GPIO pins.本次使用的数据集包含约 250 条问答对,均提取自树莓派官方手册,覆盖 RP2040、RP2350、Pico、Pico 2、CM4 等多款产品。模型在这些数据上训练后,能够输出基于手册的精准事实,而非虚构参数。
训练时并非所有模型都能完整放入 GPU 内存,教程后续使用的脚本提供了多种适配方案:
DGX Spark 预装了定制化的 DGX OS(基于 Ubuntu 24.04),并优化了 AI 开发全栈环境,只需完成简单的初始化配置即可使用:
系统基础配置:首次启动完成时区、语言、网络设置,推荐通过 DGX Dashboard(网页端)进行操作,无需 SSH 命令行;
验证 GPU 与 CUDA:在终端执行nvidia-smi验证 GPU 驱动,执行nvcc -V验证 CUDA 版本,DGX Spark 已预装适配 GB10 芯片的 CUDA 版本,无需手动安装;
登录 Hugging Face:在终端执行huggingface-cli login,输入获取的 Access Token,完成认证,确保能正常拉取 Llama 3.2 3B 预训练模型;
启动 Docker 容器(可选):DGX Spark 集成 Nvidia 容器运行时,可从 NGC 拉取 GPU 优化的 PyTorch 容器,执行docker run --gpus all -it nvcr.io/nvidia/pytorch:latest启动容器,保证环境一致性。
核心优势:DGX Spark 的统一内存架构消除了 CPU 与 GPU 之间的 PCIe 传输瓶颈,128GB 共享内存可轻松加载大模型,大幅提升微调效率。
本部分将完整拆解Llama3_3B_full_finetuning.py脚本的核心逻辑,手把手教你基于树莓派专属 JSONL 数据集,在 NVIDIA DGX Spark 上完成 Llama 3.2 3B 模型的全参数微调,全程使用 PyTorch 框架与 Hugging Face 生态工具(TRL、Transformers),兼顾训练效率与效果。
脚本首行导入微调所需的所有工具库,各库职责明确,是 PyTorch 生态微调的标准组合:
import torch
import argparse
from datasets import load_dataset
from trl import SFTConfig, SFTTrainer
from transformers import AutoModelForCausalLM, AutoTokenizer使用 Arm 官方指定的Alpaca 三字段模板(instruction/input/response),统一训练数据格式,让模型学习固定的指令跟随模式,模板代码如下:
# Define prompt templates
DATASET_PROMPT_TEMPLATE = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.
### Instruction: {}
### Input: {}
### Response: {}"""模板中{}为占位符,分别对应问题 / 指令、补充上下文、标准答案,训练时会自动将数据集的每一条数据填充至模板中。
该函数实现加载本地 JSONL 数据集、按模板格式化数据、裁剪数据量的核心功能,代码与逐行解析如下:
def get_dataset(dataset_name, dataset_dir, dataset_files, eos_token, dataset_size=512):
# Preprocess the dataset
def preprocess(x):
texts = [
DATASET_PROMPT_TEMPLATE.format(instruction, input, output) + eos_token
for instruction, input, output in zip(x["instruction"], x["input"], x["output"])
]
return {"text": texts}
dataset = load_dataset(dataset_name, data_dir=dataset_dir, data_files=dataset_files, split="train")
if len(dataset) > dataset_size:
dataset = dataset.select(range(dataset_size)).shuffle(seed=42)
return dataset.map(preprocess, remove_columns=dataset.column_names, batched=True)关键要点:
通过from_pretrained()从 Hugging Face 拉取 Llama 3.2 3B 预训练模型,同时配置分词器(核心是设置 padding token),代码如下:
# Load the model and tokenizer
print(f"Loading model: {args.model_name}")
model = AutoModelForCausalLM.from_pretrained(
args.model_name,
dtype=args.dtype,
device_map="auto",
trust_remote_code=True
)
tokenizer = AutoTokenizer.from_pretrained(args.model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token核心配置:
device_map="auto":DGX Spark 会自动将模型分配到空闲 GPU,无需手动指定;tokenizer.pad_token = tokenizer.eos_token:解决 Llama 模型无默认 padding token 的问题,保证批量训练时数据长度统一。
调用上文定义的get_dataset()函数,传入命令行参数与分词器 EOS 符,完成训练数据的最终预处理,代码仅一行,简洁高效:
# Load and preprocess the dataset
print(f"Loading dataset with {args.dataset_size} samples...")
dataset = get_dataset(args.dataset, args.dataset_dir, args.dataset_files, tokenizer.eos_token, args.dataset_size)输入参数说明:
args.dataset:固定为json(因数据集是 JSONL 格式);
args.dataset_files:本地树莓派 JSONL 数据集的路径;
args.dataset_size:本次训练使用的样本量。
通过字典配置全参数微调的核心训练参数,分为训练超参、显存优化、日志配置三类,适配 DGX Spark 的硬件特性,代码与关键参数解析如下:
# Configure the SFT config
config = {
"per_device_train_batch_size": args.batch_size,
"num_train_epochs": 0.05, # Warmup epoch
"gradient_accumulation_steps": args.gradient_accumulation_steps,
"learning_rate": args.learning_rate,
"optim": "adamw_torch",
"save_strategy": 'no',
"remove_unused_columns": False,
"seed": 42,
"dataset_text_field": "text",
"packing": False,
"max_length": args.seq_length,
"report_to": "none",
"logging_dir": args.log_dir,
"logging_steps": args.logging_steps,
"gradient_checkpointing": args.gradient_checkpointing, # Save memory
}DGX Spark 优化要点:
开启gradient_checkpointing:牺牲少量计算效率,节省 50% 以上显存,是大模型微调的必备配置;
合理设置gradient_accumulation_steps:若单卡批次设为 4,累积步数设为 2,等效批次为 8,训练效果更好;
预热轮数0.05:仅用于触发模型编译,无实际参数更新,避免编译开销影响正式训练。
这是脚本的核心执行部分,分为torch.compile 模型编译、预热训练、全量正式训练三步,充分利用 DGX Spark 的 GPU 算力,提升训练速度,代码与解析如下:
# Compile model for faster training
print("Compiling model with torch.compile()...")
model = torch.compile(model)
# Warmup for torch compile
print("Running warmup for torch.compile()...")
SFTTrainer(
model=model,
processing_class=tokenizer,
train_dataset=dataset,
args=SFTConfig(**config),
).train()
# Train the model
print(f"\nStarting full fine-tuning for {args.num_epochs} epoch(s)...")
config["num_train_epochs"] = args.num_epochs
config["report_to"] = "tensorboard"
trainer = SFTTrainer(
model=model,
processing_class=tokenizer,
train_dataset=dataset,
args=SFTConfig(**config),
)
trainer_stats = trainer.train()核心亮点:
torch.compile(model):PyTorch 2.0 + 核心特性,优化模型计算图,在 DGX Spark 的 GB10 GPU 上可提升 30%+ 训练速度;
分离预热与正式训练:避免编译的一次性开销计入正式训练,保证训练指标的准确性;
SFTTrainer:封装了大模型 SFT 的所有细节(如梯度裁剪、参数更新),无需手动编写训练循环,降低开发成本。
脚本默认加载 Hugging Face 的 Alpaca 数据集,本次微调使用Arm 官方提供的树莓派数据手册 QA 数据集(包含 250 + 条树莓派硬件参数问答,Alpaca 标准格式),需先下载到 DGX Spark 的挂载目录,步骤如下:
步骤 1:在 DGX Spark 主机终端操作(非 Docker 容器内)
导航到启动 Docker 容器时的挂载目录(即-v {PWD}:/workspace中的{PWD}),执行wget命令下载数据集:
wget https://learn.arm.com/learning-paths/laptops-and-desktops/pytorch-finetuning-on-spark/raspberry_pi_qa.jsonl关键:该目录已挂载到容器的/workspace,下载后容器内可直接访问。
步骤 2:在 Docker 容器内操作,复制数据集到工作目录
进入 DGX Spark 的 PyTorch Docker 容器,将/workspace中的数据集复制到脚本所在的工作目录:
cp /workspace/raspberry_pi_qa.jsonl .将上述完整的Llama3_3B_full_finetuning.py脚本保存到 Docker 容器的工作目录(与数据集同目录),执行终端命令启动微调,全程自动化,无需手动干预。
python Llama3_3B_full_finetuning.py \
--model_name "meta-llama/Llama-3.2-3B-Instruct" \
--dataset "json" \
--dataset_files="raspberry_pi_qa.jsonl" \
--dataset_size 300 \
--output_dir "/workspace/models/Llama-3.2-3B-FineTuned"DGX Spark 的 GB10 GPU 性能强悍,本次微调仅需数分钟即可完成,训练过程中会打印以下关键日志:
模型加载与编译日志:Loading model: meta-llama/Llama-3.2-3B-Instruct、Compiling model with torch.compile();
预热训练日志:Running warmup for torch.compile(),无损失打印,仅执行编译;
正式训练日志:每 10 步打印一次训练损失(loss),loss 持续下降并趋于稳定即表示训练正常;
训练完成日志:打印训练耗时、样本吞吐量、平均 loss,最后输出Model saved to: /workspace/...。
这部分将手把手教你通过vLLM 高性能推理框架(NVIDIA 官方优化版),在 DGX Spark 上部署原始 Llama 3.2 3B 模型和树莓派领域微调后模型,通过 OpenAI 兼容的 API 接口发起请求,对比两者对树莓派硬件问题的回答效果,直观验证微调后模型在领域事实准确性上的提升,彻底解决基础模型的 “幻觉问题”。
NVIDIA 提供了预构建的 vLLM 容器,内置了大模型推理所需的所有依赖,针对 NVIDIA GPU 做了深度优化,支持 FP8/4/8 位量化、多 GPU 推理,可直接在 DGX Spark 上使用,无需手动安装 vLLM 及相关依赖。
在DGX Spark 主机终端(非任何 Docker 容器内)执行以下命令拉取 vLLM 容器(2026 年 1 月版,含最新推理优化):
docker pull nvcr.io/nvidia/vllm:26.01-py3拉取完成后,执行docker images可查看容器是否成功下载,确认镜像名nvcr.io/nvidia/vllm存在即表示拉取完成。
本次启动 vLLM 容器需配置GPU 独占、目录挂载、端口映射核心参数,让容器可访问本地 Hugging Face 缓存、微调后模型文件,并通过 8000 端口对外提供 OpenAI 兼容的 API 服务,实现外部终端的 HTTP 请求调用。
在 DGX Spark 主机终端执行以下启动命令:
docker run --gpus all -it --rm --ipc=host \
-v $HOME/.cache/huggingface:/root/.cache/huggingface \
-v ${PWD}:/workspace -w /workspace \
-p 8000:8000 nvcr.io/nvidia/vllm:26.01-py3执行命令后,终端会进入 vLLM 容器的交互式界面,后续所有 vLLM 服务启动操作均在此容器内执行。
在验证微调后模型前,先部署原始未微调的 Llama 3.2 3B-Instruct 模型,测试其对树莓派硬件问题的回答效果,建立基础效果基线,清晰看出基础模型的知识短板与幻觉问题。
在已启动的 vLLM 容器终端,执行以下命令启动 vLLM OpenAI API 服务,加载原始 Llama 3.2 3B 模型:
python3 -m vllm.entrypoints.openai.api_server \
--model "meta-llama/Llama-3.2-3B-Instruct" --trust-remote-code \
--tensor-parallel-size 1 --quantization fp8 \
--gpu-memory-utilization 0.80启动参数深度解析(适配 DGX Spark 硬件)
--model:指定加载 Hugging Face 上的原始 Llama 3.2 3B 指令版模型,容器会从挂载的本地缓存加载,无需重新下载;
--trust-remote-code:允许加载带自定义代码的模型,Llama 系列模型必备配置;
--tensor-parallel-size 1:单 GPU 推理,适配 DGX Spark 的硬件配置,多 GPU 可调整数值;
--quantization fp8:开启 FP8 量化,大幅降低模型显存占用,同时提升推理吞吐量,不损失核心效果;
--gpu-memory-utilization 0.80:限制 GPU 显存使用率为 80%,因 DGX Spark 采用 CPU-GPU 统一内存架构,预留 20% 显存给系统,避免内存溢出。
新开一个 DGX Spark 主机终端(非 vLLM 容器内),执行以下curl命令,向 vLLM 服务发送RP2350 内存大小的问题(Alpaca 标准指令格式),测试原始模型的回答:
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\n
Instruction:\nHow much memory does the RP2350 have?\n\n### Response:", "max_tokens": 200}'原始模型因未学习过树莓派官方数据手册,会编造看似合理但完全错误的答案,典型输出如下:
{
"id": "cmpl-91e070e2a34aaf01",
"object": "text_completion",
"created": 1770998840,
"model": "meta-llama/Llama-3.2-3B-Instruct",
"choices": [
{
"index": 0,
"text": " \nThe RP2350 has 256MB of memory.",
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 35,
"total_tokens": 48,
"completion_tokens": 13
}
}关键问题:原始模型回答 RP2350 有 256MB 内存,与官方数据手册的520 KB SRAM相差三个数量级,属于典型的大模型 “事实幻觉”,也是本次微调需要解决的核心问题。
完成原始模型测试后,停止当前 vLLM 服务,部署树莓派领域微调后模型,使用相同的问题发起请求,验证微调后模型的事实准确性提升,这是本次教程的核心验证环节。
在运行 vLLM 服务的容器终端,按下Ctrl + C组合键,即可停止当前的原始模型推理服务,容器会回到交互式命令行状态,准备启动微调后模型。
当前 vLLM 容器内置的transformers库版本为旧版,不支持微调时使用的transformers v5的tokenizer_class配置,需手动修改微调后模型的tokenizer_config.json文件,将分词器类改为兼容的PreTrainedTokenizerFast。
在 vLLM 容器终端执行以下sed 命令完成补丁修改(路径为微调后模型的保存路径):
sed -i 's/"tokenizer_class": "TokenizersBackend"/"tokenizer_class": "PreTrainedTokenizerFast"/' /workspace/models/Llama-3.2-3B-FineTuned/tokenizer_config.json执行后无任何输出即表示修改成功,无需额外验证,直接进入下一步即可。
在 vLLM 容器终端,执行以下命令启动推理服务,加载本地微调后模型,命令与原始模型基本一致,仅修改--model参数为本地模型路径:
python3 -m vllm.entrypoints.openai.api_server \
--model "/workspace/models/Llama-3.2-3B-FineTuned" --trust-remote-code \
--tensor-parallel-size 1 --quantization fp8 \
--gpu-memory-utilization 0.80核心修改:--model参数从 Hugging Face 模型 ID 改为本地微调后模型的目录路径/workspace/models/Llama-3.2-3B-FineTuned,容器会直接加载本地模型文件,推理速度更快。
同样等待 30-60 秒,直到终端显示服务启动成功的提示。
在同一台 DGX Spark 主机的外部终端,执行与原始模型完全相同的 curl 命令,发送 RP2350 内存大小的问题:
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\n
Instruction:\nHow much memory does the RP2350 have?\n\n### Response:", "max_tokens": 200}'微调后模型因学习了树莓派官方数据手册的精准知识,会输出与官方规格完全一致的答案,典型输出如下:
{
"id": "cmpl-bad36ff5edddfb74",
"object": "text_completion",
"created": 1770999123,
"model": "/workspace/models/Llama-3.2-3B-FineTuned",
"choices": [
{
"index": 0,
"text": " The RP2350 has 520 KB of on-chip SRAM.",
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 35,
"total_tokens": 51,
"completion_tokens": 16
}
}微调后模型的核心优势(对比原始模型)
本教程完成了在 NVIDIA DGX Spark 上从环境初始化、领域数据集制作、PyTorch+Hugging Face 微调到vLLM 效果验证的全流程,核心亮点在于:
DGX Spark 的开箱即用 AI 环境,省去了复杂的依赖配置和硬件适配;
基于 JSONL 格式的监督式微调,让 Llama 3.2 3B 快速学习树莓派领域知识;
vLLM 的高效推理,实现了基础模型与微调后模型的快速对比验证。通过该流程,可快速将通用大模型适配到特定领域,实现领域专属问答、文档解析等场景的落地。
原始教程:
https://learn.arm.com/learning-paths/laptops-and-desktops/pytorch-finetuning-on-spark/