1. 从一次本地训练翻车说起:我为什么转到ModelArts
先交代一下背景。我之前一直在本地用笔记本跑一些小模型,数据量小的时候还凑合,直到有一次要训练一个图像分类模型,数据集大概几千张图。笔记本的显卡转得跟风扇赛跑一样,一个 epoch 跑二十分钟,从头到尾调了两天参数,实在顶不住。身边做算法的朋友跟我提过几次“云上训练”,其中被提得最多的就是华为云 ModelArts。当时我对它的理解很模糊,以为就是一个“远程跑代码的服务器”,后来真用下来才发现,它比我想象的要完整得多——尤其是把训练和部署串成一条线这件事。
这篇学习笔记,我尽量按照我实际操作的顺序来写,从注册账号开始,到数据准备、训练作业、模型部署,最后把在线服务调通,全程基于华为云 ModelArts 完成。文中会穿插不少我第一次使用时踩过的坑,也有一些选型思路,尽量让第一次接触的朋友能少走一点弯路。
ModelArts 是一个面向 AI 开发者的托管式平台,你可以理解为“AI 开发全流程的一站式流水线”。它把数据准备、模型训练、模型部署这三个原本分散在好几套系统里的事情,集中到同一个平台上操作。对我这种不想自己搭 GPU 服务器、不想折腾 Docker 镜像、又不想写后端推理接口的人来说,它的价值是很直接的。
这篇笔记适合谁看?我觉得是两类人。一类是刚接触机器学习、想找一个能快速验证想法的环境;另一类是已经在本地跑过一些代码,但被环境和算力问题反复折磨,想了解云上流程怎么走通的人。如果你是这些情况中的一种,下面这些内容应该对你有用。
2. 先搞明白 ModelArts 到底帮我省了哪些事
2.1 它和我自己租台 GPU 服务器到底有什么区别
其实一开始我纠结过一个问题:我不就是用 GPU 跑代码吗,为什么不直接租一台带显卡的云服务器,自己装环境?后来想明白,ModelArts 和云服务器的区别,不只是一个“有没有预装环境”的区别。
自己租服务器的路线是这样的:买服务器、装驱动、装 CUDA、装深度学习框架、装各种依赖库,然后写脚本把数据传上去,跑完以后把模型下载下来,接着还得自己想办法把模型包装成 HTTP 接口,部署成服务。这条路不是走不通,而是每一步都在消耗你的注意力。尤其是环境安装,一次版本不兼容就能耗掉一晚上的时间。
而 ModelArts 把这些做了抽象,你不需要关心底层机器长什么样,只需要关注三件事:数据准备好了吗、训练脚本正确吗、模型怎么上线。它把“训练环境”和“推理环境”都封装成了可复用的服务,我只要选择算法、指定数据路径、配置资源,它会在后端的资源池里调度一台机器来跑,跑完以后结果直接存到对象存储里。
2.2 完整的链路价值:不只是训练,而是“训完就能部署”
我个人体会最深的一点是,ModelArts 不只是把“训练”这一个环节托管了,它把全流程都串起来了。数据在对象存储里,训练任务直接读;训练输出自动写回对象存储;然后可以在平台上一键把这个输出注册成 AI 应用;最后部署成 API 服务在线调用。
这种串联带来的好处,是你在每一步之间不用再做额外的搬运工作。我第一次走通全流程时的体感是:原来从“一个数据集”到“一个可以调用的接口”,中间竟然可以没有断点。这对学习阶段的帮助很大,因为减少了很多无意义的工程调试,把精力留给了模型本身。
2.3 我给自己规划的思路:先跑通,再深入
第一次接触 ModelArts 的时候,我担心它会不会很复杂,于是给自己定了一个最小目标:用一个小型数据集,跑通“数据上传 → 训练 → 部署 → 调用”这条链路。只要这条链路通了,后面再换自己的数据和算法,就只是替换中间环节的问题。
这个思路对我自己非常有效。后续所有章节里,我都会按照这个学习路径来展开。如果你也想快速建立对 ModelArts 的整体认知,建议你先别惦记那些高级功能,先让它把一条最简单的链路跑起来。
3. 开通账号与环境准备:最容易卡住的第一关
3.1 账号开通与实名认证
开始之前需要有一个华为云账号,这一步按官网提示操作就可以。我提醒一句:实名认证最好提前做完,因为创建部分资源、使用某些付费服务时,都会校验认证状态。如果之前没有注册过,整个过程大概十来分钟。
登录控制台以后,搜索“ModelArts”进入服务页面。首次使用需要点击“开通”,平台会自动在你的账号下创建一个独立的资源空间。这个“开通”操作是一次性的,后面使用就不需要再重复了。
3.2 创建 OBS 桶:先搞清楚它和 ModelArts 的关系
ModelArts 本身不保存你的原始数据和模型文件,它需要从对象存储服务 OBS 里读取数据,训练完成后再把输出写到 OBS。所以 OBS 桶是整条流程的“底座”,相当于你的数据仓库。
我创建 OBS 桶时第一次踩坑,就是在区域选择上。OBS 桶所在的区域,必须和 ModelArts 所在的区域保持一致。不然后面创建训练作业时,你会在数据路径里找不到自己的桶,或者明明上传了数据,训练任务却说文件不存在,实际上就是区域不通。我当时没注意,随便选了个区域,结果后面又把数据重新传了一遍,很浪费时间。
提示:区域这个概念一定要重视。控制台左上角有区域切换,创建 OBS 桶和后续使用 ModelArts 时,务必保持同一个区域。
3.3 桶的权限配置:学习阶段用私有桶就够了
创建桶的时候有一个“桶权限”选项,默认就是私有桶。对个人学习来说,私有权限完全够用。有些朋友会把权限设置成公共读,方便下载数据,但也会带来安全问题。学习阶段不用折腾权限,保持默认即可。
有一点需要说明:ModelArts 访问你的 OBS 桶是靠“委托”机制来完成的。创建训练作业时,平台会提示你授权一个委托,赋予 ModelArts 访问 OBS 的权限。按引导创建一个新的委托即可,比如选择“自动创建”,它会自动配置好最小必要权限,不需要手动折腾策略。
3.4 数据上传:控制台拖拽还是命令行工具
数据量小的时候,直接用 OBS 控制台上传就行,网页端支持拖拽上传,几百张图片、几十 MB 的规模完全没问题。
可我第一次遇到的情况是:数据集分了十几个子目录,单张图片虽然不大,但整体有差不多两个 GB。网页上传这种东西会非常吃力,中途断掉还得重新来。这时候最好用obsutil命令行工具,支持批量上传、断点续传,速度也要稳得多。
# 配置 obsutil 并上传一个文件夹到桶 ./obsutil config -i=你的AccessKey -k=你的SecretKey -e=你的Endpoint # 递归上传本地 data 目录 ./obsutil cp data obs://your-bucket-name/data -rAccessKey 和 SecretKey 在“我的凭证”里可以创建,建议只授权需要的权限。把数据传到 OBS 之后,可以在控制台里看到桶对象列表中已经出现完整的数据目录。
3.5 费用问题:学习阶段的省钱方案
这里必须说一下费用,因为这也是我第一次使用时比较担心的方面。ModelArts 多数能力都是按量计费的,比如训练作业按运行时长计费,在线服务按部署时长计费。学习阶段,只要不用的时候把资源释放掉,费用通常可控。
我自己建议一个原则:没在跑训练、没有在调试服务的时候,就把训练作业停掉,把在线服务删除。不要觉得“挂着也没事”,在线服务是按小时扣费的,挂一天就是一天的钱。后面第五节我会专门讲怎么控制这部分成本。
4. 数据准备:一份规范的数据集能省下大量调错时间
4.1 数据集从哪来:先用现成的,别自己折腾
我建议第一次学习时,不要一上来就用自己的业务数据。原因很简单:业务数据往往需要清洗、标注、格式整理,这些工作会和平台本身的流程问题混在一起,出了问题很难判断是数据的问题还是平台使用的问题。
ModelArts 的 AI Gallery 里有不少现成的数据集,找一个小规模的图像分类数据集来练手。我第一次用的是花卉分类数据,大概十几个类别,几千张图片,数据已经做好了标注,下载下来导入 OBS 就能用。先把流程跑通,之后再换自己的数据,逻辑是一样的。
4.2 上传到 OBS 之后的目录结构设计
数据集上传到 OBS 之后,目录结构会直接影响训练脚本的读取逻辑。这里有一个容易犯的错误:想当然地在脚本里写本地路径,比如./data/train,结果训练作业运行时根本找不到这个目录。
在 ModelArts 中,训练任务的输入路径是从 OBS 指定的,你需要把数据集在桶里的位置映射为训练脚本里的一个参数。比如:在创建训练作业时设置一个名为data_url的参数,值为obs://your-bucket-name/flower_data。脚本里通过环境变量或 argparse 读取这个参数,再去访问数据集。
import argparse parser = argparse.ArgumentParser() parser.add_argument("--data_url", type=str) parser.add_argument("--train_url", type=str) args = parser.parse_args() # 如果平台把 OBS 路径挂载到了本地,可以直接用本地路径读取 # 否则需要借助 moxing 把数据拷贝到本地4.3 数据集切分:训练集、验证集、测试集
最开始我还纠结过数据集的切分逻辑,后来发现 ModelArts 的数据管理功能可以直接做切分。在数据集创建界面里,可以设置训练集和验证集的比例。我一般按 8:1:1 来切,也就是 80% 用于训练,10% 用于验证,10% 用于测试。
如果是使用 AI Gallery 的数据集,通常已经内置了切分好的标注信息,直接创建数据集即可。这里不需要做太复杂的事情,不要为了切分而切分,把精力留到后面训练环节。
4.4 数据标注:先理解平台需要什么样的标注格式
图像分类数据集的标注格式很简单,每个图片对应一个类别标签。ModelArts 的数据集创建流程中,会列出已经识别到的标注信息。如果你用的是自己的数据,需要在“数据标注”页面做一些标注操作,好在这个平台支持自动标注和人工标注结合,效率不低。
我第一次用的时候,以为标注一定要自己手工一张张做,后来发现平台具备自动标注能力,可以先跑一轮“自动分组”或“智能标注”,再人工修正一部分,效率能高不少。
注意:无论什么类型的数据集,最终都要保证“图片文件名”和“标注信息”能对得上。数据管理页面里可以预览,多看一眼能避免后面训练时标签错乱。
5. 训练作业:从预置算法到自定义脚本
5.1 第一次训练:先用预置算法建立基准线
在 ModelArts 里创建训练作业时,有两种常见方式:使用“预置算法”或者使用“自定义镜像/脚本”。第一次接触的话,我强烈建议先用预置算法跑一轮。
预置算法相当于平台帮你写好了一套完整的训练代码,你只需要指定数据路径和输出路径,再设置几个关键参数就行。这个过程能让你快速感受“训练作业”这个抽象概念是怎么运作的,也不会因为脚本 bug 给自己增加挫折感。
我用预置的图像分类算法跑完一轮之后,得到模型的准确率大概在什么水平,心里就有个底了。这个底数很重要,后续换自定义脚本时,可以拿它来对照,判断自己写的方法到底有没有问题。
5.2 自定义训练脚本:三个位置最容易出错
等流程跑通之后,就可以开始用自己写的脚本了。我自己在自定义脚本阶段踩了不少坑,集中在三个地方:
第一个是依赖库的安装。ModelArts 的预置镜像带了不少常见的库,但未必有你需要的那个版本。如果脚本里 import 了一个不存在的包,训练作业会在最开始阶段就报错。解决办法是在创建训练作业时,加上“安装依赖”的配置,把需要的库写到requirements.txt里,例如:
scikit-learn==1.2.2 tensorflow==2.10.0第二个是数据的读取。上一节说过,OBS 的路径和本地路径不一样,脚本里不能想当然地写死。ModelArts 的旧一些版本会通过moxing把 OBS 数据拷贝到本地缓存目录,再读取本地路径。新版本的训练作业也支持直接访问 OBS,但逻辑会略有差异。最简单的做法,是把数据路径作为参数传入脚本:
import moxing as mox # 调用 moxing 把 OBS 数据拷贝到本地 /cache/data mox.file.copy_parallel(args.data_url, "/cache/data")第三个是模型输出位置。训练完成后的模型文件必须写到args.train_url对应的路径下。如果脚本里把模型保存到了当前目录,训练结束后你在 OBS 里就什么都找不到。
# 保存模型到输出路径 mox.file.copy_parallel("/cache/model", args.train_url)5.3 资源选择:GPU 还是不选 GPU
创建训练作业的时候,需要选择资源规格。学习阶段,建议选择按量付费的 GPU 规格,能明显缩短跑一轮的时间。如果你只是用很小的数据集验证流程,CPU 规格也能跑,但时间会拉长不少。
我个人经验是:先选小的,比如一个单卡规格,用最小的数据集跑通全流程;确定脚本没问题后,再回到控制台升级规格跑完整数据。没必要一开始就上大配置,那纯属烧钱。
5.4 日志查看与训练过程诊断
训练作业运行的时候,我建议养成顺手看日志的习惯。在训练作业详情页,可以直接打开日志视图,看到实时输出的 stdout 和 stderr。如果你发现日志一直停在那不动,不一定是卡死了,可能是框架初始化比较慢,也可能是输出缓冲导致日志没有实时刷新。
一个很实用的技巧:在脚本最前面加上环境变量,强制标准输出实时刷新。
import os os.environ["PYTHONUNBUFFERED"] = "1"这样日志里的print操作就会立即出现在训练日志中,定位问题会快很多。我第一次跑训练时,日志停留在“加载数据”那个阶段很长时间,差点以为死机了,后来加了这一行,才看到实际是在下载和预处理数据。
6. 模型部署:把训练结果变成可调用的接口
6.1 把模型文件注册成 AI 应用
训练完成后,模型文件会保存到之前指定的输出路径obs://your-bucket-name/train_output/下。接下来需要在 ModelArts 控制台里,直接“创建 AI 应用”,把它注册成一个可部署的应用。
这里有两种方式:如果用预置算法跑出来的模型,平台会自动识别模型文件的格式;如果是自定义模型,通常需要提供一份model目录,里面包含模型文件和推理脚本。学习阶段建议先用预置算法生成的模型做部署,成功率最高。自定义模型需要额外学习推理代码的编写,这部分可以放到第二步再深入。
6.2 部署在线服务:配置规格与等待启动
AI 应用创建成功之后,点击“部署-在线服务”,进入部署配置页面。这里可以选服务的规格。分类问题不大,一个 CPU 实例基本就能支撑测试请求;如果要做性能验证再考虑 GPU 实例。
部署过程需要等待几分钟。第一次部署时,我盯着状态栏等得有点着急,其实这个过程是在把模型文件加载到服务环境中,是正常的。看到服务状态变为“运行中”,就说明已经部署成功了。
6.3 调用接口:测试一下模型能否正常工作
服务部署完成后,平台会给你一个 API 地址。拿到地址以后,就可以发送请求来测试了。
一个最简单的测试方式,是直接上传一张图片,通过平台的在线测试页面看到预测结果。如果想用代码测试,可以这样发起 POST 请求:
curl -X POST https://your-service-endpoint/v1/infers \ -H "Content-Type: application/json" \ -H "X-Auth-Token: your-token" \ -d '{"image_url": "https://example.com/test.jpg"}'图片如果不在外网可访问的地址,也可以直接把图片转为 base64 编码传过去。返回结果一般会包含每个类别的置信度,取最大的那个就是推理结果。
6.4 部署之后别忘了一件事:关闭服务
这一步看起来简单,但真的很重要。在线服务是按部署时长持续计费的,如果你试验完就让服务一直挂着,费用会一直在涨。我自己的做法是:测试完就把在线服务删除,下次需要时再重新部署。重新部署一次也就几分钟,但省下的费用是实打实的。
提醒:所有“按需计费”的资源,只有真正在跑的时候才花钱。养成用完即停的习惯,是每一位初学者的必修课。
7. 几个常见卡的点和我的解决办法
7.1 区域不一致导致“找不到数据”
这个坑我前面提到过,实在值得单独列出来。OBS 桶在上海区域,ModelArts 却选在北京区域,创建训练作业时无论怎么填数据路径,系统都提示找不到对应路径。检查方法也简单:看控制台左上角的区域位置,保证桶和 ModelArts 一致,必要时在两个区域各创建桶,但不要跨区域引用数据。
7.2 训练脚本一运行就报“No module named xxx”
这个问题基本上就是依赖缺失。处理思路是:先在本地把训练脚本跑通,记录用到的所有第三方库及其版本号,再在创建训练作业时把它们写进requirements.txt。如果某个库版本比较特殊,建议先在本地验证一下这个版本能正常导入和调用。
7.3 训练日志里什么都没有,等得心慌
如果日志长时间没有任何输出,优先检查是否 Python 输出被缓冲。很多初学者都遇到过这种情况,不是作业卡死了,而是输出还在缓冲区里没刷出来。解决办法就是加环境变量PYTHONUNBUFFERED=1,脚本里尽早设置os.environ。如果设置之后仍然长时间没有输出,再考虑是不是数据读取阶段卡住,这时候可以在数据读取代码前后各加一个print来缩小问题范围。
7.4 模型部署后调用返回 500 或异常结果
部署本身是成功的,但调用的结果不对,大概率是推理脚本里对输入数据的处理方式不匹配。比如训练时图片做了归一化,推理时也要做相同的归一化;训练时图片尺寸是 224×224,推理时也要统一缩放到相同尺寸。这类前后处理不一致的问题,在自定义模型中尤其容易出现。如果使用的是预置算法生成的应用,一般不容易遇到这种问题,这也是我建议先跑预置算法的原因。
8. 学习路线和后续可以深入的方向
写到这里,我的学习笔记主体已经基本完成了。最后想说一下接下来可以继续深挖的几个方向,算是我自己规划的一点点思路。
首先是自定义模型部署。我现在跑通的还是预置算法的部署流程,接下来打算研究一下如何把自己训练的模型包,打包成 ModelArts 需要的 AI 应用格式。这部分需要编写推理脚本和模型配置文件,算是整个平台里工程难度相对大的环节,但学会了以后应用面会广很多。
其次是训练参数调优。云上训练最大的好处是可以并行开多组实验,直接对比不同学习率、不同优化器的效果,不需要像本地那样一个个排队跑。这个特性用好了,调参效率能比本地高一个量级。
还有一个值得探索的是自动学习功能。它对不需要深度学习细节的场景很友好。如果你手头有数据但不想写训练代码,可以试试自动学习,它会自动完成模型训练和调优,适合解决“快速拿到一个能用的模型”这类需求。
个人体会是,ModelArts 学习曲线其实不算陡,前提是不要一开始就追求把所有功能都理解透彻,而是先让它帮你跑通一个最小的流程。等你亲眼看到数据从 OBS 走到训练作业、再从训练作业变成在线服务的整个过程,这整条链路就不再是黑盒了。后面再叠加自己的数据、自己的脚本、自己的模型,都会顺理成章很多。