上个帖子我测的4位Flux.1-dev跑在苹果M5 Max上,免训练的块残留缓存效果到底怎么样,现在交作业。简单说,缓存确实能用,但绝对不是一刀切的胜利。
固定间隔的缓存产生了真实的加速,然后被一个同种子PSNR门槛打得这么惨,我差点就写错结论。图像不见得差,只是它们偏离了无缓存去噪轨迹。这一下把我拖进了指标地板、窗口化SSIM、LPIPS、CLIP评分、提示分层以及交错计时的深水里。
代码在这里:github.com/kkjcodes/m5-flux-block-cache-benchmark。这不是胜利者的巡礼,也不是承诺下一个加速已经搞定,更像是一个交接点:到这里,块缓存不再是那个最让人睡不着的问题了。
实验找到的最佳策略是一个预热分割方案:联合块12至18在start_step=8时启动,单块28至37在start_step=6时启动,间隔设为2,值模式用残留。代码里start_step就是预热边界,边界步骤仍然是刷新点,允许在间隔未命中之后重复使用。
这个方案通过了1.125倍的交错计时门槛。数据是实锤,同时也是被框死的结果。
缓存不是像素级一致的,它仍然通不过严格的同种子轨迹检查。而且改进效果极度依赖内容:人像、产品渲染和排版与无缓存参考图的差距极小,而密集室内场景一直是翻车的重灾区。
这就是按提示分层的真实画面。表格本身就是最前线——不是“缓存管用”,也不是“缓存失败”。更准确的说法是:延迟预热的残留重复利用在某些内容类别上逼近保真度,但密集室内场景把所有短板都翻了出来。
挑一个容易案例看看。同样的提示、同样的种子,左边是无缓存参考图,右边是预热分割的缓存变体:
下面这个案例让结果保持在诚实水平。即使过了残留门槛,密集室内场景仍然让算法吃瘪。两个缓存版本彼此几乎无法区分,这也恰好说明问题:门槛触发了,但没能对失败模式产生足够改变。
我原本以为自适应门槛能救场。想法很直白——保留预热分割调度,但当某个块的残留相对于其近期历史变化太大时,禁止重复使用,转而重新计算该块。我用大白话预注册了目标:把密集室内场景的PSNR从22.62拉升到大约29,同时还不能跌出分割策略的计时级别。
这事没成。
在同一轮交错计时比较中,分割策略测得1.121倍,门控策略测得1.093倍。门槛把速度给还回去了。质量只挪了一丁点:密集室内场景需要约6分贝的改善,实际拿到手大约0.2分贝。差得太远。
接着我去核查门槛是否在正确的时机触发。结果发现它触发太频繁了。中等提示也受影响,而且大部分被阻止的重复使用本来也没那么大的质量杀伤力。换个说法:
我在控制一个比实际信号更嘈杂的东西。
块内部的残留波动被用于双块架构本来就会产生的噪声所主导,至少在这种时序调度下是这样。一旦过了阈值,相当于在说“所有变动都有信息量”——这个假设太苛刻了,最后过滤掉的多数是噪声,还让计时付出了代价。
到这里,缓存问题告一段落。交付物如下:一个工作的1.125倍加速,一个清楚标注出来的失效区域,以及一个表面看着靠谱、实测却垮掉的自适应方案。测评代码、结果文件、测试用的提示和psnr-ssim-lpips-clip门控管道全部在仓库里。
现在真正有意思的问题变了:不是“还能挤出多少缓存”,而是“扩散已经在哪些环节把时间还给我们了”。
FLUX的块缓存本质上是在recompute边界上做文章——当你被I/O或内存带宽卡住,而计算单元有闲置时,省掉某些块的能力就有价值。但这也是很多扩散模型损失的真正来源:不是某个单独步骤慢,而是整个调度把时间花在了可能压根没必要去的地方。
这个视角一换,问题就从“怎么砍掉一些块的计算”变成了“哪些步骤本身就贡献不大”。这个问题更棘手,但回报也可能更大。尤其是目前发布的少数内部步进解码器,以及已经能在早期退出机制下保质量的扩散Transformer,趋势已经开始浮出水面了。
仓库里的数据大概能支撑后续这个方向。分层提示的指标、步骤级别的SSIM轨迹、延迟热图、残留量级随去噪进展的变化曲线,能不能在不用重训的前提下勾画出“效率阶梯”的大致形状,还得看后续分析。
如果你对这个方向有想法,或者你也在做端点上的扩散推理、低功耗场景的DiT部署、甚至在量化误差分配上有不同的建模假设,欢迎聊一聊。我特别关注的是:当有人把某个自适应机制砍掉并说它没用时——那个机制到底是在错误的地方生效了,还是在正确的地方但代价太高了。
热门跟贴