资讯动态

华为云ModelArts深度学习实战:从训练到部署全流程踩坑指南

发布时间:2026/10/13 23:59:19 来源:尧图企业网站定制
1. 从零上手华为云 ModelArts一个深度学习从业者的踩坑实录搞深度学习这行的绕不开一个现实问题模型训练和部署到底放在哪里跑。自己攒机器吧一张像样的显卡动辄上万电费、散热、维护全是隐形成本用本地工作站吧跑个小模型还行一旦上ResNet、RoBERTa这种量级的网络显存分分钟告急。我前阵子因为项目需要系统地把华为云ModelArts跑了一遍从数据准备到模型训练再到在线部署整个链路走通之后觉得有必要把过程中的关键细节和踩过的坑整理出来。ModelArts是华为云面向AI开发者推出的一站式平台核心能力覆盖数据处理、模型训练、模型管理、模型部署全流程。说得直白一点你可以把它理解成一个云端的工作台——数据传上去代码配好选好算力规格点一下开始训练训练完直接部署成API接口对外提供服务。它解决的核心问题是让没有GPU集群的团队也能跑深度学习任务让有GPU的团队不用自己维护底层基础设施。这篇文章适合几类人看一是刚接触云端模型训练、想找个平台练手的在校学生二是需要快速验证算法效果、不想在环境配置上耗时间的算法工程师三是准备参加华为ICT大赛云赛道、需要熟悉ModelArts操作流程的参赛者。我会按照实际操作的顺序把每个环节的关键配置、参数选择的理由、容易出问题的地方都讲清楚尽量做到你照着做就能跑通。2. 训练前的整体设计与方案选型2.1 为什么选ModelArts而不是自己搭环境先说说选型逻辑。自己搭训练环境最头疼的不是买显卡而是环境依赖。CUDA版本、cuDNN版本、PyTorch版本、Python版本这四个东西的兼容矩阵能把人逼疯。我见过太多人卡在ImportError: libcudart.so.11.0: cannot open shared object file这种报错上一整天。ModelArts提供的是预置镜像主流框架的版本组合已经调好了开箱即用省掉了大量环境调试时间。另一个考虑是算力弹性。本地一张L20显卡24GB显存跑ResNet50做图像分类绰绰有余但如果你想跑对比实验同时开三组不同超参数的任务本地机器就捉襟见肘了。ModelArts支持按需申请算力训练完就释放按实际使用时长计费。对于实验阶段这种“跑一批看结果再决定下一步”的场景弹性算力比固定投入划算得多。还有一点是部署的便利性。本地训练完的模型要对外提供服务你还得自己搭Flask或者FastAPI配Nginx搞负载均衡。ModelArts的在线部署功能训练完的模型可以直接发布成在线服务自动生成API端点省掉了整套服务化的工作。2.2 训练方案的整体架构整个流程可以拆成五个阶段数据准备与上传、训练脚本开发与调试、创建训练作业、模型评估与调优、部署为在线服务。每个阶段都有它的关键动作和容易出问题的地方。数据准备阶段核心是把数据传到华为云的对象存储服务OBS上。OBS相当于云上的硬盘ModelArts的训练作业可以直接读取OBS里的数据。这里有个细节数据上传的方式会影响后续训练的效率。如果数据量小几个GB以内直接用OBS Browser客户端上传就行如果数据量大几十GB以上建议先压缩打包再上传到训练容器里再解压这样比传几万个小文件快得多。训练脚本开发阶段关键是要适配ModelArts的目录约定。ModelArts在训练容器里预置了几个环境变量比如$MA_JOB_DIR指向作业目录$MA_CURRENT_APP_DIR指向代码目录。训练脚本里读取数据、保存模型的路径最好基于这些环境变量来写这样代码在本地调试和云端训练时都能跑。创建训练作业阶段需要配置几个核心参数算力规格选什么显卡、镜像用什么框架版本、数据路径OBS里的数据位置、代码路径训练脚本的位置、超参数学习率、batch size等。这些参数的选择直接决定训练能不能跑起来、跑得快不快。模型评估与调优阶段重点是看训练日志和TensorBoard。ModelArts的训练作业支持实时查看日志也可以配置TensorBoard可视化。如果发现loss不下降或者出现NaN需要回头检查数据预处理和超参数设置。部署阶段把训练好的模型发布成在线服务配置好推理规格和自动扩缩容策略就可以通过API调用了。2.3 关键参数选择的底层逻辑选算力规格的时候很多人不知道该选哪个。我的经验是看模型大小和batch size。以ResNet50为例batch size设为32的时候显存占用大概在8GB左右选单卡16GB显存的规格就够用。如果跑RoBERTa这类NLP模型base版本batch size 16大概需要12GB显存large版本就需要24GB以上。ModelArts的算力规格从单卡到多卡都有选的时候留出20%左右的显存余量比较稳妥。镜像选择上如果你用的是PyTorch就选PyTorch的预置镜像版本尽量选较新的稳定版。我实测下来PyTorch 1.8以上的版本在ModelArts上兼容性都还不错。TensorFlow的话选2.x版本。镜像里已经装好了CUDA和cuDNN不需要自己再装。学习率这个参数我踩过的坑最多。用预训练模型做微调的时候学习率设太大比如0.01loss很容易震荡甚至变成NaN设太小比如1e-6收敛又太慢。一般经验是微调时学习率设在1e-4到1e-5之间比较合适具体还要看batch size和优化器。用Adam优化器的话1e-4是个比较安全的起点。3. 核心细节解析与实操要点3.1 数据上传与OBS目录结构设计数据上传看起来简单但目录结构设计不好后面训练脚本读取数据时会很麻烦。我建议在OBS里按以下结构组织obs://your-bucket/dataset/ ├── train/ │ ├── class_0/ │ ├── class_1/ │ └── ... ├── val/ │ ├── class_0/ │ ├── class_1/ │ └── ... └── test/ └── ...这种按类别分文件夹的结构配合PyTorch的ImageFolder或者TensorFlow的image_dataset_from_directory可以直接读取不需要额外写数据索引文件。上传工具方面OBS Browser适合传少量大文件obsutil命令行工具适合批量上传和脚本化操作。如果数据在本地已经整理好了用obsutil的cp命令递归上传整个目录obsutil cp -r /local/dataset obs://your-bucket/dataset -flat-flat参数表示不保留本地目录结构直接传到目标路径下。这个参数在上传前一定要确认好传错了要重新传很浪费时间。注意OBS的存储按容量和请求次数计费训练完成后如果数据不再使用记得清理或者转归档存储不然会一直产生费用。3.2 训练脚本的适配改造本地写的训练脚本要放到ModelArts上跑需要做几处适配。最关键的是路径处理。ModelArts的训练容器里代码会被拷贝到/home/ma-user/modelarts/user-job-dir/下面数据路径通过环境变量传入。我通常会在脚本开头加一段路径解析逻辑import os import argparse def get_args(): parser argparse.ArgumentParser() parser.add_argument(--data_url, typestr, default./data) parser.add_argument(--train_url, typestr, default./output) parser.add_argument(--epochs, typeint, default10) parser.add_argument(--batch_size, typeint, default32) parser.add_argument(--lr, typefloat, default1e-4) return parser.parse_args() args get_args() # 如果是在ModelArts上运行data_url和train_url会是OBS路径 # 需要先拷贝到本地容器目录再读取 if args.data_url.startswith(obs://): import moxing as mox mox.file.copy_parallel(args.data_url, /cache/data) data_path /cache/data else: data_path args.data_url这里用到了moxing库这是ModelArts提供的OBS文件操作库可以像操作本地文件一样操作OBS上的文件。copy_parallel是并行拷贝比逐个文件拷贝快很多。训练完成后模型保存到train_url指定的路径。同样地如果train_url是OBS路径需要先把模型保存到本地容器目录再用mox.file.copy_parallel上传到OBS。实操心得/cache目录是ModelArts容器里的本地SSD读写速度比OBS快很多。训练时把数据拷贝到/cache再读取能显著减少数据加载的等待时间。但要注意/cache的容量有限一般50GB左右数据量太大的话要分批处理。3.3 超参数配置与调优策略超参数的配置在创建训练作业时通过界面或者JSON文件传入。我习惯把超参数都做成命令行参数这样在ModelArts界面上可以直接修改不用改代码重新上传。学习率、batch size、epochs这三个是最常调的。我的调参顺序是先固定一个较小的学习率比如1e-4和适中的batch size比如32跑几个epoch看loss曲线。如果loss下降太慢适当增大学习率如果loss震荡厉害减小学习率。batch size的调整主要看显存占用显存够就适当增大能加快训练速度。还有一个容易忽略的参数是权重衰减weight decay。用Adam优化器的时候weight decay一般设1e-4到1e-5。设太大模型会欠拟合设太小又起不到正则化效果。我一般从1e-4开始试。如果训练过程中loss变成NaN大概率是学习率太大或者数据里有异常值。先把学习率降一个数量级试试如果还是NaN就要检查数据预处理了。常见的原因是输入数据没有归一化或者标签里有非法值。3.4 预训练模型的使用技巧用预训练模型做微调是深度学习里性价比最高的做法。ModelArts的预置镜像里已经包含了一些常用预训练模型的权重文件但版本可能不是最新的。我的做法是从PyTorch Hub或者Hugging Face下载预训练权重上传到OBS训练时从OBS加载。以ResNet50为例加载预训练权重的代码import torchvision.models as models import torch # 方式一直接从torchvision加载需要容器能访问外网 model models.resnet50(pretrainedTrue) # 方式二从OBS加载本地权重文件 model models.resnet50(pretrainedFalse) state_dict torch.load(/cache/pretrained/resnet50.pth) model.load_state_dict(state_dict)注意ModelArts的训练容器默认不能访问外网所以pretrainedTrue这种方式在云端训练时会失败。必须提前把权重文件上传到OBS训练时拷贝到本地加载。RoBERTa这类NLP预训练模型也是同样的道理。Hugging Face的from_pretrained方法默认会联网下载在ModelArts上需要改成从本地路径加载from transformers import RobertaModel, RobertaTokenizer tokenizer RobertaTokenizer.from_pretrained(/cache/pretrained/roberta-base) model RobertaModel.from_pretrained(/cache/pretrained/roberta-base)4. 完整实操流程与核心环节实现4.1 创建训练作业的详细步骤登录华为云控制台进入ModelArts服务在左侧导航栏选择“训练管理”下的“训练作业”点击“创建训练作业”。接下来按步骤配置基本信息作业名称起一个能区分实验的比如resnet50-finetune-lr1e-4-bs32。描述可以写这次实验的目的和关键参数方便后面回溯。参数配置这是最核心的部分。算法来源选“常用框架”框架选PyTorch版本选1.8以上。代码目录选OBS里存放训练脚本的路径启动文件填训练脚本的文件名比如train.py。数据来源选OBS填数据集的OBS路径。训练输出位置选一个OBS路径用来存模型和日志。超参数在“超参数”区域添加命令行参数。比如添加--epochs值为20--batch_size值为32--lr值为0.0001。这些参数会以--epochs 20 --batch_size 32 --lr 0.0001的形式传给训练脚本。算力规格根据模型大小选。ResNet50选单卡16GB显存的规格就够。如果跑RoBERTa-large选单卡32GB显存。规格选好后系统会显示预估费用确认没问题再提交。作业日志提交后可以在作业详情页查看实时日志。日志会显示数据加载进度、每个epoch的loss和accuracy、以及最终的模型保存路径。如果作业失败日志里会有错误堆栈根据报错信息排查。实操心得第一次跑的时候建议把epochs设小一点比如2先验证整个流程能不能跑通。跑通之后再改成完整的epochs重新提交。这样能避免跑了几个小时才发现代码有bug的尴尬。4.2 训练过程的监控与调试训练作业提交后可以在ModelArts控制台看到作业状态排队中、运行中、已完成、失败。排队中说明算力资源紧张需要等一会儿。运行中就可以看日志了。日志里重点关注几个信息数据加载是否正常有没有报文件找不到、loss是否在下降、显存占用是否接近上限。如果显存占用超过90%说明batch size设大了需要调小。TensorBoard的配置稍微麻烦一点。需要在训练脚本里加TensorBoard的日志记录from torch.utils.tensorboard import SummaryWriter writer SummaryWriter(/cache/tb_logs) # 训练循环里 writer.add_scalar(Loss/train, loss.item(), global_step) writer.add_scalar(Accuracy/train, acc, global_step)训练完成后把/cache/tb_logs目录拷贝到OBS然后在本地下载下来用TensorBoard打开。或者用ModelArts的TensorBoard功能直接指定OBS里的日志路径。如果训练中途失败先看日志最后的报错信息。常见的错误类型和排查方向错误类型可能原因排查方向CUDA out of memorybatch size太大或模型太大减小batch size或换更大显存的规格FileNotFoundError数据路径不对检查OBS路径和容器内路径的映射Loss is NaN学习率太大或数据异常降低学习率检查数据归一化RuntimeError: expected scalar type数据类型不匹配检查输入数据的dtype和模型要求的dtype4.3 模型部署为在线服务的操作训练完成后模型文件会保存在指定的OBS路径下。接下来把它部署成在线服务。在ModelArts控制台选择“模型管理”下的“模型”点击“导入”。填写模型名称选择“从OBS导入”指定模型文件的OBS路径。推理框架选“TensorFlow”或“PyTorch”根据你的模型类型来。如果模型有自定义的推理逻辑需要提供一个推理脚本customize_service.py在里面实现模型加载和预测方法。推理脚本的基本结构from model_service.pytorch_model_service import PTServingBaseService import torch import torchvision.transforms as transforms from PIL import Image import io class ImageClassificationService(PTServingBaseService): def __init__(self, model_name, model_path): self.model torch.load(model_path, map_locationcpu) self.model.eval() self.transform transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) def _preprocess(self, data): images [] for k, v in data.items(): for file_name, file_content in v.items(): image Image.open(io.BytesIO(file_content)) image self.transform(image).unsqueeze(0) images.append(image) return torch.cat(images, dim0) def _inference(self, data): with torch.no_grad(): outputs self.model(data) _, predicted torch.max(outputs, 1) return predicted.tolist() def _postprocess(self, data): return {predicted_class: data}模型导入后点击“部署”下的“在线服务”配置服务名称、推理规格根据QPS要求选、是否开启自动扩缩容。提交后等待几分钟服务状态变成“运行中”就可以调用了。调用方式是在“在线服务”详情页找到API地址用POST请求发送数据curl -X POST https://your-service-endpoint/v1/infers/xxx \ -H Content-Type: application/json \ -H X-Auth-Token: your-token \ -d {images: [{file_name: test.jpg, file_content: base64编码的图片数据}]}注意在线服务是按运行时长计费的不用的时候记得停止服务不然会一直扣费。可以设置自动停止策略比如空闲30分钟后自动停止。4.4 从训练到部署的完整链路验证整个链路跑通的标准是本地准备数据 - 上传OBS - 创建训练作业 - 训练完成模型保存到OBS - 导入模型 - 部署在线服务 - API调用返回预测结果。我建议第一次跑的时候用一个很小的数据集比如每个类别10张图片模型用ResNet18这种轻量级的epochs设2先把链路跑通。链路通了之后再换成完整数据集和正式模型。验证的时候可以写一个简单的Python脚本从本地读一张图片转成base64调用在线服务的API看返回的预测类别是否正确。这一步能验证从数据预处理到模型推理的整个流程是否一致。5. 常见问题与排查技巧实录5.1 训练阶段的典型报错与解决问题一训练作业一直处于“排队中”状态。这是算力资源紧张导致的。解决办法是换一个规格或者选择非高峰时段提交。如果用的是免费算力额度排队优先级会比较低等待时间可能较长。问题二日志显示“No module named xxx”。说明训练脚本依赖的某个包在预置镜像里没有。解决办法是在训练脚本开头加一段安装依赖的代码import os os.system(pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple)但要注意训练容器默认不能访问外网需要配置代理或者使用内网镜像源。ModelArts提供了内网的pip源可以直接用。问题三训练速度比本地还慢。可能的原因有几个一是数据从OBS读取没有拷贝到/cache每次读数据都要走网络二是算力规格选低了三是数据加载的num_workers设太小。解决办法分别是把数据拷贝到/cache、换更高规格的算力、把num_workers设成CPU核数。问题四loss变成NaN。前面提过主要是学习率太大或数据异常。还有一个容易被忽略的原因是混合精度训练AMP的缩放因子设置不当。如果用AMP可以先把loss_scale设成固定值试试。5.2 部署阶段的常见坑问题一模型导入失败提示“模型文件格式不支持”。ModelArts对模型文件的格式有要求PyTorch模型需要保存为.pth或.pt文件TensorFlow模型需要是SavedModel格式。如果保存的是整个模型对象torch.save(model)可能不被识别建议保存state_dicttorch.save(model.state_dict())。问题二在线服务启动失败日志显示“端口未监听”。推理脚本里需要确保服务监听在正确的端口上。ModelArts的推理容器默认监听8080端口自定义推理脚本里不要改这个端口。问题三API调用返回“403 Forbidden”。认证问题。需要在请求头里带上正确的Token。Token的获取方式是在华为云控制台的“我的凭证”里创建API凭证然后用这个凭证换取Token。问题四推理延迟高。可能的原因模型太大、推理规格太低、没有做模型量化。解决办法换更轻量的模型、提高推理规格、用ONNX Runtime或者TensorRT做推理加速。5.3 成本控制的实操经验ModelArts的计费方式是按需计费训练作业按实际运行时长计费在线服务按运行时长计费。控制成本的关键是训练完及时释放算力在线服务不用时及时停止。我自己的做法是训练作业提交后如果预估要跑几个小时就设个闹钟跑完第一时间去检查结果并释放资源。在线服务部署后如果只是测试用设置自动停止策略比如30分钟无请求自动停止。还有一个省钱的技巧用竞价计费模式。ModelArts支持竞价实例价格比按需实例便宜很多但缺点是可能被随时回收。适合那种可以容忍中断的训练任务比如跑对比实验。实操心得训练作业的日志和模型文件都会占用OBS存储空间长期积累下来也是一笔费用。建议定期清理不再使用的日志和中间模型文件只保留最终需要的模型。5.4 从华为云获取数据的几种方式除了用OBS Browser和obsutil上传数据还有几种从华为云获取数据的方式一是用ModelArts的“数据管理”功能可以在线标注数据、做数据增强然后直接用于训练。适合没有现成标注数据的场景。二是用华为云的数据集服务比如ModelArts内置的一些公开数据集可以直接订阅使用。三是用API从其他华为云服务获取数据比如从云数据库RDS读取数据或者从数据仓库DWS读取。这种方式适合数据已经在华为云上的场景。如果数据在本地NAS上比如飞牛NAS可以通过SMB协议挂载到本地电脑再用obsutil上传到OBS。或者如果NAS支持也可以直接配置NAS到OBS的同步任务。6. 几个容易被忽略的细节和我的个人体会6.1 镜像选择对训练效率的影响ModelArts的预置镜像有好几种除了框架版本不同底层操作系统和CUDA版本也不同。我实测下来Ubuntu 18.04 CUDA 10.2 PyTorch 1.8这个组合在大多数场景下兼容性最好。如果用到比较新的模型可能需要CUDA 11.x那就选对应的镜像。还有一个细节镜像里预装的包版本可能和你的代码不兼容。比如镜像里装的是numpy 1.19你的代码用了numpy 1.20的新特性就会报错。解决办法是在训练脚本开头用pip指定版本安装或者自己做一个自定义镜像。6.2 分布式训练的参数配置如果单卡跑不下需要用多卡分布式训练ModelArts也支持。关键是在创建训练作业时选择多卡规格然后在训练脚本里用torch.distributed初始化进程组。ModelArts会自动设置MASTER_ADDR、MASTER_PORT、RANK、WORLD_SIZE这些环境变量脚本里直接读取就行。分布式训练的数据加载要注意每个进程只加载一部分数据用DistributedSampler来实现。不然每个卡都加载全量数据不仅浪费IO还可能导致batch size不一致。6.3 模型版本管理与回溯做实验多了之后模型版本管理是个问题。我的做法是每次训练作业的名称里带上关键超参数比如resnet50-lr1e-4-bs32-epoch20。模型保存的OBS路径也按这个命名规则来。这样后面要回溯哪个实验看名字就知道参数配置。另外训练日志建议保留一份到本地或者另一个OBS桶不要只存在训练作业的默认输出路径里。因为训练作业删除后默认输出路径下的日志可能也会被清理。6.4 关于免费算力额度的使用华为云对新用户有一些免费算力额度可以用来跑训练作业。免费额度一般有使用期限过期作废。如果只是学习练手用免费额度就够了。但要注意免费额度通常只覆盖训练作业在线服务部署可能不在免费范围内部署前先确认计费规则。免费算力的规格一般比较低跑大模型可能显存不够。我的建议是用免费额度跑小模型练手熟悉整个流程正式项目再考虑付费算力。6.5 从训练到部署的衔接问题训练时用的数据预处理方式部署时也要用同样的方式。我见过有人训练时用了归一化部署时忘了加导致预测结果完全不对。解决办法是把预处理逻辑封装成一个独立的模块训练和推理都调用同一个模块。还有一个衔接问题是类别映射。训练时类别是按文件夹名称排序的部署时也要用同样的排序方式。不然预测出来的类别索引对应的标签就错了。建议在训练完成后把类别映射关系保存成一个JSON文件部署时加载这个文件来做标签映射。整个流程走下来我的体会是ModelArts把模型训练和部署的门槛降低了很多但要把整个链路跑顺还是需要对深度学习的各个环节有基本的理解。平台解决的是基础设施的问题算法层面的问题还是得自己调。另外云端训练的成本控制很重要养成用完即释放的习惯能省下不少钱。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑