3. GPU 准备:租机器、装环境、下模型¶
从这一章开始花钱。开机前确认已经读完第 1~2 章,并在本地准备好上传包。
本章速览
- 本章做什么:开一台 RTX 4090 云主机;看懂
nvidia-smi;上传项目;建立训练用的 Python 环境;从魔搭下载 8 GB 基座并校验;在 JupyterLab 里选对内核 - 需要准备:GPU 平台账号和余额;本地电脑上执行
python3 tools/build_gpu_zip.py打出的llm-lora-tutorial-gpu.zip(只含代码、数据和分词器,几 MB) - 做完得到:
.venv-train环境通过自检;models/qwen3-4b/校验通过;Notebook 已用 LoRA · Python 3.11 内核打开 - 大约耗时:30~60 分钟,主要花在装依赖和下载权重
本章的五步和它们解决的问题:
| 步骤 | 解决什么问题 | 不做会怎样 |
|---|---|---|
| 3.1 选机器 | 显存要装得下 4 bit 基座 + 训练中间结果;磁盘要放得下环境、基座和合并模型 | 训练时 OOM,或合并到一半磁盘写满 |
3.2 看 nvidia-smi |
确认显卡、驱动版本和空闲显存 | 后面装的 PyTorch 可能和驱动不兼容,报“CUDA 不可用” |
| 3.3 上传 + 建环境 | 用固定版本的库建一个项目私有环境,注册成 Jupyter 内核 | 用了镜像自带的旧版库,代码行为和教程对不上 |
| 3.4 下载基座 | 拿到和本教程逐字节一致的模型权重 | 版本不同,回答和数字都对不上;缺分片要到加载时才报错 |
| 3.5 打开 Notebook | 选对内核 | Notebook 跑在系统 Python 上,导入失败或用错版本 |
3.1 GPU 主机与文件¶
在哪里租:智川云¶
本书全部 GPU 操作都在 智川云 上完成,推荐初学者直接用它,主要是因为价格低、上手快:
| 项目 | 智川云上的情况 |
|---|---|
| 价格 | RTX 4090D(24 GB)按量 ¥1.25/小时,包日 ¥29、包周 ¥200、包月 ¥800(2026-10-11 页面价格,以下单时为准)。本书主线约 2~3 小时,只要三四块钱 |
| 新人优惠 | 首次充值满 1 元送 5 元代金券,基本够跑完一遍主线 |
| 型号 | RTX 3090 / 4090 / 4090D / 4090 Lite / 5090、A100、L40S 等,1~8 卡,多个地区 |
| 镜像 | 有本书用的 PyTorch 基础镜像 2.7.1-CUDA12.6-Py3.11-Ubuntu22 |
| 使用 | 实例页面一键打开 JupyterLab、SSH、VSCode;附带 50 GB 数据盘 |

怎么选:GPU 型号选 RTX 4090、4090D 或 4090 Lite 任一,都是 24 GB 显存,本书命令不用改(4090D 是国内版,算力略低于 4090,显存相同);镜像选 PyTorch → 2.7.1-CUDA12.6-Py3.11-Ubuntu22;计费选按量,用完关机。
实测的两点经验,开机后先处理:
- 项目放到数据盘。 实例的家目录
/root在 30 GB 系统盘上,装完训练环境、下载 8 GB 模型,再装 vLLM 就会写满。用df -h找到约 50 GB 的那块盘(作者的实例挂在/root/rivermind-data),把项目解压到那里。 - PyTorch 官方源可能连不上。 第 3.3 节和第 5.4 节都给了国内镜像的备用命令。
注册链接:https://gpuhome.cc/auth/register?code=zt4f01m0,注册时填写邀请码 zt4f01m0 领取新人代金券。这是作者的邀请链接,你首充后作者也会获得平台代金券;代金券由平台手动发放,满足条件后联系客服领取,有效期三个月。
本次使用的主机配置¶
本章按我们已选定并启动的 RTX 4090 云主机操作。以下配置来自 2026-09-29 保存的开机截图;登录后还要核对实际设备和环境。
| 项目 | 本次选择 | 操作时注意什么 |
|---|---|---|
| GPU | 1 张 RTX 4090,24 GB 显存 | 本教程使用单卡;第 4 章默认跑满 1 个 Epoch(约 72 步) |
| CPU / 主机内存 | 15 核 / 100 GB | 满足教程建议的 32 GB 主机内存,以及后续 CPU 合并时建议的 64 GB |
| 系统盘 | 30 GB SSD | 项目、训练环境和模型尽量放在数据盘 |
| 数据盘 | 50 GB SSD,截图中未启用扩容 | 完整流程建议扩到 100 GB;下载前检查实际剩余空间 |
| 基础镜像 | 2.7.1-CUDA12.6-Py3.11-Ubuntu22 |
Ubuntu 22、Python 3.11,预装 PyTorch 2.7.1 / CUDA 12.6 |
| 计费方式 | 按量计费 | 完成当次实验后按平台规则停止闲置实例,并核对存储费用 |
下图是本次确认的 GPU 与镜像配置:

镜像已经选好,接下来在里面建立项目自己的训练环境。 镜像预装的是 PyTorch 2.7.1,本教程的代码和依赖固定使用 PyTorch 2.8.0。下一节会创建 .venv-train 并安装 2.8.0 + cu126,保持原镜像环境不变。官方安装命令见 PyTorch 2.8.0。
当前已经启动机器,但尚未验证这台主机上的驱动、依赖、训练显存与耗时。本章完成环境、下载和内核准备,第 4 章在 Notebook 里观察原模型并更新 LoRA 参数。
其他 GPU 的选择参考¶
下表指桌面标准版,用于 Qwen3 4B、4bit QLoRA、最长 4096 Token、单次一条样本的配置规划。实际占用与耗时仍要实测;租用时核对完整型号、单卡显存和是否独占 GPU。
| GPU 型号 | 单卡显存 | 选择建议 |
|---|---|---|
| RTX 4090 | 24 GB GDDR6X | 本次使用的型号,沿用下面的 cu126 命令 |
| RTX 3090 | 24 GB GDDR6X | 已有设备或实际租价更低时可选,使用 cu126 |
| RTX 5090 | 32 GB GDDR7 | 显存余量更多;安装 PyTorch 时把索引末尾的 cu126 换成 cu128 |
5090 采用 Blackwell 架构,需要支持它的主机驱动。bitsandbytes 0.48.2 的支持表在 CUDA 12.8 构建中包含它所需的 sm120。若使用 5090,下面检查脚本中的 CUDA 版本断言也要从 12.6 改为 12.8。本次使用 4090,直接执行下一节的命令。
3.2 先读懂 nvidia-smi:驱动、CUDA 与显存¶
登录 GPU 主机后第一件事是运行 nvidia-smi。它的输出大致是:
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 560.35.03 Driver Version: 560.35.03 CUDA Version: 12.6 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 4090 Off | 00000000:01:00.0 Off | Off |
| 30% 35C P8 20W / 450W | 0MiB / 24564MiB | 0% Default |
+-----------------------------------------+------------------------+----------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
| 位置 | 含义 | 你要关心什么 |
|---|---|---|
Driver Version |
内核驱动版本,由平台镜像决定,普通用户改不了 | 决定了下面的 CUDA 上限 |
CUDA Version |
这个驱动最高支持的 CUDA 版本,不是已安装的 CUDA | PyTorch 的 cu126 要求它 ≥ 12.6;vLLM 0.21 的 cu129 要求 ≥ 12.9 |
Memory-Usage |
已用 / 总显存 | 训练前应接近 0;训练时看它涨到多少;启动 vLLM 前确认训练内核已释放 |
GPU-Util |
GPU 算力利用率 | 训练和压测时应持续较高;长期为 0 说明程序卡在 CPU 或等待 |
Processes |
哪些进程占着显存 | 找到忘记关闭的 Jupyter 内核 |
驱动、CUDA、PyTorch 的关系: 驱动装在操作系统里,和显卡绑定;CUDA 是 NVIDIA 的计算库,PyTorch 的 wheel 包自带它需要的那份(torch==2.8.0 的 cu126 后缀就是"内置 CUDA 12.6 的运行库"),所以不用自己装 CUDA 工具包;唯一的约束是驱动支持的版本不能低于 wheel 内置的版本。镜像名里的 CUDA12.6 说的是预装的工具包,和驱动上限是两回事,以 nvidia-smi 为准。
类比:驱动像操作系统内核版本,CUDA 运行库像应用自带的依赖,nvidia-smi 像 top 加 free -h。
显存和主机内存是两块独立的内存:模型权重、训练中间结果、KV Cache 都必须在显存里,主机的 100 GB 内存只用来中转和在 CPU 上做合并。显存不够时,报错是 CUDA out of memory,解决办法是减小占用(量化、更短的样本、更小的并发),不是加主机内存。
3.3 上传项目,准备训练内核¶
把上传包 llm-lora-tutorial-gpu.zip 上传到 GPU 数据盘,通过平台文件上传功能完成。这个包在本地项目根目录用下面的命令生成;Notebook、代码或数据有改动时重新生成一次。包里的分词器来自本地 models/qwen3-4b/,所以第一次打包前要先按第 2.8 节执行一次 lab.download --tokenizer-only:
打包脚本会拒绝带运行输出的 Notebook,保证上传的是干净版本。上传后,在上传位置打开终端解压:
所有后续 GPU 命令都在这个项目目录执行。Notebook 会打印实际绝对路径;不要在 notebooks/ 内再解压出第二层项目。已有旧版项目时,在另一个目录解压新版,保留原来的 runs/ 和模型下载目录,不要直接覆盖训练结果。
上传包里有什么¶
压缩后约 4 MB,解压后约 17 MB,共 31 个文件。它只放“在 GPU 上训练和部署需要、但网上下载不到或必须和本教程一致”的东西:
llm-lora-tutorial/
├── GPU_UPLOAD_README.md GPU 上的操作速查:建环境 → 下权重 → 打开 Notebook
├── notebooks/01_gpu_train.ipynb 训练主入口,第 4 章逐格执行
├── data/
│ ├── dataset.json 唯一的数据文件:事实卡 + train/val/test 对话(第 2 章)
│ └── README.md 数据逐字段说明
├── lab/ Notebook 和命令行共用的 Python 代码
│ ├── common.py 拼提示词、生成训练样本和掩码(第 2.5 节)
│ ├── data.py 读入并校验 dataset.json、按回答拆样本
│ ├── download.py 下载并校验基座权重(第 3.4 节)
│ ├── download-lock.json 12 个模型文件的大小和 SHA-256,下载后逐个核对
│ ├── training.py、train.py 训练器配置与命令行训练(第 4.6 节、第 6 章)
│ ├── prepare.py、audit.py 命令行快照与 Token 检查(第 4.6 节、第 6 章)
│ ├── infer.py、evaluate.py A/B/C 对照推理与盲评(第 6 章)
│ └── merge.py 命令行合并 adapter(第 5.1 节)
├── models/qwen3-4b/ 基座的“说明部分”,没有权重
│ ├── config.json 等配置 模型结构、默认生成参数
│ ├── tokenizer.json、vocab.json、merges.txt、tokenizer_config.json 分词器和聊天模板
│ ├── model.safetensors.index.json 权重分片索引(分片本身还没下载)
│ ├── model-lock.json 本教程固定的模型版本号
│ └── LICENSE、README.md 模型许可证与模型卡
├── requirements-train.txt 训练依赖(Transformers、PEFT、TRL、bitsandbytes 等,版本固定)
├── requirements-download.txt 下载依赖(ModelScope;备用镜像用的 huggingface_hub 随 Transformers 安装)
├── requirements-notebook.txt Jupyter 内核与画 loss 曲线的依赖
├── requirements-data.txt 数据检查依赖
└── pyproject.toml 项目元数据
| 包里没有的 | 原因 | 从哪里来 |
|---|---|---|
8 GB 权重分片 model-0000X-of-00003.safetensors |
太大,上传慢;GPU 主机从国内源下载更快 | 第 3.4 节在 GPU 上下载,按 download-lock.json 校验 |
| PyTorch 和其他依赖本身 | 和显卡、CUDA 版本绑定,要在 GPU 主机上装 | 下面的 pip 命令按 requirements-*.txt 安装 |
训练结果 runs/、快照 data/processed/ |
都是在 GPU 上生成的产物 | 第 4 章训练、第 4.6 节生成快照时产生 |
自动化测试 tests/、电子书源码 |
GPU 上用不到 | 完整项目或电子书“源码下载”页(第 8.1 节) |
带分词器是为了让 GPU 主机在下载权重前就能核对模型版本,下载时只需补齐三个权重分片。Notebook 直接读 data/dataset.json,不需要先运行 lab.prepare。50 GB 数据盘需要同时容纳训练环境、原权重、合并权重和推理环境;完整部署建议扩到 100 GB。
在 GPU 终端建立项目环境:
python3.11 -m venv .venv-train
.venv-train/bin/python -m pip install --upgrade pip
.venv-train/bin/python -m pip install torch==2.8.0 --index-url https://download.pytorch.org/whl/cu126
.venv-train/bin/python -m pip install -r requirements-train.txt -r requirements-download.txt -r requirements-notebook.txt
.venv-train/bin/python -m pip check
.venv-train/bin/python -m ipykernel install --user --name lora-train --display-name "LoRA · Python 3.11"
训练使用固定版本 Torch/Transformers/TRL/PEFT;ModelScope 只负责下载;ipykernel 让平台 Jupyter 使用这套环境。已经按旧教程装好 .venv-train 时,可复用它,补装新增依赖并注册内核。普通 Python 包源连接慢时可使用平台提供的 PyPI 镜像;模型下载源与 pip 软件包源是两回事。
连不上 download.pytorch.org 时(报 Network is unreachable 或一直重试): 第三条命令用 --index-url 把下载地址临时换成了 PyTorch 官方源,国内主机常常访问不到。只换普通 PyPI 镜像(清华、阿里等)解决不了:它们只有 PyPI 上的默认版 torch 2.8.0(内置 CUDA 12.8),下面的自检要求 12.6。改用阿里云的 PyTorch 镜像,它有同一个 2.8.0+cu126 包:
.venv-train/bin/python -m pip install 'torch==2.8.0+cu126' -f https://mirrors.aliyun.com/pytorch-wheels/cu126/
-f 只让 pip 去这个页面找 torch 本体;torch 依赖的 nvidia-*、triton 等包仍从你配置的 PyPI 源下载。版本号写成 2.8.0+cu126,避免 pip 装成 PyPI 上的 cu128 版本。装好后接着执行上面第四条命令(requirements-*.txt),后续步骤不变。想长期固定 PyPI 源,可执行 .venv-train/bin/python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple,用 pip config list 查看当前配置。
.venv-train/bin/python - <<'CHECK'
import sys, torch, transformers, trl, peft, bitsandbytes
print("Python:", sys.executable)
print("Torch / CUDA:", torch.__version__, torch.version.cuda)
assert torch.__version__.split("+")[0] == "2.8.0"
assert torch.version.cuda == "12.6"
assert torch.cuda.is_available() and torch.cuda.is_bf16_supported()
print("GPU:", torch.cuda.get_device_name(0))
print("依赖:", transformers.__version__, trl.__version__, peft.__version__, bitsandbytes.__version__)
CHECK
通过后才继续。若 CUDA 不可用,先检查内核、驱动和 wheel;镜像预装 Torch 2.7.1 不能代替本项目环境。内核注册方式依据 IPython 官方文档。
3.4 在国内 GPU 主机下载完整权重¶
默认操作使用阿里系的 ModelScope / 魔搭,仓库是 Qwen/Qwen3-4B-Instruct-2507。它有自己的 SDK,不是把 HF_ENDPOINT 指向魔搭首页。
不要加 --tokenizer-only。这个命令会保留上传包里的 model-lock.json 和已核对的分词器,补齐缺少的三个权重分片。网络中断后重跑同一命令,保留 .cache 与版本锁,不需要重新准备数据。
download.py 依据 download-lock.json 核对远端文件大小、SHA-256,再核对实际下载内容。魔搭使用 master 获取文件,但必须与本次锁定的 Hugging Face revision 字节一致;若仓库内容变了就停止,避免混用版本。清单中的 12 个文件已核对两边元数据,三个权重约 8.0 GB(十进制)。
下载后可以独立执行离线检查:
只有出现 “校验通过:12 个文件;完整模型权重已就绪”,且命令正常结束,才进入训练。文件目录应有:
models/qwen3-4b/
├── model-lock.json
├── config.json
├── tokenizer.json
├── tokenizer_config.json
├── model.safetensors.index.json
├── model-00001-of-00003.safetensors
├── model-00002-of-00003.safetensors
└── model-00003-of-00003.safetensors
其他配置、词表和许可证也要保留。只看到 model-lock.json、权重索引,或日志写着 Returning existing local_dir,都不意味着权重已下载。新版下载器会拒绝这种不完整结果。
备用:通过 Hugging Face 国内镜像下载¶
魔搭服务不可达时,可以显式选择 hf-mirror.com:
.venv-train/bin/python -m lab.download --source hf-mirror --output models/qwen3-4b
.venv-train/bin/python -m lab.download --check-only --output models/qwen3-4b
代码将镜像地址显式传给 Hugging Face SDK,不需要修改安装包源码或永久改全局环境变量,并继续使用同一版本锁与文件校验。此镜像是独立的第三方服务,不是阿里云官方魔搭;能否访问取决于 GPU 主机网络。依据 Hugging Face 下载接口。
已在开发机实测魔搭配置/分词器下载并校验通过,三个大权重文件也通过了少量字节的下载测试。尚未在这台 GPU 主机下载 8 GB 完整权重,最终以主机上面的完整校验结果为准。
| 现象 | 怎么处理 |
|---|---|
huggingface.co / Network is unreachable |
使用明确的 --source modelscope,或备用 --source hf-mirror |
| 缺权重分片 | 在同一目录重跑完整下载,不加 --tokenizer-only |
| 本地文件哈希不匹配 | 把报错文件移到旁边备份后重下,保留版本锁;不要跳过检查 |
| 远端文件与锁定版本不一致 | 停止使用该来源,尝试另一个来源获取锁定内容;不要直接修改哈希放行 |
No space left on device |
核对项目所在分区并扩容/迁移到数据盘,不删除未备份的实验结果 |
3.5 打开 Notebook,从模型训练开始¶
在 JupyterLab 打开 01_gpu_train.ipynb,选择 LoRA · Python 3.11 内核。未看到时刷新 Jupyter;不要选择镜像自带的普通 Python 3 内核。
第一次用 Jupyter 的话,只需要知道这几件事:
| 操作 | 怎么做 |
|---|---|
| 执行当前格 | 点进代码格,按 Shift+Enter;执行后自动跳到下一格 |
| 判断是否在运行 | 代码格左侧 [*] 表示正在跑,[3] 这样的数字表示第几次执行完成 |
| 看输出 | 输出直接显示在代码格下方;太长会折叠,点左侧蓝条展开 |
| 换内核 | 菜单 Kernel → Change Kernel;右上角显示当前内核名 |
| 重来 | Kernel → Restart Kernel 清空内存里的所有变量,磁盘上的文件不受影响 |
| 释放显存 | Kernel → Shutdown Kernel;关闭浏览器标签页不会释放 |
Notebook 使用直接的 Python 训练代码,每个代码格下面分三段:做什么、为什么、执行后你会看到。第三段写出预期输出和每个数字的含义,你的实际值会略有不同。第 1 格设置 ROOT 和 RUN_DIR,默认结果是 runs/science-001/。从项目或 notebooks 目录打开时会识别路径;其他位置手工填写 ROOT。
接下来按第 4 章逐格训练。原模型回答也是 Notebook 的一部分,无需额外运行旧版 A/B 命令。