实验室的GPU又一次被训练任务占满了,而这回轮到我自己要用。等了三个小时后,我决定不再排队,直接把实验拆成几份:数据预处理留在本地CPU工作站上跑,模型训练切给某个临时租来的云端实例,小规模消融实验在CPU上过一遍再说。那台机器倒也没让我失望,半天时间,原来要排两天队的实验跑完了。这段经历让我意识到,实验室无GPU这件事,真正的问题不是"没法做深度学习",而是"没有针对无GPU条件设计一整套工作流"。
这篇内容就是为那些还在CPU集群或者普通台式机上做深度学习的人准备的——可能是研究生,也可能是初创团队里的算法同学,还可能是想入门的自学者。下面我会从算力边界判断、替代算力方案、CPU优化、模型压缩、代码适配和课题选择六个方面,给出我反复验证过的一整套可复用的做法。如果你正被"没有显卡"卡住,这篇文章应该能帮你把课题继续推进下去。
1. 先盘算力家底:无GPU环境的边界到底在哪里
1.1 先算一笔账:你的机器实际能承载多大的模型
很多人以为"没有GPU就做不了深度学习",但实际操作下来,很多任务在纯CPU上是可以跑的,只是需要严格控制模型规模、数据量和迭代次数。第一件事永远是盘家底,重点看三样硬件:CPU核数、内存大小、磁盘读写速度。
- CPU核数决定矩阵乘法的并行上限。桌面级16线程工作站,能比较舒服地训练百万参数级别的小模型。32线程以上的服务器CPU,能把千万参数模型从"跑不动"变成"慢但能跑"。
- 内存大小决定batch size和数据集能否全部载入。16GB内存勉强够一个小型Transformer微调,32GB以上可以把预处理结果直接缓存到内存里,省掉大量IO等待。
- 磁盘类型容易被忽视。SSD和机械硬盘在数据增强频繁时差距能到5到10倍,数据管线如果反复读图做随机裁剪,机械盘往往比CPU还明显的瓶颈。
用这个粗略公式估算一下训练代价:参数量×单条样本前向计算量×样本数×epoch数。举一个实际例子,一个参数规模在1亿左右的BERT类轻量模型,在12核CPU上做文本分类微调,跑一个epoch大约需要30到60分钟;如果数据量只有几千条,几个epoch跑完就是一个晚上的事。这完全在可接受范围里。
1.2 划分"可跑""勉强可跑""不该跑"三类任务
我把深度学习任务粗略分成三档,在选题的时候不用一直纠结:
| 任务类型 | CPU可行性 | 典型例子 |
|---|---|---|
| 可跑 | 表格数据、小规模文本分类、图嵌入、特征融合、小模型微调 | 几千样本的文本分类、结构化数据的MLP集成、微型Transformer蒸馏 |
| 勉强可跑 | 中等规模图像分类、序列标注、小模型对比学习 | 一个epoch几十分钟,需要接受数天训练周期 |
| 不该跑 | 大模型预训练、大规模图文预训练、超大batch对比学习 | 动辄几十亿参数,CPU上硬跑等于浪费生命 |
这条分界线不是固定的,但提供了一个重要判断逻辑:无GPU条件下,优先选择"参数规模小、收敛轮次少、数据量可控"的任务。很多人在实验室用CPU硬跑一个大模型,跑了一星期还没收敛,最后只能放弃,这才是真正的时间黑洞。所以第一步永远是先算清楚时间账,再决定方案。
2. 补算力的四条路:免费额度、按量付费、共享硬件与混合分工
2.1 四种方案的真实体验与适用场景
盘完家底之后,如果发现任务规模和CPU能力的差距太大,下一步是给实验"补算力"。我试过四条路,分别记一下体验:
- 免费在线开发环境:适合入门实验、小规模验证、教学场景,提供免费CPU和少量GPU额度。缺点是GPU配额不稳定,跑稍大任务会断连,而且数据上传下载比较麻烦。优点是启动成本为零,学生拿来跑课程作业和小实验的对比验证足够了。
- 云厂商按量付费GPU实例:这是无GPU实验室最推荐的补充路线。按小时计费,用完就释放,适合几天到几周的集中训练。不用的时候不心疼,用的时候能上比较大的模型。关键是选对计费方式和实例规格,后面细说。
- 二手入门级显卡:适合预算只有两三千块的团队。选二手入门卡,显存普遍在8GB到12GB之间,跑中小规模CNN和轻量级Transformer微调都没问题。坑点是需要自己配电源、散热,还有一定概率碰到长时间高负载跑过的卡,最好带着满载压力测试工具当场验证。
- 混合分工:把数据预处理、baseline实验放在CPU上做,把最终的大规模训练放到云上或本地显卡上做。这样云GPU的每一分钟都真正用于训练,而不是浪费在CPU预处理上。
2.2 云实例的选型踩坑与数据安全
云实例选型,我建议优先关注三件事:显存容量、计费模式和网络带宽。显存决定能不能装下模型加batch,网络带宽决定数据上传时间。之前踩过一次坑,花了三个小时上传数据集,最后发现实例规格选小了,显存装不下,直接重来。所以现在的流程是:先本地把数据压缩、脱敏、整理好,再上传,做时间预算的时候一开始就把上传耗时算进去。
数据安全必须重视。很多实验室的数据不能出内网,这时候就应该用脱敏脚本把所有样本去标识化后再上传,或者干脆选择纯CPU方案,不让数据离开本地。我的习惯是在实例上开启地址白名单访问,用完立刻释放,不做任何持久化存储,从根本上减少数据暴露的风险。
成本控制上,建议设一个硬性预算上限。比如一个实验只值三百块,那么每天最多用两小时贵实例,其余时间让它在后台自己跑。按量付费和包时套餐之间有明显价差,同一型号实例包月分摊到每天往往不到按量的1/3。如果整组人经常要用,不如合租一台长期实例,比反复开机关机划算得多。
3. CPU单机优化清单:把纯CPU训练从"不能忍"变成"可以跑"
3.1 框架级调优:CPU加速扩展包、线程数与内存布局
既然决定在CPU上跑,就不要用默认内存布局和默认线程配置。我做的第一步是安装PyTorch生态中某个芯片厂商提供的CPU加速扩展包,社区里一般直接叫它ipex。装上之后,在训练脚本里加两行优化设置,模型推理和训练在部分常见模型上能获得明显加速,尤其在同一芯片厂商的CPU搭配对应指令集时,收益最明显。对其他厂商CPU,至少保留默认配置也能跑,只是加速幅度没那么夸张。
线程数设置也是一个容易踩的坑。默认情况下,PyTorch会开满所有逻辑核,但深度学习任务是典型的内存带宽消耗型,线程开太满反而会因为缓存争抢变慢。我的经验是:先留出1到2个核心给DataLoader和数据预处理,训练线程数设置为物理核数减一,然后跑一遍基准测试确认耗时。比如一个24线程机器,torch.set_num_threads(22),配合OMP_NUM_THREADS=22,实测比24线程全开反而快了10%左右。
内存布局同样值得调。如果跑的是CNN类模型,把输入张量转成channels_last格式,也就是PyTorch里的一行to(memory_format=torch.channels_last),卷积算子的访存效率会明显提升。如果跑Transformer类模型,保持默认布局即可,转格式没有意义。PyTorch 2.x之后的torch.compile在CPU上也能用,它会把子图融合,减少算子启动开销,我在一个图像分类小模型上实测节省了大概15%到20%的单epoch耗时,代价是第一次编译会花掉几分钟到十几分钟,属于一次投入、长期受益。
3.2 数据管线优化:让CPU时间都花在矩阵乘法上
很多人在CPU上训练慢,其实慢的不是矩阵乘法,而是数据读取。数据管线一旦成了瓶颈,CPU核心大部分时间都在等数据,利用率上不去。无GPU环境下,DataLoader的配置要到"每轮都能吃满CPU"才算合格。
几个具体配置项,按优先级排列:第一,num_workers至少设为2到4,不能是0,否则主进程既要做数据增强又要做训练,两边都卡。第二,prefetch_factor调到2以上,让下一个batch的数据在训练进行时提前准备。第三,数据预处理结果能缓存就缓存,比如随机裁剪、缩放这类增强操作,对同一份训练集每次epoch都重复做太浪费了。可以把预处理后的张量直接以序列化格式存到磁盘或内存,训练时直接读张量,原始图片读取和增强只做一次。
如果你做的是文本模型,建议把所有句子提前tokenize到固定形状的id矩阵,训练时直接用索引切片,不要每个batch在线调用tokenizer。在线tokenize在CPU上开销非常大,我以前踩过这个坑,一个epoch从4小时直接降到50分钟,只因为把tokenize从训练循环里挪到了预处理阶段。
3.3 训练策略调整:梯度累积、early stopping与混合精度误区
CPU训练还要主动调整训练策略。最实用的三招:梯度累积、早停、超参小范围预热。
梯度累积解决的是"显存小所以batch小"的问题。CPU没有显存限制,但batch太大也不行,单步计算时间太长,收敛效率反而下降。我的做法是保持单步batch在16到32之间,每4步累积一次梯度再更新参数,等价于一个大batch的效果。在PyTorch里就是loss.backward()之后不调optimizer.step(),等累积步数到了再一次step和zero_grad。
早停在这种慢训练里特别重要。因为没有GPU推着你快速迭代,一个错误配置可能要跑十几个小时才会暴露。一定要在前几百个step里把验证集指标打出来观察,并设置patience参数,连续几个epoch验证集没有改善就停止。我自己的习惯是最多连续3个epoch没提升就直接停掉,省下来的时间足够开新实验。
混合精度在CPU上要格外小心。很多人习惯把GPU上训练的自动混合精度代码直接搬过来,换成CPU模式,结果发现没有加速,有时候反而更慢。CPU上的低精度运算在很多架构上并没有对应的快速指令,收益远不如GPU明显。所以CPU训练优先保持float32,只有在推理阶段且模型支持动态量化时,再考虑低精度方案。
4. 模型侧减负三板斧:量化、剪枝、蒸馏的真实收益边界
4.1 量化:训练期省不了,推理期很值
模型压缩三件套是"无GPU深度学习"里最值得下功夫的。先说明白一件事:量化主要省钱在部署和推理阶段,而不是训练阶段。如果你需要反复训练同一个模型来迭代,量化帮助有限;但如果你要在资源受限设备上部署模型,或者想把一个用云端GPU训好的模型塞进实验室老机器里跑,量化就能派上大用场。
两种常用方案,训练后静态量化(PTQ)和量化感知训练(QAT)。PTQ操作简单,拿一批校准数据跑一遍,把权重和激活从高精度映射到int8,速度提升明显,代价是精度小幅下滑。QAT则把量化误差模拟进训练过程,精度保持更好,但需要额外训练,在CPU上训练成本偏高。如果课题方向就是"低精度模型部署",QAT本身就是研究对象,即便没有GPU也可以做小模型版本的对比实验,产出量并不低。
4.2 结构化剪枝比权重稀疏更实用
剪枝分结构化剪枝和非结构化剪枝两类。非结构化剪枝把权重矩阵里接近零的元素直接置零,参数稀疏率能做得很高,但CPU上普通算子没办法利用这种稀疏性,实际计算时间并不会减少。结构化剪枝直接移除整个通道、过滤器或注意力头,虽然精度损失略大,但剪完之后矩阵变薄了,CPU计算可以直接受益。对无GPU的场景,结构化剪枝是性价比更高的方向。
举个例子,一个图像分类模型有多个卷积层,输出通道数逐层增加。如果中间某一层被剪掉一半通道,后续所有层的输入通道都会跟着变少,前向计算量能有明显下降。做这一步时先把每一层的归一化通道缩放因子拿出来排序,把贡献低的通道剪掉,再微调几个epoch恢复精度。整个流程在CPU上可以完成,数据集控制在几千张以内时,每个微调epoch也就十来分钟。
4.3 知识蒸馏:最稳定的实验产量来源
蒸馏是最适合无GPU环境产出的技术路线。用一个大模型的软标签去教一个小模型,小模型往往能逼近大模型的精度,但参数量和推理成本少一个数量级。更妙的是,蒸馏实验在CPU上也能做,因为student模型很小,teacher的推理只需要跑一次离线,把所有的logits存成文件缓存下来,后续训练完全不依赖teacher。
具体做法是:先在云上用GPU把teacher模型跑完,保存所有样本的logits;然后回到CPU本地,用KL散度蒸馏loss让student去拟合这些logits。温度T一般取2到5,loss里软标签和真实标签按0.5比0.5或0.7比0.3加权。我试过一段文本分类实验,teacher是2亿多参数的模型,student只有3000万参数左右,在CPU上跑5个epoch收敛后,精度只掉了不到2%,推理速度快了不少。这个方向的实验周期短、可对比性强,做消融实验也好做——可以换teacher大小、换student结构、换温度超参,每换一组就是一组有效数据。
5. 无GPU环境特有的代码改造和踩坑清单
5.1 跨设备加载checkpoint:map_location是第一课
实验室经常出现这种情况:组里一台有GPU的机器上训好的模型,拿到无GPU的机器上继续做推理或二次开发。在CPU上加载GPU保存的checkpoint,不指定设备映射会直接报错,提示在CPU上尝试加载计算设备张量。正确写法是torch.load(ckpt_path, map_location='cpu'),模型再用load_state_dict加载。别小看这一行代码,很多同学在这一步卡了一两天,还以为是模型文件坏了。
跨设备保存也有讲究。建议只保存裸的state_dict,而不是整个模型对象。整个模型对象里会带设备信息、类路径等额外内容,跨环境加载特别容易出问题;state_dict只是参数张量字典,干净且兼容性最好。顺手在脚本里把模型输入输出的数据类型和维度打印出来,能省掉后续大量排查时间。
5.2 数据装载和进程数的隐性踩坑
无GPU机器往往内存也不大。DataLoader设num_workers过高时,多个worker会把内存撑爆,特别是图像数据集经过增强后,每个worker都会复制一份缓存。我之前在16GB内存的机器上把num_workers调到8,跑了两分钟内存就满了。调回2到4,并限制单个批次解码范围,内存就稳定住了。
另一个隐性坑是内存泄漏。长时间跑实验时,每个epoch结束后的loss、缓存、验证集预测结果如果不及时清理,内存占用会逐轮升高,最后把机器拖死。养成习惯:每个epoch结束后主动释放大对象引用,必要时加上gc.collect(),这在无GPU机器上尤其重要,因为一旦触发交换区,训练速度会断崖式下跌。
5.3 合理规划训练时间:给任务设置"熔断"
无GPU训练最难过的是时间不可控。同样的实验在GPU上10分钟跑完,在CPU上可能跑一晚上,中间如果代码有bug,损失完全是两个量级。我建议在脚本里加硬性超时控制:设定训练最多跑几小时,到点自动保存当前最优模型并退出。可以用时间戳判断,也可以在每一个epoch开始时检查运行时长。这样晚上离开实验室前启动一个任务,第二天早上来能看到一个保存好的模型或一条超时日志,而不是一个跑了一夜还没结束的进程。
对长时间训练任务,要定期把最优模型持久化到磁盘。我一般每两个epoch保存一次带验证指标命名的checkpoint,只保留最新两份,防止磁盘被checkpoint占满。
6. 选题策略:把"没GPU"变成课题筛选器
6.1 适合无GPU深耕的方向
如果摆在面前的两个课题,一个需要大规模预训练,一个做模型压缩和部署,无GPU环境下应该选哪个,答案很明确。我把适合方向总结成一个简表:
| 方向 | 为什么适合无GPU环境 | 参考做法 |
|---|---|---|
| 模型压缩(量化、剪枝、蒸馏) | 研究对象本身就是变小变快,实验成本天然低 | 先云端训大teacher,CPU训小student |
| 小样本学习 | 数据量少,训练轮次少,CPU完全兜得住 | 用公开小数据集,关注学习方法而非规模 |
| 可解释性分析与鲁棒性测试 | 主要是推理和调试,不需要大量训练 | 在CPU上加载预训练模型做归因分析 |
| 轻量化网络结构搜索 | 搜索空间小、候选结构少 | 用代理任务在CPU上做采样评估 |
| 表格数据与特征工程 | 数据量适中,MLP和集成模型对GPU依赖很低 | 直接CPU跑,还能和深度模型做对比 |
这些方向有一个共性:不依赖"大算力堆叠",而是依赖实验设计和分析深度。可持续的研究产出由逻辑和测量结果支撑,而不是靠烧显卡烧出来的。
6.2 明确避开的方向
同时也要诚实说清楚哪些方向别碰。大规模预训练语言模型、超大规模多模态对齐、基础模型的可扩展性研究,对GPU集群的要求是无GPU环境补不上来的。这类课题即便拿到了云资源,成本也不是常规预算能覆盖的。另一个容易踩雷的是大batch对比学习,它对显存和通信带宽的要求极高,CPU方案和入门显卡方案都做不了。
这并不意味着彻底不能沾这些方向,而是要把触角换成"用别人的底座做二次开发":使用别人已经开源的小模型、预提取的特征或教师输出做后续工作,核心实验仍然落在自己可控的小规模任务上。
6.3 一个三个月周期的时间预算样板
最后给一个时间预算样板,适合写课程论文或小论文的前期探索。第一个月:在CPU上完成数据清洗、baseline模型和消融实验设计,跑通所有依赖,关键代码全部适配无GPU配置。第二个月:租用一台按量GPU实例,把需要大算力的teacher训练和主力模型全量实验集中在两周内做完,同时CPU上的小规模实验并行推进。第三个月:收尾消融、画图、整理结果,这时已经进入写作阶段,对GPU的需求会直线下降。
这个计划的核心是避免"每一步都等GPU"的串行节奏。让CPU干活的同时,云GPU只处理最贵的那一段计算,两者并行,整体周期能缩到原来的一半。我实际执行下来,感觉最重要的不是硬件,而是把实验流程拆成可并行、可回滚的小块——这比有一块好显卡更重要。
我在这套流程里反复试了半年多,最大的体会是:无GPU并不可怕,真正可怕的是没有按算力预算来设计实验。实验室没有显卡,反而逼着我把实验拆得更细、流程排得更顺。现在哪怕有GPU可用,我也保留着先跑CPU小实验再上大算力的习惯,这个习惯让很多明显跑不通的方案在浪费算力之前就被拦了下来。
如果你正好也卡在无GPU的实验室里,别急着去买卡或开一堆实例。先花一周时间盘清楚家底,把数据管线和训练策略调好,再给每个实验设置时间和费用的双重边界。坚持两三个月,你会发现自己比那些只依赖硬件的人,更清楚每一步计算到底换回来了什么。