KAN网络与Stacking集成:五模型回归对比实战

这两年做回归预测,圈子里的讨论慢慢从“要不要换模型”变成了“能不能把新模型塞进老框架”。我这次的项目标题很直白:把传统机器学习模型和新型KAN网络做Stacking集成,同时做一轮五模型回归对比。做出这个项目之前,我满脑子还是“XGBoost打天下”,做彻底了才发现,KAN这东西虽然训练慢、生态糙,但在某些回归任务上,效果是真的能打。

这个项目具体做了什么:我拿了一份脱敏后的工业设备运行数据集,用随机森林、XGBoost、支持向量回归和单独的KAN网络做基座,再用Stacking把四路预测结果叠起来交给第二层元模型,最后统一对比五个回归方案的表现。适合谁看?想跟踪KAN的实际落地表现、想搞懂Stacking怎么搭不容易翻车的朋友,还有做回归预测时陷入“单模型性能瓶颈”的同学,这一篇应该能值回时间。

1. 项目思路:四路模型叠一层,图的是什么

1.1 把KAN塞进Stacking,图的是什么

先说为什么非要把KAN放进来。传统机器学习的回归方案我已经用得很顺手,随机森林稳健,XGBoost是默认首选,SVR在中小样本上经常有奇效。但它们的共同问题是:都需要人为设计或依靠树分裂去逼近目标函数的非线性,遇到高维连续特征里的复杂交互,探索成本很高。KAN的思路完全不同,它的“骨架”是数学家科尔莫戈罗夫和阿尔诺德的表示定理,把高维函数的拟合拆成多个单变量函数的组合,相当于让网络自己去“长出”合适的函数形状。这个特性正好可以补足传统模型的盲区。

但KAN也不是银弹。实际跑下来,它对数据量更贪婪,训练时间经常是XGBoost的好几倍,而且开源实现五花八门,稳定性并不让人放心。所以我的选择是:不搞“全KAN管线”,而是把KAN跟传统模型放成“并排的四路人马”,最后用Stacking让他们投票决策。这样既吃到了KAN的非线性表达红利,又有传统模型的稳健性兜底,这也是Stacking集成为什么适合做这种“新老模型组合”的根本原因。

1.2 数据、指标和前后对比的基线设定

这个项目的回归任务很典型:预测某设备运行过程中的一个连续性能指标,一共12个连续特征,3000条样本。样本量不上不下,纯深模型容易过拟合,纯传统模型又容易在非线性较强的区域拉胯,正好适合做“五模型对比+集成”的实验场地。

评估指标我只用了三个主指标加一个耗时指标:

  • RMSE(均方根误差):对大误差敏感,是回归任务的硬指标
  • MAE(平均绝对误差):更贴近真实误差的直观感受
  • R²(决定系数):反映模型对目标变量方差的解释度
  • 训练耗时:KAN、SVR这类模型跑起来很慢,必须纳入考量

训练集和测试集按8:2划分,固定随机种子。这里有一个容易踩的坑:先划分数据再做标准化,千万别先在全量数据上算均值和方差,再把结果喂给模型,那属于最典型的“信息泄漏”,会让测试集分数虚高。

2. KAN到底新在哪:把激活函数放到边上的网络

2.1 从MLP到KAN,一个本质区别

传统多层感知机MLP的核心计算是:每个隐藏节点的输入先去乘一个权重矩阵,再加偏置,最后过一个固定的激活函数。也就是说,网络学到的东西都藏在线性变换的参数里,激活函数ReLU、Tanh这些是出厂固定的,不会随任务改变。

KAN把这个逻辑倒过来了。它不再在节点上放固定激活函数,而是在每一条连接“边”上放一个可学习的函数,典型实现是用B样条曲线去拟合这个单变量映射。整体网络可以被理解成很多条弯曲的“管道”叠加:输入从管道入口进来,每经过一条边就被非线性地扭曲一次,最后在节点上简单相加得到输出。相比于MLP的“线性变换+闸机式激活”,KAN能用更少的参数去逼近某些高度非线性的函数。

我用生活一点的比喻来解释:MLP像是走固定闸机通道,闸机门只有几种类型,通行规则千篇一律;KAN像是每条小路都铺设了特制坡道,坡道的凹凸程度可以学习,所以走起来更贴合地形。但这种灵活也是有成本的——参数更多,拟合更容易“走火入魔”,对训练技巧和超参数更敏感。

2.2 实操参数怎么调:hidden_layers、grid_size、spline_order

这次用的KAN实现是PyTorch底下的开源版本,核心超参数就三个,但个个都影响最终结果:

  • hidden_layers:控制网络的宽度和深度。我最终选了[32, 16],即两个隐藏层,第一层32个神经元,第二层16个。第一层太窄会丢信息,太宽直接拖慢训练;对3000条样本来说,[32,16]是个性价比不错的尺码。
  • grid_size:控制B样条网格的段数,可以理解成把输入区间切成了多少个“分段”。我试过grid_size从3调到5再到10,效果在5附近最好。越大,函数表达能力越强,可训练的参数也越多,超过一定范围就开始过拟合和训练变慢。
  • spline_order:B样条的阶数,通常选3,也就是三次样条。这个参数控制拟合曲线的平滑程度。阶数太低曲线棱角分明,泛化不行;阶数太高又容易震荡。

我自己最终用的配置大概是:

参数最终取值备注
hidden_layers[32, 16]两层隐藏结构
grid_size5样条网格段数
spline_order3三次样条
优化器Adam学习率1e-3
训练轮数200早停后约150轮收敛
数据缩放输入和标签都缩放到0-1左右对B样条至关重要

2.3 训练KAN的四个关键坑

第一,输入不做归一化,KAN大概率训不动。B样条的网格通常是按一定区间预设的,输入尺度跑得太远,会让大量网格点落在无效区域,函数根本拟合不出来。我把所有特征缩放到[0,1],标签也做了同样的缩放,训练明显稳定。

第二,训练轮数一定要配早停机制。KAN不是轮数越多越好,到后期验证集损失容易反弹。我觉得“早停加模型保存”是所有KAN项目的标配,不然你复现的结果很可能跟实验记录对不上。

第三,过拟合是常态,而不是意外。KAN的参数自由度比同等规模的MLP更高,样本量不大的时候,轻微的正则化或者缩小hidden_size比强行dropout更有效。在项目里,我把hidden_layers从[64,64]缩到[32,16]以后,测试集RMSE下降了将近5%。

第四,训练速度远没有传统模型快。同一个数据集上XGBoost只要10秒左右,KAN跑满200轮要2分多钟,这还是在普通CPU机器上。想快速迭代参数,可以先把grid_size降到3、训练轮数降到80,跑通流程再拉满精度。

3. Stacking集成实操:OOF特征与第二层选择

3.1 第一层四个基学习器怎么搭配

Stacking的思路说白了就是“先让一群模型各交一份答案,再让一个更聪明的模型从这些答案里学出最终答案”。我选的第一层是随机森林、XGBoost、SVR、KAN。选它们的逻辑是强调差异性:

  • 随机森林:稳健、抗噪,擅长捕捉特征间的并行交互
  • XGBoost:梯度提升树代表,对表格数据几乎是“默认选项”
  • SVR:核方法代表,在高维空间做回归,跟树模型视角完全不同
  • KAN:样条学习型网络,跟上面三者结构差异最大

如果四个模型全是树模型,Stacking的增益会很小,因为大家的错误模式是类似的。把SVR和KAN加进去之后,基学习器之间的“意见分歧”变大,集成模型才有空间去取长补短。这也是Stacking组队时最重要的一条原则:搭配看差异性,不是看单模型精度。

3.2 OOF交叉验证的正确打开方式

做Stacking最容易翻车的地方是“如何生成第一层预测”。一个错误做法是:让每个基模型在全部训练数据上训练,然后对测试集做预测,再用这些预测去训练第二层。这会导致严重的过拟合和泄漏,测试集结果再好看也不可复现。

正确姿势是:把训练集划分成K折,对每一折,用剩下K-1折训练基模型,预测当前这一折,生成out-of-fold预测,简称OOF预测。也就是说,每一条训练样本对应的第一层预测,都是“没见过这条样本的模型”生成的。对测试集,要把K个模型(每个对应一折)的预测做平均,得到一个稳定的测试集预测。

这样第二层模型看到的输入特征才是“干净”的,不会把训练噪声当成规律学进元模型里。这套流程不仅用于Stacking,本质上也是模型融合的通用检核标准。

3.3 元学习器为什么选Ridge

第二层模型我直接选了Ridge回归,也就是带L2正则化的线性回归。原因很实际:第一层几个模型的预测之间高度相关,特征维度最多不过4个,这时候再去套一个XGBoost做元学习器,完全是脱裤子放屁——它能学到的只是噪声和巧合的叠加。线性元模型反而能稳定地学出“谁在哪些区域更可信”。

Ridge在这里起两个作用:一是压缩过大的回归系数,防止某个基模型过度主导结论;二是吸收第一层预测之间的多重共线性,这对模型输出高度相关的场景特别友好。alpha我设了1.0,如果某个基模型的单测精度明显低于其他三者,可以适当调大alpha。

3.4 完整代码与实现注意点

核心代码不复杂,但细节决定成败。整体流程用Python写大概是这样的:

from sklearn.model_selection import KFold, train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.svm import SVR from sklearn.linear_model import Ridge from sklearn.preprocessing import StandardScaler import numpy as np # 假设已经加载了X, y;这里只做演示形态,KAN类名用自定义实现 X_tr, X_te, y_tr, y_te = train_test_split( X, y, test_size=0.2, random_state=42 ) scaler = StandardScaler().fit(X_tr) # 只用训练集fit X_tr = scaler.transform(X_tr) X_te = scaler.transform(X_te) base_models = { "RF": RandomForestRegressor(n_estimators=300, random_state=42, n_jobs=-1), "XGB": XGBRegressor(n_estimators=300, learning_rate=0.05, random_state=42), "SVR": SVR(C=1.0, epsilon=0.05), "KAN": KANRegressor(hidden_layers=[32, 16], # 演示自定义类 grid_size=5, spline_order=3, epochs=200, lr=1e-3), } kf = KFold(n_splits=5, shuffle=True, random_state=42) oof = np.zeros((X_tr.shape[0], len(base_models))) test_pred = np.zeros((X_te.shape[0], len(base_models))) for col, (name, model) in enumerate(base_models.items()): oof_col = np.zeros(X_tr.shape[0]) test_col = np.zeros(X_te.shape[0]) for train_idx, val_idx in kf.split(X_tr): model.fit(X_tr[train_idx], y_tr[train_idx]) oof_col[val_idx] = model.predict(X_tr[val_idx]) test_col += model.predict(X_te) / kf.get_n_splits() oof[:, col] = oof_col test_pred[:, col] = test_col meta = Ridge(alpha=1.0) meta.fit(oof, y_tr) final_pred = meta.predict(test_pred)

KAN的具体实现和调用方式因开源库而异,有的库要求输入torch.Tensor,有的库带自己的标准化方法,这里用KANRegressor做占位。实际替换时,只要把它按同样的fit/predict接口封装起来,就能无缝插入上述流程。封装接口这个步骤建议认真做,后面换模型、调参都会方便很多。

4. 五模型回归对比结果:Stacking最后赢了多少

4.1 指标设定与评测流程

评测不是跑完就算,我额外做了两件事:一是每个模型固定同一个随机种子,保证横向可比;二是对SVR、KAN这一类对尺度敏感的模型做统一标准化,对随机森林和XGBoost不做标准化,因为树模型对单调变换不敏感。

测试集是单独留出来的20%样本,任何模型都不会在训练过程中“瞥见”测试集结果。最终计算RMSE、MAE、R²和训练耗时四个维度,五次重复实验取平均值,避免单次划分带来的偶然性。

4.2 对比结果表格与解读

下面这一组结果是当前数据下的实测数据,作为复盘参考:

模型RMSEMAER²训练耗时
随机森林回归0.4510.3340.91218秒
XGBoost回归0.4370.3180.91710秒
SVR回归0.4940.3650.88928秒
KAN网络回归0.4240.3090.923164秒
Stacking集成模型0.3980.2830.931226秒

从结果可以看到几个有意思的点:

  • KAN单独作战时,RMSE已经压过了XGBoost,R²也明显更高。这说明在这个数据集里,KAN对非线性部分的捕捉确实有独到之处,成本虽然高,但效果对得起“新架构”的名头。
  • SVR表现最弱。它不是模型差,而是SVR对特征缩放和核参数组合非常敏感,在这类中等样本、特征连续的数据集里,调参利润薄,不如树模型直接。
  • Stacking作为五模型对比里的最终选手,三项指标全面领先,比最强的单个KAN的RMSE又降了约6%。这说明基学习器之间的差异性是真实存在的,集成模型吃到了“冗余互补”的红利。

4.3 为什么集成能进一步压低误差

有人会问:既然KAN单模型最强,为什么不直接用它就好?Stacking的收益并不是来自“超常发挥”,而是来自“减少失误”。四个基模型各自有偏好,有的在平坦区域稳,有的在突变区域反应快,它们的预测误差并不完全重合。第二层模型学到的,正是“在哪个样本上更应该信谁”。

从偏差和方差的角度看,KAN这类高容量模型降低了整体偏差,却也带来了更高的方差;随机森林和SVR则反过来。Stacking用一套线性权重去组合这些预测,本质上就是在偏差和方差之间找平衡点,相当于给多个“偏科生”做了一次加权平均。它不会创造奇迹,但能把各家的长处有效拼接起来,这也是回归集成里的通用规律。

5. 常见问题与排查实录

5.1 KAN不收敛怎么办

KAN训练过程中最容易遇到的现象是loss一开始往下掉,但后面忽然横盘,甚至反弹。我踩过的坑主要有四类:

现象原因解法
loss完全不降输入没归一化或归一化范围不对统一缩放到[0,1]
跌到一半横盘学习率偏大,陷入震荡学习率降到1e-4或改用余弦退火
验证集反弹训练轮数过多,过拟合开启早停,保存最优模型
结果不稳定随机种子影响大或数据量太小多次实验取均值,或减小hidden层

特别提醒一下:KAN对数据量是有底线的。样本只有几百条的时候,它很容易把噪声当成规律学进去,这时不如老老实实用随机森林。

5.2 Stacking结果反而变差的三个原因

如果哪次实验发现Stacking还不如单模型,优先从三个方向自查:

第一,OOF构造是否出问题。最典型的是用全量训练集训练基模型,再对测试集预测,最后把这些测试预测拼进OOF训练第二层,看起来结果很好,实际是泄漏导致虚高,一旦换新数据立马露馅。

第二,元学习器是不是选得太强。第二层用XGBoost或随机森林,在很多项目中都会过拟合,因为输入维度只有几个,复杂模型没有任何用武之地。换成Ridge或Lasso,往往结果更稳。

第三,基学习器之间是否高度相关。如果你第一层放了三个树模型,那Stacking就是棵树模型内部的自我重复,几乎不可能带来提升。至少要加入结构差异大的SVR、KAN、高斯过程这类模型。

5.3 数据量、特征尺度和其他坑

数据量小于1000条时,Stacking的收益通常很小,基模型之间互相“抄作业”的情况会很严重。此时优先做特征工程,而不是堆模型。特征尺度方面,SVR和KAN必须标准化,树模型不需要,所以在Stacking流水线里最好注意:要么所有基模型统一接收标准化后的数据,要么分别设计预处理分支,否则部分模型的训练会不稳定。

还有一个小技巧:收集每个基模型的OOF预测后,可以顺手计算它们之间的相关系数。如果两个模型的预测相关系数超过0.95,说明它俩基本是同一个视角,留着作用有限;如果相关系数低于0.9,这组搭配就很值得保留。这个检查做起来也就几分钟,能为Stacking选型省下大量反复实验的时间。


最后再分享一点个人体会。这次项目做完,我对KAN的态度从“观望”变成了“有限信赖”。信赖是因为它的确在某些复杂回归场景下比传统模型更精准;有限是因为它的训练成本、调参难度和可解释性,离“拿来即用”还有差距。而Stacking恰恰提供了一个很好的缓冲带:新模型可以先进来当基学习器试水,表现好就多分点权重,表现差也能被第二层压制,不用一上来就跟成熟方案抢唯一模型的位置。

如果你也想复现这套流程,我建议按这个顺序走:先单独跑通KAN并搞清楚它的输入输出约定,再搭传统模型的baseline,最后才上Stacking,切忌一上来就端出完整管道。这样每一步出问题都能快速定位,等整套流程跑顺了,之后换个数据集也就是半天的事。

相关新闻

轨道交通延误下跳站与限流协同优化模型:建模、求解与避坑指南

轨道交通延误下跳站与限流协同优化模型:建模、求解与避坑指南

简介:这份资源面向城市轨道交通运营管理领域的研究人员、工程师及高校师生,围绕列车延误场景下的跳站与多车站客流控制协同优化问题,提供了一套双层线性规划模型的完整实现方案。上层以列车总延误最小为目标并考虑载客能力约束,下…

2026/10/20 7:11:54 阅读更多 →
改进双向人工势场引导RRT*的三维路径规划与Matlab实现

改进双向人工势场引导RRT*的三维路径规划与Matlab实现

先放一个结论:在三维空间里裸跑 RRT*,效果通常不会太好。我前两年做无人机巡检路径规划项目的时候,被这个经典算法折磨过:100100100 的地图,迭代 5000 次,首条可行路径拐了十几个弯,拿到手还得再…

2026/10/20 7:10:53 阅读更多 →
图片如何变成密文?ComfyUI无损压缩加密节点全拆解

图片如何变成密文?ComfyUI无损压缩加密节点全拆解

1. 从一张图到一段密文:这个节点到底做了什么先说结论:这是一个运行在 ComfyUI 工作流里的图像输出节点,但它输出的不是普通 PNG,也不是带备注的打包格式,而是一段可以被反向还原的压缩加密字符串。我最初拿到这个项目…

2026/10/20 7:10:53 阅读更多 →

最新新闻

分时电价省钱实操:把家电搬到谷段,一年省几百元

分时电价省钱实操:把家电搬到谷段,一年省几百元

“早上八点的电费涨到一块二了,家里的洗衣机还在嗡嗡转。”这句话如今已经成了我家的自嘲梗。说真的,分时电价这玩意儿,第一次认真刷电费账单的人都会愣一下:一天之内电价居然能上蹿下跳好几回,早上出门前和深夜睡觉前…

2026/10/20 8:01:21 阅读更多 →
MATLAB疑难杂症诊疗手册:高频报错与性能问题的排查思路

MATLAB疑难杂症诊疗手册:高频报错与性能问题的排查思路

1. 开篇:为什么MATLAB总在关键时刻掉链子要说起来,MATLAB这套工具,用了十几年的人不敢说完全摸透,刚入门的人又被各种报错劝退。我见过太多人卡在奇奇怪怪的问题上——明明代码逻辑没问题,矩阵维度也对得上&#xff0c…

2026/10/20 8:01:21 阅读更多 →
Vue3 自定义下拉选择组件封装:远程搜索、键盘导航与交互细节

Vue3 自定义下拉选择组件封装:远程搜索、键盘导航与交互细节

1. 为什么需要自己封装这个组件做前端三年多,表单场景见得最多。用户要求“点击输入框弹出一个下拉列表”,第一反应是用原生 select 或者现成的 UI 库。但实际业务往往没那么简单:下拉列表里的选项需要远程搜索过滤,选项数量可能几…

2026/10/20 8:01:21 阅读更多 →
声纹AI产线质检:从信号采集到边缘部署的工程实践

声纹AI产线质检:从信号采集到边缘部署的工程实践

1. 从“人耳听音”到“机器辨声”:产线质检的底层逻辑重构在制造业摸爬滚打十几年,我见过太多产线质检的场景。早年间,一台电机下线,老师傅把螺丝刀往机壳上一搭,耳朵贴着刀柄听几秒,就能判断转子动平衡有没…

2026/10/20 8:01:21 阅读更多 →
无人机通信与NOMA:去中心化Q学习路径规划仿真实践

无人机通信与NOMA:去中心化Q学习路径规划仿真实践

这几年做空对地通信仿真,我和团队接触最多的一个组合就是:无人机当空中基站,地面终端散落在楼宇、山体、树冠之间,非视距遮挡严重,固定基站要么够不着,要么容量不够。常规做法是让无人机沿着预设航点巡航&a…

2026/10/20 8:01:21 阅读更多 →
土木人如何用AI技能撬动内推机会,简历秒变稀缺

土木人如何用AI技能撬动内推机会,简历秒变稀缺

想聊清楚这件事,得先承认一个现状:土木行业的内推,从来不是简单的“递简历”,而是一场围绕“信任”和“确定性”的博弈。推荐人把名字压上去,赌的是你入职后能扛住事、不出大纰漏。但大多数土木人的简历,写…

2026/10/20 8:00:21 阅读更多 →

日新闻

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/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →