华为云ModelArts实战:图像分类模型训练到在线服务部署全流程解析
去年年底接到一个图像分类项目交付deadline就剩一周本地工作站一张卡只有11G显存跑个ResNet级别的模型都捉襟见肘更别说上线接口给业务方调用。临时抱佛脚把华为云ModelArts完整走了一遍从数据准备到模型训练再到在线服务部署全流程在一个平台里闭环。这条路径确实能解决问题但过程中踩的坑也不少。这篇学习笔记就是把这段实战经历拆开把我配置过的参数、遇到的报错、调试的思路全部整理出来给准备用华为云ModelArts跑“训练部署”全流程的朋友一个可复用的参考。这篇笔记的适用人群我大概分三类一是刚接触ModelArts、想拿自己数据跑通第一个训练任务的人二是手上有训练好的权重、急着要对外提供API服务的人三是正在“自建GPU服务器”和“云上训练平台”之间犹豫的团队。接下来我不铺开讲平台概念只讲实际操作里最关键的环节和那些文档里不会写的细节。1. 为什么是ModelArts先把这笔账算清楚很多教程上来就让你创建训练作业但没有交代选型逻辑。同一个深度学习项目摆在面前的无非三条路自建GPU服务器、按小时租GPU算力、用ModelArts这类云上训练部署平台。我在做选择之前把三者的核心差别列了一张表。对比维度自建GPU服务器按小时租GPU算力华为云ModelArts环境准备驱动、CUDA、Docker、训练框架全要自己装一般给基础镜像但训练脚本和依赖仍要自己维护预置PyTorch/TensorFlow/MindSpore等训练框架开箱即写业务逻辑训练管理自己写日志、盯GPU利用率、处理进程崩溃基本裸算力训练状态要自己记录训练作业粒度管理内置日志、监控、可视化部署上线自己写推理服务、管端口、搞鉴权和进程守护训练和部署通常不在同一环境要二次迁移模型注册后可视化创建在线服务直接拿到API地址成本结构显卡折旧加电费加维护人力按小时计费停机不跑就不花钱按量计费训练作业结束即停止计费团队协作抢卡、环境互相搞乱是常态各租各的无法统一沉淀模型同账号下训练作业、模型版本统一管理自建GPU听起来最可控实际上只是把问题从“怎么训”转移到了“怎么维护”。装一次环境不难难的是隔三差五有人把conda环境弄坏、磁盘被日志塞满、CUDA版本和框架对不上。我见过太多团队从自建迁到云平台不是因为算力不够而是因为不想再当运维。按小时租算力适合算法调优阶段的快速验证但你和上线之间还隔着一层。模型训练完之后你仍然需要把它搬到另一个能跑推理的环境里。ModelArts的价值在于把“训练作业”和“模型部署”串成了一个闭环这一点正好打中我当时的痛点。不过它也不是银弹——如果只是周末跑个小模型自己看结果或者数据高度敏感必须留在内网那这个平台未必适合你。选工具的第一原则不是哪个强而是哪个能让你少操一份心。2. 数据准备OBS目录设计与数据集版本管理任何云上训练平台都不会直接读你电脑里的文件ModelArts的训练作业读取的是OBS里的数据。所以真正意义上的第一步是梳理数据怎么放、怎么传、怎么管理。2.1 按“输入与输出分离”设计OBS目录我是吃过目录混乱的亏的。第一版随便建了个bucket数据、脚本、模型输出全堆在一起后来想定位一个旧模型翻了半天。第二版开始老老实实按下面的结构组织obs://my-ml-project/ ├── datasets/ │ ├── raw/ # 原始数据只读永不修改 │ ├── annotations/ # 标注文件 │ └── processed/ # 预处理后的训练集、验证集 ├── code/ # 训练脚本、推理脚本 ├── output/ │ ├── train-{task}/ # 训练输出的模型权重和checkpoint │ └── eval-{task}/ # 评估结果 └── models/ # 最终注册模型的OBS路径这样设计最直接的好处是raw目录永远是干净的哪怕后面数据被污染需要重建数据集也可以从原始数据重新走一遍。训练输出和最终模型分离做版本回退时也不会拿错文件。数据上传我用的obsutil命令行工具几万张小图片这种场景一定要加递归和断点续传./obsutil config -i你的AK -k你的SK -eendpoint ./obsutil cp ./dataset obs://my-ml-project/datasets/raw/ -r -f第一次全量上传后后面再次同步只需要重新执行一次cp命令obsutil会对比文件差异增量更新。如果你有大量小文件强烈建议在本地打包成zip或者tar后再传不然几万次文件请求会慢到怀疑人生。2.2 ModelArts数据集管理的实际用法ModelArts的“数据管理”模块可以自动扫描OBS路径并创建数据集支持图像分类、物体检测、文本分类、语音分割等场景。但有一点必须提醒目录式分类数据集要求每个类别一个文件夹文件夹名就是标签。我接过一批原始数据是散图加一个CSV标签表这种必须先写脚本整理成目录结构或者走标注流程二次处理不能指望平台帮你脑补。样本少的手工标注没问题样本一旦上千建议用平台的预标注功能。先跑一个粗糙的模型生成候选框或候选标签标注人员只需要校正和确认效率能提升一半。标注完成后务必备份一份标注结果到OBS原始数据旁边数据集清单可能变但导出的JSON/XML不会骗人出问题时有这份备份能兜底。2.3 数据校验和数据集版本创建数据集时有个“数据校验”开关我强烈建议打开。平台会扫描损坏图片、标注缺失的无效样本并自动标记出来。第一次用ModelArts时我没开这个开关训练过程中反复出现某张图片解码失败日志刷屏定位浪费了大半天。数据校验就几分钟的事但能省掉训练阶段最烦人的排障时间。数据每次导入新数据或修正标注我都建议生成一个新版本。因为在训练作业里可以指定数据集版本模型上线后如果效果异常可以快速回退到旧版本数据重新实验不需要把全量数据重新整理一遍。这个习惯越早建立越好。3. 训练作业从框架选型到监控调优数据就位后进入重头戏——创建训练作业。ModelArts的训练作业本质上是帮你拉起一个带GPU的容器把代码、数据、输出目录挂载进去执行你的训练命令。但这里面的细节远不止“点一下运行”那么简单。3.1 创建训练作业的核心配置进入“训练管理 训练作业”创建训练作业的时候主要关注这几个字段算法来源选择“我的算法”然后指定代码目录的OBS路径和启动文件训练输入选择数据集或OBS路径对应脚本里读取的数据目录训练输出模型产物写回OBS的位置运行参数超参数通常以--learning-rate0.001或者环境变量的形式传入容器。我的训练脚本里习惯用argparse接收参数这样本地调试和云端训练用的是同一套代码入口import argparse parser argparse.ArgumentParser() parser.add_argument(--data-url, typestr, requiredTrue) parser.add_argument(--train-url, typestr, requiredTrue) parser.add_argument(--epochs, typeint, default50) parser.add_argument(--learning-rate, typefloat, default1e-3) args parser.parse_args() print(data_url:, args.data_url) print(train_url:, args.train_url)这里有个小坑不同框架版本里ModelArts传参的方式不太一样有的通过环境变量有的直接映射到sys.argv。我的建议是训练正式跑批量任务之前先加一行把所有环境变量和参数打印出来确认路径真的传对了再安心睡觉等结果。3.2 预训练模型、规格选型和算账逻辑做深度学习项目99%的情况不应该从随机初始化开始训。用预训练模型是标配图像分类直接上ResNet-50的ImageNet预训练权重中文NLP任务用RoBERTa中文预训练模型做底座。这些权重放在OBS里训练脚本启动时加载进来再在自己的数据上微调收敛速度和最终精度都会好很多。但ModelArts训练作业在GPU上运行时I/O瓶颈问题非常容易被低估。数据在OBS里每个epoch都要从OBS读本地缓存没做好GPU就一直在空转等数据。我第一次训练时就发现loss下降很慢日志里每个step的耗时忽高忽低。后来改成先把数据下载到训练节点的本地缓存目录再让DataLoader读取训练速度立刻稳定下来。ModelArts默认的本地缓存路径是/cache把数据解压到那里是最常见的做法。规格选型本质上是算账。V100、A800这类卡申请容易但价格也高而且资源是按时长计费的训练作业一结束就停止计费。一个很务实的方法是先在小规模数据上试跑一个step用nvidia-smi看显存占用再决定能不能加大batch_size。比如ResNet-50在输入224x224、batch_size64时大约占10GB显存V100的32G可以放心跑但如果你换成更大分辨率或者更重的模型一定要先测再开长任务。3.3 超参调试、TensorBoard与NaN排查下面这组超参起始值是我多次跑模型的经验值不保证最优但作为起点足够可靠超参经验起始值常见问题learning_rate1e-3配合warmup过大会发散过小收敛缓慢batch_size32或64过大影响泛化过小GPU利用率低epochs30~50太多会过拟合结合验证集早停optimizerAdamW配合weight decay使用这次实战里最花时间的坑是训练过程中loss突然变成NaN。我的排查顺序是第一步把learning_rate降到1e-4试跑排除学习率过大的因素第二步检查数据管线看预处理后的张量里是否有NaN输入第三步看loss从一开始就是NaN还是中途变NaN如果一开始就是基本要怀疑模型里的归一化层或损失函数实现出了问题。ModelArts的训练日志会记录每个step的loss建议脚本里加上定期保存checkpoint的逻辑每个epoch存一次到OBS后半程挂了还能从最近的checkpoint续跑不用整个重来。TensorBoard在ModelArts里的配置方式是在训练作业里开启“可视化”开关并把日志输出到指定目录。这样作业详情页的“可视化”标签里能直接看到loss曲线比在终端盯滚动日志直观得多。但TensorBoard的event文件同样会占OBS存储长训练记得定期清理旧日志。4. 模型评估、打包与版本注册训练结束只是一个中间节点离“模型能对外提供服务”还差着一个模型打包和注册的过程。ModelArts并不是直接把权重文件拖上去就能部署它需要的是符合推理规范的模型包。4.1 从训练输出到标准模型包训练结束后output目录下通常是一堆散落的权重文件、配置和日志。复盘我最终采用的模型包结构大致是这样my_model/ ├── model/ │ ├── resnet50.pth │ └── model_config.json # 模型结构描述 ├── customize_service.py # 自定义推理逻辑包含预处理和后处理 ├── config.json # 推理服务配置定义输入输出格式 └── 1.0.0/ └── .manifest # 版本描述文件customize_service.py是最容易出问题的文件。它负责把HTTP请求里的原始数据转成模型能吃的张量再把模型输出转成用户友好的结构。以图像分类为例核心逻辑大致长这样class ModelService(object): def _preprocess(self, data): # data里的一般是base64字符串列表 image data[images][0] img base64_to_image(image) img resize(img, (224, 224)) img normalize(img, mean, std) # mean/std必须和训练时完全一致 return img.unsqueeze(0) def _postprocess(self, data): pred torch.argmax(data, dim1).item() return {label: str(pred), score: float(data[0][pred])}这里我踩过一个非常典型的坑训练时图像预处理用了随机裁剪、随机翻转、标准化这套逻辑如果照搬到推理阶段结果必然不对。推理阶段的预处理应该固定为中心裁剪而且标准化用的mean和std要和训练时保持一致。当时我用一张固定图片在本地脚本和在线服务各跑一次对比输出最后发现是预处理里一个Resize参数不一致导致结果差了好几个百分点。所以部署前准备至少10张“探针图片”记录它们的预期输出上线后随时可以做回归测试这是每个做模型上线的人都该养成的习惯。4.2 模型评估与版本管理在ModelArts里可以把训练作业一键注册成模型也可以从OBS手动导入模型包。注册时建议自己控制版本号不要用平台默认的时间戳。我一般循着“算法名-日期-序列号”的规则比如resnet50-cls-20250115-01这样哪怕同时部署几个服务也能一眼看出线上跑的是哪个时代的模型。模型评估方面ModelArts提供离线评估能力能自动在测试集上跑出混淆矩阵、精确率、召回率、F1值。但如果你的任务比较冷门或者评估指标和平台内置的不一致更靠谱的做法是把测试集推理结果自己导出成JSON或CSV再用自己的脚本算指标。平台指标是参考业务方要的指标一定以自己的脚本为准。版本管理这件事不只是“多个版本并存”更重要的是把每个版本的训练数据和超参一并保留下来。ModelArts的训练作业里能看到历史参数但跨账号、跨时间长光靠平台记录不够。我后来习惯在训练脚本里加一行把超参摘要写入输出目录的config文件。一个月后回来看模型有这份残留的配置才能准确回忆起当时为什么这么调。5. 部署在线服务鉴权、调用与扩缩容模型注册完成后下一步就是部署在线服务。这是把模型真正变成“产品”的最后一段路也是很多人在训练阶段完全不会遇到的问题集中爆发的地方。5.1 创建在线服务的关键选择从模型列表选中版本点击“部署 在线服务”需要填服务名称、资源规格、实例数。CPU实例和GPU实例的取舍很简单低并发、对时延不敏感就选CPU便宜任务对单次推理时延有要求就老老实实用GPU实例。在线服务创建成功后ModelArts会分配一个公网访问地址和端口。但这里有个冷知识如果不在创建时配置安全认证服务在生产环境就是裸奔状态任何人都能调用你的模型接口既费钱又可能被刷到崩溃。我建议创建服务时直接选“APP认证”或“AK/SK认证”其中APP认证最简单在“服务详情”页申请一个AppCode调用时放在请求头里即可。5.2 调通第一个请求调通在线服务的第一个请求全程最折腾的地方往往是输入数据的格式。图片模型一般要求base64字符串但不同服务的字段名五花八门有的是image_base64有的是images有的是data。我最开始反复收到40x错误最后发现是字段名多了一个字母。调接口调到怀疑人生之前先去看模型包里config.json的输入定义再去看customize_service.py到底读了哪个key。一个可复用的调用模板大致如下import requests import base64 with open(test.jpg, rb) as f: img_b64 base64.b64encode(f.read()).decode() url https://your-endpoint/v1/infers payload {images: [img_b64]} headers { Content-Type: application/json, X-Auth-Token: your_token, # 用APP认证则替换为AppCode } resp requests.post(url, jsonpayload, headersheaders, timeout30) print(resp.status_code) print(resp.text)如果需要做批量测试或者压测建议不要用requests在Python里直接写循环而是配合简单的并发工具。我当时用并发脚本模拟了20路同时请求很快就暴露了服务实例数不足和冷启动延迟这两个问题。5.3 稳定性冷启动、超时与自动扩缩容在线服务刚部署完第一次请求特别慢是正常现象。模型权重要从OBS加载到显存容器要初始化推理框架这个冷启动过程少则十几秒多则几分钟。尤其当平台因空闲销毁了实例后下一个请求会重新经历冷启动监控里就会看到时延尖刺。解决思路有两个一是把最小实例数设置为1让服务一直热着二是部署完成后立即发起一次探活请求把模型预加载起来。超时配置也很值得检查。如果你传的是高分辨率大图预处理耗时可能远超默认超时时间。一种更聪明的做法是在customize_service.py里限制输入尺寸比如先等比压缩到最长边不超过1280再做推理。这样既降低了时延也让推理成本更可控。扩缩容方面ModelArts支持手动修改实例数也支持按CPU/GPU利用率和请求量自动扩缩。我的建议是先手动固定一个保守的实例数跑一周观察平均时延、请求量、GPU利用率这些指标再设置自动扩缩策略。一上来就配10个实例资源和预算都经不起造。告警一定要接请求失败率、平均时延超过阈值就发邮件或短信至少出事时不是等业务方投诉你才知道服务挂了。顺便提一句大模型部署的场景。如果你的目标是部署大语言模型、Diffusion这类动辄几十GB权重的模型ModelArts平台也能承载但这种场景的推理通常需要vLLM这类专门加速框架对资源规格和模型打包方式的要求和传统CNN完全不同。不要简单套用前面那套“config.json customize_service.py”的通用逻辑优先找针对大模型推理的方案更稳妥。回头梳理这次用ModelArts从训练到部署的完整流程我最大的感受是云平台解决的是基础设施和流程标准化而不是替你解决模型效果。真正决定模型上线质量的依然是数据质量、预处理一致性、超参调优和一套可靠的发布流程。如果你也是一个人或小团队、没有专职运维ModelArts确实能帮你省掉很多杂活。但别把平台当黑盒训练脚本里的每一行都值得亲手掌握那才是项目真正的资产。最后再分享一条经验无论平台功能多完整先把数据目录和模型版本管好再谈自动化。版本乱了再好的算力也救不了你。

相关新闻

测试报告编写指南:核心价值与结构化设计

测试报告编写指南:核心价值与结构化设计

1. 测试报告的核心价值与常见误区刚入行测试那会儿,我最头疼的就是写测试报告。记得有次加班到凌晨三点赶出来的报告,第二天被项目经理当着全组的面批得一文不值——"这堆数据能说明什么问题?"、"关键缺陷为什么没有优先级标注…

2026/10/15 9:26:24 阅读更多 →
AI内容降重工具评测与实战指南

AI内容降重工具评测与实战指南

1. 工具选型背景与核心需求在内容创作领域,AI生成内容的检测与优化已成为刚需。根据2024年斯坦福大学数字内容研究中心报告,约67%的在线平台已部署AI内容识别系统。这促使创作者需要掌握有效的降AI率工具,使生成内容更贴近人类写作风格。降AI…

2026/10/15 9:26:24 阅读更多 →
AI漫剧角色一致性工作流:从参考图、LoRA到算力成本优化的完整实践

AI漫剧角色一致性工作流:从参考图、LoRA到算力成本优化的完整实践

做AI漫剧做了快一年,踩过最大的坑不是模型不会跑,而是同一个角色在不同镜头里长得像两个人。眼睛、发型、服装细节一飘,观众立刻出戏,弹幕直接开喷。这一期聊聊我怎么把“角色一致性”这件事从玄学变成流程,再把“算力…

2026/10/15 9:25:23 阅读更多 →

最新新闻

新能源汽车热管理系统Simulink建模与仿真实践

新能源汽车热管理系统Simulink建模与仿真实践

1. 项目背景与核心价值在新能源汽车快速发展的今天,热管理系统设计正面临前所未有的挑战。传统燃油车的热管理相对简单,主要关注发动机冷却和空调系统。而电动车和混合动力车型需要管理电池、电机、电控等多套系统的热交换,还要兼顾不同驱动模…

2026/10/15 10:15:14 阅读更多 →
impeccable:用CLI与浏览器扩展约束AI生成前端代码的设计质量

impeccable:用CLI与浏览器扩展约束AI生成前端代码的设计质量

1. 从"impeccable"说起:一个被低估的前端质量命题第一次看到"impeccable"这个词被拿来命名一个前端工具,我的反应是:这名字起得挺狂。impeccable,无懈可击、无可挑剔,放在前端设计语境里&#xff…

2026/10/15 10:15:14 阅读更多 →
汽车热管理系统建模与仿真关键技术解析

汽车热管理系统建模与仿真关键技术解析

1. 传统车热管理系统建模概述热管理系统作为整车能量流动的"交通枢纽",直接影响着发动机效率、座舱舒适性和零部件寿命。在传统燃油车领域,热管理建模需要同时考虑发动机冷却系统、润滑系统、空调系统以及排气系统之间的耦合关系。我从业十年间…

2026/10/15 10:15:14 阅读更多 →
ponytail插件是什么?轻量可插拔模块的挂载与卸载实战指南

ponytail插件是什么?轻量可插拔模块的挂载与卸载实战指南

1. 从“ponytail”这个热词说起:它到底指什么第一次看到“ponytail”被当成一个技术词条来搜,我其实愣了一下。字面意思就是马尾辫,一个再日常不过的发型词,怎么会跟“skill”“插件”“如何使用”这些词绑在一起冲上热搜&#xf…

2026/10/15 10:15:14 阅读更多 →
操作系统期末复习:用手写笔记抓住进程、内存与文件系统三大核心

操作系统期末复习:用手写笔记抓住进程、内存与文件系统三大核心

简介:这份手写笔记围绕桂电操作系统期末考点整理,面向备考本科生的复习场景,帮助快速串联操作系统基本概念、进程管理、存储管理、文件管理和设备管理等章节。笔记按章节标注了考试占比,并重点梳理了三态模型、进程调度算法比较、…

2026/10/15 10:15:14 阅读更多 →
正弦波转方波方案对比:比较器、施密特、运放与专用芯片选型指南

正弦波转方波方案对比:比较器、施密特、运放与专用芯片选型指南

简介:这份PPT资料面向电子工程、测控仪器相关专业的学生与工程师,围绕正弦波转方波这一常见电路设计问题,系统比较了四种实现方案并给出详细电路图。内容以220V/50Hz正弦波转10V/50Hz方波为设计目标,依次讲解由555定时器构成的施密…

2026/10/15 10:14:14 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →