news 2026/10/1 2:09:44

ML 工程中的 CPU 内存配置指南:容量规划、典型用途与 mmap 内存误报排查(ml-engineering)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ML 工程中的 CPU 内存配置指南:容量规划、典型用途与 mmap 内存误报排查(ml-engineering)
  • 人工智能
  • 大模型
  • AI 技能/插件
  • 分布式训练
  • 微调
  • 深度学习

【免费下载链接】ml-engineering

Machine Learning Engineering Open Book

项目地址:https://gitcode.com/gh_mirrors/ml/ml-engineering
点击查看免费下载

CPU 内存(RAM)往往是 ML 训练集群规划中最容易被忽视的一环:GPU 显存有明确的规格书,而节点内存的"够用"标准却缺乏量化依据。本篇指南基于 ml-engineering 仓库的 compute/cpu-memory/README.md 章节,系统讲解 CPU 内存的容量下限经验法则、六大典型用途(权重加载/保存、参数与激活 offload、DataLoader 预取、软件运行时开销),并深入剖析 DataLoader 使用 HFdatasetsmmap 模式时出现的"Resident 内存异常占用"误报问题。读完你将能够为自己的 8 卡节点制定合理的内存采购与分配方案,并能正确解读top/free中的内存指标,避免被 mmap 映射产生的假象误导。

CPU 内存:越少人需要操心的部分越好

ml-engineering 将 CPU 内存章节定位为全书最短的章节之一(见 compute/README.md 的描述:"how much CPU memory is enough - the shortest chapter ever"),因为相对于 GPU 显存,CPU 内存的调优空间很小——这本身是件好事。绝大多数 ML 计算发生在 GPU 上,CPU 内存主要扮演"数据中转站"和"后备仓库"的角色。

这一"简短"建立在一条清晰的经验法则之上:

每个节点的 CPU 内存至少应与该节点的 GPU 显存总量持平。

例如,一个 8× 80GiB H100 节点拥有 640GiB GPU 显存,那么该节点的 CPU 内存就至少应为 640GiB。主流云厂商的高端机型通常标配 1–2TiB CPU 内存,完全可以覆盖这一需求。这条规则确保了任何需要先在 CPU 侧落脚、再流向 GPU 的数据都有足够的周转空间。

ML 工作负载中 CPU 内存的六大用途

虽然 GPU 承担了绝大部分计算,但以下六类操作都离不开 CPU 内存,且多数是**瞬时(transitory)**使用——用完即归还。

1. 加载模型权重(瞬时占用)

模型权重在启动时从磁盘读入 CPU 内存,然后被搬运到 GPU。这一阶段的内存占用是瞬时的:一旦所有权重转移到 GPU,CPU 侧占用便归零。对于动辄数十 GB 的模型,若节点 CPU 内存不足,加载阶段就可能触发 OOM 或严重的 swap。

2. 保存模型权重(瞬时占用)

保存检查点时存在两种路径:

  • 各 GPU 直接写盘:每个 GPU 进程把自己持有的分片直接写入磁盘,CPU 侧几乎不额外占用;
  • 先在 CPU 侧重组再写盘:模型被在 CPU 内存中重组成完整形态后再写盘,需要临时容纳整个模型的 CPU 内存。

无论哪种方式,这同样是瞬时占用,但规划容量时仍需保证峰值需求能被满足,尤其是第二种路径。

3. 参数与优化器状态 offload(可能的大额需求)

使用 DeepSpeed,其中还指出:DeepSpeed 一类的框架还能把部分计算工作 offload 到 CPU 而不形成瓶颈,这种情况下额外多核 CPU 也有收益。

4. 激活值 offload

forward过程中计算的、且backward阶段仍需使用的激活值,除了丢弃后在反向时重算(gradient checkpointing 的路线),也可以被 offload 到 CPU 内存暂存。这避免了重算带来的额外开销,代价是占用 CPU 内存并增加 CPU↔GPU 的传输量。这一用途在显存紧张的大模型训练中常与梯度检查点方案交替使用,需要根据传输带宽与重算代价权衡。

5. DataLoader:通常是最大的 CPU 内存消耗者

DataLoader 是 CPU 内存最主要、最不稳定的占用来源。默认配置num_workers=0是同步取数,但异步取数(num_workers>0)才是消除 IO 与数据预处理对加速器阻塞的关键(详见 training/performance/README.md 的 "Asynchronous DataLoader" 一节)。

典型节点上每块加速器配 2 个 worker,即每个 8 卡节点至少运行 2×8=16 个 DataLoader worker 进程,每个进程都持有若干数据样本。当数据以流式方式从云端拉取且数据分片(shard)很大时,这 16 个进程轻松就能吃掉数百 GB CPU 内存——IDEFICS-80B 训练时的实测是约 1TiB CPU 内存仍不足以支持足够的 worker 数量,导致 DataLoader 成为训练瓶颈(training/performance/README.md 中的 case study)。

CPU 核数规划也与 DataLoader 直接相关:按 compute/cpu/README.md 的公式,每块加速器需要 1 个进程核 + 每个 worker 1 个核,8 卡节点总计约8*(num_workers+1)+4个核(NLP 场景num_workers=2约需 28 核,CV/VLM 场景num_workers=4约需 44 核)。worker 数越多,内存与核数双重需求越大。

6. 软件与依赖库本身(通常可忽略)

Python 运行时、框架及其依赖库也会占用少量 CPU 内存,但相比上述用途通常微不足道,无需特别规划。

必须知道的一件事:mmap 模式下 Resident 内存的巨大误报

若 DataLoader 使用 HFdatasets的 mmap 模式,top中显示的 Resident 内存(RSS)可能高得吓人——它会把整个数据集都"映射"到地址空间里。但这是一种误导:当其他程序需要内存时,OS 会把未被引用的 mmap 页换出(page out)还给系统。

这一机制值得深入理解,因为它同时解释了两个问题:为什么 mmap 是 HFdatasets的默认路径,以及为什么你看到的高 RSS 不是内存泄漏。

mmap 为什么是默认路径:Arrow 的按需分页读取

HFdatasets把数据保存在 Apache Arrow 文件中——一种二进制列式格式,磁盘上的字节布局与内存中使用的布局一致,因此读取某一行无需任何解析步骤。这让内存映射成为默认方式(load_from_disk,或load_dataset不指定keep_in_memory):文件被映射进地址空间,行访问退化为一次缺页(page fault)而不是一次read系统调用。仓库中的 storage/README.md 对此有完整的技术剖析,并附有基准数据。

假象的真相:RSS 高 ≠ 内存泄漏

映射所显示的 Resident 内存并非泄漏——OS 可以回收未被引用的页。当内存紧张时,未使用的 mmap 页会被自动换出,因此系统整体内存不会被无限消耗。这一认知不仅适用于 HFdatasets,任何使用mmap的数据集都遵循同样的行为(compute/cpu-memory/README.md)。

mmap 与顺序读取的实测差距:何时需要放弃 mmap

mmap 并非免费的。仓库中的 storage/README.md 记录了用 mmap-io-bench.py 测得的实测数据(1GiB 文本、32768 行、每行 32KiB、三个 Arrow 分片,每次运行前用posix_fadvise(POSIX_FADV_DONTNEED)丢弃页缓存):

1GiB 的读取方式本地 NVMe相对顺序读的降速Lustre相对顺序读的降速
顺序read()整文件0.14s0%1.87s0%
mmap,按行顺序遍历0.53s279%3.11s66%
mmap,随机打乱行序0.78s457%94.2s4_937%

结论非常明确(storage/README.md):

  1. 按序消费分片(校验、格式转换、单遍 tokenize):直接用普通read()大块读取,不要映射;
  2. for row in ds遍历映射数据集:本地 NVMe 上映射代价 279% 但仍半秒读完 1GiB,可接受;在 Lustre 上每页都要走网络,训练前应先把分片拷到节点本地盘;
  3. 随机打乱ds[i](常规 shuffled 训练):在 Lustre 上每 GiB 耗时 94.2s,是顺序读的约 50 倍,绝不可直连网络文件系统。解决方案包括:把分片暂存到节点本地 NVMe 再映射、预打乱成 epoch 分片后按序读取、或流式加缓冲内打乱;keep_in_memory=True也能消除缺页,但代价是每个 DataLoader worker 都要重复承担这份 RAM。

内存观测与排障

  • 查看每个进程真实的物理内存占用,可用top/htop的 RES 列,但要结合上述 mmap 机制解读;
  • 仓库的 debug/README.md 提供了 GPU 内存分配检测脚本(如torch-distributed-gpu-test.py检查集群 GPU 间通信与显存分配能力),排查思路同样适用于 CPU 侧内存观测;
  • 若怀疑 DataLoader 内存异常,优先检查:worker 数量、数据集是否 mmap 模式、分片大小、是否流式拉取、是否使用 pinned memory(pin_memory=True会阻止对应页被换出,减少可用内存总量,详见 training/performance/README.md)。

实操检查清单:为你的训练节点规划 CPU 内存

  1. 算下限:节点 CPU 内存 ≥ 节点 GPU 显存总量(如 8×80GiB → ≥640GiB);
  2. 加 DataLoader 余量:按num_workers数量估算峰值占用,流式云端数据场景留足数百 GB 冗余;
  3. 加 offload 余量:若启用 DeepSpeed ZeRO-Offload 或激活值 offload,按模型与优化器状态规模单独估算;
  4. 理解 mmap:看到 RSS 虚高先别急着加内存,确认是否 mmap 数据集,确认 OS 是否在内存紧张时正常回收;
  5. 衡量读取模式:跑一遍 mmap-io-bench.py(需pip install datasets numpy,脚本仅支持 Linux),把训练的数据读取路径与上表对照,决定是否改走顺序读、本地暂存或keep_in_memory。

小结

CPU 内存的规划原则可以浓缩为一句话:以 GPU 显存总量为下限,为 DataLoader 和 offload 留足余量,并对 mmap 数据集的 RSS 数值保持正确的解读。掌握这三点,就能避免两类最常见的生产事故——节点因 CPU 内存不足在启动或取数阶段 OOM,以及因误读 mmap 内存占用而盲目扩容。仓库的 compute 章节体系(CPU 核数规划见 compute/cpu/README.md,文件系统与 IO 深入分析见 storage/README.md)为本文所述规则提供了完整的上下文与可复现的实验支撑。

  • 人工智能
  • 大模型
  • AI 技能/插件
  • 分布式训练
  • 微调
  • 深度学习

【免费下载链接】ml-engineering

Machine Learning Engineering Open Book

项目地址:https://gitcode.com/gh_mirrors/ml/ml-engineering
点击查看免费下载

相关推荐

上一篇:深度解析:DyberPet桌面电子宠物框架如何实现高效二次元角色养成体验
下一篇:Redwood 无障碍(a11y)指南:内置路由可达性与焦点管理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 2:09:25

SMU-ACM冬训周报:第一周基础算法训练与实战复盘

SMU-ACM 的 2026 冬训周报来了,这是第一期。写这个系列的目的很直接:把每周训练的安排、选题思路、代码实现、踩过的坑都摊开来讲,给队里同学一个复盘参考,也顺便给正在入门 ACM 的选手们一些可以抄作业的路线。这一周我们主要解决…

作者头像 李华
网站建设 2026/10/1 2:07:29

Vue3 + Element Plus 数字范围输入框组件封装实践

做后台管理系统,基本逃不掉范围筛选这个需求。价格区间、年龄区间、库存区间、评分区间,几乎每个列表页都要来一套。Element Plus 提供了单个数字输入框 el-input-number,范围选择器也有,但那是日期用的 el-date-picker&#xff0…

作者头像 李华
网站建设 2026/10/1 2:06:19

基于MySQL+Java的仓库管理系统:JDBC连接、事务与避坑指南

简介:这是一个基于MySQL与Java技术栈开发的仓库管理系统完整项目,面向计算机、数学、电子信息等专业的课程设计、期末大作业与毕业设计场景,适合已掌握Java基础、希望实战数据库增删改查与桌面端界面开发的读者。项目包含全部源码、数据库脚本…

作者头像 李华