LLM推理服务如何利用Prefill与Decode功耗不对称性降低电费成本

1. 从"电费账单"说起:为什么LLM推理服务需要看电网脸色

第一次看到这个标题的时候,我脑子里冒出来的第一个疑问是:一个做LLM推理服务优化的论文,为什么标题里会出现"Demand Response"这种电力系统里的术语?后来把整篇论文的脉络捋了一遍才明白,这背后其实是一个非常现实的成本问题。

大规模LLM推理服务的成本结构里,电费占比远比大多数人想象的要高。一个中等规模的推理集群,GPU满载运行时的功耗动辄几十千瓦起步,如果算上散热和配电损耗,实际用电量还要再往上浮一截。而在很多地区的电价体系里,工业用电并不是一个固定价格——它存在分时电价和需求响应机制。简单说就是:电网在高负荷时段电价高,在低负荷时段电价低,同时电网运营方还会在某些时段发出"削峰"信号,鼓励大用户主动降低用电功率,作为回报给予电价补偿或费用减免。

这就引出了一个很自然的想法:既然电价是波动的,那LLM推理服务能不能在电价高的时候少用点电、在电价低的时候多用点电?听起来简单,但真正做起来会遇到一个核心矛盾——推理请求是有延迟要求的。你不能因为电价高就把用户的请求晾在那里不处理,等电价降下来再算。用户等不了,SLA也不允许。

所以这篇论文要解决的核心问题就是:在满足推理延迟约束的前提下,如何让LLM服务的功耗跟随电价信号动态调整,从而降低整体用电成本。关键词里的"Phase Asymmetry"(相位不对称)就是他们找到的突破口——LLM推理的prefill阶段和decode阶段在功耗特性上存在显著的不对称性,而这种不对称性恰好可以被用来做功耗调节。

这篇文章适合谁看?如果你在做LLM推理服务的部署和优化,关心推理成本控制,或者对GPU集群的功耗管理感兴趣,那这篇论文的思路值得仔细拆一拆。如果你只是刚接触LLM推理,也没关系,我会把里面涉及的基础概念都铺开讲清楚。

2. Prefill和Decode到底哪里"不对称"

要理解这篇论文的核心洞察,得先把LLM推理的两个阶段掰开来看。很多人知道prefill和decode在计算特性上不同,但具体到功耗层面,差异到底有多大、差在哪里,可能并没有仔细想过。

2.1 两个阶段的计算模式差异

LLM推理的prefill阶段处理的是用户输入的prompt,所有token是并行计算的。这意味着GPU在这一阶段的计算密度极高,矩阵乘法规模大,Tensor Core利用率高,显存带宽主要消耗在加载模型权重和写入KV Cache上。用大白话说,prefill阶段GPU是"满负荷运转"的状态,功耗自然就高。

Decode阶段就不一样了。每生成一个token,GPU只需要计算一个位置的注意力,矩阵乘法的规模急剧缩小。虽然现代推理框架会做batch合并来提高利用率,但decode阶段的算术强度(Arithmetic Intensity)天然就比prefill低得多。GPU的计算单元大量空闲,瓶颈从计算转移到了显存带宽上——每生成一个token都要把整个KV Cache读一遍。

这个差异直接反映在功耗上。论文里给出的实测数据显示,在相同硬件上,prefill阶段的GPU功耗可以比decode阶段高出30%到50%。而且这个差距不是线性的——不是说你把batch size调大就能抹平的,因为两个阶段的瓶颈资源根本不同。

2.2 功耗不对称带来的调度空间

这个功耗差异意味着什么?意味着如果你能把一部分计算从高电价时段"搬"到低电价时段,你搬动的"重量"是不一样的。Prefill阶段的计算是"重"的,搬一个prefill请求省下来的电费,可能相当于搬好几个decode请求。

但这里有个陷阱:prefill和decode不是独立的任务,它们有严格的依赖关系。一个请求必须先prefill完才能进入decode。你不能说"我现在只做decode不做prefill",因为那样新请求永远进不来。反过来,你也不能只做prefill不做decode,因为那样用户永远拿不到完整的输出。

论文的巧妙之处在于,他们发现虽然两个阶段有依赖,但在调度层面存在灵活空间。具体来说:

  • Prefill的时机可以调整——请求到达后,你可以选择立即prefill,也可以稍微等一等,攒一批一起prefill。
  • Decode的速率可以调整——你可以选择每个step生成更多token(如果框架支持),也可以选择在低电价时段加快decode。
  • 两个阶段的资源分配比例可以调整——在电价高的时候,把更多GPU资源分配给必须完成的decode,把prefill尽量推迟;在电价低的时候,集中资源做prefill。

这种调整之所以可行,是因为prefill和decode对延迟的敏感度不同。Prefill的延迟主要影响首token时间(TTFT),而decode的延迟影响的是每token生成时间(TPOT)。用户对TTFT的容忍度通常比TPOT高——等首token等个一两秒可以接受,但每个token都慢就很难受了。

2.3 为什么叫"相位不对称"

"Phase Asymmetry"这个说法,我理解是在强调两个阶段在功耗-延迟权衡曲线上的不对称。对于prefill,你稍微增加一点延迟(比如把batch攒大一点),功耗效率会显著提升;对于decode,你增加延迟带来的功耗节省就没那么明显,因为decode本身就是带宽瓶颈,batch大了功耗增加也有限。

这种不对称性意味着,功耗调节的"杠杆"主要应该加在prefill阶段。论文的调度策略本质上就是在做这件事:在电价高的时候,把prefill的优先级压低,让decode优先跑;在电价低的时候,把prefill的优先级拉高,集中处理积压的请求。

这里有个容易误解的点:压低prefill优先级不等于不处理prefill。如果一直不处理,请求队列会无限增长,最终TTFT会突破SLA。所以论文里一定有一个队列长度或等待时间的约束,超过阈值就必须强制prefill。这个约束的设计是整篇论文工程价值最高的部分之一。

3. 调度策略拆解:怎么在SLA边缘反复横跳

理解了不对称性之后,接下来的问题就是:具体怎么调度?论文里提出的方案不是简单的"电价高就少做prefill",而是一套带反馈的动态调节机制。我把它拆成几个关键组件来讲。

3.1 电价信号的获取与预测

Demand Response的前提是你能拿到电价信号。在实际部署中,电价信号通常有两种来源:一种是电网运营方提前发布的分时电价表,这个是可以提前知道的;另一种是实时需求响应事件,这个是突发的,可能提前几分钟到几十分钟通知。

论文里假设系统能够获取这两类信号。对于分时电价,系统可以提前规划;对于突发需求响应事件,系统需要快速响应。这里有个工程细节:电价信号的粒度通常是15分钟或1小时,而推理请求的调度粒度是毫秒级的。所以系统需要把粗粒度的电价信号"翻译"成细粒度的调度决策。

论文采用的方式是设置一个目标功耗曲线。根据当前电价和预测的未来电价,系统计算出一个目标功耗值,然后调度器尽量让实际功耗跟踪这个目标值。电价高的时候目标功耗低,电价低的时候目标功耗高。

3.2 请求队列的双优先级设计

这是整个调度策略的核心。论文把请求队列分成了两个优先级:

  • 高优先级队列:存放已经完成prefill、正在decode的请求。这些请求必须尽快处理,因为用户已经在等输出了。
  • 低优先级队列:存放等待prefill的新请求。这些请求可以适当延迟,只要TTFT不超过SLA。

调度器在每个决策时刻做两件事:第一,决定给decode分配多少GPU资源;第二,决定是否从低优先级队列取请求做prefill。当电价高时,调度器倾向于把资源都给decode,prefill能拖就拖;当电价低时,调度器会主动从低优先级队列取请求做prefill,甚至提前prefill一些还没到截止时间的请求。

这个设计的精妙之处在于,它把"功耗调节"转化成了"队列管理"问题。功耗高是因为prefill在跑,那我就控制prefill的启动时机。而decode的功耗相对稳定,因为它必须持续跑。

3.3 延迟约束的硬边界

前面说了,prefill不能无限推迟。论文里设置了一个最大等待时间参数,我把它叫做max_prefill_delay。如果一个请求在低优先级队列里等待的时间超过了这个值,调度器就必须强制把它取出来做prefill,不管当前电价多高。

这个参数的设置很关键。设得太小,功耗调节的空间就小,省不了多少电费;设得太大,TTFT会经常触达SLA上限,用户体验变差。论文里给出的经验值是:max_prefill_delay应该设置为TTFT SLA的60%到70%。比如你的TTFT SLA是2秒,那最大等待时间就设在1.2到1.4秒左右。这样留出足够的余量给实际的prefill计算。

除了等待时间,还有一个约束是队列长度。如果低优先级队列积压太多,即使每个请求的等待时间还没到上限,也应该开始prefill了,否则后面来的请求会等更久。论文里用了一个简单的阈值策略:当队列长度超过某个值时,提高prefill的优先级。

3.4 功耗跟踪的反馈控制

目标功耗曲线和实际功耗之间会有偏差,因为请求的到达是随机的,每个请求的计算量也不一样。论文用了一个比例控制器来调节。简单说就是:如果实际功耗高于目标,就进一步压低prefill的优先级;如果实际功耗低于目标,就适当提高prefill的优先级。

这个反馈控制器的参数需要调。比例系数太大,系统会震荡——一会儿疯狂prefill,一会儿完全不做prefill;比例系数太小,响应太慢,电价高峰都过去了功耗还没降下来。论文里建议用一个较小的比例系数,配合一个低通滤波器来平滑功耗测量值。

实操中有一个坑:GPU功耗的测量本身有噪声,而且不同型号的GPU功耗响应速度不同。如果你直接用瞬时功耗做反馈,控制器很容易被噪声带偏。建议用滑动窗口平均后的功耗值,窗口大小设置在1到5秒之间。

4. 实测数据背后的工程真相

论文里给了一组实验结果,我挑几个关键数据来说,顺便聊聊这些数据在实际部署中意味着什么。

4.1 省电效果与SLA的权衡曲线

论文的核心实验结果显示,在典型的电价曲线下,采用Phase Asymmetry调度策略可以降低**15%到25%**的用电成本,同时TTFT的P99值增加不超过20%。这个数字看起来不算特别惊艳,但考虑到LLM推理服务的电费基数很大,15%到25%的成本节省已经相当可观了。

更重要的是,这个节省不是靠牺牲用户体验换来的。P99 TTFT增加20%意味着如果你的SLA是2秒,那P99从1.5秒变成1.8秒,还在SLA范围内。当然,这是在论文设定的负载条件下。如果你的负载本身就接近系统容量上限,那调节空间会小很多。

4.2 不同负载下的调节空间差异

论文里做了一个负载扫描实验,从低负载到高负载分别测试。结果发现:

负载水平GPU利用率成本节省TTFT P99增幅
低负载30%25%5%
中负载60%18%12%
高负载85%8%20%
接近饱和95%3%35%

这个表格很说明问题。负载越低,功耗调节的空间越大。因为低负载时系统有大量空闲资源,你可以从容地把prefill挪来挪去。高负载时系统本身就在满负荷跑,你能做的只是"拆东墙补西墙",调节空间自然就小。

这给实际部署的启示是:Phase Asymmetry调度最适合中等负载的场景。如果你的集群长期跑在90%以上的利用率,那这套方案帮不了你太多,你更需要的是扩容或者做请求优先级管理。如果你的集群利用率只有30%,那这套方案能帮你省不少电费。

4.3 与基线方案的对比

论文对比了几个基线方案:

  • 无调节:所有请求按FCFS处理,不做任何功耗管理。
  • 静态阈值:电价高于某个阈值时暂停prefill,低于阈值时恢复。
  • Phase Asymmetry:论文提出的动态调度方案。

结果显示,静态阈值方案在高电价时段确实能省电,但电价降下来之后会有大量积压请求集中prefill,导致功耗尖峰,而且TTFT的波动很大。Phase Asymmetry方案通过动态调节,把积压请求更平滑地分散到低电价时段,避免了功耗尖峰,TTFT也更稳定。

这个对比说明了一个道理:功耗管理不是简单的开关控制,而是需要精细的流量整形。就像交通管理一样,你不能简单地封路,而是要通过信号灯配时来平滑车流。

5. 落地这套方案需要想清楚的几件事

论文读完了,思路也理解了,但真要把它落地到自己的推理服务里,还有几个工程问题需要想清楚。

5.1 你的推理框架支持细粒度调度吗

Phase Asymmetry调度的前提是你能独立控制prefill和decode的调度。但很多现成的推理框架(比如一些早期的推理引擎)是把prefill和decode混在一起调度的,你没法单独控制prefill的启动时机。

如果你用的是vLLM这类支持continuous batching的框架,那恭喜你,它天然就把prefill和decode分开了,你可以在调度层做文章。如果你用的是更传统的框架,可能需要先做一轮改造,把prefill和decode的调度逻辑拆开。

具体来说,你需要能在调度器里做这几件事:

  1. 维护两个独立的请求队列(等待prefill的和正在decode的)。
  2. 在每个调度step,能独立决定是否从等待队列取请求做prefill。
  3. 能控制prefill的batch size,避免一次prefill太多请求导致功耗尖峰。

5.2 电价信号的接入成本

Demand Response的前提是你能拿到电价信号。如果你是在自建机房跑推理服务,那电价信号可能来自你的配电系统或者电网的公开接口。如果你用的是云服务,那云厂商通常有预留实例和按需实例的价格差异,但实时的电价信号可能拿不到。

论文里假设系统能获取实时电价,这在学术环境下是合理的,但在实际部署中可能需要额外的对接工作。一个折中方案是:用历史电价数据训练一个简单的预测模型,提前预测未来几小时的电价曲线,然后基于预测做调度。预测误差可以通过反馈控制来补偿。

5.3 多租户场景下的公平性

如果你的推理服务是多租户的,那功耗调节会带来公平性问题。电价高的时候,低优先级队列里的请求会被延迟,如果这些请求恰好来自某个特定租户,那这个租户的体验就会变差。

论文里没有深入讨论这个问题,但在实际部署中必须考虑。一个可能的方案是:在租户层面做轮转,确保每个租户的请求被延迟的概率是均等的。或者给不同租户设置不同的优先级,高优先级租户的请求不参与功耗调节。

5.4 硬件异构性的影响

论文的实验是在同构GPU集群上做的。如果你的集群里有不同型号的GPU,那功耗特性会不一样。比如A型号的GPU在prefill和decode之间的功耗差异是40%,B型号只有25%,那调度策略需要针对不同型号做适配。

一个实用的做法是:在系统启动时对每种GPU型号做一次功耗标定,测量prefill和decode阶段的典型功耗值,然后把这些参数喂给调度器。这样调度器就能根据当前可用的GPU型号来调整调节策略。

6. 从这篇论文延伸出去的几个想法

读完这篇论文,我脑子里还冒出了几个相关的方向,不一定成熟,但值得想一想。

第一个想法是:能不能把功耗调节和请求的优先级结合起来?比如,对于延迟不敏感的请求(比如离线批处理任务),可以完全跟着电价走,电价低的时候集中跑,电价高的时候完全暂停。对于延迟敏感的在线请求,则用Phase Asymmetry的方式做精细调节。这样可以把两类请求的调度策略分开,各自优化。

第二个想法是:功耗调节的粒度能不能更细?论文是在GPU级别做调节的,但现代GPU支持更细粒度的功耗管理,比如可以限制GPU的功率上限(power cap)。如果在电价高的时候不仅减少prefill,还适当降低GPU的功率上限,可能会进一步省电。当然,降低功率上限会影响计算速度,需要权衡。

第三个想法是:这套思路能不能用到其他类型的推理服务上?比如图像生成、语音识别,这些服务也有类似的计算阶段划分,也可能存在功耗不对称性。如果能把Phase Asymmetry的思路推广到更多类型的推理服务,那价值就更大了。

最后分享一个我在实际调优中的小经验:做功耗调节的时候,不要只盯着GPU功耗。CPU、内存、网络设备的功耗加起来也不是小数目。特别是在高负载场景下,CPU的功耗可能占到总功耗的20%以上。如果你的调度策略只优化GPU,可能会忽略掉其他组件的功耗变化。建议在功耗测量时把整个节点的功耗都纳入进来,这样优化目标更准确。

另外,功耗调节的效果和你的请求模式强相关。如果你的请求到达非常均匀,那调节空间主要来自prefill时机的微调;如果你的请求有明显的波峰波谷,那调节空间会大很多,因为你可以把波峰时段的prefill挪到波谷时段。所以在部署之前,先分析一下你的请求到达模式,评估一下理论上的调节上限,再决定要不要投入精力做这套调度。

相关新闻

零幻觉AI客服技术解析:RAG检索增强与置信度阈值实践

零幻觉AI客服技术解析:RAG检索增强与置信度阈值实践

1. 从“零幻觉”说起:AI客服到底在解决什么真问题做客服系统的人都有一个共识:用户找客服,十次里有八次是带着情绪来的。订单没到、退款没到账、功能不会用、账单对不上——这些问题背后往往藏着焦虑甚至愤怒。传统客服体系里,解决…

2026/10/20 16:08:29 阅读更多 →
论文解读与源码复现|NegBench:视觉语言模型其实不懂“否定“(CVPR 2025)

论文解读与源码复现|NegBench:视觉语言模型其实不懂“否定“(CVPR 2025)

论文解读与源码复现|NegBench:视觉语言模型其实不懂"否定"(CVPR 2025) 论文首页题目与摘要截图 一、前言 "检索一张没有人的海滩"、"查询无证据显示肺炎的胸片"——否定(negation&…

2026/10/20 16:08:29 阅读更多 →
手写持久化B树KV存储引擎:从原理到工程实现

手写持久化B树KV存储引擎:从原理到工程实现

直接手写一个支持持久化的B树KV存储引擎,这件事听起来像是在重复造轮子,但真正动手之后你会发现,数据结构教材里的那几页纸和工程实现之间的距离,远比你想象的大。这个项目适合两类人:一类是想彻底搞懂B树、B树原理的开…

2026/10/20 16:08:29 阅读更多 →

最新新闻

Agentic Harness Workflow:从能跑通代码到可交付工程的AI编程框架

Agentic Harness Workflow:从能跑通代码到可交付工程的AI编程框架

1. 为什么"能跑通的代码"和"能交付的工程"之间隔着一道鸿沟 如果你最近半年深度用过任何一款 AI 编程助手,大概率经历过这样的场景:你让它写一个功能,它三下五除二吐出一大段代码,你复制粘贴进去,…

2026/10/20 17:04:26 阅读更多 →
Postman接口关联实战:从登录Token到下单的自动化流程

Postman接口关联实战:从登录Token到下单的自动化流程

某B2C在线商城的API接口文档里,最经典的一条业务就是“登录-选择商品加入购物车-下单”。我拿到这个需求的第一反应是:请求参数倒是不难,难在这些接口之间要传一堆动态数据,登录返回token、商品列表返回productId、购物车返回购物…

2026/10/20 17:04:26 阅读更多 →
Agentic Harness Workflow:用状态机+Agent工程化框架驾驭AI编码

Agentic Harness Workflow:用状态机+Agent工程化框架驾驭AI编码

1. 为什么“让AI写代码”这件事需要一套工程化框架 1.1 从“对话式写代码”到“流程化跑任务”的认知转变 过去一年多,我身边不少开发者对 AI Coding 的态度经历了三个阶段:最开始是好奇,拿它写个正则、补个单元测试;然后是依赖&…

2026/10/20 17:04:26 阅读更多 →
InstallShield中附属MSI的安装卸载实战与调试

InstallShield中附属MSI的安装卸载实战与调试

前两天帮人看一个安装包的诡异问题:主程序明明是装成功了,但被一起带上的那个MSI组件死活装不上,卸载的时候还赖在系统里不走。这个场景搞Windows安装包的朋友应该不陌生——主程序用InstallShield打成一个安装包,安装时还要顺带把…

2026/10/20 17:04:26 阅读更多 →
HUSB351快充芯片:小体积PD协议芯片的工程落地逻辑

HUSB351快充芯片:小体积PD协议芯片的工程落地逻辑

1. 从“机乐堂”供应链变动看快充芯片选型的底层逻辑最近在整理一批快充配件的BOM清单时,注意到一个细节:某款标称30W PD快充的迷你插线板,其协议识别模块的丝印从常见的“FP6606”悄然换成了“HUSB351”。进一步交叉查证发现,该产…

2026/10/20 17:04:26 阅读更多 →
MVMD联合小波阈值去噪:多通道非平稳信号MATLAB实战

MVMD联合小波阈值去噪:多通道非平稳信号MATLAB实战

简介:这份资源面向信号处理、故障诊断与振动监测方向的学习者和研究人员,提供一套基于MATLAB的完整联合去噪方案,用于从含噪多通道信号中恢复原始信号。核心流程涵盖MVMD多元变分模态分解、基于相关系数的有效模态筛选、小波阈值去噪、模态重…

2026/10/20 17:03:25 阅读更多 →

日新闻

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 阅读更多 →