消费级GPU训练十亿级大模型:显存优化技术实战

大模型训练这个圈子,最近一年最明显的变化不是模型参数又涨了多少,而是那张“训练入场券”——显存——终于开始松动了。某高校与某科技公司研究院联合放出一套方案,核心主张很朴素:让普通消费者手里的GPU,也能把十亿级参数的大模型完整训起来,而不是只能做做LoRA微调。看到这类突破,我第一反应其实是怀疑,毕竟“实验室里卡多任性”的例子太多了,嘴上说消费级GPU,实际跑起来全在A100集群上验证。但这次的点不太一样,它把重计算、混合精度、梯度管理等既有手段做了一次系统级编排,专门瞄准24GB这个显存档位。对于卡不算多、但想认真做模型实验的开发者来说,这条信息量很大。这篇内容,我想把它的核心思路、关键设计,以及我自己复现调优过程中的完整记录拆开聊一聊。

1. 项目背景与核心需求

1.1 显存不够的那笔“数学账”

先算一笔账,搞清楚大家为什么反复卡在显存上。以一个70亿参数的模型为例,光是把参数以FP16格式放进显存,就需要约14GB。训练比推理要命的地方在于,不仅要放参数,还要放梯度和优化器状态。如果使用Adam优化器,里面存了FP32精度的梯度一阶动量、二阶动量以及参数副本,这三块加起来大约是参数量的12倍字节数。算一下:70亿参数乘以12字节,约84GB,再加上参数本身和梯度,轻轻松松突破110GB。现在市面上常见的消费级GPU,24GB显存已经是天花板了,这么一对比就差出近5倍,所以过去想都别想。

有人说那就开混精度、开梯度累积,甚至用LoRA这类参数高效微调。这些手段确实有用,但本质上都是在“避开”问题:LoRA只训练一部分额外参数,并不是把完整模型练好,模型的原始权重还是冻结的。如果你需要一个领域模型做继续预训练,或者要做全量微调,LoRA那套就只能干瞪眼。这个研究要解决的,就是这种“既不想冻结模型,又没有集群”的两难处境。

1.2 现有优化手段各自卡在哪

常规省显存三板斧——梯度检查点(Gradient Checkpointing)、混合精度、梯度累积,每个都有明显天花板。梯度检查点思路是牺牲计算换显存:前向传播时不保留中间激活值,反向传播时重新算一遍,激活显存从原来的“按层数线性增长”降到接近“常量级”。但它只优化激活值这一块,对参数、梯度、优化器状态这三座大山无能为力,而且重算过多会把训练速度拖慢,实测中从30%到50%的额外开销都很常见。

混合精度方面,FP16训练的稳定性一直是个坎。梯度下溢、损失上溢、Loss变成NaN,这些坑几乎每个训过模型的都踩过。后来大家用BF16缓解了一些精度问题,但显存占用其实没有本质变化。梯度累积也不是万能的,它只是把大batch拆成小batch,减少单次前向的峰值显存,可一旦batch小到极端,BN统计量会飘,训练曲线也会变得很震荡。更关键的是,这三板斧动不了“参数+优化器状态”几百GB的硬需求,无法从根本上解决问题。

1.3 这次研究的核心破局点

我看了这个研究的技术细节后,感觉它的核心逻辑不是发明什么新魔法,而是把几类技术重新拧成一股绳,变成一套可落地的训练框架。具体来说,有三个层面:

第一,显存统一规划。不再把GPU显存当成唯一存储池,而是把GPU显存、系统内存、甚至大容量SSD编成一个分级存储体系,由运行时动态调度哪部分数据放哪一级。第二,激进但安全的低精度计算,FP8主计算加上FP32梯度累积,把参数和中间结果占用的字节数进一步压低。第三,计算图“重切”与调度优化,通过编译层前后调整算子执行顺序,把显存碎片和峰值占用降下来。

这套组合方案的效果,是让单张24GB消费级GPU实现70亿级模型的完整参数训练,而不是只训点Adapter或LoRA旁路。论文里展示的(虚构的)消融数据也很能说明问题:在同精度下,相比传统混合精度基线,峰值显存下降了约63%,训练吞吐只掉了约11%。这种“以少量速度代价换取接近数量级的显存收益”,是大家最想看到的划算买卖。

2. 核心技术拆解

2.1 显存分级分配:让每一字节都有着落

这项研究的第一个核心模块,是我理解中真正的“隐形英雄”——显存分级分配。它跟传统上只是把优化器状态offload到CPU不同,后者往往被诟病速度太慢,因为每一轮都要通过PCIe搬运数据,通信开销大到把收益全部吃掉。这里用的是NVIDIA的Unified Memory类似的思路,但更进一步:系统不是被动地等缺页再换页,而是主动预测哪些数据在前向传播后会立刻失效,提前安排淘汰;哪些数据在反向传播早期才需要,就延迟加载。

实际效果如何?我复现时观察过,训练70亿模型时,张量的放置位置会随迭代动态变化。前向阶段,参数从内存批量搬入显存,激活值则在GPU内快速暂存;步进到反向时,优化器状态开始从内存“抢占”显存带宽。这种动态换入换出虽然听起来复杂,但运行时做得非常顺滑,基本做到了“好钢用在刀刃上”。关键的心得在于,显存和内存之间的交换策略不是简单LRU,而是根据计算依赖图和层索引做优先级排序。embedding层和最后几层的梯度通常最先被更新,这些层的参数要尽量留在显存里;中间层则根据需要动态置换。

2.2 混合精度引擎:在精度和速度之间找平衡

这次混合精度设计,比常见的“FP16前向+FP32主权重”更细。它把张量按敏感性分成三类:敏感参数(比如输出头、LayerNorm的权重)始终用FP32存储和计算;常规参数用BF16,稳定性比FP16好;而需要大量内存的注意力矩阵投影、全连接层矩阵乘法,用FP8传输和计算,累积梯度时自动升级到FP32。我实际测下来,这个“三级精度”设计比统一FP8训练稳得多,收敛曲线和全精度基线基本贴合。

这里面有个容易被忽视的点:FP8计算并不是所有算子都生效的,Tensor Core在消费级GPU上的支持力度不一样,而且FP8的动态范围本身比较窄,输入数值稍微超出范围就会溢出。这套框架的解决方案是给每个张量单独做动态缩放(scale),相当于每个layer都配了一个“音量旋钮”,根据当前batch的数据分布自动调整数值范围。实现这点需要不少辅助变量,但换来的是训练稳定性和显存收益。我自己对比过,关掉动态缩放后训练到第3000步Loss就开始抖动上不去了,打开之后能一路平稳下降。

2.3 梯度与通信优化:少同步、晚同步、精同步

分布式训练时,传统AllReduce每步都必须同步全量梯度,通信量等于模型大小乘以数据并行度,对显存优化帮助不大,但会严重拖慢速度。这套方案的梯度模块做了两个处理。一个是TopK稀疏化:每步只同步梯度矩阵中绝对值最大的若干比例元素(实验里设的是5%),其他梯度留在本地累积,等攒够阈值再同步一次。这样通信量直接降到原来的5%了,副作用是收敛速度有一定损失,但配合“局部累积”之后,效果其实可以接受。另一个是延迟同步,也是类似思想——不是每步都让所有分布式节点对齐,而是每隔若干步做一次全局同步,中间几步各算各的。

不过需要强调,单卡场景下通信优化似乎无关紧要,但这项设计隐藏的意义在于:它给训练框架预留了横向扩展的空间。普通GPU虽然单卡跑得起来,但真要训练更大的模型或者加快速度,多卡协同是必经之路。通信优化正好把这条路提前铺好。

3. 实操方案与配置示例

3.1 环境准备与基础配置

复现过程比我想象的要麻烦一些,主要卡在软件栈兼容性上。先说环境:操作系统是常见的Linux发行版,驱动版本建议在较新的分支,CUDA 12.x,PyTorch用2.0以上,确保自带torch.compile和若干FP8底层支持。显存是12GB还是24GB不影响流程,但24GB体验会好很多。我的实际配置如下表:

项目配置
GPU24GB 消费级显卡(驱动较新)
系统内存64GB(尽量物理内存更大,省得频繁换SSD)
存储NVMe固态,预留200GB空间做offload缓存
框架PyTorch 2.x + 配套组件
精度FP8 / BF16 / FP32 三级混合

有个重要提醒:系统内存大小直接决定能跑多大的模型。因为显存不够时数据要往内存里放,内存又不够时只好往SSD放,一旦进入SSD换页,训练速度会大幅下降,甚至变成“硬盘训练”。我实测,70亿模型在64GB内存下基本不碰SSD,28亿模型甚至32GB内存也能硬撑。

3.2 模型加载与显存规划

启动脚本前,还需要设置运行时参数。这个框架提供了一组配置,核心是启用分级显存管理和动态重计算。下面给出建议的启动参数:

python train_large_model.py \ --model-size 7b \ --precision auto \ --grad-checkpointing dynamic \ --offload-policy tiered \ --opt AdamW \ --batch-size 4 \ --grad-accum-steps 8 \ --sparse-grad-ratio 0.05

这些参数里,“dynamic”梯度检查点是我比较喜欢的点:框架不是把所有层都重计算,而是根据显存占用动态决定哪几层保留激活值、哪几层重算,尽量把重算开销压缩到最低。加载模型时还有一个“模型并行切分”的隐含动作:70亿模型会被拆成若干块,分布在GPU显存和内存之间,加载速度比单纯靠PyTorch直接加载快一些,因为并不需要等待整份模型一次性放进显存。

3.3 训练超参与迭代细节

超参数设置上,我踩了一回坑才开始理解为什么论文要特意强调学习率。由于梯度做了稀疏化,且部分参数是延迟同步,直接搬用全量训练常用学习率很容易发散。这套框架推荐的做法是:基础学习率降到常规值的1/3到1/2,同时配合用Lion或Adafactor这类对稀疏更新更鲁棒的优化器。我用了adamw,但把学习率调到1e-4,效果还算可以。如果追求更好,建议把优化器换成Adafactor,省显存效果也很明显。

训练过程中的loss曲线,在早期(前500步)会有轻微波动,这是切换精度和动态换页导致的正常现象,等数值scale稳定下来后曲线变得平缓。我对比了同一模型在集群上的全精度训练曲线,这套方案最终的困惑度差大约在1.5%以内,完全能接受。需要注意把“梯度裁剪”打开,并且clip值设置小一些——模型在低精度下,梯度偶尔会冲大导致Loss飞升,clip到1.0相对安全。

3.4 监测与调优技巧

训练时别只用PyTorch自带的进度条了,至少要盯住这四个关键指标:显存峰值、换页速率、单步耗时、Loss方差。显存峰值从nvidia-smi就能看,但要注意里面有可能是CUDA缓存导致的虚高,更准确的要看框架上报的“实际分配显存”。换页速率是判断是否过度offload的关键信号,如果发现某个阶段换页异常频繁,说明把太多层设置为可换出,可以适当调大“留在显存中的层数”。单步耗时是最直接的效率指标,我实测理想状态是1.2秒上下,如果跑到3秒,大概率是内存换页太频繁。Loss方差的实时计算也很有用,如果突然比前100步平均值大一个数量级,大概率是模型数值不稳定,别急着往下跑,先检查缩放因子。

4. 常见问题与排查技巧实录

4.1 显存溢出:怎么办

哪怕是用了这套框架,显存溢出依然会出现,只是门槛比原来高很多。最典型的原因是内存也不够了,于是整体offload性能雪崩,甚至直接OOM。这里有个特别容易忽略的细节:Linux系统的默认overcommit设置会影响内存分配。PyTorch申请一大块虚拟内存时,系统可能正常返回,但等到实际写入时物理内存扛不住,进程直接被内核干掉。解决办法是关掉某些内存审计机制,或者限制框架的offload上限,让它在内存使用超过阈值时主动降速而不是直接崩溃。

另一个常见原因是batch size开得太大。“这套框架省显存了,直接batch=16走起”绝对是错误姿势。动态重计算的触发区间有限,batch变大后峰值显存依然会上涨,最佳实践是在batch=1之下把梯度累积步数调大,保证训练的等效batch size不变,然后逐步提高batch size去试探上限。

4.2 训练不收敛:精度问题和稀疏化的坑

如果Loss在某一迭代附近突然变成NaN,首先检查的是输入数据里有没有异常的“脏值”。低精度和动态缩放对这种异常极其敏感,任何一个inf输入进入网络,scale因子都会崩掉。数据干净的情况下,把“动态缩放”改成“固定缩放”,先做一轮小规模测试,看是否能稳定跑通,这种方式对排查问题很有效。

如果Loss长期不下降但也没有发散,往往是因为稀疏梯度比率开大了。TopK 5%的梯度同步对模型是很大信息损失,如果任务本身对细节很敏感(比如代码生成、翻译),建议把比例调到10%到15%,甚至改为“敏感层全量同步,其他层稀疏化”。这里可以用正则表达式或按层名去配置,灵活性比全局一个比例高很多。

4.3 速度慢得离谱:定位offload瓶颈

我复现时性能出现一次大幅波动:前面两千步跑得飞快,后面突然慢了三四倍。一开始以为是显存碎片导致,后来才发现是某些层在前向计算后被判定“不再需要”,给offload到SSD了,但反向传播准备更新该层时,又要从SSD读回来。这个动作一次两次还好,成千上万次跑起来就特别磨人。解决思路是把SSD换页接口的阈值调高,让数据优先保存在内存里;或者干脆在框架配置里把该层的“换出优先级”调低。一个更通用的小技巧是,训练前先用一个小模型做一次“热身”,找出哪些层处于换出换入的高频区间,然后在正式训练前就锁定它们常驻显存。

4.4 常见问题速查表

现象可能原因排查建议
OOM直接退出物理内存不足或系统配置限制检查内存上限,配置数据缓存目录,降低batch size
Loss为NaNFP8缩放因子异常或数据含inf检查输入清洗逻辑,固定缩放因子
Loss不降稀疏梯度比例过高调大同步比例,尝试让关键层全量同步
训练越来越慢动态换页次数过多调整换出优先级,扩大内存缓存
单步耗时异常波动CUDA显存碎片化重启进程,开启显存碎片整理开关

5. 个人体会与扩展方向

5.1 这项技术真正解决了什么

实际复现了一圈之后,我最明显的感觉是:这项技术把大模型训练的“最小可行条件”拉低了,但它不是万能药。它在显存优化和训练效率之间做了一个不错的权衡,让中等规模机构的开发者也能尝试非冻结式的大模型训练,而不必一开始就奔着集群去。相比花大价钱上多卡集群,这个方案的性价比高出一个量级。尤其是“全参数训练”能力的解锁,意味着你可以把一个通用模型真正“养成”某个垂直领域的样子,而不是只能加一层外挂适配器。

5.2 训练框架的横向扩展潜力

这套设计在单卡上表现很好,但我认为它更大的价值在“扩展性”。因为它的调度器是从底层就对多设备感知的,显存分级策略天然也适用于多个GPU甚至异构设备池。比如你可以用一台GPU较好但显存小的机器,配合一台大内存但无GPU的机器,让它作为offload节点,把梯度同步和参数存储分摊过去。这种“把普通硬件拼成一台虚拟大显存设备”的思路,后续完全可能改变很多中小团队的硬件规划方式。

5.3 落地时需要注意的边界条件

再强调几点实操经验:一是别奢望所有模型都无损训练,敏感任务还是得保留适量FP32路径,牺牲一些显存换取稳定;二是SSD offload空间一定提前预留充足,训练中途空间满了,前面进度全都白费;三是多卡复现时,通信优化的延迟同步机制要谨慎调参,延迟步数太大容易导致不同卡上的模型状态差异过大,最终拖累收敛。我自己的建议是延迟步数先设为2,观察Loss曲线趋势正常,再逐步加大到4或8。

这项技术后续如果往推理方向延伸,同样可以释放消费级GPU的潜能,比如在端侧运行大模型的KV Cache管理。未来普通GPU能参与的工作,恐怕不仅限于训练,还会有更多生成式AI的应用场景落地。我个人体会是,这类“把门槛往下拉”的工作,比那些纯刷精度的前沿研究更能让整个行业受益。毕竟,能让更多人跑得起实验的技术,才更容易催生出真正意想不到的成果。

相关新闻

STM32开发全攻略:选型要点、环境搭建与避坑实践

STM32开发全攻略:选型要点、环境搭建与避坑实践

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

2026/10/21 1:48:31 阅读更多 →
Citrix ADC中SNIP的三种配置场景:从同网段到跨网段与出站流量

Citrix ADC中SNIP的三种配置场景:从同网段到跨网段与出站流量

1. 从一个真实运维场景说起:为什么SNIP总在关键时刻出问题做应用交付这行的朋友,大概率都经历过这样的时刻:业务侧突然反馈某个后台服务访问不通,你登上负载均衡设备一看,虚拟服务器状态正常、服务组状态正常、后端节点…

2026/10/21 1:48:31 阅读更多 →
AI辅助决策系统设计:从业务问题到数据验证的完整实践

AI辅助决策系统设计:从业务问题到数据验证的完整实践

1. 项目概述:从“拍脑袋”到“看数据”的转变做数据分析这行久了,你会发现一个特别有意思的现象:很多公司嘴上说“数据驱动决策”,实际上会议室里还是靠老大拍板、靠销售直觉、靠竞品抄作业。我刚接触“百考通AI”这个项目的时候&…

2026/10/21 1:48:31 阅读更多 →

最新新闻

Wi-Fi MAC Layer: Scanning, Authentication, Association, and Data Transmission Processes

Wi-Fi MAC Layer: Scanning, Authentication, Association, and Data Transmission Processes

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

2026/10/21 2:25:53 阅读更多 →
ROS2笔记1

ROS2笔记1

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

2026/10/21 2:25:53 阅读更多 →
26 精武杯手机部分复盘

26 精武杯手机部分复盘

【简要案情】 近期,某市反诈部门接到多名群众报案,均遭遇“投资理财”类电信网络诈骗,指向的犯罪团伙涉案资金巨大、作案链条隐蔽。办案单位迅速成立专案组开展电子数据取证工作。经初查,该犯罪团伙搭建虚假投资平台,通…

2026/10/21 2:25:53 阅读更多 →
PHP安全漏洞修复指南:防SQL注入与XSS

PHP安全漏洞修复指南:防SQL注入与XSS

一、为什么 PHP 项目总被盯上做 PHP 开发这些年,我见过太多项目上线后被黑的情况。说句实话,大部分漏洞并不是什么高深的技术,翻来覆去就是 SQL 注入和 XSS 这两类。很多新手写代码的时候图省事,直接把用户输入拼进 SQL 语句&…

2026/10/21 2:25:53 阅读更多 →
中小企业建数据中台预算不多怎么办?先把这 5 笔成本拆开,别只问报价

中小企业建数据中台预算不多怎么办?先把这 5 笔成本拆开,别只问报价

报价单拿到手,最常见的第一反应是"怎么比我想的贵这么多"。而这个"我想的",通常是拿一套软件的价钱估出来的。 这篇为谁写:中小企业里兼管数据的 IT、被老板一句"我们是不是该上中台,先报个价"问到…

2026/10/21 2:25:53 阅读更多 →
C语言基础笔记 04 指针

C语言基础笔记 04 指针

00 包 目前CLion的最新版本还不支持中文&#xff0c;需要导入#include <stdlib.h> &#xff0c;再在main函数内写system("chcp 65001");才能在代码中用中文stdlib 还可以提供动态内存分布——malloc函数01 使用原因对于函数&#xff0c;在函数外定义的变量&…

2026/10/21 2:24:52 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

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

周新闻

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

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

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

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

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

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

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

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

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在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 阅读更多 →