一、10 月 30 日商汤开源了什么10 月 30 日商汤在 Hugging Face 与 GitHub 同步放出 SenseNova-Loop-9B-Preview权重以 Apache 2.0 协议开放。官方定位很明确面向长上下文与 Agent 工作流的多模态模型文本和图像输入文本输出。核心数字只有三个总参数约 9B、推理等效约 14.6B、每次前向传播执行 56 次解码器层计算。56 次层计算从 32 组独立权重里跑出来靠的就是 Looped Transformer中间 24 层共享权重依次执行两遍。商汤的官方口径是在 9B 参数规模下媲美 27B 参数模型并在 WorkBuddy Bench、RaccoonPPT Bench、AutomationBench 三个榜单上超过 Qwen3.5-27B。训练侧的信息也一并公开文本、图像、代码和工具调用轨迹的混合监督最长训练序列262,144 个 token。模型已经接入商汤小浣熊客户端做真实任务验证说明这不是停留在论文里的架构玩具。开源模型这两年的主航道是参数规模和上下文长度Loop-9B 把第三条路计算深度第一次做到了可下载、可部署、可商用的尺寸。官方新闻稿反复强调一句话从参数规模到计算深度。这句话值一篇完整拆解因为它直接改写端侧和私有化部署的成本结构。时点信号也值得注意权重以 Apache 2.0 协议直接开放商用零门槛社区的框架适配和第三方复现评测会很快跟上。需要提醒的是评测口径WorkBuddy Bench、RaccoonPPT Bench、AutomationBench 这三个榜单偏办公和 Agent 执行场景数据来自官方自测独立第三方的复现结论还没有出现。这不妨碍拆解架构本身因为 32 层权重 56 次执行、双流 mHC、混合注意力这三件事都写在公开的模型卡和配置文件里是可以独立验证的硬事实。这篇文章不重复新闻稿只拆三个工程问题56 次执行怎么排布、mHC 双流残差在防什么、显存账到底省在哪。二、循环解码器B(B(h)) 的 56 次层计算Loop-9B 的解码器一共 32 个独立层输入先经过第 0 到 3 层随后第 4 到 27 层这个连续块整体执行两遍最后由第 28 到 31 层和输出头收尾。用 B 表示循环块、h 表示输入循环计算就是 B(B(h))第二遍以第一遍的输出为输入复用同一组权重。层数账很直白4 加 24 乘 2 再加 4等于56。参数账值得细算。词表大小248,320隐藏维度4096仅词嵌入一项就占约 1.02B。每层按隐藏维度 4096、前馈维度 12288 估算SwiGLU 三个矩阵加注意力投影合计约 2.3 亿参数。32 层权重合计约 7.5B加上嵌入层后落在官方给出的约 9B 口径之内。换成执行口径再算一遍首尾 8 层各算一次约 1.9B中间 24 层算两遍约 11.3B再加嵌入正好逼近官方给出的14.6B 推理等效参数。这组数字说明循环计算买到的不是免费午餐存储按 9B 付钱计算量按 14.6B 付换的是不加显存负担的额外深度。延迟侧也要诚实56 次层执行意味着同样权重下推理耗时比 32 层稠密模型高约 75%这是用时间换空间的明确交易。FLOPs 账再往细算一层忽略注意力项单 token 前向的主力开销约等于每层参数量乘两次运算56 次层执行合计约 258 亿 FLOPs 每 token而 32 层稠密版本只要约 147 亿。但拿它和 27B 稠密模型对比时方向会反过来27B 每 token 约 540 亿 FLOPsLoop-9B 的计算量仍然只有对方一半左右存储和计算两头都占便宜。把三笔账并排放权重存储约为同能力稠密模型的三分之一每 token 计算量约为二分之一代价仅仅是比同参数量的 9B 稠密模型慢约 75%。有效深度的价值集中体现在多步推理链上循环块的第二遍相当于让模型对同一份中间表示再做一轮抽象加工这是官方在复杂任务榜单上追平 27B 的主要结构来源。循环块选在第 4 到 27 层也不是随意决定靠近输入的前 4 层和靠近输出头的后 4 层保持独立权重词表嵌入到语义空间的映射和解码输出前的表示精修都不被循环复用。这种首尾独立、中间共享的切法同时照顾了两头底层的特征提取需要专用权重高层的输出校准也需要专用权重中间的概念加工才是可以反复复用的部分。从训练成本角度看共享权重还有一个隐性收益循环块只存储一份参数优化器状态和梯度副本也同步减少微调时的显存峰值比同执行深度的稠密模型低得多。三、混合注意力循环边界为什么必须对齐四层组Loop-9B 的注意力不是单一形态而是每四层为一个循环单元三层 Gated-DeltaNet 线性注意力加一层全注意力。全注意力层采用16 个查询头配 4 个 KV 头的 GQA 结构带 QK 归一化和注意力输出门。线性注意力层维护的是常数大小的循环状态计算量随序列长度线性增长不需要存历史 KV。位置编码使用交错式 M-RoPE旋转比例因子 0.25只有四分之一的维度参与旋转其余维度保持原样。关键设计在边界循环块第 4 到 27 层恰好是6 个完整的四层组两遍执行看到完全相同的注意力排列。如果边界切在某个四层组中间第二遍的层序就会和第一遍错位共享权重在两遍里承担不同角色训练好的表示直接被拆散。按 56 次执行摊开算全注意力一共出现14 次首尾各 2 层加循环两遍各 6 层线性注意力出现42 次。这个 3 比 1 的比例决定了长上下文的成本结构也是下一节显存账的前提条件。Gated-DeltaNet 值得单独展开它是线性注意力的一个变体用门控加 delta 规则维护并更新一个常数大小的循环状态状态维度与序列长度完全无关。这正是 42 层线性注意力不需要存历史 KV 的原因无论上下文是 4K 还是 256K这些层的显存占用都是同一个常数。M-RoPE 的 0.25 也有明确含义每个注意力头 256 维里只有 64 维参与旋转并携带位置信息其余 192 维专注于内容匹配长上下文外推时位置干扰更小。三比一的分工可以这样理解全注意力负责精确检索长距离依赖线性注意力负责以常数成本压缩背景信息比例本身就是召回能力和推理成本之间的折中点。GQA 的 4 比 1 头数配比同样服务于推理成本4 个 KV 头相对 16 个查询头把 KV 写入量直接压到四分之一和线性注意力层的常数状态形成同一套降本逻辑。这些选择叠加起来的风格非常一致凡是随序列长度增长的量全部压缩凡是常数项才允许保留长上下文场景的显存曲线因此变得可线性外推。反过来讲这个设计的软肋也清晰线性注意力对需要逐字精确回溯的任务天然吃亏所以 14 次全注意力层的召回质量决定了整个模型在长上下文检索任务上的上限。四、显存账权重省了KV cache 怎么算权重侧省得很直接9B 参数按 BF16 存储约18GB同档 27B 稠密模型要 54GB单卡部署门槛差了整整一档。KV cache 一侧容易被误读。GGUF 移植方的说明写得很清楚循环块的两次执行各自保留自己的注意力 KV 和 GDN 循环状态。也就是说 KV cache 按56 次执行记账不按 32 层记账权重共享在这里不带来任何折扣。真正的节省藏在注意力结构里56 次执行中只有 14 次是全注意力其余 42 次线性注意力只维护常数状态不随序列变长。按演示口径估算假设值可替换每个 token 在单层全注意力的 KV 占用是 4 个 KV 头乘 256 维头维度再乘 K 和 V 两份乘 BF16 两个字节约 4KB。14 层全注意力合计约56KB 每 token128K 上下文约 7.2GB256K 满载约 14.4GB。对照一个假设的 27B 稠密配置64 层全注意力、8 个 KV 头、128 维头维度每 token 每层同样约 4KB64 层约 256KB128K 上下文就要约 32.8GB。口径Loop-9B-Preview假设的 27B 稠密模型权重显存BF16约 18GB约 54GB128K 上下文 KV cache约 7.2GB约 32.8GB层执行次数5632 组权重6464 组权重全注意力层数14其余为线性注意力64存储参数 / 推理等效9B / 约 14.6B27B / 27B结论很工程化Loop-9B 用 1.75 倍的层执行换 3 倍的权重显存压缩KV cache 再靠混合注意力砍掉四分之三以上。对 24GB 到 48GB 显存的单卡场景这个组合意味着 128K 长上下文第一次变得可以在本地认真考虑。Agent 会话的 KV 增长曲线更能说明问题多轮工具调用场景里 KV 随轮数线性累积7.2GB 每 128K 的口径意味着 24GB 显卡在装下 18GB 权重之后仍然有完整长会话的回旋空间。预填充带宽账也连带受益KV 总量小四分之三意味着写入带宽同比节省长文档预填充阶段的显存峰值压力同步下降。边界同样要说清楚42 层线性注意力的循环状态本身也占显存且随 batch 大小和头数增长但它是常数项不随上下文长度变化256K 满载时总量完全可预测。还有一个部署层面的推论权重 18GB 加 128K 会话 KV 约 7.2GB合计 25GB 出头一张 32GB 级显卡就能同时装下权重和满配长上下文。放到 Agent 工作流里看更具体每一轮工具调用都会把工具返回追加进上下文几十轮下来上下文轻松突破 64KKV 曲线的斜率直接决定单会话的显存寿命。对服务端批量部署同样有意义单卡能容纳的并发会话数由权重加 KV 总量决定KV 砍四分之三意味着同卡并发数接近翻倍这部分收益和权重压缩相互独立。五、mHC 双流残差Sinkhorn 在防什么循环计算的老问题是信息混叠同一组权重跑两遍如果第二遍的输入只经过一条残差通路梯度和特征很容易在两遍之间互相污染。Loop-9B 的解法是 mHC流形约束超连接。循环块内部始终维护两条残差流每一层通过可学习映射决定怎么从双流里读出、怎么把层输出写回双流。约束体现在混合矩阵上流间混合映射不做自由加权而是经过Sinkhorn 归一化 20 次迭代逼近一个双随机矩阵。双随机矩阵的行和与列和都等于 1意味着信息在两条流之间重新分配时总量守恒不会出现某条流被无限放大或者逐渐饿死。这本质上是把最优传输里的熵正则思想搬进了残差通路比朴素的多路加权求和稳定得多。数值精度上也能看出刻意保护主干用 BF16 存储mHC 路由参数全程用FP32混合矩阵的计算不吃半精度舍入误差。消融实验给了直接证据引入 mHC 之后GPQA Diamond 提高 4.42 分TeamBench 提高 13.34 分后者正是多步骤 Agent 任务的榜单。13.34 分的提升幅度说明双流残差对长链路任务的帮助远大于对单轮推理题的帮助这和官方主打的 Agent 工作流定位完全自洽。谱系上看 mHC 并不是凭空出现残差连接从 ResNet 时代的单流开始Hyper-Connections 把残差拓宽成多条流并允许跨流自由混合mHC 则是在循环场景下给混合矩阵加上了流形约束。为什么恰好是两条流而不是四条流数翻倍意味着混合矩阵和读写映射的参数量同步翻倍Sinkhorn 迭代成本也上涨两条流是 9B 规模下收益和开销之间的折中。双随机约束还有一个等价解释任何一条流的更新都是两条流的凸组合再叠加本层输出信息流自带归一化性质深层堆叠时激活尺度更可控。训练稳定性的收益也直接相关两遍执行共享权重时梯度会跨时间步累加混合矩阵被约束在双随机流形上梯度路径不会在两条流之间越走越偏。Sinkhorn 迭代自身的成本几乎可以忽略2 乘 2 的混合矩阵做 20 次行列归一化相对每层千万级的矩阵乘法只是零头约束的性价比非常高。官方也提到后续会探索 DSA 稀疏注意力和自适应迭代次数说明双流加循环只是一个可扩展框架的第一组配置不是终点形态。六、最小复现PyTorch 验证 32 层权重 56 次执行下面这段代码不加载任何权重只用标准 PyTorch 复现 Loop-9B 的三个结构声明32 组权重、56 次层执行、双流 mHC 加 Sinkhorn 混合。代码直接可运行末尾的断言会逐一核对这三个数字并验证 Sinkhorn 迭代确实收敛到双随机矩阵。import torch import torch.nn as nn CFG dict( n_layers32, # 独立解码器层数 loop_start4, # 循环块起点含 loop_end28, # 循环块终点不含 loop_passes2, # 循环块执行遍数 d_model256, n_heads4, d_ff768, vocab1000, mhc_streams2, sinkhorn_iters20, ) def sinkhorn(logits, iters): # 行列交替归一化逼近双随机矩阵 m logits for _ in range(iters): m m - torch.logsumexp(m, dim-1, keepdimTrue) m m - torch.logsumexp(m, dim-2, keepdimTrue) return torch.softmax(m, dim-1) class Block(nn.Module): def __init__(self, d, h, f): super().__init__() self.attn nn.MultiheadAttention(d, h, batch_firstTrue) self.ffn nn.Sequential(nn.Linear(d, f), nn.SiLU(), nn.Linear(f, d)) self.n1 nn.LayerNorm(d) self.n2 nn.LayerNorm(d) def forward(self, x): n self.n1(x) a, _ self.attn(n, n, n) x x a return x self.ffn(self.n2(x)) class MHC(nn.Module): # 双流流形约束超连接读双流、跑层、按双随机矩阵写回 def __init__(self, d, streams, iters): super().__init__() self.read nn.Linear(d * streams, streams) self.mix_logits nn.Parameter(torch.randn(streams, streams) * 0.5) self.write nn.Linear(d, streams) self.iters iters def forward(self, streams, layer_fn): cat torch.cat(streams, dim-1) rw torch.softmax(self.read(cat), dim-1) x sum(rw[..., s:s 1] * streams[s] for s in range(len(streams))) out layer_fn(x) mix sinkhorn(self.mix_logits, self.iters) ww torch.softmax(self.write(out), dim-1) return [sum(mix[s, t] * streams[t] for t in range(len(streams))) ww[..., s:s 1] * out for s in range(len(streams))] class LoopDecoder(nn.Module): def __init__(self, cfg): super().__init__() self.cfg cfg self.emb nn.Embedding(cfg[vocab], cfg[d_model]) self.layers nn.ModuleList( Block(cfg[d_model], cfg[n_heads], cfg[d_ff]) for _ in range(cfg[n_layers])) self.mhc MHC(cfg[d_model], cfg[mhc_streams], cfg[sinkhorn_iters]) self.head nn.Linear(cfg[d_model], cfg[vocab], biasFalse) self.exec_count 0 def forward(self, idx): c self.cfg h self.emb(idx) for i in range(c[loop_start]): # 头部 0-3 层 h self.layers[i](h); self.exec_count 1 streams [h, h.clone()] # 开两条残差流 for _ in range(c[loop_passes]): # [4,28) 跑两遍 for i in range(c[loop_start], c[loop_end]): streams self.mhc(streams, self.layers[i]) self.exec_count 1 h sum(streams) / len(streams) for i in range(c[loop_end], c[n_layers]): # 尾部 28-31 层 h self.layers[i](h); self.exec_count 1 return self.head(h) torch.manual_seed(0) model LoopDecoder(CFG) logits model(torch.randint(0, CFG[vocab], (1, 16))) stored_layers len(model.layers) assert stored_layers 32, f存储层数应为 32实际 {stored_layers} assert model.exec_count 4 24 * 2 4 56 mix sinkhorn(model.mhc.mix_logits, CFG[sinkhorn_iters]) assert torch.allclose(mix.sum(-1), torch.ones(2), atol1e-2) assert torch.allclose(mix.sum(-2), torch.ones(2), atol1e-2) print(f存储权重层数: {stored_layers}) print(f实际层执行次数: {model.exec_count}) print(f输出 logits 形状: {tuple(logits.shape)}) print(fSinkhorn 混合矩阵行和: {mix.sum(-1).tolist()}) print(fSinkhorn 混合矩阵列和: {mix.sum(-2).tolist()})跑完之后四个断言全部通过存储层数 32、执行次数 56、混合矩阵行和与列和都收敛到 1 附近。这个复现还暴露了一个实现细节循环块的两次执行共享 ModuleList 里的同一批模块权重从头到尾只有一份翻倍的只是计算图。把 d_model 换成 4096、d_ff 换成 12288、词表换成 248,320参数统计就会落到 9B 量级和官方规格表完全对上。训练侧有一个注意点共享权重的模块在反向传播时会收到两遍执行累加的梯度优化器实际看到的是两个时间步梯度之和学习率口径和稠密模型不能直接对齐。推理内核侧的接口形状也要先对齐进入循环块时把隐藏状态复制成两条残差流离开循环块时再取平均合并自定义算子必须完整复现这个分叉再汇合的结构。如果要把这个复现改成生产实现还需要补上三件事混合注意力的层型交替、M-RoPE 的部分维度旋转、以及循环块两次执行各自独立的 KV 缓存槽位。这段复现在纯 CPU 上几秒钟就能跑完不依赖 GPU 和任何外部权重文件读者可以直接改配置做自己的结构实验。比如把 loop_passes 改成 3执行次数会变成 76等效参数进一步上涨这就是官方说的自适应迭代次数机制的雏形。七、部署现实推理框架还没跟上官方核对的推理环境是 Transformers 5.18.0 加 PyTorch 2.11.0CUDA 13.0加载时必须带 trust_remote_codeTrue走仓库自带的自定义实现。本地推理三件套的现状要泼一盆冷水llama.cpp、LM Studio、Ollama 目前都还不认识 sensenova_loop 这个新架构。社区能用的 GGUF 来自 AtomicChat作者明确标注文件是用打过补丁的 llama.cpp 构建的基于 ggml-org/llama.cpp 的 commit 5047748f11上游支持 PR 仍在排队。这批 GGUF 目前只覆盖文本部分视觉塔没有包含在内多模态能力暂时只能走官方 PyTorch 路径。推理加速方面MTP 多 token 预测已经可用Dspark 和 Dflash2 两种加速方案还处在训练阶段。训练侧商汤放出了自己的 torchtitan 分支单机 8 卡可以对 Loop-9B 做带 mHC 的微调脚本和配置都挂在 GitHub 仓库里。对想尝鲜的团队现实路径只有一条官方 Transformers 路线单卡 BF16 起步等 llama.cpp 上游合并之后再考虑端侧量化部署。部署清单值得逐项核对配置、分词器、对话模板、自定义模型代码、权重分片五件套缺一不可缺任何一个 trust_remote_code 加载都会在中途报错。量化展望也值得提前算BF16 下 18GB 的权重意味着 INT8 后约 9GB、INT4 后约 4.5GB56 次执行带来的延迟会被量化换来的显存和带宽收益部分对冲。文本 GGUF 已经可以先跑起来做架构验证和长上下文压测等视觉塔进入移植版本之后再评估端侧多模态两条线不要互相等待。另一个现实约束是多模态输入的训练上下文口径262,144 token 是训练时的上限实际推理时的有效长度还受显存和位置外推能力约束需要按场景实测。生态响应速度可以参考先例Qwen 系新架构从发布到 llama.cpp 合并通常以周计sensenova_loop 有官方权重和活跃社区适配周期大概率不会拖太久。在此期间做技术选型的团队可以先用官方环境跑通任务基线把准确率和延迟数据记录下来等端侧链路成熟后直接平移配置。采购和评估环节还要把 Preview 标签写进预期管理这意味着权重、配置甚至架构细节都可能在正式版中调整基于它的微调投入要控制在小步验证的规模内。八、这条赛道还看什么Loop-9B 不是孤例。今年 Hyperloop Transformers 等研究已经证明给循环中间块配上超连接可以用约一半的参数追平深度对齐的标准模型。商汤的贡献是把这条研究线拉到了可用的多模态尺寸并且把 Qwen3.5 级骨干、Gated-DeltaNet、M-RoPE 这些现役组件一次性组装到位。官方路线图上有三个方向值得盯DSA 稀疏注意力、自适应迭代次数、以及更大规模下的循环 Scaling。自适应迭代次数最有想象力简单输入跑一遍循环困难输入跑三遍把计算深度变成按输入定价的可变资源。Preview 标签也在提醒边界这是一个架构探索版本真实 Agent 负载下的稳定性还需要社区实测数据回填。对显存受限的边缘和私有化场景循环计算给出了一条和量化、蒸馏正交的新路不压缩权重本身而是让同一份权重多干一遍活。接下来 30 天值得盯三个信号llama.cpp 上游支持 PR 是否合并、第三方独立评测能否复现 27B 级结论、Dspark 与 Dflash2 两种加速方案是否按期落地。对读者的行动建议很直接显存充裕的团队走官方 PyTorch 路径做 Agent 负载实测显存受限的团队等 GGUF 生态成熟架构研究者把重点放在 mHC 的混合矩阵约束上。量化掉的是数值精度蒸馏丢的是能力上限循环付出的只是延迟三种手段叠加起来的端侧模型组合会是明年最值得跟踪的工程方向。
阅读完成 · 觉得有帮助?