☰
基于RHEL 8的AWS深度学习训练环境部署与优化指南
2026/9/30 7:58:05 网站建设 项目流程

说句实在话,在AWS上跑机器学习任务,大多数人第一反应是直接用现成的托管服务,很少有人会去认真磨一台自建的深度学习实例。但当你开始接触需要深度定制训练环境、严格控制框架版本、或者要做分布式训练的项目时,你会发现托管的便捷性往往伴随着灵活性的牺牲。这也是我最近半年逐步转向在RHEL 8上部署AWS Deep Learning AMI的原因。

这篇文章不是入门教程,更像是我自己踩了无数坑之后的一份操作复盘。如果你正准备在AWS上搭一套严肃的、能长期演进的机器学习训练环境,并且对性能和扩展性有要求,那么这篇内容应该能帮你省下不少冤枉时间。

1. 选型前先想清楚:RHEL 8 与 Deep Learning AMI 的组合到底是为了解决什么问题

1.1 为什么多数人默认选Ubuntu,而我会选RHEL 8

先说个普遍现象:市面上关于深度学习环境搭建的教程,十有八九是基于Ubuntu的。原因很直接——Ubuntu的社区支持最活跃,PyTorch、TensorFlow这些框架的官方二进制包往往是Ubuntu优先适配,出了问题搜一下Stack Overflow,答案也多到翻不完。

但Ubuntu在严肃的生产环境里有一个绕不开的问题:更新太激进。你在Ubuntu上装好的CUDA驱动,可能因为一次普通的apt upgrade就出现内核模块和驱动版本不匹配的情况。对于跑了几十个小时的训练任务来说,这种不确定性是致命的。

RHEL 8走的是企业级稳定路线。它的软件仓库更新节奏慢,但每个版本的兼容性验证做得非常充分。特别是在驱动、内核、CUDA这套底层组件的配合上,RHEL 8的保守策略反而成了优势——一旦跑通,环境稳定性高得令人发指。另一个现实因素是很多企业本身就有RHEL订阅或内部合规要求,选RHEL 8不会让运维团队觉得你在引入一个"野生"系统。

不过我也要泼一盆冷水:RHEL 8默认的软件包版本偏老旧。如果你用的是最新版本的PyTorch,直接yum安装大概率会碰壁。这个问题后面会详细讲,核心思路是RHEL 8提供稳定底座,深度学习框架层通过conda环境隔离来解决版本冲突。

1.2 Deep Learning AMI 的版本演进与选型对照

AWS的Deep Learning AMI(简称DLAMI)并不是一个简单的装机镜像,它内部集成了NVIDIA驱动、CUDA Toolkit、cuDNN、深度学习框架、以及一系列配套工具。AWS会针对不同实例类型做驱动和框架的适配验证,这一点是自建环境无法比拟的。

DLAMI有几条产品线,需要根据实际场景选择:

AMI类型适用场景特点
AWS Deep Learning AMI (DLAMI)多数通用深度学习场景预装PyTorch/TensorFlow/MXNet,conda环境管理
AWS Deep Learning AMI with HabanaHabana Gaudi加速器专用特定硬件,一般用不到
AWS Deep Learning Base AMI需要完全掌控环境只预装驱动/CUDA,不预装框架

我在RHEL 8上选择的是完整版DLAMI。原因很简单:完整版省去了大量手动编译框架的时间,而conda环境的隔离机制又提供了足够的定制空间。对于有洁癖、喜欢从零开始装环境的人来说,Base AMI可能更有吸引力,但我个人的经验是——如果你不是框架本身的开发者,完整版DLAMI的默认预装已经足够好用,没必要自己重复造轮子。

需要注意的坑是:DLAMI的版本更新非常频繁,AWS几乎每个季度都会发布新的AMI版本。在启动实例时,不要惯性选择最新的AMI,而应该先确认你要用的框架和CUDA版本是否在最新版AMI中有对应支持。我遇到过几次"最新AMI预装的PyTorch版本反而比项目要求的版本更新"导致兼容性出问题的情况。

2. 实例启动与系统环境的初始化:坑最多的前30分钟

2.1 实例类型与GPU型号的选择逻辑

第这个阶段看起来简单,但选错实例类型会让后续所有优化工作变成白费力气。

AWS的GPU实例族主要分为几类:T4适用轻量级推理和中等规模训练,A10G偏向推理,V100和A100是训练主力,H100则是当之无愧的旗舰选择。在RHEL 8 + DLAMI的环境中,我个人比较推荐按这个优先级考虑:

  • 单卡训练且预算有限:g4dn系列(T4)或g5系列(A10G)
  • 单卡训练、追求性能上限:p3系(V100,性价比高但架构偏老)或p4d系(A100)
  • 大规模预训练与多卡并行:p4d系列(8xA100)或p5系(8xH100)

一个比较容易被忽略的点是GPU显存大小直接决定了训练策略。如果你选的实例只有16GB显存,而你的模型在单卡上需要20GB,那就不得不引入梯度累积或者模型并行。这会显著增加开发复杂度。所以我的建议是:在预算允许的范围内,尽量选显存大一到两档的实例,把精力集中在模型本身而不是工程调优上。

2.2 根卷与数据卷的存储规划

很多人在启动DLAMI实例时,直接使用默认的根卷配置。默认的根卷一般是100GB左右,看起来不小,但如果你的数据集动辄几十GB,加上checkpoint、日志、conda环境,根卷很快会被占满。

我的存储规划方案是这样的:

  1. 根卷:保证120GB以上,只为操作系统、CUDA库和conda环境服务
  2. 数据盘:单独挂载一块更大的EBS卷(或者直接用Amazon FSx for Lustre),用于存放训练数据集
  3. checkpoint卷:高频写入checkpoint的话用EBS io2或io2 Block Express,能明显降低训练过程中的IO等待

关于EBS卷的选型,有一个经验公式:训练过程中GPU利用率出现周期性下降,大概率是数据读取瓶颈而非计算瓶颈。此时先检查EBS卷的IOPS是否达到上限,再检查数据管线的prefetch逻辑。前者比后者更容易排查。

还有一点值得注意:DLAMI后来支持在启动时通过CloudFormation或实例元数据自动挂载额外的EBS卷。如果你在用Terraform管理AWS资源,一定要把存储挂载这一步纳入基础设施即代码的范畴,避免手动操作的一致性问题。

2.3 第一次登录后的环境验证

实例启动后,环境验证是必须做的初始化动作。不要因为DLAMI"开箱即用"的宣传就跳过这个环节。

登录实例后,我通常会依次执行以下操作:

  1. 确认内核版本和操作系统版本是否匹配
  2. 检查nvidia-smi输出的驱动和CUDA版本,确认和DLAMI文档描述一致
  3. 验证conda基础环境列表,确认PyTorch/TensorFlow的版本
  4. 跑一个简单的GPU矩阵运算,验证CUDA是否真的能用

其中第三条最容易踩坑。DLAMI启动后,默认创建一个名为"amazon"的conda环境,这个环境里的框架是老版本。如果你直接在新环境里创建新conda环境并安装最新版本PyTorch,原来的CUDA对应关系可能不匹配。我的做法是:优先使用ami版本对应的默认环境,只有明确需要最新版本框架时,才在独立conda环境中重建,并通过环境变量LD_LIBRARY_PATH显式指定CUDA库路径。

3. 深度学习栈的部署顺序:CUDA、cuDNN、框架版本的一致性

3.1 为什么不能随手pip install

之前在Ubuntu上用DLAMI或者自建GPU环境,安装框架可以简单粗暴地执行pip install torch。但在RHEL 8上,这种操作习惯要彻底改掉。

原因在于RHEL 8的系统Python是受Red Hat管理的,直接全局安装Python包容易破坏系统的包管理机制。更严重的是,PyTorch等框架的安装包会依赖特定版本的NVIDIA CUDA库,而驱动层的CUDA版本、框架编译用的CUDA版本、cuDNN版本三者必须保持精确对应。任何一个版本错位,在训练时都可能爆出奇奇怪怪的CUDA runtime错误——这些错误在Stack Overflow上往往没有直接答案,排查起来极其痛苦。

正确做法是:

  1. 使用conda创建独立环境
  2. conda环境内安装由NVIDIA或PyTorch官方提供的完整包
  3. 环境变量明确指定CUDA_HOME指向DLAMI预装的CUDA路径

我推荐的安装方式是这样的:

conda create -n myenv python=3.9 conda activate myenv conda install pytorch torchvision torchaudio cudatoolkit=11.7 -c pytorch -c nvidia

注意:cudatoolkit的作用是提供运行时所需的CUDA库,并不包含驱动。驱动在系统层由DLAMI预装提供。用conda管理框架依赖库后,删环境重装只需要一条conda命令,不会污染系统。

3.2 用conda环境管理框架依赖

如果是新项目,建议一个项目对应一个conda环境。这样不同项目的依赖版本互相隔离,即使预训练期间需要升级框架,也只影响当前环境。

在RHEL 8上,conda的默认源速度达不到理想状态,建议配置镜像源。但这里我要提醒一句:不要为了速度把镜像源换成非官方源,防止引入不明来源的二进制包。

对于训练项目的部署,场景性的依赖管理策略通常是这样:

依赖类型管理方式说明
框架主版本conda如PyTorch、TensorFlow
传统神经网络库pip安装到conda环境如transformers、mmcv
系统级依赖yum尽量少,必须时明确rpm来源
CUDA相关库DLAMI预装 + conda内覆盖如cudnn、nccl

我这里特别想强调NCCL这个库。多卡训练或者多机训练时,NCCL是通信的核心,它的版本必须和框架版本、CUDA版本严格一致。如果不一致,多卡训练会莫名其妙地卡死或报错。在DLAMI中,AWS已经对NCCL做了适配,但如果你在自定义conda环境中重装框架,要特别关注NCCL版本的兼容性。

4. 性能优化:让训练过程真正吃满GPU

4.1 GPU利用率的检测:别被表象迷惑

很多人判断GPU有没有被"喂饱",只看nvidia-smi显示的GPU利用率。我一度以为90%以上的利用率就是性能达标了。后来发现在很多情况下,GPU利用率高并不代表算力被有效利用,可能大部分时间都在做无意义的重算或等待。

判断性能是否真正达标的指标应该看以下三个:

  1. SM(Streaming Multiprocessor)占用率:可以通过nvidia-smi --query-gpu=utilization.gpu,compute_apps_sm_utilization --format=csv查看
  2. 显存带宽利用率:通过ncu(NVIDIA Nsight Compute)检测
  3. 训练吞吐:实际每秒处理的样本数(samples/sec)

如果SM占用率高而训练吞吐低,说明模型算了太多无效计算,可能的原因是padding过多、卷积尺寸不匹配等网络设计问题。如果SM占用率低,则大概率是数据加载或通信拖了后腿。

4.2 数据读取管道优化:最简单也最见效的优化

数据读取是分布式训练中非常常见的大坑。特别是在大规模数据集中,CPU解压图片/音频、做数据增强等操作的速度如果跟不上GPU的消费速度,GPU就会进入空转状态。

优化数据读取管道的三个核心动作:

  1. prefetch:保证数据在GPU计算完成之前已经排队等待
  2. 多进程加载:设置num_workers为CPU核心数的合理倍数
  3. 缓存:中小数据集直接放到内存或小型本地NVMe盘

在RHEL 8 + DLAMI环境下,我优先选择把数据读取的GPU与计算调优到流水线重叠的方式。即在GPU空闲时预加载下一batch数据,这样整个training step可以看成"数据读取+GPU计算"的并行执行。

再提一下存储优化:如果发现数据读取仍然慢,需要检查EBS卷的IOPS上限是否成为瓶颈。以我在真实项目中改过的某次训练为例:原数据集放在EBS gp3卷上,GPU利用率只有60%左右;把数据迁移到内存盘并用in-memory cache之后,GPU利用率直接到了95%以上。这种优化和数据管线的代码结构无关,纯粹是物理IO的差异,效果立竿见影。

4.3 混合精度训练:A100/H100上必须开启的功能

如果你用的是A100或H100,不开混合精度训练相当于把一半以上的算力浪费了。Tensor Cores的运算能力远远超过普通FP32,而混合精度训练的核心思想就是:在模型前向传播和反向传播的过程中用FP16存储张量,梯度更新阶段用FP32存储主权重。

PyTorch的做法是使用AMP(Automatic Mixed Precision)。开启AMP的方式非常简单:

from torch.cuda.amp import autocast, GradScaler scaler = GradScaler() for data, label in dataloader: optimizer.zero_grad() with autocast(): loss = model(data) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()

开启AMP后,训练速度一般能提升1.5到3倍,具体取决于模型的卷积/矩阵运算占比。DLAMI中预装的框架版本基本都支持AMP,但要确认CUDA版本和驱动能配合Tensor Cores使用。

如果切换到FP16后loss明显放大或训练不收敛,通常是因为FP16的动态范围过小导致梯度下溢。这时要检查模型中是否有极大或极小的数值,必要时配合loss scale策略调整。PyTorch的GradScaler已经对loss scale做了动态调整,不需要手写。

4.4 EFA与网络优化:决定了分布式训练的上限

单机训练优化到尾声后,仍然难以满足扩展需求,多机分布式训练是绕不开的方向。AWS上的多机训练,选择网络基础设施时优先使用Elastic Fabric Adapter(EFA)。

EFA是AWS专为高性能计算设计的网络接口,它绕过了操作系统内核网络协议栈,使用libfabric直接与用户态通信,显著降低网络延迟和CPU开销。在DLAMI中,EFA驱动和库已经预装,只要确保实例类型支持EFA,并且实例位于同一可用区、同一安全组即可。

开启EFA后,多机训练通信的延迟和带宽表现会明显优于普通ENA网络。我实测过同一套代码,使用EFA后,Horovod AllReduce的时间缩短了约30%左右。这个提升在百卡以上规模时更明显。

如果你使用的是V100系列(p3实例),不支持EFA,网络性能会受限。所以在规划分布式训练时,建议优先考虑p4d(8xA100)、p4de等可以支持EFA的实例类型。

5. 可扩展性:从单机到多机训练的平滑过渡

5.1 分布式训练选项:Horovod vs DeepSpeed vs PyTorch DDP

聊完单机性能,来说说可扩展性。最核心的问题是如何从单机训练平滑过渡到多机分布式训练。这里的"平滑"包含了两层意思:一是代码改动尽量小,二是扩展之后性能确实能线性增长。

主流方案有三种:

  • PyTorch DDP:最简单自然。由PyTorch框架原生提供,单机代码改为DDP模式后换到多机,改动极小。
  • Horovod:老牌的分布式训练框架,对多机多卡的支持很成熟,但项目维护活跃度有所下降。
  • DeepSpeed:微软出品的训练框架,不仅仅支持DDP级别分布式,还引入了ZeRO优化器,在大模型场景下几乎是标配。

从部署角度看,DLAMI三个工具都预装了。但真实使用中最适合直接上手的就是PyTorch DDP,因为其从单机到多机改动最小,而且兼容性极好。DeepSpeed适合当显存不够用、需要进行ZeRO内存优化时再引入。

5.2 数据并行与模型并行的适用边界

数据并行是最常用也最有效的扩展方式。多台机器共享同一份模型参数,各自处理不同batch的数据,梯度同步交给通信框架完成。PyTorch DDP优化的核心逻辑就在梯度通信阶段。

但数据并行也有不适用的时候——模型太大,单卡放不下。这时候需要模型并行(把模型切分到多台机器上)或者流水线并行。模型并行对通信的要求更高,因为每一层的激活和梯度传输都会被频繁调用。相比之下,数据并行每个step仅需要做一次梯度同步,通信压力可控得多。

在RHEL 8 + DLAMI的环境里,我的建议是:模型能放进单卡,就优先数据并行;模型放不下,考虑DeepSpeed的ZeRO-Offload,而不是一上来就手动切分模型。

5.3 弹性训练:让集群规模随数据量变化

传统分布式训练在稳定性上的痛点是一台机器故障,全群训练终止。在云上,恢复和重启非常花钱,也很花时间。AWS的DLAMI和环境设计上已经有意识支持容错和弹性,但框架层面的弹性训练能力是另外一回事。

PyTorch DDP本身不具备自动容错机制,如果训练中断,需要从头加载checkpoint恢复。此时设置高频checkpoint就显得很重要。业界也出现了TorchElastic等方案,能在部分节点故障时重新调整工作节点数量继续训练,不用全群重启。好在RHEL 8 + DLAMI跑主流框架,可以开箱使用这些弹性能力,而不需要额外安装太多底层依赖。

如果你训练的时长非常长,启动新实例加入集群这个过程本身可能很慢,建议提前规划新增节点的Launch template,一旦需要扩容,用Auto Scaling Group自动拉起训练实例,而不是手动创建实例再手动加入集群。

6. 监控、日志与成本控制:跑起来只是开始

6.1 GPU监控体系:肉眼盯nvidia-smi不是长久之计

训练开始之后,合理的监控和预警体系直接决定了你在生产环境能不能放心睡觉。仅靠nvidia-smi在训练终端里肉眼看输出,属于最低限度的手段。

瞥一眼nvidia-smi可以看可视化数据,但更合适的做法是接入CloudWatch或Prometheus监控GPU使用率、温度、显存带宽和功耗。如果是轻量方案,直接在实例上用CloudWatch Agent自定义指标推送。

我在生产环境里的做法是:用Prometheus + NVIDIA DCGM exporter采集GPU指标,Grafana做可视化。DLAMI系统本身对DCGM的支持较好,没有额外编译驱动的负担。配合CloudWatch Alarm,如果GPU利用率异常下降(比如低于50%持续10分钟),立即发送SNS通知,这时候再去确认训练任务是否已经失败或卡住。

6.2 训练日志的管理

多机分布式训练时,日志分散在各台机器上是个大问题。每台实例上运行一个日志采集器,把输出集中到CloudWatch Logs。在Logs里设置关键词告警——比如"CUDA out of memory"、"RuntimeError"、"segmentation fault"——一旦出现即触发邮件通知。

DLAMI本身预装了多个调试工具,如TensorBoard。建议把TensorBoard日志写到S3或EFS,集中管理,这样即使实例被回收,训练曲线仍然保留。

6.3 成本控制:预算限制下的效率策略

成本控制的话题在云端训练环境中永远不过时。GPU实例按秒计费,训练任务跑得越久费用越高。所以节流和提效是长期演进的核心问题。

有几个实践上的方向值得考虑:

  • Spot实例:对于可中断、可恢复的训练任务,用Spot实例部署训练集群能把成本直接打到按需价格的三折以下。配合checkpoint机制,即便Spot实例中断,也不需要完全从头开始。
  • 按FIFO或Batch策略使用预留实例:如果训练任务是定期的,例如每晚跑批,建议使用Savings Plans覆盖基础容量。
  • 训练完成即回收实例:不要把实例闲置在那里。如果确实不想做自定义调度,可以在训练完成后用CloudFormation或Lambda自动判断是否需要继续保留实例。

再分享一个经验:DLAMI要记得做快照。我一般是在环境配置好、跑通一次基线模型之后,制作一个自定义AMI作为工作镜像,后续的实例都基于这个自定义镜像启动。这样不用每次从官方DLAMI开始折腾,节省的不仅是配置时间,还有可能出现的版本漂移问题。

最后再分享一点实践经验

我见过很多项目在初期并不会考虑RHEL 8和DLAMI这样的组合,大家通常是在遇到稳定性问题或者需要多机扩展时,才意识到环境基础的重要性。从我个人的使用感受来说,RHEL 8确实比Ubuntu少了很多"惊喜",而AWS DLAMI把驱动、CUDA、框架之间的兼容性工作提前做出了验证。两者搭配起来,虽然刚开始需要重新适应RHEL的包管理习惯,但长期稳定性带来的收益远远大于前期多花的那点时间。

如果你现在正准备启动自己的第一个深度学习实例,我的建议是从一个配置好的自定义AMI开始,先跑通一个小模型,验证数据管线和管理组件,然后再把正式的大模型任务放上去。这样既能保证扩展性,又能在遇到问题时快速定位到是模型的问题还是环境的问题。环境一旦稳定下来,你就能把精力腾出来,安心做研究本身了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询