CANN内测实战:从环境初始化到模型推理的完整指南

前阵子看到某社区的“内测招募,免费体验CANN开发环境”活动,我第一时间就报名了。说实话,当时打动我的不只是“免费”两个字,而是想看看这个面向昇腾AI处理器的异构计算架构,在过去一年里到底进化到了什么程度。

CANN这个开发环境,简单理解就是昇腾芯片的“软件地基”。你写算子、调模型、做推理部署,表面上用的是AscendCL、ATC这些工具,底层全是CANN在承接调度。它对标的就是NVIDIA生态里CUDA那一层,只不过围绕的是昇腾硬件。对正接触昇腾设备的开发者来说,CANN先不先进、稳不稳定、好不好上手,直接决定整个项目的开发体验。

这篇文章我不打算做成官方文档复读,而是从一个实际内测参与者的视角,把申请流程、环境初始化、模型转换、推理跑通的完整链路,以及我在内测阶段遇到的坑和解决办法,全部写清楚。如果你是做AI应用开发、算子开发,或者正考虑是否要报名此类内测,可以对照这份记录评估一下值不值得投入时间。

1. 报名前的判断:内测到底测的是什么

1.1 CANN解决的核心问题,以及它和CUDA的对应关系

有GPU开发经验的读者,理解CANN会非常快。CUDA是NVIDIA GPU的编程模型和运行时,CANN则是昇腾AI处理器的异构计算架构。它们承担的职责高度相似:统一底层硬件差异、提供内存管理和算子调度能力、屏蔽不同芯片型号之间的编程差异。

CANN内部包含几个关键件:AscendCL负责应用层API封装,ATC负责把训练好的模型转换成昇腾可执行的om离线模型,GE图引擎做计算图优化和算子融合,TBE算子开发框架则给需要自定义高性能算子的人提供一套DSL——你用它写算子,最终编译成昇腾AI Core上跑的指令。还有MSProfiler之类的工具链,用于分析算子耗时和系统瓶颈。

在报名之前我其实最关心一个问题:CANN的算子覆盖率和工具链成熟度,能不能撑起一个已经在GPU上跑通的视觉推理项目。因为算子覆盖不够,意味着你辛辛苦苦在GPU上优化的网络,迁移到昇腾上可能某个算子不支持,要么改图,要么手写算子,这工作量可不小。从内测的实际结果看,常用CV和NLP模型的主流算子覆盖已经算完整,但个别小众算子确实还会缺失,需要自己补。

1.2 内测资格和正式版的区别:免费免在哪几个环节

这类内测活动的“免费体验”,通常免的不是别的,是算力配额和技术支持。我在内测期间获得的是一套远程开发环境,配置大致是单张昇腾310推理卡、8核CPU、32GB内存,使用期限以活动说明为准,到期后资源回收。对于想验证模型能否迁移、算子能否正常工作的人来说,这个配额足够用。

免费还有一层意思:官方会把部分不易获取的调试工具、profiling采样能力开放给内测用户,并承诺问题反馈的响应通道。这在正式商业环境中,往往对应着不低的售前支持成本。参与内测的人实际是在用反馈换支持,用提前试用换未来的技术选择经验。因此申请前要有心理准备:你不是来白嫖算力的,而是来当产品体验官的。

1.3 什么样的情况不适合报名

如果只是好奇,“玩一玩”,我建议把机会留给有明确需求的人。因为内测审核会有筛选,后续也需要你真实跑任务、提问题。虽然不强制必须提交反馈,但拿着一个环境一两周不碰,既浪费机会也影响审核方对真实开发者需求的判断。

我身边有位做端侧推理的朋友,没有明确迁移计划,单纯为了尝鲜申请,结果环境开通后只跑了个hello world,再也没有登录过。而另一位需要把图像检测模型部署到昇腾设备上的开发者,利用内测两周内就完成了从模型转换到性能调优的完整验证,收获非常大。两者的差别不在技术,而在目标是否清晰。

2. 申请流程与开通细节:比想象中简单,但周期要预留

2.1 申请前需要准备好的四样材料

申请入口通常在平台官网或官方社区的内测专题页,找到报名表单后,不要急着填。先把下面四样东西准备齐全,会明显降低来回沟通成本:

  • 平台账号,通常需要完成基础注册或实名认证。未认证的账号往往无法提交内测申请。
  • 开发经验描述,不用太长,一句话说清楚你用过的框架、熟悉程度即可。但“用过TensorFlow/PyTorch”这种还是比“接触过AI”更有说服力。
  • 计划跑的主体内容,比如“想把ResNet50图像分类迁移到昇腾310”“需要自定义一个LSTM算子”,越具体越好,审核方最怕收到“什么都想试试”的模糊需求。
  • 硬件环境说明,如果你本机已有昇腾设备或相关开发板,可以标注出来,这代表你后续有持续使用的可能,会提高通过率。

我第一次填的时候只写了两行字,结果等了一周没动静,后来补充了详细计划后很快收到了通过通知。合理的推测是审核人员在用有限名额匹配真需求。

2.2 从提交到开通的完整时间线

按照我的实测记录,时间线大致是:周二下午提交申请,第二周周三收到审核通过邮件,周五拿到环境访问方式和一份部署文档,合计八个工作日。这个周期不算快,所以如果你的项目有硬性截止时间,建议预留至少三周。

开通后会收到几类信息:远程环境的SSH登录方式或容器入口、一个初始账号、一套环境变量配置脚本的路径,以及一份针对当前CANN版本的内测说明。登录进去后先别急着看算子,第一件事是按照文档做基础校验,确认驱动、固件和toolkit版本对齐——这是新手最容易忽略的,版本错位会导致后面所有报错信息都变得不可解释。

2.3 控制台与本地命令行的配合

这个内测环境允许我从本地SSH远程访问,也提供了网页控制台。我的习惯是:网页控制台上传模型文件和代码,本地终端保持SSH窗口做实时调试。这样省去来回下载日志的麻烦。有一点很实用:环境里有官方预置的样例工程目录,路径在环境说明里有提示。先复制一份到自己的工作目录再修改,不要直接在原目录改,防止版本升级或重置时丢失你的改动。

3. 环境开通后的第一件事:把官方样例完整跑通

3.1 设备初始化和npu-smi检查

无论装什么版本,第一步永远是确认设备对开发者可见。登录后会看到一个类似GPU场景下nvidia-smi的排查习惯,这里对应的是npu-smi命令。执行npu-smi info,能看到昇腾设备的型号、健康状态、当前算力使用率和温度。

我在第一次执行时,输出里有个字段显示驱动状态为“uninitialized”。注意,这不代表设备坏了,通常说明固件或驱动未加载成功,或者环境变量没有指向正确的主设备。这时候先去检查驱动安装,而不是急着换环境。如果用npu-smi info已经能正常显示设备,那么硬件这一关就过了。

然后执行环境初始化脚本,一般路径类似/usr/local/Ascend/ascend-toolkit/set_env.sh。这一步很关键,它会设置AscendCL、ATC工具链相关的环境变量。有些新手跳过这一步,直接调用atc命令,会得到“command not found”,这不是没装,而是环境变量没配。

3.2 跑通一个最小推理样例的完整命令序列

官方样例里通常会有一个基于ResNet50的图像分类demo,这个样例是最接近真实使用场景的模板。在跑它之前,我先做了三件小事:

# 查看设备状态 npu-smi info # 加载环境变量(每次新开终端都要执行) source /usr/local/Ascend/ascend-toolkit/set_env.sh # 确认关键工具版本 atc --version

随后目录切换到样例工程,按其README执行构建。如果样例支持Python版本,通常一条命令完成推理;如果是C++版本,需要先cmake再make。C++版本的构建过程会比Python慢不少,第一次编译大概在五到十分钟,取决于环境配置。注意观察编译输出里的告警,别因为能跑通就忽略,有些告警会在运行时变成“段错误”或数据错乱。

第一次跑通时,我用了样例自带的测试图片,确认top5分类结果和预期一致后,才敢把自己的模型放进去。实际测试发现,官方样例是最低门槛,哪怕你不用它做产品,也建议完整跑一遍,因为它能帮你验证环境所有通路是否正常。

3.3 从样例到自己代码的过渡建议

很多人拿到环境就直接写自己的推理脚本,遇到莫名其妙的报错就怀疑环境有问题,其实大半是数据处理或者内存管理的问题。我的建议是分三步走:先跑通样例确认基础链路,再改样例的输入数据换成自己的图片确认处理函数,最后再插入自己的模型。每一步都有验证节点,出问题时能快速定位是模型转换的锅、数据处理的锅,还是环境本身的锅。

4. 实际任务:用一个图像分类项目把内测环境完整榨了一遍

4.1 为什么选了ATC离线模型转换路线,而不是在线推理

昇腾设备上的推理有两条路线:一是把模型先导入图引擎在线推理,二是通过ATC工具把模型离线转换成om格式再加载执行。我这次选择离线om路线,原因有两个:第一,om模型在推理时不需要反复做图编译,执行开销更小;第二,它更贴近生产环境的部署习惯。

使用ATC转换时,输入模型我准备的是ONNX格式。转换命令的大致形式如下:

atc --model=resnet50.onnx \ --framework=5 \ --output=resnet50_om \ --soc_version=Ascend310 \ --input_format=NCHW \ --input_shape="actual_input_1:1,3,224,224"

其中--framework=5代表ONNX,--soc_version要根据你的芯片型号填写,写错会直接报错;--input_shape最好显式写清楚,尤其当你的预处理已经将图片resize到固定尺寸时,用固定shape可以避免后续动态shape带来的额外开销。

转换成功后,会生成一个.om文件。这个文件就是后续推理程序的主输入。

4.2 AscendCL核心调用逻辑与内存管理

加载和运行om模型使用的是AscendCL的C++ API,整体流程可以总结为:初始化、指定设备、创建上下文、加载模型、准备输入输出、执行推理、清理资源。

// 初始化 aclInit(nullptr); // 指定设备 aclrtSetDevice(0); // 创建上下文 aclrtCreateContext(&context, 0); // 加载模型 aclmdlLoadFromFile("resnet50_om.om", &modelId); // 准备数据并执行 aclmdlExecute(modelId, inputBuffer, outputBuffer);

代码用起来比看起来更需要注意细节。AscendCL中申请内存用的是aclrtMalloc,而不是普通的malloc,它需要传入一个可对齐的内存大小,并且区分设备内存和主机内存。这个很容易踩坑,后面我专门写了一节。

推理完成后,务必要在结束前依次销毁上下文、卸载模型、调用aclrtResetDevice和aclFinalize。否则下一次运行时会提示设备被占用,严重时甚至需要重启容器才能恢复。这些细节在官方sample里都有,但如果你是从头写自己的代码,很容易漏掉。

4.3 实测性能数据的解读

跑完一轮后,我用profiling工具拉取了算子的执行耗时。结果里有个AI Core利用率的数值,我的ResNet50在批处理为1时利用率大概在30%上下。如果只看这个数字会觉得不高,但这里有个认知问题:利用率低不代表环境有问题,而是模型单batch时算子无法完全打满硬件。

我试着把batch从1调整到4,利用率立刻升到了接近60%,整体吞吐明显提升。这说明在昇腾设备上,盲从GPU时代“单batch低延迟”的经验并不完全适用。如果应用场景允许,适当增大batch拿吞吐换延迟,在推理侧往往收益更大。

5. 内测阶段真实踩过的坑,每条都带着解法复盘

5.1 默认日志级别足够刷爆终端,还会拖慢启动

第一次跑推理程序时,控制台被大量的INFO级日志刷屏,执行时间比预期慢了很多。一开始我以为模型转换有问题,查了半天才意识到是日志级别的问题。

解决办法是设置环境变量:export ASCEND_GLOBAL_LOG_LEVEL=3。这里3对应的日志级别是ERROR,切换后日志立刻安静了。如果你还需要调试,可以改成1(DEBUG)临时看细节,但调试完记得恢复。这个设置每次登录都要重新执行,或者直接写进.bashrc,避免忘记。

5.2 反复“设备内存不足”,源于host侧内存没有释放

我用完一张测试图片后马上测试第二张,第二次一直报内存申请失败。反复尝试后发现,我只关注了模型加载占用的设备内存,却忽略了每次推理前用aclrtMalloc申请的输入输出内存,推理结束后没有释放。

这类内存申请在循环里执行,每次泄漏一点,到十几轮之后就会把内存耗尽。解决办法是执行结束后统一aclrtFree,并且尽量把内存申请放到循环外,循环内只做数据搬运。这个和CUDA编程里cudaMalloc的使用习惯是一致的,经验可以平移。

5.3 profiling结果比预期慢一个数量级,根因是数据搬运

有一轮我把profiling打开,发现算子执行时间从毫秒级变成了上百毫秒,直接吓一跳。后来查资料和对照排查,才知道profiling工具在采集时需要把设备端的性能数据搬运到host端,这个过程本身会产生额外开销,同时它还会让部分算子插入探针,影响执行时序。

这不是环境问题,也不是模型问题,纯粹是profiling模式带来的测量开销。解决方案是:正式计时时关闭profiling,只看前后端时间戳;性能分析时只在关键阶段开启profiling,减少全流程采样。这个教训提醒我,内测环境的工具链已经帮你把“知道瓶颈在哪”这件事简化了,但也需要懂得测量本身会改变结果。

为了便于排查,我把几个常见问题和对应方向整理成了一张表:

现象常见原因优先排查方向
atc命令找不到环境变量未加载检查set_env.sh是否source
模型转换报错op类型不支持当前版本算子覆盖有限查算子支持清单,或简化模型
推理结果全错输入数据预处理与模型要求不符核对归一化、mean/std、NHWC与NCHW
程序退出时卡死资源未按顺序释放检查aclrtFree、销毁上下文顺序
运行比官方样例慢很多profiling开关或batch过小关闭profiling,增大batch

5.4 环境变量丢失问题

远程SSH每次登录后环境变量都是全新的,如果忘记source set_env.sh,后面所有命令都会连锁失败。我后期直接把source语句写进了.bashrc,省去重复操作。内测期间被这个问题浪费的时间加起来至少一小时,写出来给后来人避坑。

6. 申请前最该问自己的三个问题

6.1 你需要的到底是一个开发环境,还是一个现成的模型平台

这件事我在内测期间想得很清楚:如果你需要的只是快速部署现成模型,并不想接触底层算子和编译工具链,直接使用模型服务或推理平台会更省力。CANN这类开发环境面向的是需要对算子和推理链路做深度调优的人,它给你的是更大自由度,不是更少的开发量。

如果你是第一次接触昇腾生态,建议先从官方文档和样例入手,不要一上来就写自定义算子。先跑通标准链路,再逐步深入图引擎、算子融合这些高级功能,学习曲线会平缓很多。

6.2 没有物理昇腾设备,内测资格值不值得争取

值得。原因很简单:这类内测在算力资源、技术支持和文档完整度上,都优于你自己找一台二手设备折腾。哪怕之后你没有昇腾硬件规划,内测经历中积累的推理优化经验,对理解异构计算体系的整体设计也有很大帮助。

在内测期间我还特意验证了一个想法:把自己社区账号下沉淀的问题和回答迁移到新的评论区,发现对这种技术社区来说,干货内容的复用性极强。这也让我更确定,参加一次高质量内测并输出过程记录,比拿到环境就埋头跑模型有价值得多。当然这个建议只针对愿意写文档的开发者,纯编程爱好者可以跳过。

6.3 内测结束后代码的可移植性好不好

这是我在申请时就特别关注的。CANN相关的代码主体是AscendCL API,它和C++/Python标准库隔离得比较干净,所以我计划内的核心推理模块都封装在一层接口里。内测阶段验证的代码,结束之后可以留作知识沉淀,之后如果真有昇腾设备,迁移成本控制在很小的范围内。

如果你有长期使用昇腾设备的计划,建议在内测期间就养成“代码适配层”的思维方式,把可复用部分和跟硬件绑定的部分做隔离,哪怕只写注释标注哪些函数需要按设备类型替换,都能给未来的自己省下大量时间。

我个人在内测过程中最大的体会是:这类开发环境的“免费”确实是一种值得珍惜的机会,但前提是带着明确任务去用。如果你也想报名,我建议在申请表单里写清楚你准备跑的模型、预期的性能指标,即使只是估计的数值,审核人员也会认为你是认真打算使用的。等到真正拿到环境的那一天,你会发现之前花在准备上的时间,都转化成了上手时的从容。

相关新闻

Redis单线程还是多线程?从4.0到7.2的线程模型演进真相

Redis单线程还是多线程?从4.0到7.2的线程模型演进真相

1. 这个问题为什么值得花十分钟认真搞懂“Redis 到底是单线程还是多线程?”——这句提问在技术群、面试现场、甚至线上课程评论区里,几乎每周都会高频出现。它表面看是个“是非题”,但背后牵扯的是你对 Redis 性能本质、架构演进逻辑、以及高…

2026/10/21 3:31:24 阅读更多 →
LabVIEW实时扭矩控制:CAN FD+硬件同步的四驱车在线闭环系统

LabVIEW实时扭矩控制:CAN FD+硬件同步的四驱车在线闭环系统

简介:本资源是全国虚拟仪器大赛获奖作品——基于LabVIEW的汽车扭矩主动分配测控系统完整实现方案,面向自动化、车辆工程及测控技术方向的高年级本科生与工程实践者,聚焦于驱动轮间实时扭矩调控这一核心控制问题,适用于智能驾驶辅助…

2026/10/21 3:31:24 阅读更多 →
回拨模式全面解析:外呼系统从机制、优势到实战落地

回拨模式全面解析:外呼系统从机制、优势到实战落地

1. 先搞懂回拨模式到底是个什么机制很多人第一次听说“回拨模式”时,会下意识觉得:这不就是让系统自动把电话打回去嘛,有啥稀奇的?其实这个理解只对了一半。回拨模式的核心逻辑不是“帮你回电话”,而是改变整个外呼任务…

2026/10/21 3:31:24 阅读更多 →

最新新闻

基于React18与TypeScript构建完整业务后台管理面板的实战复盘

基于React18与TypeScript构建完整业务后台管理面板的实战复盘

最近我在梳理手头的一个前端练习项目时,发现一个很有意思的代号挂在文件夹里——rea。它是我用 React 生态完整搭起来的一个业务管理面板 Demo,用来模拟日常后台系统中最高频的那些场景:列表展示、筛选搜索、数据详情、状态流转、主题切换等等…

2026/10/21 4:50:55 阅读更多 →
51单片机驱动RC522射频模块实战:SPI时序、寄存器配置与防冲突全流程

51单片机驱动RC522射频模块实战:SPI时序、寄存器配置与防冲突全流程

简介:本资源是面向嵌入式初学者与51单片机开发者的RC522射频识别(RFID)系统实战资料包,聚焦13.56MHz非接触式读写应用,适用于门禁控制、智能卡实验及物联网基础项目开发。内容涵盖RC522与51单片机的SPI硬件接口详解、初…

2026/10/21 4:50:55 阅读更多 →
立体仓库堆垛机输送系统设计要点与调试经验分享

立体仓库堆垛机输送系统设计要点与调试经验分享

1. 项目总览与核心需求拆解立体仓库这个东西,本质上就是让货架变得更聪明、让地面上的货物流转起来。很多人在看到“立体仓库 堆垛机 输送机 智能物流”这一串词的时候,第一反应是“这项目肯定特别复杂”,但实际上,把它拆开来看&a…

2026/10/21 4:50:55 阅读更多 →
从知道到做到:技能盘点与刻意练习的实用指南

从知道到做到:技能盘点与刻意练习的实用指南

Skills,翻译成中文就是技能。但这些年我在职场里见过太多人,把“知道”当成“会”,把“会”当成“精通”,最后在真正需要展示的时候,才发现自己的技能体系其实很脆弱。这篇文章不聊鸡汤,也不搞那种“一周精…

2026/10/21 4:50:55 阅读更多 →
Flutter for OpenHarmony通讯录助手实战:flutter_contacts适配指南

Flutter for OpenHarmony通讯录助手实战:flutter_contacts适配指南

说实话,看到这个标题的第一反应是“终于有人在OpenHarmony上认真捣鼓第三方库了”。我在某公司做跨平台客户端开发,去年下半年接到一个内部工具型App的适配需求,要求同时跑通安卓和OpenHarmony平板。团队技术栈是Flutter,业务里有…

2026/10/21 4:50:55 阅读更多 →
彻底搞懂 torch.manual_seed:从随机种子原理到完整复现配置指南

彻底搞懂 torch.manual_seed:从随机种子原理到完整复现配置指南

有一段时间我被一个现象折磨得不轻:同一份训练代码,连超参数都没动,下午跑出来的模型和早上跑的模型,准确率能差上两个点。排查到最后,问题根源锁定在所有随机数的源头——torch.manual_seed() 这个函数上。准确地说&a…

2026/10/21 4:49:55 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →