1. 这不是“点点鼠标就完事”的云平台体验,而是一次真实模型落地的全链路复盘
ModelArts这个名字在华为云生态里出现频率极高,但很多人第一次点开控制台时,面对“训练作业”“推理服务”“Notebook”“AI Gallery”一堆入口,第一反应其实是懵的——这到底该从哪下手?我手头有个CSV数据集,想做个能识别设备故障的二分类模型,是该先建个OBS桶?还是直接进Notebook写PyTorch?训练完模型文件存在哪?怎么让别人用API调用它?这些不是文档里一句“支持端到端流程”就能糊弄过去的。这篇笔记,就是我用ModelArts跑通一个完整工业图像分类项目的真实记录:从原始JPG图片上传、数据标注、模型选型(没用AutoML,手动搭了ResNet18微调)、超参调试、训练中断恢复,到最后部署成HTTP接口并用Python脚本实测调用延迟。过程中踩过OBS路径权限坑、镜像版本不兼容坑、服务启动后502错误坑,也验证过哪些操作必须用华为云CLI才能绕过控制台限制。它不讲大道理,只告诉你每一步“为什么非得这么点”“参数填错会卡在哪”“日志里哪行报错才是真正线索”。如果你刚接触ModelArts,或者正卡在“训练成功但部署失败”这个阶段,这篇笔记里的每一个截图级操作细节、每一处配置值、每一条CLI命令,都是我反复试错后确认有效的。它适合两类人:一类是想跳过概念堆砌、直接抄作业的工程师;另一类是想搞懂“云上训练和本地训练到底差在哪”的技术决策者。
2. 项目整体设计与思路拆解:为什么选择ModelArts而非本地GPU或其它云平台?
2.1 核心需求倒推架构选型
这个项目最硬性的三个约束条件,直接锁死了技术路线:
数据不出内网:原始图像来自某实验室的边缘设备,按安全要求,所有训练数据必须存储在华为云华东-上海一Region内,且不能通过公网传输。这就排除了“本地训练+模型上传”的方案——因为本地机器没有固定公网IP,无法直连OBS,而走临时URL上传又涉及密钥暴露风险。
团队协作刚需:项目组有3人,需同时访问同一份标注数据、共享预训练权重、复现他人训练结果。本地环境每人一套CUDA版本、PyTorch版本、OpenCV版本,三天一小冲突、五天一大崩。ModelArts的Notebook实例天然带统一环境镜像(如
tensorflow-2.13.0-py39-cuda11.8),且所有代码、数据、模型自动存OBS,打开链接就能看到同事昨天改的loss曲线。上线节奏压得死:客户要求2周内交付可调用的API。如果自己搭Kubernetes集群部署Triton推理服务器,光网络策略、证书配置、健康检查探针就得耗掉5天。ModelArts的在线服务(Inference Service)点选“创建服务”→ 上传模型包 → 设置并发数 → 启动,全程图形界面操作,平均耗时11分钟,且自动生成调用文档和SDK示例。
这三个条件叠加,让ModelArts成为唯一解。它不是因为“功能多”被选中,而是因为“刚好堵住了我们所有流程漏洞”。
2.2 模型训练路径的取舍:AutoML vs 手动训练
ModelArts提供两种主流训练方式:AutoML(自动学习)和训练作业(Training Job)。我最初也尝试过AutoML——上传标注好的图片,勾选“图像分类”,5分钟出结果。但问题立刻浮现:
AutoML强制要求标注格式为“每个子文件夹一个类别”,而我们的数据是CSV映射表(
image_id, label_id, device_type),且device_type有7个子类,但label_id只有0/1。AutoML无法处理这种多维度标签映射,强行转换会导致标签错位。AutoML生成的模型结构不可见,当验证集准确率卡在82%不上升时,你无法判断是数据分布问题、还是模型容量不足、或是学习率衰减策略失效。而手动训练作业中,我在
train.py里加了torchsummary.summary(model, input_size=(3,224,224)),一眼看出ResNet18最后全连接层输入通道数是512,但输出节点数被AutoML默认设为2(二分类),而我们需要的是7(设备类型),必须手动修改。最关键的是资源调度:AutoML底层用的训练镜像不开放自定义,而我们的数据增强需要
albumentations库,其最新版依赖numpy>=1.24,但AutoML镜像自带numpy==1.21,pip install会破坏环境。手动训练作业则允许指定Docker镜像URI,我直接用了华为云官方维护的swr.cn-east-3.myhuaweicloud.com/modelarts-modelzoo/pytorch-1.13.1-cuda11.7:20231215,再通过requirements.txt注入依赖,完美解决。
所以最终方案是:用AutoML做快速baseline验证(确认数据质量没问题),然后切到训练作业模式,完全掌控代码、依赖、日志、断点续训。
2.3 部署方案的三层验证逻辑
部署不是“训练完导出模型文件→上传→启动”这么简单。我设计了三层验证闭环:
第一层:本地Mock验证
在Notebook里写test_local_inference.py,加载.pth模型,用torch.no_grad()跑单张图,输出logits和softmax概率。这步确认模型本身无bug,且预处理(resize、normalize)和后处理(argmax)逻辑与训练时一致。曾因训练时用transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225]),而部署时忘了加,导致输入像素值范围错乱,预测全错。第二层:OBS模型包结构验证
ModelArts要求模型包必须是ZIP格式,且内部结构严格固定:model.zip ├── model/ │ ├── model.pth # 模型权重 │ └── model.py # 必须含class ModelService,实现_preprocess、_postprocess、_inference ├── config.json # 指定model.py中类名、入口函数等 └── requirements.txt # 额外依赖少任何一个文件,或
config.json里"model_file": "model/model.pth"写成"model_file": "model.pth",服务启动必报错。我专门写了校验脚本,解压后检查文件树和JSON schema。第三层:服务启动后端口探测
服务状态显示“运行中”不等于可用。我用curl -X POST https://xxx.execute-api.cn-east-3.modelarts.ai/v1/{project_id}/services/{service_name}/invocations -H "Content-Type: application/json" -d '{"input": "base64_string"}'实测,但发现返回502。查日志发现是model.py里_inference函数没加@torch.no_grad()装饰器,GPU显存溢出被OOM Killer干掉。这层验证必须在服务启动后立即执行,否则上线后才发现,代价太大。
这三层不是可选项,是ModelArts部署的铁律。跳过任何一层,都会在后续环节付出十倍时间成本。
3. 核心细节解析与实操要点:从OBS桶创建到模型包打包的避坑指南
3.1 OBS桶创建:命名规则与权限陷阱
OBS(对象存储服务)是ModelArts的数据底座,但它的命名规则藏着致命坑:
桶名必须全局唯一,且只能小写字母、数字、中划线(-),不能以中划线开头或结尾,长度2-64字符。我第一次建桶叫
modelarts-data,提示“已存在”,改成modelarts-data-2024才通过。但更隐蔽的坑是:桶名一旦创建,永远无法修改。如果后期想把训练数据和模型文件分桶管理,必须提前规划好,比如myproject-train-data、myproject-models、myproject-logs。权限设置是最大雷区。ModelArts训练作业默认使用“委托授权”(Delegated Authorization),即用你的IAM用户权限访问OBS。但如果你的IAM策略里只给了
obs:Objects:GetObject,没给obs:Objects:ListBucket,训练作业会卡在“准备数据”阶段,日志只显示Waiting for data initialization...,没有任何报错。必须确保策略包含:{ "Version": "1.1", "Statement": [ { "Effect": "Allow", "Action": [ "obs:Objects:GetObject", "obs:Objects:PutObject", "obs:Objects:DeleteObject", "obs:Objects:ListBucket" ], "Resource": ["urn:iam::xxxxx:bucket/myproject-*"] } ] }目录结构决定数据加载逻辑。ModelArts的
Dataset类默认按/train/cls1/,/train/cls2/结构读取,但如果你的数据在/raw/images/下,且用CSV标注,就必须在训练脚本里手动构造Dataset。我用pandas.read_csv加载CSV,再用torch.utils.data.Dataset重写__getitem__,这样比强行改目录结构更可控。
提示:OBS控制台右上角“区域切换”按钮常被忽略。华东-上海一Region的OBS endpoint是
https://obs.cn-east-3.myhuaweicloud.com,而华北-北京四Region是https://obs.cn-north-4.myhuaweicloud.com。如果训练作业选的Region是上海一,但OBS桶建在北京四,会报Connection refused,且错误日志里不显示endpoint,只显示Failed to connect to OBS。务必在创建OBS桶时,右上角确认Region与ModelArts所在Region完全一致。
3.2 Notebook实例配置:显存、镜像、挂载的黄金组合
Notebook是代码开发主战场,但配置不当会直接拖慢迭代速度:
GPU型号选择:ModelArts提供P100/V100/A100三种。P100显存16GB,V100 32GB,A100 40GB。我的数据集共12万张图,batch_size=64时,V100刚好够用(显存占用92%),P100会OOM。但A100价格是V100的1.8倍,没必要。关键是显存不是越大越好——A100的Tensor Core对FP16加速极强,但如果代码没加
torch.cuda.amp.autocast(),反而因精度损失导致收敛变慢。我实测V100+FP32训练30轮,准确率89.2%;A100+FP16训练30轮,准确率88.7%,还多了2小时调试amp的时间。镜像版本必须匹配框架。华为云文档说“推荐使用最新镜像”,但最新镜像
pytorch-2.0.1-cuda11.8里torchvision==0.15.2,而我的数据增强用到了torchvision.transforms.v2.RandomPhotometricDistort(v2模块),该函数在0.15.2里不存在,要升级到0.16.0。但pip install torchvision==0.16.0会触发torch版本冲突,因为0.16.0要求torch>=2.1.0。最终方案是:放弃最新镜像,选用pytorch-1.13.1-cuda11.7(自带torchvision==0.14.1),然后手动安装albumentations替代v2模块,稳定性和兼容性反而更好。OBS挂载路径必须带协议前缀。在Notebook里执行
!ls /home/ma-user/work/data/看不到OBS文件,因为挂载路径实际是obs://myproject-train-data/train/。正确做法是:在Notebook左上角“更多”→“挂载OBS路径”,填入obs://myproject-train-data/train/,挂载点设为/home/ma-user/work/train_data,然后!ls /home/ma-user/work/train_data才能列出图片。如果挂载点写成/train_data,系统会创建本地目录而非OBS映射,后续训练读不到数据。
3.3 训练作业提交:超参、日志、断点续训的实操密码
训练作业是生产环境主力,其配置项直接影响结果可复现性:
超参配置必须用
--arg而非环境变量。ModelArts支持两种传参方式:命令行参数(--lr 0.001 --epochs 50)和环境变量(export LR=0.001)。但环境变量在分布式训练(多卡)时可能不同步,且日志里不记录。我坚持用--arg,并在train.py里用argparse.ArgumentParser解析,这样每次训练的日志头都自动打印Args: Namespace(lr=0.001, epochs=50, ...),复现时直接复制粘贴即可。日志路径决定调试效率。ModelArts默认将
print()输出写入/log/output.log,但框架日志(如PyTorch Lightning的trainer.fit()进度条)写入/log/training.log。我习惯在代码里加logging.basicConfig(filename='/log/custom.log', level=logging.INFO),把关键指标(每个epoch的val_acc、lr值)单独记日志。这样在控制台“查看日志”时,切换到custom.log标签页,5秒内定位到性能拐点,不用在几千行output.log里grep。断点续训不是“自动”而是“半自动”。ModelArts支持
--resume-from参数,但前提是你的训练脚本实现了保存/加载state_dict。我在train.py里加了:if args.resume_from: checkpoint = torch.load(args.resume_from) model.load_state_dict(checkpoint['model_state_dict']) optimizer.load_state_dict(checkpoint['optimizer_state_dict']) start_epoch = checkpoint['epoch'] + 1然后在训练循环里每5个epoch保存一次:
if epoch % 5 == 0: torch.save({ 'epoch': epoch, 'model_state_dict': model.state_dict(), 'optimizer_state_dict': optimizer.state_dict(), }, f'/cache/checkpoints/epoch_{epoch}.pth')注意
/cache/是ModelArts提供的高速临时盘(约100GB),比写OBS快10倍。训练中断后,在新作业里填--resume-from /cache/checkpoints/epoch_45.pth,就能从第46轮继续。
注意:
/cache/内容在作业结束后自动清空!所以必须在训练结束前,用!obsutil cp /cache/checkpoints obs://myproject-models/checkpoints/ -r同步到OBS,否则断点文件永久丢失。
3.4 模型包打包:model.py与config.json的生死契约
部署的核心是模型包,而model.py和config.json是它的灵魂,错一个字符就启动失败:
model.py必须继承BaseService且函数签名固定。模板如下:from model_service.model_service import SingleImageBaseService import torch import numpy as np from PIL import Image import torchvision.transforms as transforms class ModelService(SingleImageBaseService): def _preprocess(self, data): # data是base64字符串,转PIL.Image img = Image.open(io.BytesIO(base64.b64decode(data))) # 预处理必须和训练时完全一致 transform = transforms.Compose([ transforms.Resize((224,224)), transforms.ToTensor(), transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225]) ]) return transform(img).unsqueeze(0) # 加batch维度 def _inference(self, data): with torch.no_grad(): # 关键!否则OOM output = self.model(data) return output def _postprocess(self, data): # data是tensor,转numpy再转list probs = torch.nn.functional.softmax(data, dim=1) return probs.cpu().numpy().tolist()[0]注意三点:
_preprocess返回torch.Tensor且必须有batch维度;_inference必须加@torch.no_grad();_postprocess返回list而非numpy.ndarray,否则API返回JSON解析失败。config.json字段名大小写敏感且不可缺。标准模板:{ "model_framework": "pytorch", "model_file": "model/model.pth", "code_dir": "model/", "model_class": "ModelService", "dependencies": ["requirements.txt"], "inputs": [{"name": "input", "type": "string", "shape": []}], "outputs": [{"name": "output", "type": "array", "shape": []}] }曾因
"model_class"写成"model_class_name",服务启动日志报KeyError: 'model_class',但控制台只显示“服务异常”,必须进日志才能看到。"inputs"和"outputs"的"shape"字段不能为空数组[],填null或删掉都会报错。requirements.txt必须精确到小版本。我的依赖是:torch==1.13.1+cu117 torchvision==0.14.1+cu117 pillow==9.5.0 numpy==1.23.5如果写
pillow>=9.0.0,ModelArts会装最新版10.2.0,而新版PIL的Image.open()对某些损坏JPG的容错机制变了,导致线上API随机500错误。必须锁定小版本,这是血泪教训。
4. 实操过程与核心环节实现:从零开始的全流程命令级记录
4.1 环境初始化:5分钟完成OBS+Notebook+训练作业准备
以下是在ModelArts控制台的实际操作序列,每一步都有明确目的:
创建OBS桶(Region:华东-上海一)
- 桶名:
myproject-2024-data(全局唯一,小写+数字+中划线) - 存储类别:标准存储(高频访问)
- 服务端加密:关闭(训练作业不支持SSE-KMS加密桶)
- 权限:公共读(仅用于测试,生产环境必须关)
- 桶名:
上传数据到OBS
本地终端执行(需先安装obsutil):# 创建目录结构 mkdir -p ./data/train/normal ./data/train/fault # 假设图片已按类别放入对应文件夹 # 上传到OBS obsutil cp ./data/ obs://myproject-2024-data/train/ -r -f上传后,在OBS控制台确认路径为
obs://myproject-2024-data/train/normal/xxx.jpg。启动Notebook实例
- 规格:
p100.2xlarge(24GB显存,够用) - 镜像:
pytorch-1.13.1-cuda11.7:20231215(稳定版) - 挂载OBS:源路径
obs://myproject-2024-data/train/,挂载点/home/ma-user/work/train_data - 网络:默认VPC(确保与后续训练作业同VPC)
- 规格:
在Notebook中验证数据加载
新建test_data.ipynb,运行:import os print(os.listdir('/home/ma-user/work/train_data')) # 应输出 ['normal', 'fault'] print(len(os.listdir('/home/ma-user/work/train_data/normal'))) # 应输出图片数量若报
FileNotFoundError,检查挂载点路径是否正确,或OBS桶Region是否匹配。
4.2 训练作业提交:命令行与控制台双轨操作
训练作业有两种提交方式,我推荐“控制台创建+CLI更新”组合:
控制台创建基础作业
- 作业名称:
resnet18-finetune-v1 - 计算规格:
p100.2xlarge(与Notebook一致,避免环境差异) - 数据来源:OBS路径
obs://myproject-2024-data/train/ - 代码来源:Notebook中
/home/ma-user/work/train.py(先用!obsutil cp /home/ma-user/work/train.py obs://myproject-2024-data/code/train.py上传) - 启动命令:
python train.py --lr 0.001 --epochs 50 --data-path /cache/train/注意
--data-path指向/cache/,因为ModelArts会自动把OBS数据同步到/cache/,读取速度比直接读OBS快5倍。
- 作业名称:
CLI更新超参并提交(更灵活)
安装华为云CLI(pip install huaweicloudsdkcore huaweicloudsdkmodelarts),然后:# 获取训练作业ID(从控制台URL复制,形如 `job-xxxxxxxx`) JOB_ID="job-abc123def456" # 更新超参:学习率调为0.0005,加早停 huaweicloud modelarts update-training-job \ --job-id $JOB_ID \ --command "python train.py --lr 0.0005 --epochs 50 --patience 7" \ --resource-spec "p100.2xlarge" # 启动作业 huaweicloud modelarts start-training-job --job-id $JOB_IDCLI的优势在于:可以批量更新多个作业的超参,且命令可存为脚本,避免控制台重复点击。
监控训练过程
- 控制台“训练作业”页,点作业名进入详情页,看“资源使用率”图表:GPU利用率持续>80%说明数据加载无瓶颈;若显存占用<50%但GPU利用率<20%,大概率是
DataLoader的num_workers设太小,需在代码里调到4或8。 - 日志页切换到
/log/custom.log,实时看Epoch 10/50, Val Acc: 0.852,比刷output.log高效得多。
- 控制台“训练作业”页,点作业名进入详情页,看“资源使用率”图表:GPU利用率持续>80%说明数据加载无瓶颈;若显存占用<50%但GPU利用率<20%,大概率是
4.3 模型包构建:从.pth到可部署ZIP的七步法
模型包是部署的输入,必须手工构建,无捷径:
在Notebook中导出模型
训练完成后,在train.py末尾加:torch.save({ 'epoch': epoch, 'model_state_dict': model.state_dict(), 'optimizer_state_dict': optimizer.state_dict(), }, '/home/ma-user/work/model_final.pth')然后用
!obsutil cp /home/ma-user/work/model_final.pth obs://myproject-2024-data/models/resnet18-v1.pth上传。创建模型包目录结构
本地新建文件夹model_package,结构如下:model_package/ ├── model/ │ ├── model.pth # 从OBS下载的resnet18-v1.pth │ └── model.py # 上文写的完整Service类 ├── config.json # 按3.4节模板填写 └── requirements.txt # 精确版本依赖编写
model.py(关键!)
复制3.4节代码,重点检查:self.model = torch.load('/cache/model.pth')路径是否为/cache/(ModelArts部署时自动解压到/cache/)_preprocess中transforms.Resize尺寸是否与训练时一致(224x224)_inference是否加with torch.no_grad()
编写
config.json
确认"model_file": "model/model.pth","model_class": "ModelService","code_dir": "model/"三者路径完全匹配。生成
requirements.txt
在Notebook中运行:!pip list --format=freeze > requirements.txt # 编辑requirements.txt,只保留必要项,并锁定小版本压缩为ZIP
终端执行:cd model_package zip -r model-resnet18-v1.zip .检查ZIP内容:
unzip -l model-resnet18-v1.zip,确认无多余目录层级。上传模型包到OBS
obsutil cp model-resnet18-v1.zip obs://myproject-2024-data/models/model-resnet18-v1.zip
4.4 在线服务部署:从创建到压测的12分钟实战
部署是最后一步,也是最容易翻车的一步:
创建在线服务
- 服务名称:
resnet18-service-v1 - 模型来源:OBS路径
obs://myproject-2024-data/models/model-resnet18-v1.zip - 计算规格:
c3.large(4核8G,足够处理10QPS) - 弹性伸缩:最小实例数1,最大实例数3(防突发流量)
- 网络:与训练作业同VPC,安全组放行
8080端口(ModelArts服务默认端口)
- 服务名称:
启动服务并等待就绪
点击“启动”,状态从“创建中”→“启动中”→“运行中”,通常需3-5分钟。不要跳过“查看日志”:点“日志”页,筛选/var/log/nvidia-container-runtime-hook.log,确认无CUDA driver version is insufficient错误(说明GPU驱动正常)。获取服务Endpoint
服务启动后,“基本信息”页显示Endpoint,形如:https://xxx.execute-api.cn-east-3.modelarts.ai/v1/12345678901234567890123456789012/services/resnet18-service-v1/invocations
这是调用API的URL。本地压测脚本验证
写test_api.py:import base64 import requests import time url = "https://xxx.execute-api.cn-east-3.modelarts.ai/v1/.../invocations" headers = {"Content-Type": "application/json"} # 读取测试图片 with open("test.jpg", "rb") as f: image_bytes = f.read() b64_str = base64.b64encode(image_bytes).decode('utf-8') # 发送请求 start = time.time() response = requests.post(url, json={"input": b64_str}, headers=headers, timeout=30) end = time.time() print(f"Status: {response.status_code}") print(f"Latency: {end-start:.3f}s") print(f"Response: {response.json()}")运行后,若返回
{"output": [0.02, 0.98]}且延迟<1.2s,说明部署成功。配置API网关(可选但推荐)
为生产环境,用API网关封装ModelArts Endpoint:- 创建API网关,后端类型选“HTTP”,后端地址填ModelArts Endpoint
- 添加认证:APP Code(生成App Key/Secret,调用时需在Header加
X-Api-Key: xxx) - 这样可实现流量控制、调用审计、HTTPS卸载,且Endpoint变更时只需改网关后端,不改客户端代码。
5. 常见问题与排查技巧实录:那些文档里不会写的“真问题”
5.1 训练作业常见问题速查表
| 问题现象 | 根本原因 | 排查命令/位置 | 解决方案 |
|---|---|---|---|
| 作业状态卡在“准备中”超30分钟 | OBS桶权限不足,缺少ListBucket | 查看/log/output.log,搜索PermissionDenied | 更新IAM策略,添加obs:Objects:ListBucket权限 |
训练日志报OSError: Unable to open file (unable to open file) | 数据路径写错,或OBS文件未同步到/cache/ | !ls /cache/train/,确认目录是否存在 | 检查训练作业“数据来源”OBS路径,确保与挂载路径一致;或改用--data-path /home/ma-user/work/train_data(Notebook挂载点) |
| GPU利用率<10%,CPU利用率>90% | DataLoader瓶颈,num_workers太小或pin_memory=False | nvidia-smi看GPU,htop看CPU | 在DataLoader中设num_workers=4, pin_memory=True,并确保batch_size足够大(≥32) |
| 训练到第20轮突然OOM | 模型中存在torch.nn.BatchNorm2d,训练时track_running_stats=True,但验证时没关 | 查/log/custom.log,看OOM前最后几行是否在val_step | 在验证循环中加model.eval(),或torch.no_grad()上下文 |
5.2 在线服务部署问题深度解析
问题1:服务启动后状态“运行中”,但调用返回502 Bad Gateway
这不是网络问题,而是服务进程崩溃。根本原因是model.py里_inference函数未加@torch.no_grad(),导致GPU显存持续增长直至被OOM Killer杀死。
排查方法:
- 进服务日志页,筛选
/var/log/supervisor/supervisord.log,搜索killed process - 或用CLI查容器日志:
huaweicloud modelarts show-service-logs --service-name resnet18-service-v1 --log-type container
解决方案:在_inference函数上加装饰器,并在__init__里加self.model.eval()。
问题2:调用返回400,错误信息Input data format error
这是config.json的"inputs"定义与实际请求不符。例如config.json里写"shape": [1],但请求体是{"input": "base64_string"}(无数组)。
排查方法:
- 对比
config.json的"inputs"字段和API文档中的请求示例 - 用
curl -v看完整请求头和体
解决方案:config.json中"inputs"的"shape"必须为[](标量),因为base64字符串是单个值。
问题3:服务启动后延迟高(>3s),且CPU占用100%
这是模型首次加载慢。ModelArts服务启动时,会执行model.py的__init__,如果里面做了耗时操作(如torch.hub.load下载模型),就会阻塞。
排查方法:
- 在
__init__里加print("start loading model")和print("model loaded"),看日志时间差
解决方案:把模型加载移到_preprocess或_inference中,并加缓存:
def __init__(self, model_path): self.model_path = model_path self.model = None # 延迟加载 def _inference(self, data): if self.model is None: self.model = torch.load(self.model_path) self.model.eval() # ... rest of inference5.3 实操心得:三个让我少熬20小时的技巧
技巧1:用
obsutil代替控制台上传大文件
控制台上传单个文件>1GB会超时失败。obsutil支持断点续传和并行上传:obsutil cp ./large_dataset/ obs://myproject-data/train/ -r -f -c 10 # -c 10 表示10线程,并行上传我传12万张图(85GB)用时23分钟,控制台预估要6小时。
技巧2:训练作业日志分级存储
默认日志只保留最近7天,且/log/下文件混杂。我在train.py开头加:import logging from datetime import datetime timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler(f'/log/train_{timestamp}.log'), logging.StreamHandler()