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

华为云ModelArts实战指南:从数据准备到模型部署全流程解析

华为云ModelArts实战指南:从数据准备到模型部署全流程解析 ★ FEATURED ARTICLE
搞了个把月ModelArts从上传数据到部署上线完整走了一遍现在回头把这阵子的学习笔记整理出来。这篇文章适合两种人看一种是刚接触华为云AI平台、还不清楚从哪里下手的初学者另一种是平时用本地GPU训练、想试试云上流程但一直没动手的朋友。我会按照自己实际操作的顺序来写把每一步为什么要这么做、有哪些细节值得注意都讲清楚。1. 为什么选ModelArts而不是自己在服务器上折腾说实话最开始我是在本地机器上跑的模型训练。装驱动、配CUDA、调环境变量每次换一台机器都要重新来一遍相当折磨人。后来数据量上来本地显卡显存明显不够用训练一个稍大点的模型要跑两三天我就开始考虑云平台。华为云ModelArts进入我视野主要有几个原因。第一它把整个模型生命周期都串起来了——从数据准备、代码调试、模型训练到最后的部署上线不需要在多个服务之间来回跳。第二按需付费的模式很灵活不像自己买服务器那样前期投入大。第三平台预置了不少常用框架的镜像省去了配环境的痛苦。从实际体验来看ModelArts值得用的核心场景是这几个模型训练需要GPU但本地没有合适硬件训练好的模型要快速变成一个可供外部调用的API服务希望用自动学习AutoLearning快速验证一个想法不用写太多代码学ModelArts的过程中我最大的感受是它不只是把算力卖给你更重要的是把工程化的流程给标准化了。你只管写好训练脚本、调好参数剩下的事情平台帮你处理但前提是你得理解其中的工作逻辑。2. 切入ModelArts之前先搞清几个核心概念的边界在真正动手之前我建议你先花半小时理解ModelArts的基本概念不然很容易晕头转向。我有好几个朋友一上来就卡在概念混淆上。2.1 OBS存储与数据集的管理逻辑ModelArts本身不存数据数据放在华为云的对象存储服务OBS里。你可以把OBS理解成一个网络硬盘ModelArts的训练作业、Notebook实例都从OBS读取数据训练产物也回写到OBS。我第一次用的时候犯了个错误直接把数据传到ModelArts的Notebook里结果发现Notebook实例一旦释放数据就没了。正确的做法是先把数据整理好传到OBS的桶Bucket里ModelArts各个模块都通过OBS路径来访问数据。在OBS里建议这样组织数据bucket-name/ ├── data/ │ ├── train/ │ └── val/ ├── code/ │ └── train.py └── output/这样的好处是训练脚本和数据的路径清晰后续调试和模型版本管理都方便。2.2 Notebook、训练作业、自动学习之间的分工ModelArts里有几个高频使用的模块它们的定位完全不同Notebook适合做代码调试和小规模实验。你可以理解为一个JupyterLab环境在里面写代码、看图、调参非常灵活。但NoteBook适合做探索不太适合跑大规模训练。训练作业Training Job适合正式训练。你把训练脚本和数据集路径指给它它会在独立分配的算力资源里跑训练任务。训练作业会有更完善的日志、监控和故障重启机制。自动学习AutoLearning适合不想写代码的场景。你只需要上传标注好的数据平台会自动构建模型并训练整个过程像用傻瓜相机一样简单。搞清楚自己处于哪个阶段选择对应的模块就不会把时间浪费在不合适的工具上。我通常的模式是Notebook里做数据探索和脚本调试然后在训练作业里跑正式训练最后用自动学习做快速验证和基线对比。2.3 模型注册与部署服务的关系训练完成后模型需要先注册到ModelArts的模型管理里然后才能部署为在线服务。注册模型时要指定模型文件和推理代码的OBS路径以及运行环境的元数据。这里我踩过一个坑本地能跑的模型部署到ModelArts上却不工作。原因是我本地的依赖版本和平台预置镜像不一致。后来我学会了在模型注册时明确指定推理代码所用的依赖问题才解决。后面我会专门讲这个。3. 第一次从零跑通一个图像分类训练的完整拆解理解了概念接下来看实操。我选了一个经典的图像分类任务作为入门案例数据集是公开的CIFAR-10。这个案例不大不小既能走完整个流程又不会因为训练时间太长而让人失去耐心。3.1 上传数据到OBS桶数据准备这步看似简单但细节不少。CIFAR-10数据集下载下来之后原始格式是pickle序列化文件不适合直接用于训练需要先转换成图片目录结构。我用了一段Python脚本做转换import os import pickle import numpy as np from PIL import Image def unpickle(file): with open(file, rb) as fo: dict pickle.load(fo, encodingbytes) return dict # 解压训练集和测试集 # 生成目录: train/类别名/图片.jpg # 生成目录: val/类别名/图片.jpg转换完成后我通过OBS控制台上传数据。数据集总大小不到200MB上传速度还行。如果数据量较大推荐用OBS命令行工具obsutil断点续传和并发上传的能力更强# 配置obsutil ./obsutil config -i你的AK -k你的SK -e你的Endpoint # 上传目录 ./obsutil cp ./data obs://你的桶名/data/ -r上传成功后的数据路径是obs://桶名/data这个路径后面会经常用到。3.2 在Notebook里调试代码我把训练脚本的初版写在Notebook里用一小部分数据跑通流程。选择modelarts.xlarge规格的实例每小时费用不高适合开发调试。在Notebook里调试有几个好处。一是可视化的图表输出方便检查数据预处理的效果二是可以实时看到每行代码的输出排查问题效率高。我习惯先用1%的数据验证模型能正常收敛再决定是否提交训练作业。示例如下import torch import torchvision import torchvision.transforms as transforms transform transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) trainset torchvision.datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform) trainloader torch.utils.data.DataLoader(trainset, batch_size64, shuffleTrue, num_workers2) # 定义简单的CNN模型并训练3.3 从Notebook迁移到训练作业调试完毕把脚本迁移到训练作业里。训练作业和Notebook有一个关键区别训练作业不是交互式的它执行完train.py就自动退出你需要用argparse接收参数。我的脚本结构调整为import argparse parser argparse.ArgumentParser() parser.add_argument(--data_url, typestr, requiredTrue, help训练数据路径) parser.add_argument(--train_url, typestr, requiredTrue, help训练输出路径) parser.add_argument(--epochs, typeint, default10) parser.add_argument(--batch_size, typeint, default64) args parser.parse_args()在创建训练作业时我指定了这两条路径数据来源选为obs://桶名/data训练输出位置填obs://桶名/output。平台会自动把OBS数据目录映射到训练容器里的本地路径并把输出目录回传到OBS。3.4 训练作业的参数配置与掌控训练作业页面里需要配置的地方不少我最关注的有三个规格选择、日志输出和训练参数设置。规格选择直接影响训练速度也影响费用。CIFAR-10这种小数据集我选了单卡GPU规格大约10分钟完成10个epoch的训练。如果是大模型建议关注多卡分布式训练的能力但入门阶段单卡足够。日志是排查问题的关键。训练脚本里我添加了打印loss的代码for epoch in range(args.epochs): running_loss 0.0 for i, data in enumerate(trainloader, 0): inputs, labels data optimizer.zero_grad() outputs net(inputs) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() if i % 100 99: print(f[epoch {epoch1}, batch {i1:5d}] loss: {running_loss / 100:.3f}) running_loss 0.0在训练作业的日志面板里这些print内容会实时刷出来观察loss变化就能快速判断模型是否在学习。4. 训练过程中的日志监控与异常排查训练跑起来之后不代表可以高枕无忧了。在ModelArts上跑训练日志和异常排查能力是每天都用得上的硬技能。4.1 实时查看训练日志和资源指标训练作业页面有日志查看入口可以看到标准输出和标准错误。我一般会重点关注几个指标loss值是否稳定下降、每轮epoch的耗时、是否存在GPU显存溢出OutOfMemory。资源监控里可以看到GPU利用率、显存占用、CPU利用率和内存使用情况。有一次训练到第40个epoch时GPU利用率突然掉到个位数日志里又没有任何报错。排查后发现是数据加载的瓶颈——磁盘IO跟不上GPU的消费速度。解决方法是增加num_workers和预取数据的prefetch_factorGPU利用率重新回到90%以上。4.2 训练过程中出现的NaN问题定位方法很多人训练时遇到过loss变成nan的情况我这次在调大学习率时也复现了。第一次遇到时比较慌后来总结出了排查思路先看学习率是否过大这是最常见的nan诱因再看数据预处理是否标准化输入值量级不一致会导致梯度爆炸查看网络结构里有没有除零操作或log(0)的场景检查loss计算是否溢出我把学习率从0.01调小到0.001后nan问题消失。如果调小学习率仍出现nan就要检查数据的标签是否有异常值以及损失函数实现中是否有数值不稳定问题。4.3 服务异常时的告警配置与自动化恢复对于跑长时间训练的任务我建议配置告警规则。ModelArts支持在训练作业中设置事件通知当训练异常结束时可以触发短信或邮件告警不用一直盯着屏幕。除了告警还可以开启训练作业的自动重启机制。当训练因为可恢复的系统故障中断时平台会自动拉起新的实例并从上次保存的checkpoint继续训练。前提是你得在脚本里加上保存checkpoint的逻辑checkpoint_path os.path.join(args.train_url, fcheckpoint_epoch_{epoch}.pt) torch.save({ epoch: epoch, model_state_dict: net.state_dict(), optimizer_state_dict: optimizer.state_dict(), loss: loss, }, checkpoint_path)5. 模型部署的三种路径与在线服务的详细配置训练出模型只是第一步把模型变成可用的服务才是关键。ModelArts部署模型有几种路径我每种都试了一遍。5.1 在线服务的部署流程和配置细节最常见的需求是把模型部署为在线服务输入数据返回推理结果。操作上有几个关键步骤创建模型时除了模型文件路径还要配置推理脚本customize_service.py这个脚本定义了如何加载模型、如何处理输入输出。平台规定了推理脚本需要继承一个基类并实现_preprocess和_postprocess方法from model_service.pytorch_model_service import PTServingBaseService import torch import torchvision.transforms as transforms from PIL import Image import json import numpy as np class CIFAR10Service(PTServingBaseService): def __init__(self, model_name, model_path): super().__init__(model_name, model_path) # 加载模型 self.model torch.load(model_path, map_locationcpu) self.model.eval() self.transform transforms.Compose([ transforms.Resize((32, 32)), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) def _preprocess(self, data): # 处理请求中的图片数据 img data[image] if isinstance(img, str): img Image.open(img) img self.transform(img).unsqueeze(0) return img def _postprocess(self, data): # 将输出转为可读结果 probabilities torch.nn.functional.softmax(data, dim1) values, indices torch.max(probabilities, 1) return {predicted_class: int(indices[0]), probability: float(values[0])}部署时会让你选择计算规格我当时选了CPU规格推理耗时大约200毫秒对于这个模型体量足够了。GPU规格的响应更快但费用更高需要根据业务场景权衡。5.2 模型版本管理与灰度发布当模型迭代了一个新版本后旧版本在线服务需要平滑升级。ModelArts的模型管理支持多版本管理我可以在模型列表看到v1、v2这样的版本记录。更新在线服务时可以选择新版本模型并可设置灰度策略先让一小部分流量打到新版本上稳定后再全量切换。这个机制很实用。有一次我更新了模型后新版本对某种图片的识别结果偏离预期由于设置了灰度只影响了5%的流量很快排查出问题并回滚没有造成大的影响。5.3 批量推理和边缘部署作为补充路径对于不需要实时响应的场景可以创建批量推理作业一次性处理大量数据结果输出到OBS。这种方式适合离线打分、数据清洗等任务费用相对更低。如果模型将来要部署到设备端ModelArts还支持模型转换可以把模型转成适用于边缘设备的格式。这个方向我还在探索中入门阶段先专注在线推理会更高效。6. 结合其他部署方向的经验对比与思考学习ModelArts的过程中我也了解了一些业界常见的模型部署方式比如本地部署大模型、利用Ollama跑推理服务等这些和ModelArts形成了很好的参照。6.1 ModelArts与传统服务器部署的差异传统方式是自己买服务器、配环境、写API服务、做监控每一步都要自己来自由度最高但维护成本也最大。ModelArts把推理服务的底层运维封装好了可以快速上线和弹性伸缩。但代价是对底层环境控制力较弱有些特殊的依赖不一定能装进去。我的建议是追求快速上线、需要弹性伸缩、不想维护基础设施的场景选ModelArts需要深度定制运行环境、对数据安全有极高要求的场景考虑自建部署两者结合在ModelArts上做开发和验证模型稳定后再迁移到自有环境6.2 模型部署上线前的压测与容量规划不管你用哪种方式部署上线前做一次简单的压力测试是很有价值的。我写了一段简单的Python脚本用并发请求检验服务的吞吐import requests import concurrent.futures def call_once(url): img open(test.jpg, rb) resp requests.post(url, files{image: img}) return resp.status_code url 你的在线服务URL with concurrent.futures.ThreadPoolExecutor(max_workers20) as executor: futures [executor.submit(call_once, url) for _ in range(100)] results [f.result() for f in futures] print(fsuccess: {results.count(200)}/100)通过这个小工具我确认了当前规格能支撑的并发量避免了上线后服务被打爆。7. 从入门到熟练的关键总结与真实心得走完整个流程回头看ModelArts其实并不复杂核心是掌握几个关键环节的逻辑关系和细节处理。以下几个建议是我在实际操作中觉得最有价值的费用控制方面我在Notebook和训练作业上都设置过预算提醒。ModelArts的计费是按资源使用时长来的用完记得释放Notebook实例释放资源不然即使没在干活也会产生占用费用。有一个月我忘记关一个Notebook实例白白多花了几十块钱。对于长期不用的训练作业配置建议删掉或停止。数据处理和路径问题上OBS路径格式为obs://桶名/对象名在平台各个模块间传递很方便。养成把数据、代码、输出分开存放的习惯后续模型管理和回溯会省很多事。我见过有人把所有东西塞在一个目录下等模型出问题时想找对应的训练数据集和代码版本根本理不清。脚本设计方面尽量把训练脚本写成可以通过命令行参数控制的形式数据集路径、输出路径、超参数都通过argparse接收这样在不同平台间迁移时只需要改参数不需要改代码。这个习惯在从Notebook迁移到训练作业时帮了大忙。最后分享一个小技巧在模型部署上线后可以用一个简单的健康检查接口定期探测服务状态一旦返回异常就触发告警。ModelArts在线服务本身也提供健康检查配置设置好之后能第一时间发现问题。我在实际使用中发现在线服务偶尔会因为后端实例异常导致请求失败健康检查能快速发现这类问题并触发重建。把这个机制用起来服务稳定性会有一个明显的提升。
阅读完成 · 觉得有帮助?
咨询建站