首页 / 资讯中心 / 文章详情

华为云ModelArts实战:ResNet模型训练与部署全流程

华为云ModelArts实战:ResNet模型训练与部署全流程 ★ FEATURED ARTICLE
1. 从零上手华为云 ModelArts一个后端开发的模型训练与部署实录说起来有点汗颜我做了七八年后端开发真正第一次把深度学习模型从训练跑到线上部署是在去年底的一个内部工具项目上。需求很简单给一批商品图片做自动分类识别出主图和细节图方便运营同学批量整理素材。听起来是个典型的图像分类任务但我之前从来没碰过 ModelArts也没正经训过模型属于纯小白。这篇文章就是那次折腾的完整记录。我会把从数据准备、模型训练、调参踩坑到最终部署上线的全过程拆开讲包括我踩过的那些坑——比如 loss 突然变成 nan、免费算力额度怎么用、ResNet 预训练模型怎么选、部署时镜像和推理脚本怎么配。如果你也是后端或者运维出身想快速用华为云 ModelArts 跑通一个自己的模型这篇应该能帮你省下不少查文档的时间。核心关键词先摆出来华为云 ModelArts、模型训练、模型部署、ResNet 预训练模型。整篇内容围绕这四个词展开但不会只讲概念重点是我实际怎么操作的、为什么这么选、哪些地方容易翻车。2. 为什么选 ModelArts 而不是自己搭环境2.1 自建训练环境的三个现实问题在决定用 ModelArts 之前我其实先试过自己搭。公司有几台带 3090 的工作站我想着装个 PyTorch、配个 CUDA 不就完事了。结果第一天就卡在驱动版本上显卡驱动、CUDA Toolkit、cuDNN、PyTorch 版本四者之间的兼容矩阵稍微错一个就报CUDA error: no kernel image is available for execution。我折腾了整整一个下午才把环境跑通。第二个问题是数据管理。训练数据放在本地磁盘每次换机器就要重新拷贝几十个 G 的图片拷来拷去效率极低。第三个问题是训练过程的可视化自己搭 TensorBoard 要额外开端口、配反向代理多人协作时谁改了参数都说不清楚。这三个问题叠加起来让我意识到对于我这种非算法岗、只是偶尔要跑个模型的人来说自建环境的投入产出比太低了。2.2 ModelArts 解决的到底是什么问题ModelArts 本质上是把“算力 环境 数据 训练框架 部署”这一整条链路做成了托管服务。你不需要关心底层是哪种 GPU、驱动什么版本、CUDA 装没装只需要选一个预置镜像把代码和数据挂上去点开始训练就行。它对我最大的价值有三个环境开箱即用预置了 PyTorch、TensorFlow、MindSpore 等主流框架的镜像版本组合都是官方验证过的省去了兼容性排查。算力按需付费不用一次性买卡训练几小时就付几小时的钱对小项目特别友好。而且新用户通常有免费算力额度我那次训练基本没花钱。训练到部署一条龙训练完的模型可以直接在平台上做推理部署不用自己搭服务、配网关。提示ModelArts 的免费算力额度一般有时间和规格限制建议先在免费规格上把流程跑通确认代码没问题再换高配规格跑正式训练避免额度浪费在调试上。2.3 什么场景适合用什么场景不适合我的经验是中小规模的图像分类、文本分类、OCR 微调这类任务用 ModelArts 非常合适。但如果是超大规模预训练、需要多机多卡长时间跑的任务或者对底层有极致定制需求比如要改框架源码那还是自建集群更灵活。另外要提醒一点ModelArts 上的操作很多是通过网页控制台完成的如果你习惯纯命令行前期会有点不适应。不过它也提供了 SDK 和 CLI熟悉之后可以脚本化。3. 数据准备从本地到华为云 OBS 的完整路径3.1 数据该放哪里OBS 是绕不开的一环ModelArts 的训练数据默认从对象存储服务 OBS 读取。所以你第一步要做的是把本地数据传到 OBS 的某个桶Bucket里。我一开始想偷懒直接把数据放在 Notebook 的本地目录结果发现训练任务启动时根本读不到——因为训练是在独立的容器里跑的只有 OBS 和平台数据集才是持久化的。正确的做法是在 OBS 里建一个桶比如叫my-model-data然后在里面按用途分目录my-model-data/ ├── raw/ # 原始数据 ├── train/ # 训练集 ├── val/ # 验证集 └── output/ # 训练输出模型文件、日志这种分目录的习惯很重要后面配置训练作业的输入输出路径时直接指向对应目录就行不会乱。3.2 数据上传的两种方式与选择建议上传数据有两种方式网页控制台直接拖拽或者用 OBS 客户端 / SDK。如果数据量在几个 G 以内网页拖拽最省事。但我那次有将近 20G 的图片网页上传经常断后来改用 OBS Browser 客户端支持断点续传稳定很多。再大一点的数据量建议用obsutil命令行工具可以写脚本批量上传。# obsutil 上传示例需先配置好访问密钥 obsutil cp -r -f ./local_images obs://my-model-data/raw/这里有个坑要注意OBS 的访问密钥AK/SK权限要控制好。我一开始图方便用了主账号的密钥后来被安全同学提醒改成了只有特定桶读写权限的子账号密钥。这个习惯建议一开始就养成。3.3 数据集格式与标注的注意事项图像分类任务ModelArts 支持两种数据组织方式一种是按文件夹分类每个类别一个文件夹另一种是用标注文件如 txt、csv指定路径和标签。我用的是第一种因为最直观train/ ├── main_image/ # 主图 │ ├── 001.jpg │ └── 002.jpg └── detail_image/ # 细节图 ├── 003.jpg └── 004.jpg注意文件夹名称就是类别名不要用中文或特殊字符否则训练时标签映射容易出问题。我有个同事用了中文文件夹名结果训练报错找了好久。另外训练集和验证集的比例我按 8:2 划分。如果某类样本特别少比如只有几十张建议做数据增强或者用迁移学习的方式别硬训。4. 模型训练从 ResNet 预训练模型到自己的分类器4.1 为什么选 ResNet 预训练模型我这次的任务是图像分类样本量不算大每类几百张如果从零训练很容易过拟合而且收敛慢。所以直接用ResNet 预训练模型做迁移学习是最优解。ResNet 的好处是结构成熟、权重容易获取、在各种图像任务上表现稳定。ModelArts 的预置镜像里通常已经包含了 torchvision可以直接加载resnet50(pretrainedTrue)。我选的是 ResNet50因为它在精度和速度之间比较平衡如果对推理速度要求高可以换 ResNet18。迁移学习的做法是冻结前面的卷积层只训练最后的全连接层。这样训练快、不容易过拟合对小数据集特别友好。import torchvision.models as models import torch.nn as nn model models.resnet50(pretrainedTrue) # 冻结特征提取层 for param in model.parameters(): param.requires_grad False # 替换最后的分类层 num_features model.fc.in_features model.fc nn.Linear(num_features, 2) # 2 个类别4.2 训练作业的关键参数怎么配在 ModelArts 控制台创建训练作业时有几个参数必须搞清楚参数项我的配置说明算法来源预置镜像 自定义脚本用官方 PyTorch 镜像代码放 OBS算力规格GPU 单卡如 V100小任务单卡足够免费额度优先数据输入OBS 的 train 目录挂载到容器内路径模型输出OBS 的 output 目录训练完的模型存这里超参epoch30, lr0.001, batch32可在界面直接传参这里有个细节代码里读取数据的路径要用容器内的挂载路径不是 OBS 路径。比如你在界面上把 OBS 的train/挂载到/home/ma-user/work/data/那代码里就要读这个本地路径。我第一次就是直接写了 OBS 路径结果报文件不存在。4.3 训练过程监控与日志查看训练启动后可以在作业详情页看实时日志。我习惯重点盯三个东西loss 曲线是否稳定下降有没有震荡或突然变 nan。学习率是否按预期衰减。GPU 利用率如果一直很低可能是数据加载成了瓶颈。日志里如果出现lossnan基本就是学习率太大或者数据里有脏样本。我遇到过一次排查发现是某张图片损坏读出来全是 0导致梯度爆炸。解决办法是在数据加载时加一层校验跳过异常图片。实操心得训练脚本里一定要加 checkpoint 保存逻辑每隔几个 epoch 存一次。我有次训练到第 25 个 epoch 因为超时被中断幸好有 checkpoint续训没白跑。5. 模型部署把训练结果变成可调用的服务5.1 部署前的模型转换与推理脚本训练完的模型是.pth文件要部署成在线服务需要准备一个推理脚本customize_service.py里面定义模型怎么加载、怎么处理输入、怎么返回结果。这是部署环节最容易卡住的地方。推理脚本的核心结构大概是这样from model_service.pytorch_model_service import PTServingBaseService import torch 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() def _preprocess(self, data): images [] for _, file in data.items(): img Image.open(io.BytesIO(file)).convert(RGB) # 这里要做和训练时一致的预处理 images.append(transform(img)) return torch.stack(images) def _inference(self, data): with torch.no_grad(): return self.model(data) def _postprocess(self, data): # 转成类别标签返回 ...关键点预处理必须和训练时完全一致。归一化的均值方差、resize 的尺寸错一个都会导致推理结果离谱。我一开始就是 resize 尺寸写错了训练用 224推理写成 256结果准确率掉了一大截。5.2 部署配置与在线服务测试在 ModelArts 里创建在线服务时选“从模型导入”指定模型文件所在的 OBS 路径和推理脚本然后选一个 CPU 或 GPU 规格。小模型用 CPU 就够成本低大模型或者对延迟敏感才上 GPU。部署完成后平台会给你一个 API 地址。可以直接在控制台的“预测”页面传图片测试也可以用 curl 调curl -X POST https://your-endpoint/v1/infers/xxx \ -H Authorization: Bearer YOUR_TOKEN \ -F imagestest.jpg注意在线服务是按小时计费的测试完记得停掉不然会一直扣费。我就因为忘了停白白多花了几十块。5.3 部署后的性能与成本优化如果服务调用量不大可以考虑用“批量服务”代替“在线服务”成本更低。另外模型可以量化压缩把 float32 转成 int8推理速度能提升不少精度损失通常在可接受范围内。还有个经验把预处理逻辑尽量放到客户端做服务端只做推理这样能减少服务端的计算压力响应也更快。6. 常见问题与排查技巧实录6.1 训练报 nan 的排查思路lossnan是训练里最常见的问题我的排查顺序是检查学习率是不是太大先降到 1e-4 试试。检查数据里有没有损坏图片或标签越界。检查损失函数分类任务用 CrossEntropyLoss 时输入不要自己加 softmax。加梯度裁剪torch.nn.utils.clip_grad_norm_。6.2 部署后推理结果不对怎么查先确认预处理是否和训练一致这是 90% 的问题来源。其次检查模型加载时是不是漏了eval()导致 dropout 和 batchnorm 还在训练模式。最后看输入数据的通道顺序PIL 读出来是 RGBOpenCV 是 BGR别搞混。6.3 常见问题速查表问题现象可能原因解决办法训练读不到数据路径写成 OBS 路径改用容器内挂载路径loss 变 nan学习率过大/脏数据降 lr、清洗数据、加梯度裁剪部署推理慢用了 CPU 大模型换 GPU 或量化模型服务一直扣费忘记停止在线服务测试完及时停用准确率低预处理不一致对齐训练和推理的 transform6.4 几个我踩过的坑第一个坑是免费算力额度用超了。我以为免费额度很多结果调试阶段反复启动训练作业额度很快见底。后来学乖了先在本地用小样本验证代码确认没问题再上云跑全量。第二个坑是推理脚本的依赖问题。我在脚本里 import 了一个镜像里没有的库部署直接失败。解决办法是提前确认镜像里有哪些包或者把依赖打包进模型目录。第三个坑是OBS 路径权限。训练作业用的委托权限如果没配好读不到数据也写不了输出。这个在创建作业时平台会有提示仔细看就行。7. 一些关于成本与效率的个人体会跑完整个流程我最大的感受是云上训练真正的成本不在算力而在调试时间。算力按小时计费但如果你代码有问题反复启动作业浪费的时间和额度才是大头。所以我的建议是本地能验证的逻辑尽量本地验证云端只跑最终版本。另外ResNet 这类预训练模型真的是小团队的福音。以前觉得训模型是算法工程师的专属现在发现只要会用迁移学习后端开发也能跑出可用的模型。ModelArts 把环境、算力、部署这些脏活累活都包了剩下的就是写好那几十行训练和推理代码。最后分享一个小技巧训练脚本里把关键参数学习率、batch size、epoch都做成命令行参数这样在 ModelArts 界面上改超参就不用动代码调试效率高很多。这个习惯我从第一次训练保持到现在确实省事。
阅读完成 · 觉得有帮助?
咨询建站