☰
云端AI实践:基于ModelArts的图像分类模型训练与部署全流程
2026/10/11 9:04:46 网站建设 项目流程

1. 整体思路梳理:学习笔记到底在记什么

1.1 为什么是ModelArts,而不是自己搭一套环境

先交代一下背景。这份学习笔记记录的是一次完整的“训练图像分类模型并部署成在线服务”的实操过程。所谓图像分类Demo,其实就是拿一批带标签的图片,让模型学会辨别不同类别,训练完以后部署一个HTTP接口,能接收图片返回类别结果。听起来不复杂,但真要走通一遍,中间涉及的环境搭建、数据上传、训练调度、模型发布、接口配置,任何一个环节都能卡住人。

我一开始也想过:要不要在本地机器上装环境,自己写训练脚本,训练完再用Flask包一个服务。这个思路对少量数据和实验没问题,但很快会遇到几个现实问题。第一,本地机器的显卡性能有限,跑几个epoch还能忍,数据集一大或者模型结构深一点,训练时间就是按天算的。第二,训练完的模型要给别人用,正经做法是把它封装成能并发处理请求的服务,本地机器没法保证稳定的线上运行环境。第三,环境依赖特别容易出问题,Python版本、CUDA版本、PyTorch版本,稍微对不上就能折腾一晚上。

ModelArts这套东西刚好把这些麻烦打包处理了。它本质上是一个面向机器学习的全流程平台,把数据管理、开发环境、训练资源、模型管理、部署推理串成一条线。你不需要关心物理机在哪、显卡是什么型号,只需要在后台上传数据、写代码、配置训练参数,剩下的调度和资源分配由平台完成。最终训练出来的模型,可以在同一个平台里直接发布成在线推理接口。这种“一站式”的设计,对只想把模型跑通、把服务跑起来的人来说,确实省心很多。

这份笔记面向的读者,我默认是两类人。一类是刚接触云上AI开发、想了解完整流程的同学,你可以把它当成一份地图,知道每个环节该做什么、会遇到什么;另一类是已经有些机器学习基础、但第一次用ModelArts的工程师,你可以直接跳到第3章第4章,照着步骤操作。笔记里凡是涉及具体操作的地方,我都会额外解释一句“这一步为什么要这么做”,因为纯粹照着点按钮没有意义,搞懂逻辑才能应对变化。

1.2 训练到部署的标准动作长什么样

整条流程可以拆成六个环节:开通环境、准备数据、编写代码、发起训练、导入模型、部署服务。我自己梳理了一遍,它们之间的依赖关系大概是这样的:

  1. 开通ModelArts服务,创建OBS桶(对象存储),这是所有数据的中转站。
  2. 把训练用的数据集上传到OBS桶,组织成规范目录。
  3. 创建Notebook实例,在开发环境里写代码、调参数、验证逻辑。
  4. 把验证过的代码和训练任务提交为训练作业,用弹性算力跑正式训练。
  5. 训练完成后把输出模型登记到模型管理里,完成版本注册。
  6. 创建在线服务,把模型部署为API,对外提供推理能力。

这个顺序不是随便定的,每一步都为下一步铺路。比如一开始就要建OBS桶,因为Notebook里的代码、训练用的数据集、训练输出的模型,全都得靠OBS中转。再比如先要用Notebook跑小规模试验,因为训练作业是异步的,你在等待队列里排着,如果代码有低级错误,一个小时的训练任务可能跑两分钟就崩了,纯白费钱。先小规模验证逻辑,再上正式资源,这是能省钱省时间的关键习惯。

我用到的案例是一个交通标志分类的小型数据集。总共有几千张图片,分为限速、禁止通行、转弯等几个类别。这个数据集规模不大,但对整个流程验证来说很合适:既能让模型学到有效特征,又不会让训练时间长得耽误事。整个过程从零开始到接口调通,带着学习心态一点点推进,大约花了一个工作周。如果把各个坑都提前避开,集中精力走的话,两三天完全够用。

2. 环境准备与数据环节:地基打不牢,后面全白搭

2.1 账号、权限与OBS桶的创建细节

第一次打开控制台的时候,最容易懵的不是功能本身,而是那些彼此纠缠的权限概念。ModelArts要从OBS里读数据,要把训练日志写到OBS,要在不同模块之间传模型文件,这就需要你给不同服务授权。我在这一步踩过一次坑:直接在控制台创建了一个并行文件系统,想着“先建着再说”,结果后面训练作业访问数据时提示没有读写权限,排查半天才发现存储类型和授权策略都没弄对。

正确做法是这样的。第一步,确定你要用OBS桶还是并行文件系统。ModelArts的Notebook和训练作业都能读这两种,但实际体验下来,绝大多数场景用OBS桶就够了,并行文件系统更适合需要多机并发读写的场景。第二步,创建桶时尽量选择和自己ModelArts区域一致的区域,跨区域访问会有延迟,而且可能会产生额外流量费用。第三步,检查“访问授权”面板,ModelArts控制台首页通常会引导你完成一个委托授权,这个委托允许ModelArts服务帮你读写指定的OBS路径。没有这个委托,后面导入数据、保存模型都会报权限错误。

这里有一个细节:OBS的目录结构,最好一开始就规划好。我见过有人把所有数据乱七八糟放在桶根目录,训练脚本里写死路径,换一个数据集就得改代码。更合理的结构大概是这样的:

obs://ai-project-demo/ ├── data/ │ ├── train/ │ │ ├── class_a/ │ │ ├── class_b/ │ │ └── class_c/ │ └── eval/ │ ├── class_a/ │ ├── class_b/ │ └── class_c/ ├── output/ │ ├── logs/ │ └── models/ └── codes/ └── train.py

把训练数据和评估数据分开,类别目录单独建,这对后面用PyTorch标准的ImageFolder接口加载数据非常友好。你只需要在代码里写train_dataset = datasets.ImageFolder(root=args.train_path),它会自动按子目录名生成类别标签。不用自己手写一大堆标签映射逻辑。

2.2 数据集的上传与校验:别让数据成了隐形炸弹

数据上传这块,很多人觉得不就是传到桶里嘛,用控制台拖拽一下就完事了。确实,小数据集用控制台上传没有问题,但如果你有几十G的数据,网页上传会非常慢,而且中途断了很难续传。我用到的数据集规模还不算大,用的是OBS提供的命令行工具,把本地的train和eval目录一次性同步上去,速度稳定很多,传输中间出了错也能通过重跑命令续传。

数据上传好之后,强烈建议做一个完整性检查。我在第一次实践时,图省事直接开始后续流程,结果训练过程中频繁报“图像解码失败”。后来查明是上传时个别图片文件损坏。这个教训挺深刻:数据是模型的输入,输入质量决定了训练能不能顺利跑完。一个好习惯是写一段简单的脚本,遍历图片目录,用Python的PIL库尝试打开每张图片,打不开的就记录下来剔除掉。几十行代码,跑一遍也就几分钟,能把后面几小时的折腾省下来。

另外,类别标签的命名最好用英文。ModelArts的自动标注和后续模型管理对中文字段支持虽然可以,但训练脚本里的路径、日志输出、模型注册的元数据,全用英文最稳妥。交通标志的名称我用的是speed_limit、no_entry、turn_left这类语义化的英文命名,清晰又不会产生编码问题。

2.3 Notebook实例的规格选择:不是越贵越好

Notebook是ModelArts里最常用的交互式开发环境,它本质上是一个云端运行的JupyterLab。你在浏览器里打开它,写代码、跑命令,背后是平台给你分配的一台带GPU的虚拟机。这个设计对开发调试环境非常方便:不需要在本地装任何深度学习框架,打开浏览器就能用。

但选规格的时候要注意,Notebook不是配置越高越好。它的计费是按运行时长来的,你跟它耗一天,它就收一天的钱。实践中的合理做法是:日常调试代码、看看数据长得什么样、验证模型结构能不能跑通,用便宜的CPU规格或者入门级GPU规格就够了;真正要跑大规模训练的时候,再升级到高性能GPU,或者直接把任务提交成训练作业,用训练作业的弹性资源去跑。

这里我展开说一个观点:Notebook和训练作业这套“双轨制”设计,很多人刚接触时不太理解,觉得“我直接在Notebook里训练不就行了,为什么还要提交训练作业?”其实两者的定位完全不同。Notebook是交互式的、面向开发的,适合你反复修改、小步快跑的阶段;训练作业是批处理式的、面向生产的,适合你已经把代码逻辑验证好、需要确定性资源执行完整训练的阶段。训练作业在后台独立运行,不依赖你的浏览器会话,关掉页面它照样跑;而且训练作业能比普通Notebook调度到更强的算力资源。所以标准流程就是:Notebook负责调通代码,训练作业负责正式干活。

创建Notebook实例时,有几个参数需要稍微琢磨一下。一个是“自动停止”时间,我习惯把它设成1小时或者2小时,防止中午吃饭回来忘记关,白白计费。另一个是存储空间,默认的几GB对于代码调试足够,如果你要把完整数据集拷进Notebook本地做数据探索,那就要预留更多空间,或者干脆直接从OBS路径读取数据,不拷贝到本地。我在实践里就是把训练数据放在OBS,Notebook代码直接用OBS路径访问,这样省掉了数据同步的时间。

3. 模型训练环节:从调通脚本到跑满算力

3.1 在Notebook里把训练脚本调试到“不虚”

ModelArts的Notebook环境预装了常用的深度学习框架,PyTorch、TensorFlow都有,而且版本比较新。省去了自己配环境这一步,确实爽快。但要注意,预置环境的版本不一定和你的代码习惯完全匹配,所以推荐的稳妥做法是:在Notebook里创建一个独立的虚拟环境或者直接用系统环境,先跑一个最小的训练demo验证基础依赖。

我用的框架是PyTorch,数据加载走torchvision.datasets.ImageFolder,模型用的是ResNet18这种经典的轻量级结构,因为交通标志分类的任务复杂度不算高,用ResNet18足够了,没必要上ResNet50以上那种又重又慢的模型。训练脚本的核心逻辑不算复杂,无非是定义数据加载、定义模型、定义损失函数和优化器、然后循环迭代。但有几个细节直接关系到后面训练作业能否顺利运行。

第一个细节是数据路径不能写死。你在Notebook里调试时,数据可能在/home/ma-user/work/data,但提交训练作业以后,数据会被平台重新挂载到另一个路径。如果代码里把路径写死了,作业一跑准报错。正确做法是用argparse接收命令行参数,在提交训练作业时通过参数传入数据路径。第二个细节是超参数要集中定义,比如学习率、batch size、训练轮数,都用参数传,后面调参就不用改代码,直接在训练作业配置里改数值。第三个细节是模型保存路径,训练完的模型要保存成指定格式,并输出到指定目录,因为训练作业结束后,只有输出目录里的文件才会被平台持久化保存。

在Notebook里调代码时,我习惯先用很小的数据集规模做冒烟测试。比如直接从每个类别取几十张图片,设置只跑两三个epoch,看看loss会不会下降、模型的保存逻辑对不对、代码跑完到底会不会报错。冒烟测试通过之后,再去跑完整数据。这一步非常重要,它能把代码层面的低级错误在低成本环境下快速暴露,避免浪费训练资源。

3.2 创建训练作业:参数配置不是填空题

Notebook里的代码调通之后,下一步就是创建训练作业。这是从“开发模式”切到“生产模式”的转折点。进入训练作业创建页面,需要配置的东西包括:作业名称、算法来源(可以选择使用预置算法,也可以选择自定义镜像或者直接提交训练脚本)、训练启动文件、数据输入位置、训练输出位置、资源规格等。

我选择的是直接提交训练脚本的方式。这种方式最灵活,适合已经写好Python代码的场景。配置数据输入位置时,要指定OBS里的数据路径;配置训练输出位置时,指定一个OBS目录用来保存输出的模型文件。这里有一个非常关键的点:训练输出目录,在训练脚本里并不是一个真实存在的本地路径,你需要通过环境变量去获取它的值。

在ModelArts的训练作业机制里,平台会把用户在界面上配置的“训练输出路径”通过环境变量暴露给训练容器,常见的是TRAIN_OUTPUT_DIR或者通过参数train_output_dir传入。我第一次做的时候没搞清楚这一点,在脚本里硬编码了/tmp/model保存模型,结果训练结束一看,模型根本不在输出目录里,自然也无法导入模型管理。后来改正为:在代码里读取传入的输出目录参数,把最终模型文件保存到那个路径下,问题就解决了。

资源规格的选择,我建议量力而行。刚开始实践时,选一个中等规格的GPU实例就好,既不会贵到离谱,也能保证训练时长在合理范围内。我的项目训练数据几千张图片,ResNet18结构,在中等GPU上跑20个epoch,大概几个小时完成。如果选最低配置,虽然单价便宜,但训练时间拉长后总费用反而可能更高。这个账要会算:费用等于单价乘以时长,便宜未必省,快未必贵。

3.3 训练日志与效果分析:别只会看loss曲线

训练作业启动后,界面会展示运行状态,日志也会实时刷新。新手容易犯的错是:日志一大堆,不知道该看什么。我自己的经验是分三层去看。

第一层看启动阶段,确认环境、数据、代码都正常加载,没有出现文件不存在、模块导入失败这类错误。第二层看训练过程,关注每轮的loss数值和评估精度变化,如果loss下降平稳、精度逐步提升,说明训练是健康的;如果loss一直不降,或者数值跳来跳去,就要考虑是不是学习率设置有问题,或者数据加载有异常。第三层看结束阶段,确认模型文件是否正确保存、是否记录了一些关键指标。

如果训练作业失败了,第一步要做的不是凭直觉改代码,而是去翻日志报错信息。我遇到过几次典型的失败原因。比如代码里用了相对路径读取本地文件,而训练作业运行时的工作目录和Notebook不同,导致文件找不到。再比如代码里申请的显存超过了训练实例的显卡容量,直接就OOM崩溃。还有一种比较隐蔽的问题:训练脚本里打印的日志太多,把日志系统刷崩了,这时候要减少不必要的日志输出。

训练效果这块,光看训练集的loss是不夠的,一定要看验证集上的表现。我在脚本里设置了每个epoch都评估一次验证集精度,并把最高精度的模型保存下来。最终这个交通标志分类Demo在验证集上的准确率达到了95%以上,作为流程验证来说,效果已经完全够用了。

4. 模型部署环节:把模型变成别人能用的接口

4.1 模型导入与元数据配置:这一步有一堆细节

训练作业跑完,模型文件已经在OBS输出目录里了。这时候还需要把它“登记”到ModelArts的模型管理模块,才能继续走部署流程。很多人会困惑:我的模型就是一个.pth文件,直接拿去部署不行吗?答案是不行。ModelArts的部署模块需要你提供一份“模型配置文件”,说明这个模型的推理逻辑长什么样、输入输出是什么格式、怎么加载权重。

这个配置文件的本质,是把你训练时的PyTorch模型,包装成一个符合平台规范的推理服务。ModelArts支持两种常见的封装方式:一种是使用平台提供的推理引擎,配合一个自定义的预处理脚本;另一种是直接提供一个完整的Python推理脚本,平台按约定把HTTP请求交给这个脚本处理。我这次用的是后者,因为自定义程度更高,方便控制输入输出的具体格式。

模型配置中最核心的部分是定义一个_infer方法。平台规定,推理脚本需要实现特定的接口方法,比如接收解析后的请求数据,执行模型推理,返回结果。我当时写的处理逻辑大概是:接收前端传来的图片二进制数据,读入PIL转换成RGB三通道,缩放到模型输入尺寸(如224×224),转成Tensor,经过归一化和维度扩展,喂给模型forward,得到预测类别和置信度,最后拼成JSON返回。这一步的逻辑并不难,难的是别漏掉平台的签名约定。

除了推理脚本,还要把模型文件和配置文件放在同一个目录结构下。我之前把.pth模型放在一个嵌套很深的子目录里,结果导入时报找不到模型文件。后来按规范整理成:

model_repo/ ├── model.pth ├── config.json └── infer.py

三个文件平铺放在一起,config.json里声明模型文件路径和推理脚本名称,平台就能正确识别。这种目录要求第一次接触时觉得繁琐,但想明白了就理解:部署模块需要一个无歧义的方式来定位模型和代码,标准的目录结构就是最稳定的约定。

4.2 创建在线服务:关键参数与部署等待

模型导入成功之后,就可以创建在线服务了。这个过程在界面上看就是几步配置:选择刚才导入的模型、指定版本、选择部署的实例规格、设置服务名称和描述。但有几个参数需要提前想清楚。

一个是“实例数”,默认是1。如果在测试阶段,1个实例完全够用。如果业务预期有比较大的并发流量,再考虑调多实例,但对应的成本也会上升。另一个是“分流”,ModelArts支持把一个服务内部的流量按比例分给不同版本的模型,方便做灰度发布。第一次使用时不需要研究这么深,先部署单个版本测试通就行。

部署过程通常会持续几分钟,从状态变成“运行中”才算完成。这个等待时间里,平台在做什么?它在把你的推理脚本和模型打包进一个容器,拉起服务,做健康检查,确保接口能正常响应之后才标记为运行中。如果推理脚本里有语法错误,这个阶段就会暴露。我遇到过的情况是:本地Python环境里某个第三方库能import,但部署环境里没有预装这个库,服务启动时直接报ModuleNotFoundError。解决方法是查阅平台的预置依赖列表,尽量只使用标准库和torchvision等预置组件,或者把需要额外安装的依赖声明在配置文件的依赖字段里。

服务创建好之后,会得到一个调用地址。测试时可以直接在平台页面里上传一张图片,查看返回结果;也可以用自己的代码发HTTP请求调用这个接口。我两种方式都试过,页面调试方便但不适合反复批量测试,代码调用才能模拟真实使用场景。写了一个几十行的Python脚本,用requests库把测试图片POST到接口地址,解析返回的JSON,打印类别和置信度。第一次把接口完全调通的时候,确实有一种“闭环了”的感觉——训练好的模型,此刻变成了一个真正可访问的服务。

4.3 调用测试与运维视角:部署完不代表结束

部署完成、接口调通,很多人会觉得大功告成。但站在实际使用的角度,还有几件必须做的事。

第一件事是记录接口的鉴权信息。ModelArts的在线服务默认是需要在请求头里携带一个Token的,这个Token从控制台获取,有效期有限。刚开始测试时我忘了加请求头,或者用了过期的Token,接口返回401错误。排查几次之后才养成习惯:每次调用前先检查Token是否过期。这个细节在写调用脚本时尤其重要。

第二件事是关注服务的监控指标。ModelArts的控制台会展示服务的调用量、平均响应时延、错误率等信息。测试阶段也许看不出什么,但假如服务正式对外上线,这些指标就是运维的生命线。我在实践中就观察到,某个时间段的响应时延突然变长,查了之后发现是因为测试图片尺寸过大,推理脚本里resize逻辑加了一些额外耗时。后来优化了图片预处理流程,时延又降回去了。

第三件事是成本意识。在线服务是按实例运行时长计费的,只要服务状态是“运行中”,即使没有任何请求,也在产生费用。如果想省钱,测试完一定要记得删除部署的服务,或者把它停止。我有一次忘记删除,过了几天才想起来,白白扣了一笔费用。从那以后,我给自己定了一个规矩:每个学习阶段结束之后,第一件事是检查后台有哪些资源还在运行,该关的关,该删的删。

5. 实战问题与避坑记录:这些坑希望你不用再踩

5.1 高频问题速查与排查思路

做完整套流程,我把实际操作里遇到频率最高的问题整理成一个速查表,方便以后遇到同类问题快速定位。

现象可能原因排查方向
训练作业启动后秒失败代码里有语法错误或依赖缺失先看启动阶段日志,处理ModuleNotFoundError和路径问题
OBS数据读取报权限错误委托授权未配置或配置范围不足回到访问授权页面重新完成ModelArts委托设置
模型无法导入模型管理目录结构不符合规范按config.json + model文件 + 推理脚本的平铺目录调整
部署的服务启动失败推理脚本依赖库未预置检查平台预置依赖列表,调整代码减少额外依赖
调用接口返回401Token过期或未携带请求头从控制台重新获取Token,检查请求头拼写
模型推理结果全部是同一类别预处理逻辑与训练时不匹配确认图片Resize、归一化参数是否和训练代码一致

这张表里的每个问题,我都实际踩过。最让我印象深刻的其实是最后一个:模型推理结果全是同一个类别。第一次遇到时,我怀疑模型是不是训练坏了,重新看训练日志,训练集精度明明很高,验证集也没问题。折腾了一阵才想到,推理服务端的图片预处理逻辑和训练时不一样:训练时图片先缩放再居中裁剪,推理时我只做了缩放,没有做中心裁剪,导致输入分布的差异过大,模型输出的类别全部偏到了某一类上。找到问题后,把推理脚本里的预处理流程改成和训练保持一致,结果立刻正常。

5.2 成本控制与效率提升的几条心得

最后聊聊成本和效率,这是云上开发永远绕不开的话题。我的体会可以浓缩成几个原则。

第一个原则是“能小则小,能快则快”。在Notebook调试阶段,尽量用小数据集、少epoch、低规格实例。调通再上大规格,不要在调试阶段用大机器跑长时间任务。第二个原则是“无状态思考”。训练和推理环境都是临时的,代码里不要依赖任何本地持久化状态,所有需要保留的文件都主动保存到OBS路径。这样即使环境出问题,随时重建一个实例也能接着跑。第三个原则是“及时释放”。Notebook用完就停,在线服务测完就删,不要让它开着过夜。养成习惯之后,每个月的账单会好看很多。

关于效率还有一个建议:写脚本时把常用的功能封装成函数或模块。比如数据加载、模型构建、评估指标计算,这些代码在Notebook调试时有,在训练作业里也要用,如果一开始就写成独立模块,后面提交训练作业时直接引用就行,不用重复写。我就是一开始图省事在Notebook里写了一段扔一段,后面提交训练作业时不得不返工整理代码,浪费了不少时间。

这套流程跑通之后,我最大的感受是:ModelArts把很多底层烦琐的事情藏起来了,让注意力可以集中在模型本身的逻辑上,但前提是你得理解每一步背后的约定和数据流转方式。比如路径怎么映射、参数怎么传递、模型怎么打包,这些约定是平台自己定义的,文档里都写了,但你只有自己踩过一遍才会真正记住。这份学习笔记与其说是教程,不如说是一个踩坑记录,希望后来的人看到之后,能比我更快地跑通第一遍流程。

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

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

立即咨询