我有 Python 基础,但还没有系统学过深度学习。最近看 Happy-LLM,准备从 PyTorch 开始,逐步弄懂模型结构和训练过程。
最初的问题很实际:手上的 M1 Pro、32GB 内存,够不够用?继续往下看,又产生了另一个疑问:模型文件不过几 GB、十几 GB,为什么训练时会需要那么多显存,还要连续运行很多小时?
这两个问题连在一起,才能把“训练成本”说清楚。参数量决定了需要处理多大的模型,训练方法决定了要保存什么,而数据量和实验次数决定了这些工作要重复多久。
下面是我在开始动手前整理的一笔资源账。硬件配置已经检查过;文中的容量计算有明确假设,尚未做完整的大模型训练测速。
一次训练,比一次预测多做了什么
先看一个只有两个参数的模型:
|
|
x 是这次输入的数据,w 和 b 是模型内部可以调整的参数。假如希望模型从样本中学会 y = 2x + 1,训练就需要让这两个数逐步接近 2 和 1。
一次普通预测,只需要把输入代入当前公式。一次训练更新,则要经历更多步骤:
|
|
loss 用来衡量预测与目标的差距,梯度提供调整参数的方向信息,优化器负责执行更新。PyTorch 的训练循环就是在组织这些步骤。PyTorch 参数优化教程
两个参数的计算很轻。换成数十亿参数的网络,同样的流程会涉及大量矩阵运算和数据搬运,而且需要在许多批数据上反复执行。训练最终保存下来的是参数,但获得这些参数的过程远比读取一次文件复杂。
模型文件大小,只是内存账的一部分
模型名称里的 7B,通常表示约 70 亿个参数。先做一个只计算权重的估算:
|
|
如果所有参数都用 16-bit,也就是 2 字节保存,70 亿个参数大约需要 14GB。假设全部用 4-bit 保存,纯参数位数对应约 3.5GB;实际量化文件还包含缩放系数、元数据,以及可能保留更高精度的部分。
这些数字都只是权重的存储量。推理时还需要计算中间结果、缓存和运行时空间。训练时,要继续加上梯度和优化器状态;供反向传播使用的中间结果,也可能占用大量内存。Hugging Face GPU 内存说明
为了看清量级,假设一个 7B 模型进行全参数训练,参数和梯度都用 FP32,也就是每个值占 4 字节的 32 位浮点数;Adam 的两份状态也用 FP32,全部放在同一设备上:
| 保存的内容 | 每个参数对应的字节数 | 7B 模型的估算占用 |
|---|---|---|
| 参数本身 | 4 | 28GB |
| 梯度 | 4 | 28GB |
| Adam 的一阶矩状态 | 4 | 28GB |
| Adam 的二阶矩状态 | 4 | 28GB |
| 上述四项合计 | 16 | 112GB |
Adam 会维护一阶、二阶矩估计,作为更新参数的历史信息。这里的表格根据指定精度计算,GB 按十进制计;还没有加入各层产生并供反向传播使用的中间激活、临时张量和框架开销。PyTorch Adam 文档
112GB 是这组假设下的估算,不能当成所有 7B 训练的固定要求。混合精度、不同优化器、参数分片和卸载都会改变结果。它说明的是:“这个量化模型能装进我的电脑”和“我能更新它的全部参数”,需要分别判断。
算力账单取决于要重复多少次
内存首先决定一次计算能否放得下。放得下以后,还要看多久才能完成。
同样的模型,训练十万条短样本和训练数十亿个 token,工作量会差很多。token 是模型处理文本的单位,可以是一个字、词的一部分或其他文本片段。
假设有 10 万条样本,平均每条 512 个 token,完整遍历 3 轮,也就是 3 个 epoch。忽略补齐序列长度(padding)等额外开销,需要处理的 token 数量约为:
|
|
这已经是约 1.54 亿个 token。它不能直接换算成固定的训练小时数:模型结构、序列长度、精度、硬件、数据读取速度和实现方式都会影响吞吐。
对按 GPU 卡时收费的服务,算力费用可以先写成:
|
|
卡数增加也不保证训练时间按相同比例缩短,多卡之间需要通信,数据准备也可能成为瓶颈。实际选择时,需要比较完成同一项实验的总时间和总费用。
更容易遗漏的是实验次数。调整学习率、换数据格式、比较不同训练轮数,都可能再跑一遍。一次成功训练用了 20 小时,如果前后测试了五套相近配置,应该把这些实验一起记到账上。
因此,预算的对象最好是一轮完整实验:准备数据、调试、训练、评估,以及根据结果做出的下一次修改。
从零训练、全参数微调和 LoRA,投入方式不同
讨论训练费用前,先说明准备改变模型的哪一部分,会更容易比较。
| 方式 | 从哪里开始 | 更新哪些参数 | 成本特点 |
|---|---|---|---|
| 从零预训练 | 随机初始化的模型 | 通常更新全部参数 | 要从数据中建立基础能力,通常需要大量数据和训练步骤 |
| 全参数微调 | 已经训练好的模型 | 全部参数 | 利用已有能力适应目标任务,通常减少数据和步骤,但每一步仍有较高的内存需求 |
| LoRA 微调 | 已经训练好的模型 | 少量新增的低秩参数 | 减少需要训练、保存梯度和优化器状态的参数量 |
LoRA 的做法,是保留原有权重,在选定位置加入较小的可训练矩阵。基础模型保持冻结,只更新新增的部分。它适合用较少的训练参数调整模型在特定任务上的表现。Hugging Face LoRA 说明
QLoRA 进一步让基础权重以量化形式保存。这里节省的是基础权重占用,并不表示所有计算、梯度和中间结果都变成 4-bit。
即使采用 LoRA,基础模型仍要参与计算,还要为适配器计算梯度。文本很长、每批样本数(batch size)很大时,仍然可能超出内存。MLX 的微调文档也把缩小 batch、缩短样本、减少训练层数和使用梯度检查点列为控制内存的方法。梯度检查点会重新计算一部分中间结果,以额外计算换取更少的内存占用。MLX LoRA 与 QLoRA 文档
对个人学习者来说,LoRA 提供了一个有用的台阶:先利用已有模型做小规模实验,观察数据和训练配置如何改变结果。
GPU 以外,还有几笔容易漏掉的账
数据处理需要时间。 数据可能重复、格式不一致,或者输入与答案没有正确对应。下载一个数据集以后,还需要检查样本、清洗和划分训练与验证数据。直接扩大训练规模,会让数据问题跟着放大。
评估决定这次训练有没有价值。 训练 loss 下降,只说明模型更适应训练目标。它在新问题上的表现、格式遵循和原有能力是否发生变化,都需要用独立样本检查。人工检查花时间,调用其他模型辅助评估也可能产生费用。
存储和恢复影响重复劳动。 一次实验可能保存多个检查点。为了恢复训练,检查点还可能包含优化器等状态,大小不能只按最终发布的权重文件估算。保存过于频繁会增加磁盘和 I/O 开销,完全不保存则可能在中断后重做大量计算。
本地机器也有使用成本。 已有电脑上的小实验,直接支出主要是电费;较长训练还会持续占用内存和计算资源,影响同时进行的工作。对我目前的阶段,读懂数据、定位报错和解释结果所花的时间,更值得认真记录。
把问题放回这台 32GB Mac
我的电脑是 M1 Pro,10 核 CPU、14 核 GPU,32GB 统一内存。统一内存由系统、应用、CPU 和 GPU 共同使用,不能把它理解为 32GB 内存之外还有一份独立显存。
PyTorch 可以通过 MPS 使用苹果 GPU,适合逐步开展本地学习实验。具体代码仍要检查设备支持,使用 CUDA 专属接口或相关依赖的脚本需要适配。Apple 的 PyTorch MPS 说明
我会把第一轮实践安排成三个阶段:
| 阶段 | 实验 | 需要获得的结果 |
|---|---|---|
| 弄懂训练循环 | 线性回归、小型 MLP 分类器 | 能独立完成预测、loss、反向传播、更新和验证 |
| 看清资源变化 | 小型 Transformer,逐项调整 batch 和序列长度 | 记录耗时、峰值内存和验证表现,知道瓶颈来自哪里 |
| 尝试任务适配 | 在兼容框架中,用小模型和小数据做 LoRA | 比较微调前后同一组独立问题的表现 |
等前面的训练循环和资源记录都熟悉以后,再考虑更大的模型或租用 GPU。这样决定花钱时,已经知道当前缺的是内存容量、计算速度,还是数据和实现上的改进。
下一次实验,我准备先用 y = 2x + 1 拟合一条直线,记录学习率、训练步数、loss 和最终参数。把这几个数字之间的关系解释清楚,再把模型放大。