从去年年底开始,我一直在跟模型训练和部署死磕。本地显卡吃紧、环境反复装、一换机器就崩,这些坑想必很多人也踩过。后来我把整套流程迁移到华为云ModelArts上,从前期的数据准备、环境调试,到训练作业跑通、模型上线,断断续续记了大半本笔记。这篇就是我把笔记整理后的完整版,尽量把每一步的来龙去脉、参数配置、踩坑点都写清楚,适合那些刚开始接触ModelArts、或者正在纠结怎么把训练和部署这条链路串起来的人。
我默认你至少用过Python、知道训练脚本长什么样,但不用多熟悉云平台。我会从“为什么选ModelArts”开始,一直讲到部署出一个可以调用的API服务,中间包括数据上传、Notebook调试、训练作业创建、模型包规范这些环节。整篇都是实际操作后的记录,不是官方文档复述,所以有些地方会直接告诉你“这么设才顺手”“那里容易踩坑”。
1. 从本地显卡到ModelArts:我为什么把这套流程写成笔记
1.1 本地训练跑深度模型的真实门槛
先说原因。我手头有一张消费级显卡,显存不大,训练稍微大一点的模型就经常爆显存。为了在本地跑通一个ResNet预训练模型微调,我先要折腾CUDA、cuDNN、PyTorch版本匹配,接着处理数据集路径,然后训练到一半发现显存不够,只能把batch size调小、再调小。最难受的是,好不容易调好一轮,过了两周再跑同一个脚本,环境因为系统更新又崩了。
这就是本地训练的真实体验。你花在环境配置上的时间,往往比调模型的时间还多。尤其是需要对比多个预训练模型、改几个超参数反复跑的时候,本地显卡和工作环境根本无法支撑多任务并行。
1.2 ModelArts在训练链路里到底负责哪几件事
我选定ModelArts,不是因为它看起来“大而全”,而是因为它把训练链路里最烦的几个环节都收拢到了一起。按我的理解,它核心做了三件事:
- 开发环境:提供一个可以随时创建、随时释放的在线Notebook实例,CPU、GPU规格都可以选,镜像里已经装好PyTorch、TensorFlow、MindSpore这些常见框架,不用自己配CUDA。
- 训练作业:把训练代码、数据集、输出路径集中管理,可以选用不同规格的GPU资源池跑训练任务,训练日志、监控指标都能在控制台看到,训练完的资源自动释放。
- 模型部署:训练产物(权重文件、推理脚本)按规范打包后,可以一键部署成在线服务,服务本身支持弹性伸缩、版本更新、API调用。
对第一次用云平台的人,最直观的感受是:不用再折腾环境,也不需要有一张显卡在手边。你想用一个免费的GPU资源体验训练,或者临时租一张高性能显卡跑大模型,ModelArts都能按需提供,用完就释放,不再有硬件束缚。
1.3 什么人适合顺着这篇笔记走一遍
这篇笔记更适合下面三类人。第一种是自己跑过训练脚本,但对部署上线没概念,想补全“训练到服务”这段链路的人。第二种是学校或公司给了ModelArts配额,但打开控制台不知道先点哪里的人。第三种是本地有开发经验,但第一次用云上训练资源,想知道路径、参数怎么传,日志去哪看的人。
如果你只是想快速体验别人封装好的模型服务,那这篇笔记可能偏重,因为我会花不少篇幅讲训练作业的参数和模型包结构。但如果你想真正在ModelArts上完成一次自己的训练并部署出来,顺着这篇笔记走一遍应该能省不少摸索时间。
2. 资源链路先理清楚:OBS、Notebook、训练作业各司其职
2.1 OBS桶是训练链路里的“移动硬盘”
我在ModelArts上踩过的第一个坑,就是没搞懂OBS在整条链路里的角色。
OBS全称叫对象存储服务,简单理解就是一个云端网盘,但它是给程序读写用的,不是给人上传下载用的。在ModelArts的典型流程里,数据集、训练脚本、训练产物、模型文件,全都放在OBS桶里。Notebook要读数据,从OBS拉;训练作业要读数据集,从OBS拉;训练完的模型要保存,写回OBS;部署模型要加载权重,也从OBS读。
所以OBS是整个训练链路的“移动硬盘”,所有环节都围着它转。我开始没规划好目录,把数据、代码、模型全部堆在一个桶的根目录下,结果训练作业里填路径时来回试错,找得头晕。后来老老实实按类型分目录,清晰多了。建议大家在桶里就按这个结构规划:
bucket-name/ ├── datasets/ │ ├── train/ │ └── val/ ├── code/ │ └── train.py ├── models/ │ ├── output/ │ └── checkpoint/数据、代码、模型产物分开目录存放,后续在训练作业和部署配置里填路径时会非常省事。虽然这听起来是常识,但在实际使用中很多人嫌麻烦,最后都付出了反复排查路径的时间成本。
2.2 Notebook:适合调试,不适合硬跑大型训练
ModelArts里的Notebook,相当于给你一个云端Jupyter环境。创建实例之后,你可以在里面写代码、跑小数据量实验、查看中间结果。它的好处是即开即用,里面有多个预置镜像,PyTorch、TensorFlow都有,版本还比较新。我个人习惯把Notebook当成“实验台”,用它来完成数据处理和模型调试。
但要注意,Notebook不是用来跑完整训练的。
第一,Notebook实例的资源是常驻的,你创建了一台V100规格的实例,只要不停止就会一直计费,不像训练作业跑完就释放。第二,Notebook环境里跑的进程和训练作业相比,缺乏作业级的监控、重启、日志管理,大型训练放在里面跑既不稳定也不好观察进度。第三,Notebook的存储空间是有限的,不像OBS那样可以弹性扩展,大数据集堆在Notebook里很容易撑爆磁盘。
所以我的经验是:先拿一小部分数据在Notebook里把代码写通、参数调个大概,确认loss能正常下降,再把完整代码和数据集接到训练作业上去跑正式训练。这样既能享受Notebook的交互性,又能拿到训练作业的稳定性和算力弹性。
2.3 先定目录规范,避免后期路径全是坑
再强调一遍目录规范,因为这个问题几乎贯穿整个流程。
训练作业里的路径分成几类:数据集输入路径、代码路径、训练输出路径、模型输出路径。如果你在OBS里没有一套固定的命名习惯,每次创建训练作业都要重新整理路径;更麻烦的是,训练脚本里如果写死了相对路径与绝对路径混用,换一个数据集就全乱套。
我后来固定了一套约定:数据集统一放datasets/目录,按数据集名再加子目录区分版本;代码放code/目录,每个训练任务一个子目录;输出统一放models/output/。这样创建训练作业时,每次要填的路径都是obs://xxx/datasets/train这种结构,一眼就知道对应关系。代码里只做参数接收,不写死绝对路径,数据在哪由训练作业通过参数传给脚本。
这套规范看起来简单,但实战中能减少至少一半的“路径错误”类报错。
3. Notebook阶段:把数据处理和代码调试全部压实
3.1 创建开发环境实例时的规格选择
创建Notebook时,第一步要选类型和规格。当时我面对一堆套餐,脑子里只有一个念头:选最贵的。实际上完全没必要。
对于处理数据集、做小样本调试,一张CPU规格的实例基本够用。比如做数据清洗、图片缩放、格式转换这些操作,CPU完全可以胜任。真正需要GPU的时候,是你准备用完整训练脚本跑一个epoch、想确认显存占用和计算时间的时候,这时再用GPU实例也不迟。
规格建议可以按这个思路选:
- 纯数据处理、代码阅读:选CPU基础规格,比如2核8G甚至4核16G。
- 小规模模型调试、小batch试跑:选GPU入门规格,比如4核32G加一张基础GPU。
- 正式训练验证、多轮迭代调参:用GPU高性能规格,比如带V100或A100的套餐。
关于存储,Notebook有默认的数据盘,空间大小可以选。我的建议是默认容量即可,不要把大数据集都塞进Notebook,数据放在OBS,需要时再拉取,磁盘压力小很多。如果确实希望用Notebook做全程训练,再考虑挂载更大数据盘,但那时候更好的选择可能已经是训练作业了。
3.2 从本地上传代码与数据的高效姿势
数据从哪里来?大多数人会遇到两个场景:一个是从本地机器上传,另一个是从别处的下载链接拉取。
如果数据在本地,最常见的做法是通过OBS控制台把文件传上去。小文件可以直接网页上传,大文件建议用命令行工具或SDK。我一开始不知道有工具,用网页上传一个几个G的数据集,传到一半浏览器崩溃,痛不欲生。
给还没踩坑的人提个醒:大文件或者整个文件夹的上传,别用网页拖拽。用命令行工具一次性传上去,支持断点续传,失败也能重试。具体工具名称就不展开了,ModelArts和OBS文档里都写得很清楚。上传完成后,在Notebook里可以用obsutil或者SDK把数据从OBS同步到开发环境,直接读取本地路径。
如果数据是从外部网站下载的,比如某个公开数据集,你可以在Notebook里直接用命令行下载,省去“先下到本地再传云上”的环节。下载到一个临时目录,解压后直接使用。这也算云端开发的一个隐藏优势:带宽通常不错,公开数据集直接拉取往往比本地下载还快。
3.3 在Notebook里完成一次小规模试跑
代码调试阶段,我的习惯是小步快跑。先取几百条数据,在Notebook里把数据加载、预处理、模型前向、loss计算、反向传播全部走通。跑得通了,再逐步把batch size、epoch拉大。
这里有个重要的经验:千万不要在Notebook里直接开跑完整数据集的全量训练。一方面浪费资源,另一方面出了问题不好定位。用小数据试跑,可以快速发现数据维度不匹配、标签错位、数值溢出这类明显问题。等一切稳定,再把全套数据放到训练作业里启动正式训练。
一个小建议:在Notebook里把训练逻辑封装成一个可复用的函数或者独立的Python脚本,参数都通过命令行传入,比如数据集路径、输出路径、epoch数、学习率。这样做的好处是,之后创建训练作业时,脚本本身几乎不用改动,只要通过参数传递对应路径和超参数就行。训练作业和Notebook最大的不同在于运行模式——Notebook是交互式的,训练作业是后台批处理式的,所以脚本在设计时就应该“可命令行化”。
4. 创建训练作业:data_url、train_url和启动命令的传递逻辑
4.1 训练作业的组成:镜像、规格、路径和启动命令
解决了代码调试,下一步是创建训练作业,这也是我在整条链路里花时间最多的部分。训练作业本质上是一个后台运行的任务,它以某个镜像为基底,在指定的计算规格上执行一条启动命令,从OBS读取输入,写回输出。
创建训练作业时,主要要填这几块内容:
- 镜像:选择基础框架镜像,比如PyTorch、MindSpore或TensorFlow版本,也可以使用自定义镜像。
- 计算规格:选择GPU型号和资源大小。
- 数据输入位置:填
obs://桶名/datasets/...,这一路径会被映射到训练环境里的某个本地目录,具体路径一般通过环境变量或参数暴露给训练脚本。 - 训练输出位置:填
obs://桶名/models/output/...,训练脚本可以把模型权重、日志写回这个位置。 - 启动命令:形如
python train.py --data_url ${DATA_URL} --train_url ${TRAIN_URL}。
这里最关键的是理解输入输出路径的映射关系。你在控制台填写的OBS路径,在训练容器里会变成环境变量,比如DATA_URL和TRAIN_URL。你的训练脚本需要通过参数去接收这些路径,然后再往里面读写文件。训练脚本里一般会写成这样:
import argparse parser = argparse.ArgumentParser() parser.add_argument("--data_url", type=str, default="") parser.add_argument("--train_url", type=str, default="") args = parser.parse_args() print(f"Reading data from: {args.data_url}") print(f"Writing output to: {args.train_url}")获取到data_url之后,通常要先把OBS上的数据拉到本地磁盘再读取。原因是训练过程中频繁从OBS直接读取数据,网络I/O会成为瓶颈,特别是图片类数据集,每轮迭代都远程读文件根本吃不消。训练代码里可以用SDK或工具把数据从obs://复制到本地/cache目录,再从本地路径加载。
4.2 训练脚本里如何消费输入输出路径
一句话总结:不要把OBS路径直接塞给DataLoader去读,要先把数据拖到本地。
我第一跑训练作业时,直接把args.data_url当成本地路径传给ImageFolder,结果报了一堆路径错误,日志里全是找不到文件的提示。后来才明白,控制台里填的obs://...在训练容器的视角里只是一个“远端位置标记”,你需要自己把OBS数据同步到本地临时目录,然后再操作。很多官方示例脚本里都有一段类似的逻辑:
import moxing as mox # 将OBS上的数据复制到本地缓存目录 mox.file.copy_parallel(args.data_url, "/cache/dataset") # 将本地输出目录与OBS输出路径建立映射 mox.file.copy_parallel("/cache/output", args.train_url)有的版本里还会用mox.file.set_auth做认证,这取决于你用的框架和镜像。当第一次看到mox这个库时,你可能也会疑惑它是哪来的,其实它已经包含在ModelArts的镜像里,直接用就行。
训练输出也一样。如果你希望模型保存到args.train_url指向的OBS路径,不能直接把文件torch.save(model.state_dict(), args.train_url),因为那个路径在容器里并不是一个可写目录。正确做法是先把权重保存到本地目录,比如/cache/output/model.pth,再把这个本地目录同步到OBS。如果你在创建训练作业时填了训练输出位置,训练完成后,把/cache/output的内容整体拷贝过去即可。
4.3 训练日志、监控指标和常见报错初判
训练作业跑起来之后,你怎么知道它进展如何?看日志。
训练作业详情页里有日志查看入口,网页上就能看到实时输出的stdout。我习惯在训练脚本里多打印一些关键信息,比如当前epoch、loss值、数据batch大小、校验集准确率。这样即使不用TensorBoard,也能在日志里快速判断训练是否正常。
关于监控指标,ModelArts训练作业支持输出一些数值型指标,比如loss、accuracy,这些指标可以在控制台页面以图表形式展示。实现方式本质上是在脚本里输出特定格式的日志行,平台解析后汇总成监控曲线。不同框架和版本写法稍有差异,建议以当前版本的官方示例为准。
常见报错我先列几个,之后在第五章还会展开:
- OBS路径错误:一般表现为“NoSuchKey”或“404”,检查桶名、目录名有没有写错。
- 找不到数据:多为没有把OBS数据同步到本地就开始读取,检查代码里的路径处理逻辑。
- 显存不足:日志底部出现OOM相关字样,调小batch size或换更高显存规格。
- 启动命令无法执行:多为python环境、脚本路径、参数拼写问题,检查启动命令是否和你调试时的执行方式一致。
5. 训练排错实录:从模型不收敛到存储路径报错
5.1 模型不收敛与NaN:先怀疑学习率、数据和精度
训练作业报错不只有“崩溃类错误”,还有比崩溃更让人头疼的“不收敛类问题”。我第一次用预训练模型做微调时,epoch跑到第3轮,loss突然变成NaN,整个训练直接废了。
排查NaN的经历让我总结出一套顺序。
- 第一步,看学习率。学习率过大,loss很可能在前几步就变成NaN,尤其是使用FP16混合精度时更敏感。出现NaN时我会先把学习率降一个量级试试,比如从1e-3降到1e-4。这是最快见效的操作。
- 第二步,看数据。数据里如果混入了异常值——比如图片全黑、标签越界、文本序列长度异常——也会在计算中出现除零或数值溢出。我会在DataLoader加一个校验,先打印一批数据的shape、dtype、数值范围。
- 第三步,看精度设置。混合精度确实能显著加速训练,但对代码写法有要求。如果缩放因子处理不当,梯度更新时出现inf或NaN很常见。先关闭混合精度跑一轮,如果正常,问题基本就在精度策略上。
另一个常见问题是loss不下降,数值一直横跳或停在某个平台。这时的排查方向就变成:是否用了正确的损失函数、标签是否对齐、预训练模型是否真的加载了权重、是否在训练模式下冻结了一些层。
5.2 镜像与依赖:把requirements.txt钉死
训练作业用的是云上镜像,不是你本地环境。这句话我反复提醒自己。你在本地装了某个版本的库,训练镜像里不一定有,或者版本不同导致行为不一致。最典型的就是opencv、albumentations、transformers这些库的版本差异。
有一个教训:我用本地环境调试时transformers是4.30版,到了训练作业的镜像里默认装的是4.26版,结果某个模型的tokenizer行为变了,训练出来效果完全不对。当时排查了很久,最后才发现是版本不一致导致的。
给所有训练脚本都配一个requirements.txt,并且把版本号钉死。这不算什么高级操作,但能省很多莫名的排查时间。镜像里的预置包版本尽量先打印出来核对一下,比如:
import torch import transformers print(torch.__version__) print(transformers.__version__)如果镜像里缺包,可以在启动命令里加上安装步骤,比如先pip install -r requirements.txt再执行训练脚本。只是要注意,每次启动都会重新安装,所以别把太大体量的依赖放在这一步。
5.3 断点续训:用Checkpoint降低翻车成本
训练作业跑几个小时甚至十几个小时,中途一旦因为资源故障、显存溢出、网络问题退出,前面的计算就全白费了。这也是我强烈建议在训练脚本里做Checkpoint的原因。
实现方式不复杂:每隔固定epoch或固定步数,把模型权重、优化器状态、当前epoch数一并保存到本地,比如:
checkpoint = { "model_state_dict": model.state_dict(), "optimizer_state_dict": optimizer.state_dict(), "epoch": epoch, "best_acc": best_acc, } torch.save(checkpoint, f"/cache/output/checkpoint_epoch{epoch}.pth")在训练开始时检查有没有可加载的检查点文件,如果有,就加载并从这个epoch继续训练:
import os if os.path.exists("/cache/output/checkpoint"): ckpt = torch.load("/cache/output/checkpoint") model.load_state_dict(ckpt["model_state_dict"]) optimizer.load_state_dict(ckpt["optimizer_state_dict"]) start_epoch = ckpt["epoch"] + 1注意,要把本地的/cache/output/同步到OBS,否则当你重新创建训练作业时,之前的检查点不在新的容器里。还要在启动命令里加一个参数,比如--resume True,让脚本知道这次是要恢复训练而不是从头开始。
这种做法的意义不仅在于应对故障,也方便你做实验管理。比如你先跑了20个epoch,觉得效果还行,想续跑10个epoch,不必从头再来,直接恢复到第20个epoch继续就行。这在资源有限、预算有限的情况下特别实用。
6. 模型部署上线:模型包规范和在线服务的完整配置
6.1 从训练产物到模型包的组织结构
训练作业跑完,模型的权重文件会在OBS输出目录里。要把这个模型变成在线服务,需要按ModelArts的模型包规范重新组织文件结构。
我最初以为直接把.pth文件扔到某个路径就能部署,后来发现模型包需要包含推理代码和配置文件。下面是一个常见的最小模型包结构示例:
model/ ├── config.json ├── customize_service.py └── model/ └── model.pthconfig.json:模型配置文件,声明模型类型、推理方式、运行环境等。customize_service.py:自定义推理脚本,里面定义了模型加载、预处理、预测、后处理的逻辑。model/目录:存放模型权重的目录。
我的模型是被放到model/model.pth,配置文件和推理脚本放在上一级目录。
config.json里的字段比较多,不同版本的模型格式写法略有差异,我当时直接参照ModelArts文档里的示例改的。核心要指定运行的框架和模型类型。如果你用地MindSpore、PyTorch或TensorFlow,相关的runtime配置会不一样,创建时选择对应的模型来源即可。
6.2 推理脚本里必须处理的预处理、预测、后处理
customize_service.py是这个模型包的核心。它需要定义一个类,类里至少实现两个方法:_preprocess和_postprocess,中间还有一个模型推理的过程。
直白地说,这个脚本负责把来的HTTP请求数据变成模型能吃的张量,再把模型输出的张量变成能返回给用户的JSON。
一个简单的PyTorch推理脚本骨架大概是这样的:
import torch from PIL import Image import numpy as np class ModelService: def __init__(self): self.model = load_model("model/model.pth") self.model.eval() def _preprocess(self, data): # data是请求里传来的图片字节流 image = Image.open(data).convert("RGB") # 做和训练时一致的预处理 return tensor def _postprocess(self, result): # result是模型输出,转成可序列化的结果 return {"prediction": result.argmax().item()} def predict(self, data): tensor = self._preprocess(data) with torch.no_grad(): result = self.model(tensor) return self._postprocess(result)几个容易踩的坑:
- 预处理步骤必须与训练脚本一致,包括归一化参数、resize尺寸、通道顺序。如果不一致,部署出来的模型效果可能非常差。
- 不要用自己本地环境的相对路径加载模型,模型包的路径读取要按部署环境的结构来。
- 推理过程中最好不要有耗时很长的同步网络请求,在线服务对请求时延有要求,如果每次推理都要访问外部数据库或文件系统,很容易超时。
关于这个脚本的接口格式,不同框架和不同版本的ModelArts差异比较大。我第一次写的时候参考了官方文档里的“自定义推理脚本”示例,再结合自己的模型做修改。如果你是新版本平台,建议直接看控制台里生成的示例模板,比自己从零写要稳。
6.3 创建在线服务并完成一次API调用
模型包准备好了,就可以在ModelArts控制台创建模型,然后部署成在线服务。
部署在线服务的流程大概分几步:先创建一个模型,选择“从OBS导入模型”,填好模型包在OBS的路径,然后选择计算规格(CPU还是GPU、实例数量等)。创建完成后会生成一个服务地址和API接口。
以访问一个图像分类服务为例,请求和返回都是JSON格式。下面是常规的调用流程。
请求端要准备好图片数据,通常是把图片编码成base64字符串放进请求体里,或者用表单上传的方式提交文件。然后在请求里携带服务的鉴权信息。API调用方式有两种:一种是使用控制台生成的Token,另一种是使用AK/SK签名。我平时调试时用的是Token方式,直接在请求头里带上认证信息,简单直接。
一个请求体的例子大概是这样:
{ "data": { "req_data": [ { "image_base64": "图片的base64编码" } ] } }响应结果里会包含模型后端返回的预测结果。拿到结果后,先确认返回格式是否符合_postprocess里定义的结构,如果不符合,多半是输入字段名或预处理逻辑配置有问题。
部署过程中还有两个需要注意的点。第一,在线服务创建后不是立刻就能用的,一般要等模型加载完、实例状态变成“运行中”,这个过程可能要几分钟,别反复刷请求。第二,如果服务很长时间没有调用,实例可能会被回收或休眠。如果是生产环境长期使用,要设置合理的实例策略,避免因为休眠导致请求时延突增。
7. 成本、效率与学习心得:这套流程的实战提醒
7.1 计费维度与省钱习惯
用云端资源,成本是绕不开的话题。ModelArts的计费维度主要有几个:Notebook实例的规格与运行时长、训练作业使用的GPU资源与时长、在线服务的运行时长和规格、OBS存储容量。这些看似零散,其实就一句话:只要资源创建了、启动着,就在计费。
我在使用中吃了不少亏,总结出几条省钱习惯:
- Notebook不用时一定要停止,停止和删除是两个按钮,别忘了。有些套餐停止后不收费,但要确认你的资源类型是否属于这类。
- 训练作业尽量用脚本批处理方式,跑完自动释放资源,不要开着Notebook同时跑训练又挂着不关。
- 在线服务测试阶段先用CPU或小规格实例,确认代码逻辑无误、模型效果OK,再切换到GPU高规格。
- OBS里的旧模型、旧数据集、临时文件及时清理。存储成本虽然不高,但长期堆积也是浪费。
如果你只是学习,建议先用免费额度和低价档位把流程跑通,不要一上来就上高性能GPU。学习阶段你付的很多成本,本质上都是“试错成本”。
7.2 我最后留下的工作流
走了这么多弯路之后,我把自己沉淀成了下面这套工作流,每次训练部署都按这个来:
- 数据先上传OBS,按
datasets/、code/、models/三个目录组织。 - 在Notebook里用少量数据调试代码,确认能够正常收敛。
- 把训练脚本参数化,通过
argparse接收--data_url和--train_url。 - 创建训练作业,在启动命令里传入数据路径和输出路径,开启训练。
- 训练期间通过日志观察loss变化,定期保存Checkpoint。
- 训练完成后,把权重文件按模型包规范整理到
model_package/目录,编写推理脚本。 - 创建模型并部署在线服务,用Postman或者Python脚本调用API验证效果。
这套流程跑顺之后,我从数据处理到部署一个服务,基本可以在一天内完成,而且其中大多数时间花在数据调试和模型效果调优上,没有花在环境配置和路径排错上。
7.3 一个最实用的建议
如果整篇只能留下一句话,我会说:把代码和路径的耦合彻底解掉。
在ModelArts上训练和部署,跟本地最大的不同就是环境的“不可见性”。本地调试你可以不断print、不断加断点;云上训练你只能靠日志和保存的中间文件来判断。如果你的代码里写死了本地路径、写死了某一台机器的环境配置,上到训练作业和模型部署时,一定会反复出问题。
所以,从写代码那天起,就把所有路径当参数,把环境依赖用requirements.txt管理,把每个中间输出都留痕。这些习惯在本地看是“多此一举”,到了云上就是救命稻草。
我个人实际操作中的体会是,第一次跑通整个流程的时候会有很多小挫折,但只要路径逻辑理清了、Checkpoint机制做好了,后面每一次训练和部署都会越来越顺。这个内容后续还可以往两个方向扩展:一个是用更多预训练模型做迁移学习对比,另一个是尝试自定义镜像来固定一套自己的训练环境。希望这篇笔记能给你省点时间,少踩几个我踩过的坑。