资讯动态

从本地训练到ModelArts:模型训练部署全流程与踩坑记录

发布时间:2026/10/23 9:12:10 来源:尧图企业网站定制
1. 为什么把模型训练从本地挪到ModelArts1.1 本地训练暴露的三个老大难问题在此之前我习惯在本地用显卡训练模型模型本身不大但是整个流程越走越不顺畅。归纳起来有三个问题比较明显一是显卡资源不够灵活二是环境一致性难保证三是部署环节几乎从零开始。显卡资源的问题很现实。本地卡的显存有限模型稍微做深一点、batch size调大就直接OOM。想用多卡又要配驱动、配通信库折腾的时间比调模型的时间还长。更尴尬的是训练任务不是每天都有平时空着浪费电真要用的时候又不够用。环境一致性是最让我头疼的。本地跑通的代码换到另一台机器上经常要重新装依赖。之前遇到过训练完的模型在另一台机器上推理结果异常排查到最后发现是底层库版本问题。这种问题最消耗精力也最容易让项目卡住。部署环节其实是最典型的“没有人提前告诉你”的工作。训练只是一个中间步骤最终要给别人用就得把模型包装成服务处理并发、鉴权、监控。本地做这件事要自己选框架、自己配反向代理、自己考虑进程管理非常零碎。而且一旦换了部署机器环境问题会再出现一遍。1.2 ModelArts恰好补上了这些短板第一次接触ModelArts时我的第一反应是“这不就是一个云上训练平台嘛”真正用下来才发现它更像一个从数据到服务的一站式平台。数据标注、训练、评估、模型管理、在线服务部署都在同一套体系里而不是必须自己去把各个环节拼起来。对我这种想减少重复劳动的人来说最直接的感受是环境问题被收敛了。训练作业在标准镜像里跑依赖版本固定训练资源按需申请不用自己考虑显卡驱动部署服务也变成平台上的一个配置操作。整个学习笔记记录的重点其实不是某一个算法的精度而是怎么把“训练到部署”这条路走通。当然ModelArts也不是万能药它有自己的学习成本和配置约定。接下来的笔记我就按实际使用顺序记录从全流程拆解开始然后到具体实操、踩坑记录最后说说成本和体感。2. 训练到部署的整体链路先看清数据流和状态流转2.1 一条典型的ModelArts任务链路过一遍我第一次做的时候对平台上各种概念之间的关系很迷糊。后来按数据流动的顺序整理思路就清晰了。整条链路大概是这样准备数据上传到对象存储服务OBS的桶里。在ModelArts里创建数据集做标注或直接导入原始数据。配置训练作业指定代码、数据输入和输出位置启动训练。训练完成后输出的模型文件会落到OBS输出目录。在模型管理里注册模型指定推理脚本和模型文件。部署为在线服务平台自动拉起服务并分配调用地址。调用API做验证然后交付。这里面最容易被忽略的是OBS的桥接作用。训练容器本身是无状态的训练代码运行在临时容器里容器不保留任何数据。数据必须从OBS输入结果必须写入OBS否则任务结束后什么都留不下。理解这一点之后很多脚本路径问题都迎刃而解。2.2 Notebook与训练作业两种模式别混用ModelArts里有两个看起来很接近但用途不同的概念Notebook和训练作业。Notebook适合交互式调试像本地常用的交互式开发环境一样可以边写代码边看中间结果适合开发阶段训练作业则更面向正式的批式训练跑完自动退出资源释放更干净。我一开始习惯把整个训练都放到Notebook里跑后来发现两个问题一是Notebook实例一直保持运行哪怕代码空转也会持续计费二是Notebook里跑完的模型要手动拷贝到OBS再手动注册步骤繁琐。切换到训练作业之后代码目录、数据路径、输出路径都在创建任务时一次性配置平台会自动把产物放到指定输出目录后续注册模型更方便。2.3 状态流转视角任务不是“一次就成功”的训练作业有自己的状态创建后一般是等待资源、启动镜像、运行中、成功或失败。部署服务也有类似的过程。我在实际使用时习惯随时看两个地方一个是训练日志另一个是事件列表。日志里能看到代码输出事件列表能看到平台的调度行为比如是否拉取镜像失败、是否显存不足等。把这些状态流转先梳理清楚后面实操时就不容易手忙脚乱。你只需要知道任务没有变成最终状态之前不要急着做下一步。尤其是训练作业从“运行中”变为“成功”并不代表一切正常最好去输出目录确认模型文件大小和生成时间再进入模型注册环节。3. 实操记录从空桶到跑通一次训练作业3.1 OBS桶准备与数据组织首先在OBS创建桶。桶名需要全局唯一具体命名可以根据自己的项目来。创建时注意选择区域后续ModelArts资源最好也在同一区域这样跨服务访问会减少一些网络和权限的问题。数据组织上我建议一开始就划分三个目录输入数据、代码、输出。例如bucket-name/data/trainbucket-name/data/validationbucket-name/codebucket-name/output创建桶时会有访问权限设置默认私有即可。第一次用的时候容易踩的坑是ModelArts读取OBS需要授权如果在创建桶或训练作业时看到权限相关错误多半是委托没有配置好。所谓委托简单理解就是你授权ModelArts帮你访问你在OBS里的数据。这个在ModelArts控制台的全局配置里设置一次即可。数据上传可以用控制台也可以使用OBS SDK。小文件用页面拖拽方便大批量文件我建议用SDK脚本断点续传更可靠。上传完成后可以用OBS管理界面的文件浏览验证一下目录结构。最好在刚开始就把目录固定下来不要今天一版明天一版否则后面找数据会非常痛苦。3.2 训练脚本里的路径与输出约定训练脚本是训练作业能否跑通的核心。ModelArts启动训练作业时会把输入路径和输出路径通过环境变量注入到容器中。常见的环境变量包括数据输入路径、代码目录、输出目录等具体名称在官方文档有说明但代码最好用环境变量读取而不是硬编码绝对路径。我的训练脚本结构大致是这样的import os import torch import torchvision.transforms as transforms from torchvision import datasets data_dir os.environ.get(MODELARTS_DATA_URL, ./data) output_dir os.environ.get(MODELARTS_OUTPUT_DIR, ./output) os.makedirs(output_dir, exist_okTrue) transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), ]) train_dataset datasets.ImageFolder(rootdata_dir, transformtransform) train_loader torch.utils.data.DataLoader(train_dataset, batch_size32, shuffleTrue) model torch.nn.Sequential( torch.nn.Conv2d(3, 16, 3, padding1), torch.nn.ReLU(), torch.nn.AdaptiveAvgPool2d(1), torch.nn.Flatten(), torch.nn.Linear(16, 2), ) optimizer torch.optim.Adam(model.parameters()) for epoch in range(5): running_loss 0.0 for images, labels in train_loader: optimizer.zero_grad() outputs model(images) loss torch.nn.functional.cross_entropy(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() print(fepoch {epoch 1}, loss: {running_loss / len(train_loader):.4f}) torch.save(model.state_dict(), os.path.join(output_dir, model.pth))这段代码比较简化但重点是把数据读取和输出路径都从环境变量里拿这样在本地调试和云端运行时可以保持一致。本地调试时环境变量没有设置就回退到相对目录正好可以用一小部分数据先验证流程。3.3 创建训练作业时最容易弄混的配置项创建训练作业时有几个配置项第一眼看上去很接近实际含义完全不同。下面这张表是我后来整理出来的对照方便随时查配置项含义我的建议算法来源代码和启动方式从哪里来选择自己上传的代码目录AI引擎容器内预装哪个深度学习框架及版本一定要和代码依赖匹配训练输入数据所在的OBS路径映射为容器内的环境变量训练输出结果存放的OBS路径建议按实验名分独立目录启动文件后端执行代码的入口脚本填相对代码目录的路径第一个容易弄混的是算法来源和AI引擎。算法来源指的是代码入口AI引擎则决定容器里预装哪些库。你需要让代码和所选框架版本匹配否则会出现在本地跑得好好的代码云端一启动就报没有某个模块的问题。另一个重点是训练输入和训练输出。训练输入指向OBS里的数据目录训练输出指向OBS里的结果目录。平台会为每个输入配置一个环境变量所以一个任务如果有多个输入代码里对应读取的环境变量也会不同。配置时建议把输入输出都明确到文件夹级别不要直接指向桶根目录否则容易让脚本处理大量无关文件。启动文件的选择也值得注意。它的路径是相对于代码目录的。如果你把入口脚本放在子目录需要填相对路径不要填以/开头的绝对路径。我自己第一次创建训练作业时把训练输出填成了OBS桶根目录导致后面模型版本注册时找文件很麻烦。后来固定输出到bucket-name/output/exp1这类带实验标识的目录每个实验的输出彼此隔离模型注册也更清晰。这一条建议你在开始时就可以执行。训练资源规格方面不确定时先选小规格跑通确认代码没问题再换大规格。不要一上来就申请高规格资源成本和等待时间都不合算。4. 部署上线把训练产物变成可调用的在线服务4.1 模型注册与版本管理训练作业成功之后模型文件会出现在指定的OBS输出目录。要让它变成服务第一步是注册模型概念下的一个版本。模型注册时需要指定模型文件所在的OBS目录同时指定推理脚本和依赖的AI引擎。这里的关键点是平台部署的是模型和推理代码的组合而不是单纯的权重文件。推理代码负责加载模型、预处理输入、执行推理、返回结果。你训练时预处理怎么做推理时就必须保持一致否则部署后模型表现会很离谱。模型版本的概念可以类比软件的版本号。同一个模型对象可以挂多个版本每个版本指向不同的OBS路径和推理配置。上线前先注册一个试运行版本测试通过后再创建正式版本这样可以保证线上服务不会因为一次更新就被搞挂。这个习惯我是在一次部署踩坑后养成的后面会详细说。4.2 在线服务的配置与推理接口验证服务部署时需要选择在线服务类型并配置资源规格和实例数。资源规格决定推理速度和成本实例数决定并发能力。首次部署我建议先从一个小型规格开始逐步验证推理逻辑确认无误后再考虑提升规格或增加实例。部署完成后平台会提供一个调用地址和鉴权信息。用代码调用时一般是通过HTTP POST请求提交数据数据可以是图片的Base64字符串也可以是JSON格式的文本。下面是一个简化版的调用示例import base64 import requests service_url your_service_url token your_token with open(test.jpg, rb) as f: encoded base64.b64encode(f.read()).decode(utf-8) payload { image: encoded } headers { X-Auth-Token: token } resp requests.post(service_url, jsonpayload, headersheaders, timeout30) print(resp.status_code) print(resp.text)调用之前先确认推理输入的格式跟训练代码一致。比如图像分类模型训练时用的是224x224的RGB图像推理脚本里也要先做resize和归一化不能拿着原始尺寸直接喂进去。我在笔记里专门把训练预处理和推理预处理抄在同一页就是为了提醒自己保持两边统一。部署后可以从三个方面验证服务第一用一张训练集中出现过的图片看输出是否合理第二换一张完全不同风格的图片测试鲁棒性第三直接并发发几个请求检查服务是否稳定。这三步跑完再放给下游使用会省掉很多返工。5. 实战中踩过的坑和排查思路5.1 OBS路径与本地路径混用第一个坑是路径问题。我在本地写脚本时习惯用相对路径到了训练作业里输入数据通过环境变量注入容器路径已经变了但代码还按本地路径找文件结果自然是文件找不到。排查思路是先打印关键环境变量把数据目录、输出目录的内容列出来。平台日志里能看到脚本的标准输出把目录里有什么文件打印出来很快就能确认路径映射是否正确。当时踩这个坑花了不少时间猜路径后来开始统一用环境变量读取这个问题没再出现过。5.2 资源规格选太小导致训练失败第二个坑是显存不足。刚开始为省成本选了很小的资源规格结果一个稍大一点的batch就OOM了。更麻烦的是由于训练代码没有及时保存中间结果训练一中断就只能从头再来。排查的时候看日志里的显存不足字样并查看事件信息平台也会给出任务失败的原因。解决思路有三种调小batch size换更高显存的规格开启自动重启和checkpoint保存。这里我特别推荐养成周期性保存checkpoint的习惯比如每个epoch结束保存一次权重这样即使任务中断也能从最近的checkpoint恢复。5.3 部署后模型表现和本地不一致第三个坑是部署后模型表现明显变差。最开始我以为模型文件传错了反复对比文件也没发现问题。后来回想起来是推理脚本里的预处理操作和训练时不一致。训练时我对图片做了归一化推理脚本里忘了做训练时图片会经过resize推理时直接用了原图。这些差异平时不容易发现但一旦放在线上表现就是灾难性的。后来我在本地把模型推理和云端服务推理的结果做对比一张张图比对输出才把问题定位到预处理环节。这个问题的排查思路其实很标准先在本地用相同的权重、相同的推理脚本做一遍推理得到基准结果再请求云端服务拿到结果后对比。如果本地正常、云端不正常问题基本出在环境或输入数据上如果两边都不正常则要回头检查代码逻辑。5.4 服务更新时误删旧版本最后一个是管理层面的坑。有一次我清理模型版本把旧版本误删了新版本又因为推理脚本报错无法部署线上服务一时间没有可回退的版本。这个问题的根源在于我没有把版本管理当回事。后来我给自己定了一个规则同一个模型对象至少保留一个稳定版本正式版本和试运行版本分开命名删除操作之前先确认没有在线服务引用。ModelArts的模型版本管理机制本身够用但真正让它发挥作用的是使用者的版本意识。6. 成本体感ModelArts适合谁、怎么用更划算6.1 计费方式与省钱思路成本是绕不开的话题。ModelArts的费用主要由资源规格和使用时长决定训练作业按运行的规格和时间计费在线服务也按配置的规格和部署时长计费。对我这种个人使用者来说最大的省钱技巧是避免资源闲置。训练作业跑完会自动结束不太会产生闲置费用。真正容易产生浪费的是Notebook实例和在线服务。Notebook实例只要存在哪怕页面关掉也在计费所以我会在做完调试后立即停止或者设置自动停止时间。在线服务如果只是验证验证完成后也要及时下线等到确实需要对外提供服务时再部署。另外训练时可以先选低规格把代码跑通最后确定正式训练时再切高规格这样能显著压缩高规格资源的使用时间。一上来就选高规格、中间反复修改代码是最费钱的用法。关于不同规格的具体价格控制台里都有实时显示按需选择就行。6.2 什么样的人适合直接使用ModelArts把ModelArts完整用了一轮之后我的判断是它最适合手上已经有一定模型代码基础、想快速把模型交付为服务的人。平台把你从环境搭建和各种部署细节里解放出来但不会替你写代码也不会替你保证模型效果。如果你的目标只是随便跑个实验看看效果那用轻量环境可能更合适如果你需要做正式训练并且要稳定地把模型提供给其他人或系统调用ModelArts的训练作业和在线服务组合是值得认真研究的。整个平台有一定的学习曲线但走通一遍后后面重复训练新模型、更新版本效率会高很多。我现在形成的工作习惯是小规模调试在本地或Notebook里做正式训练交给训练作业所有对外推理统一走在线服务。这套流程跑顺之后最明显的变化是被环境问题打断的次数变少了大多数时间都能专注在模型本身。这份笔记就是这段时间踩坑和梳理的结果如果你也在从单机训练往云端迁移希望这些细节能让你少走一些弯路。

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

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

免费获取报价 →
↑