模型微调何时停?早停机制与止损策略实战指南

做模型微调的人,一定都经历过这样的深夜:训练 loss 还在往下掉,验证集指标却开始横跳,你盯着屏幕反复问自己——是不是再跑几个 epoch 就好了?是不是学习率还能再救一下?是不是换一组数据采样就能突破?

今天想聊的,不是怎么把模型调得更好,而是另一个更重要的能力:在合适的时候停下来。标题说得已经很到位——不是调不动了,而是该停了。这篇内容围绕"微调止损时刻",讲讲我在实际任务里怎么判断该停、怎么设计止损规则,以及那些真正踩过的坑。适合刚开始做微调的新手,也适合每天被调参折腾得心累的从业者。

1. 先搞清楚:模型到底是"调不动了",还是"该停了"?

很多人在微调时出现"loss 不降了"的第一反应是继续调,比如换学习率、调 batch size、加正则化、换优化器,折腾一圈下来,验证集指标还是那个死样子。这时候你要先做一个判断:模型是真的"调不动了",还是已经过了最佳点,正在往过拟合的方向走?这两个问题的处理方式完全相反,前者要加资源、加手段继续强攻,后者要立刻收手止损、保存当前最好的参数。

1.1 调不动的三个典型信号

先说"调不动了"。这个状态的核心特征是训练集本身的表现不达标,而不是验证集不行。我有一次做文本分类任务,预训练模型加载之后跑了五六轮,训练准确率始终在 74% 左右徘徊,验证集也跟着不稳定。当时第一反应是学习率不够,后来把学习率从 2e-5 提到 1e-4,训练准确率反而更差。复盘后发现问题出在数据预处理:文本里有大量特殊符号没清洗干净,模型一直在学噪声。这才是真正的"调不动",靠调整超参解决不了,得先把数据侧的问题处理掉。

典型的"调不动"信号有三个。第一个是训练 loss 在高位震荡,不管怎么调参都压不下去,比如损失函数一直卡在 1 以上不掉。第二个是梯度出现异常,比如梯度范数变成 NaN,或者反向传播到浅层时梯度已经小到不更新了,这个本质是网络结构或者初始化的问题,不是多跑几轮能解决的。第三个是数据量和模型容量严重不匹配,比如拿几千条样本微调十亿参数的模型,训练集还没看完一遍就已经把样本背完了,这时无论怎么调都很难有实质提升。

1.2 该停了的三个信号

"该停了"和"调不动"最大的区别在于:训练 loss 还在降,甚至降得很漂亮,但验证集指标已经不再提升,甚至开始倒退。这才是最迷惑人的地方——你看着训练曲线一路向下,心里总觉得模型还在变好,但验证集已经给了你明确的红灯。

第一个信号是验证指标连续多轮没有改善。比如连续 3 到 4 个 epoch,验证集 F1 值都稳定在 86.2%、86.1%、86.3% 这种水平,而训练 loss 还在下降,说明模型已经开始把训练集细节背进去了,泛化能力停滞了。第二个信号是训练集和验证集的指标差距越拉越大,训练 acc 到了 97%,验证 acc 却只有 88%,这中间多出来的 9 个点,就是模型死记硬背的代价。第三个信号更量化:实际提升幅度已经小于你能容忍的最小改进量,比如你要提升 0.5% 才值得上线的模型,现在一轮只能提升 0.05%,那再跑十轮都是浪费时间。

1.3 为什么我们总想再试一次:心理账与资源账

我见过太多人(包括我自己)在"该停"的时候选择继续跑,根本原因不是技术判断,而是心理账没算清楚。已经花了三天时间、烧了几千块算力,潜意识里觉得现在停掉就"白跑了",总想着下一轮也许就突破了。这跟炒股止损是同一个逻辑:沉没成本不该影响你的下一步决策,该不该停只取决于模型当前的状态和未来收益的预期,而不是你已经投入了多少。

另外还有一个非常现实的原因:调参会产生惯性。当你连续调了几个晚上,你会陷入一种"我再试一个方案就能成"的幻觉,但多数情况下,验证集指标的变化早就进入了随机波动区间,你再怎么换方案都只是在重复采样噪声。所以我后来给自己定了一条死规矩:开始训练之前,先写下停止条件,训练过程中不临时改,除非出现明显的 bug 或数据问题。

2. 止损判断指标:别只盯着一行 loss 曲线

很多微调新手有一个致命习惯:只盯训练 loss。看着 loss 还在下降就觉得训练"还有效",结果跑到最后验证集指标一塌糊涂。实际上,loss 只是模型优化的代理指标,不是最终目标,你真正该盯的,是任务本身的评估指标,以及它和训练 loss 之间的相对关系。

2.1 任务指标才是最该盯的指标

我在做文本分类的模拟项目 X 时,用的是 F1 值作为核心指标。当时发现一个很有意思的现象:第 7 轮结束时验证 loss 最低,但如果以 F1 值来选点,最佳位置在第 5 轮和第 9 轮附近,7 轮附近的 F1 反而不是最高的。这说明 loss 和任务指标之间不是简单的正相关关系——loss 是从概率分布角度衡量误差,而 F1 是离散预测结果上的加权平均,两者优化的目标不完全一致。

不同任务要选不同的指标。分类问题看准确率、F1、AUC;序列生成任务看 BLEU、ROUGE;回归问题看 MAE、RMSE;检索任务看 Recall@K。你需要在训练之前就把主指标定下来,并且写在训练脚本的配置里,而不是训练中途才开始想"到底用哪个指标来决定停不停"。这样做的另一个好处是:当指标在验证集上达到某个阈值时,训练脚本可以帮助你自动触发保存和停止逻辑,不用靠人工盯着看。

2.2 训练损失和验证损失的喇叭口形态

过拟合的开始信号,在曲线图上有一个非常典型的形态:训练 loss 一直往下降,而验证 loss 在某个点到达谷底之后开始反弹,两条曲线拉开距离,形成一个喇叭口形状。这个喇叭口张开的起点,就是你该认真考虑停止的时刻。

有人会问,为什么不直接取验证 loss 最低的那一轮?道理很简单:验证 loss 的估计本身有噪声,尤其是验证集样本量不大时,单轮的 loss 波动可能掩盖真实趋势。所以更稳妥的做法是看连续多轮的表现:如果验证 loss 已经连续 2 到 3 轮没有创新低,同时训练 loss 还在稳定下降,就应该把"可能的停点"锁定在之前验证表现最好的那一轮。这背后的直觉可以用一个生活化的类比来理解:学生平时做练习题越来越顺(训练 loss 下降),但一上考场(验证集)成绩就不再提高了,说明他在背题,而不是在理解知识。背题背得再熟练,遇到新题目还是会露馅。

2.3 给"停"设一个量化标准:patience 与 min_delta

有了指标之后,还要把"停"这件事量化成参数,最常见的两个参数是 patience 和 min_delta。patience 表示"连续多少个评估周期没有改善就停止训练",min_delta 表示"指标提升多少才算真正改善"。它们组合起来就是在说:你最多容忍验证指标原地踏步多少次。

我实际用的取值思路是这样的:如果微调的是中等规模的预训练模型、数据集在几万条以内,patience 一般给 3 到 5;如果验证集本身波动很大,patience 可以放宽到 5 到 7,但不要更大了,否则前面几个改善周期带来的收益会被后面平台期的算力消耗吃掉。min_delta 的设置则需要结合任务指标的自然波动范围,比如 F1 值日波 0.5%,那 min_delta 就应该设成 0.1% 或者 0.2%,不要设成 0.0001%,否则任何一点噪声波动都会被当成"改善",patience 就失去了意义。

这里也顺手贴一个我常用的早停逻辑伪代码,代码本身不复杂,关键是里面的参数要在训练前定好:

class EarlyStopping: def __init__(self, patience=3, min_delta=0.001, mode="max"): self.patience = patience self.min_delta = min_delta self.mode = mode # max 表示指标越大越好 self.best_score = None self.counter = 0 def __call__(self, current_score): if self.best_score is None: self.best_score = current_score return False if self.mode == "max": improvement = current_score - self.best_score else: improvement = self.best_score - current_score if improvement > self.min_delta: self.best_score = current_score self.counter = 0 else: self.counter += 1 return self.counter >= self.patience

这套逻辑直接放到训练循环里就能用,省去人工盯着曲线的精力。

3. 止损的执行机制:从"凭感觉"到"按规矩走"

比起"知道该停",更难的是"真的停得下手"。情绪上大家都想再试一次,所以止损不能依赖意志力,而是靠机制。我现在的做法是:训练还没开始,就把退出机制写死在脚本里,所有中止和保存动作由代码自动完成。

3.1 训练开始前先定好退出策略

很多人的训练脚本是"裸奔"的——只写了一个循环,跑完设定的总轮数就结束,中途完全靠人眼观察来决定要不要提前停。这样做的最大问题在于,人的注意力不可能每分每秒都在,等你发现验证指标已经开始走低的时候,模型可能已经过拟合好几个 epoch 了。

正确的做法是,在训练循环的最外层套上早停机制,并且同时满足以下三个条件才保存模型:第一,当前 epoch 的验证指标优于历史最优;第二,当前指标和最优指标之间的提升幅度大于 min_delta;第三,还没触发 patience 上限。这样保存下来的 checkpoint 一定是你见过的表现最好的参数,而不是最后一个 epoch 的参数。我之前在一个图像分类任务里吃过亏,训练脚本没有早停逻辑,跑到最后一个 epoch 保存了模型,结果那波的验证 acc 比 5 轮前低了 2.3 个百分点,白白用了一版差模型去跑后期实验。

3.2 监控面板记什么:一个可落地的记录模板

"停止时刻"的判断依据不只是指标曲线,还要结合训练行为本身。我建议每个微调任务都建一张运行记录表,至少包含这些字段:

字段说明示例
epoch当前训练轮数7
train_loss训练集平均损失0.3215
val_loss验证集损失0.4120
val_metric任务主指标F1 = 0.8623
lr当前学习率2e-5
time_cost当前轮耗时38min
remark异常记录、判断备注验证集 F1 突然掉 1%

这张表建议用文本日志的方式输出,每结束一个 epoch 就追加一行,同时在终端打印关键值。不用搞太复杂的仪表盘,一个 CSV 文件就够了。如果你是每次跑完才看一次数据的人,那相当于错过了止损时机,因为止损决策需要实时可见。我自己的习惯是写一个简单脚本,每次训练完自动把这行记录追加到 CSV 里,最后用几行代码画出验证指标的趋势线,一眼就能看出来哪一轮是顶点。

3.3 平台期到底怎么办:降学习率重启还是直接停?

平台期是微调里最容易让人纠结的时刻:验证指标连续四五轮不涨,训练 loss 也趋于平滑,这时候是该继续等,还是换个学习率再来?我的经验是分两种情况看。如果训练 loss 本身也已经基本不降了,说明模型容量已经被充分利用,继续跑大概率只是在浪费时间,直接停;如果训练 loss 还在缓慢下降,只是验证指标不涨,那说明有欠拟合到过拟合之间的过渡空间,可以尝试加载历史最优 checkpoint,把学习率调低一个数量级,比如从 2e-5 降到 2e-6,再跑 2 到 3 轮观察。

但这里有一条非常重要的止损铁律:重启的机会只有一次,并且要在训练开始前就写在方案里。为什么?因为"降学习率重启"本质上是一个新的小训练任务,它同样有自己过拟合的风险。如果你允许自己无限制重启,那整个微调过程就会变成一个无限调参的循环,这恰恰是止损机制要避免的。我见过一个同事,本来一个大模型微调任务最多跑 20 轮就该结束,结果他反复尝试不同学习率和预热策略,硬是跑了 60 多轮,最终指标只比第 18 轮的最优版本高了 0.2%,但算力消耗翻了三倍。

4. 踩坑记录与恢复技巧

止损这个动作听起来简单,但实际操作中坑非常多。下面这几条都是我在真实项目中踩过或近距离观察过的,每一条都值得你记下来。

4.1 验证集噪声带来的假信号

验证集的指标估计是有噪声的,尤其是验证集样本量只有几百条时,F1 值在相邻 epoch 之间波动超过 1 个百分点都很正常。这意味着你可能把噪声当成真实的提升,或者把噪声当成真实的下降,两种情况都会误导止损决策。

我处理这个问题的办法是:当某轮验证指标提升幅度小于验证集自身噪声区间时,宁可认为它没有提升。举个例子,验证集有 800 条样本,二分类任务下 F1 的噪声区间大概在 0.8% 左右,如果某轮 F1 从 0.870 变成 0.876,我就不认为这是真正的改善,而是把它当作物动处理。另外,为了降低噪声,可以每次评估时随机采样多个 batch 求平均,或者干脆用 k 折交叉验证中的一折作为评估集,尽量把验证集规模做大一点。如果验证集太小又没法扩大,可以把验证指标平滑化,比如取最后三轮的移动平均,用平滑后的值来判断是否触发早停。

4.2 最佳 checkpoint 的保存与恢复

止损的前提是你保存了足够好的 checkpoint,但很多人在保存和恢复细节上踩坑。第一个坑是只保存了模型权重,没有保存优化器状态。这在停止训练后直接做推理没问题,但如果后续想从最佳 checkpoint 继续调整学习率跑几轮,没有优化器状态的话,学习率调度器和动量信息就没了,相当于从"半路"变成了"重新开始",效果会打折扣。第二个坑是恢复时盲目加载旧的优化器状态——如果你已经决定降学习率重启,优化器里积攒的历史梯度动量很可能不符合新的学习率,反而会在前几步产生剧烈震荡。我现在的做法是:保存 checkpoint 时同时保存模型权重、优化器状态、当前 epoch 和最佳指标这几个字段;重启时,模型权重一定加载,优化器状态默认不加载,除非只是完全复现上次训练中断场景。

还有一个容易忽略的点:如果训练时用了混合精度或梯度累积,恢复训练时一定要确认相关状态也被正确恢复,不然训练行为会发生微妙的变化,指标会在几轮内和上次测试时对不上。

4.3 成本视角:止损不是认输,是预算管理

止损决策本质上是一道成本题。假设你微调一个中等规模的模型,单次训练 5 小时能达到验证集 F1 的峰值,往后每多跑 5 轮,耗时增加 1.5 小时,可能换来 0.1 个百分点的提升。如果你的业务场景里,0.1 个百分点对应的是被大量噪声掩盖的收益,那这笔交易显然不划算。

用数字说话:有一回我做某跨平台系统的语义匹配模块,单卡训练一小时成本约 12 元,每轮约 40 分钟。本来第 12 轮就到最佳点了,我硬是跑到了第 20 轮才停,多花了 320 元,换来的指标提升只有 0.11%,而且这 0.11% 在后续验证中还没稳定复现。后来我把每轮训练的时间成本和指标收益都记录在案,再遇到类似的判断时,我会先问自己一句:这个提升幅度值不值得我多花这些钱和时间?如果答案是模棱两可,那就按原计划停。止损不是认输,是你把预算花在更有意义的事情上。

4.4 建立自己的"停止时钟":让经验可复用

微调做多了你会发现,类似的数据规模、模型底座和任务类型,最佳停止轮数通常落在一个相对固定的区间里。比如某类文本分类任务,数据量 5 万条,微调某个 base 规模的预训练模型,最佳点大概在第 3 到第 6 轮之间;数据量缩减到 5000 条,最佳点会提前到第 2 到第 3 轮。这些经验积累起来之后,你其实不需要等验证曲线走完就能预判大概的停点,可以提前把训练预算和早停参数设得更激进一些,省下一大笔试错成本。

我自己的做法是维护一个简单的训练记录表,每条记录包含数据规模、模型规模、任务类型、最佳 epoch、最佳指标、训练时长和备注。刚开始做微调的人也可以从这一步做起,不用太复杂,一个表格就行。积累十来个项目之后,你再遇到新的微调任务,打开记录表一对比,心里马上就有数:这次大概跑到第几轮就该盯紧了,几轮不涨就该停。

最后再分享一个小习惯:不只是"停了"就万事大吉,我会在停止训练之后额外做一件事——用最优 checkpoint 在留出的测试集上重新评估一遍,确认它的真实表现和验证集记录一致。这个过程看起来多花了几分钟,但能避免很多"验证集看着挺好、测试集惨不忍睹"的尴尬。微调这件事,真正的高手不是把模型调到极致,而是懂得在收益归零之前体面收手,把省下来的时间和算力投入到下一轮更有价值的实验里。

相关新闻

如何用Llama-3.2-3B-Instruct-FP8-Block实现128K超长上下文?RoPE 32倍缩放配置全解析

如何用Llama-3.2-3B-Instruct-FP8-Block实现128K超长上下文?RoPE 32倍缩放配置全解析

【免费下载链接】Llama-3.2-3B-Instruct-FP8-Block 项目地址: https://ai.gitcode.com/hf_mirrors/unsloth/Llama-3.2-3B-Instruct-FP8-Block 点击查看 免费下载 想让小模型一次读完一本长文档?Meta 官方 Llama-3.2-3B-Instruct 本身原生上下文只有 8K&…

2026/10/20 2:28:31 阅读更多 →
Windows 11 睡眠、休眠与电源设置如何调:10 分钟上手的实用指南

Windows 11 睡眠、休眠与电源设置如何调:10 分钟上手的实用指南

Windows 11 睡眠、休眠与电源设置如何调:10 分钟上手的实用指南 【免费下载链接】windows11 🌎 Windows 11 Settings, Tweaks, Scripts 项目地址: https://gitcode.com/GitHub_Trending/wi/windows11 Windows 11 的睡眠、休眠和电源计划没配对&am…

2026/10/20 2:27:30 阅读更多 →
C#单点登录SSO实战:.NET 6 + IdentityServer4最小可运行示例

C#单点登录SSO实战:.NET 6 + IdentityServer4最小可运行示例

简介:本资源是一个基于C#的单点登录(SSO)完整示例程序,面向.NET开发者、企业级应用架构学习者及身份认证系统实践者,聚焦解决多子站点间用户身份统一认证与会话共享问题。项目采用ASP.NET Web Forms技术栈,…

2026/10/20 2:27:30 阅读更多 →

最新新闻

5分钟粒度时间序列预测:ARIMA全流程实战与坑点解析

5分钟粒度时间序列预测:ARIMA全流程实战与坑点解析

数据准备:5分钟数据的“脏活累活” 2.1 采集与落库,先解决有没有的问题 2.2 缺失值处理,别让“空洞”骗了模型 2.3 异常值甄别,业务噪声与真实波动的边界 2.4 重采样与对齐,把时间轴捋直了 数据是一切时序建模的地…

2026/10/20 16:43:46 阅读更多 →
降AIGC软件横评:9类工具原理、避坑与实操流程

降AIGC软件横评:9类工具原理、避坑与实操流程

最近这段时间,被问得最多的问题就是“到底有没有靠谱的降AIGC软件”。经常是头像一换,那边甩过一张截图,问“这种标红要怎么办”。尤其专科生群体,课程报告、实训总结、毕业设计说明一摊开,全是AI生成常见句式&#xf…

2026/10/20 16:43:46 阅读更多 →
Apache Pulsar 2.9.1 部署实战:从解压到集群调优的完整指南

Apache Pulsar 2.9.1 部署实战:从解压到集群调优的完整指南

简介:Apache Pulsar 2.9.1 的二进制发行包,面向需要搭建高吞吐消息队列与实时流处理管道的后端开发、架构师和云原生运维人员,解决分布式消息中间件选型与自建集群时的环境前置问题。压缩包约 321.53MB,为 tar.gz 格式&#xff0c…

2026/10/20 16:43:46 阅读更多 →
AI Agent任务规划、状态管理与长任务恢复:从原理到最小实现

AI Agent任务规划、状态管理与长任务恢复:从原理到最小实现

1. 从“能聊天”到“能干活”:任务规划到底在解决什么问题 很多人第一次接触 AI Agent,脑子里想的还是“更聪明的聊天机器人”。但真正做过 Agent 项目的人都知道,聊天只是最表层的能力,真正决定一个 Agent 能不能落地干活的&…

2026/10/20 16:43:46 阅读更多 →
Python AI编程入门指南:机器学习、深度学习、NLP与强化学习实战

Python AI编程入门指南:机器学习、深度学习、NLP与强化学习实战

1. 从零到一:为什么我建议你用Python切入AI编程很多人第一次接触AI编程,脑子里冒出来的第一个问题不是“怎么学”,而是“从哪开始”。我见过太多人抱着厚厚的数学书啃了三个月,结果连一行能跑的代码都没写出来,最后热情…

2026/10/20 16:43:46 阅读更多 →
医学图像处理代码实战:从DICOM读取到三维重建与分割

医学图像处理代码实战:从DICOM读取到三维重建与分割

前一阵有个刚转行做医学影像算法的朋友来找我,说他从某医院那边拿到了一批脱敏后的CT数据,文件夹里装着一堆后缀为 .dcm 的文件。他第一反应是像处理普通照片一样用 OpenCV 直接读,结果 cv2.imread 返回一大片乱码。这个场景我太熟悉了&#…

2026/10/20 16:42:44 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* 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 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* 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 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* 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 1:01:30 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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 阅读更多 →