作者: 魏勇勤 (Wei Yongqin) 日期: 2026 年 9 月 1 日
配套论文: attention_logn_v2.pdf(仓库根目录,28 页)。
仓库: https://github.com/my21cn/attention_logn_v2
git clone https://github.com/my21cn/attention_logn_v2.git
cd attention_logn_v2本仓库实现 J-空间(Poincaré 球 B^d)中的共形注意力:query 被映到球体内部(半径 r < 1),key 被映到边界球面 S^{d-1}。注意力权重取为“把 query 移到球心的 Möbius 变换”在边界上诱导的 Jacobian 密度,即 K(q,ζ) = (1−r²)^γ / ‖q−ζ‖^{2s}。由 Newton 壳层定理,该核在边界球面上对三种 (s,γ) 取法都满足 E_σ[K] = 1,即归一化常数与 key 无关、与序列长度 n 无关——因此 不需要 softmax 的 max/sum 两次全局规约,可直接解析消去。因果聚合借助 Fenwick 规范分解 把“可加矩”组织成树结构,每 query 仅访问 O(log n) 个结点。总体复杂度:每 query O(log n)、总 O(n log n)、并行深度 O(log n)、自回归解码每 token O(log n)。
- Python ≥ 3.9
- torch(
conformal_attention.py/baselines.py依赖) - numpy(
certified.py依赖) - scipy、matplotlib(仅复现实验 / 核验脚本使用)
本仓库是纯源码,无需 pip install。把 src 目录加入 sys.path 即可:
import sys
sys.path.insert(0, r"C:\path\to\attention_logn_v2\src") # 换成你 clone 的实际位置或者用相对仓库根目录的写法(在仓库根目录下运行时):
import sys
sys.path.insert(0, "src")下面的所有示例都假设 src 已在 sys.path 上。
attention_logn_v2/
├── src/
│ ├── conformal_attention.py # 核心:配置/嵌入/核/归一化/精确与层级注意力/KV 树
│ ├── certified.py # 带证书的球树剪枝 + 精确参考 + 两种核的解析形式
│ └── baselines.py # softmax / 线性 / Performer / 稀疏 对照实现
├── experiments/
│ ├── run_experiments.py # E1–E9 全部实验入口(产物 results.json + figures/*.png)
│ ├── run_experiments2.py # 修订实验 E4b/E5b/E6b(远场精度、证书、检索)
│ ├── verify_mobius.py # Möbius 公式与主归一化恒等式数值核验
│ ├── verify_identities.py # 40 位精度独立核验(mpmath)
│ ├── verify_gegenbauer.py # 多极截断率与"驼峰"位置(任意精度)
│ ├── verify_readme.py # 抽取本文件的 python 代码块并实际执行
│ └── results.json # 所有实验的结构化结果(论文表格由此注入)
├── figures/ # 实验产出的 PNG 图(9 张)
├── paper/
│ ├── template.html # 论文 HTML 模板(A4 打印样式 + KaTeX)
│ ├── body_part1/2/3.py # 论文正文(第 1–6 节 / 7–9 节 / 附录)
│ ├── build_paper.py # 读 results.json → 渲染 attention_logn_v2.pdf
│ ├── fetch_assets.ps1 # 下载 KaTeX 渲染资源(assets/ 不入库)
│ ├── audit_pdf.py # PDF 结构自查(占位符/章节/图片/编号)
│ └── audit_layout.py # PDF 版面自查(越界/挤压检测)
├── LICENSE # 源代码:MIT
├── LICENSE-PAPER # 论文正文与插图:CC BY 4.0
├── readme.md # 本文件
└── attention_logn_v2.pdf # 配套论文
最小可运行例子:用精确共形注意力直接替换 softmax 注意力。
import torch
from conformal_attention import JSpaceConfig, conformal_attention
torch.manual_seed(0)
B, N, D, DV = 2, 128, 64, 32
q = torch.randn(B, N, D)
k = torch.randn(B, N, D)
v = torch.randn(B, N, DV)
cfg = JSpaceConfig(weight="newton", alpha=1.0) # alpha=1 复现标准温度
out = conformal_attention(q, k, v, cfg, normalize="analytic")
print(out.shape) # torch.Size([2, 128, 32])与 softmax 的对照(需要 baselines.py):
import torch
import baselines as B
from conformal_attention import JSpaceConfig, conformal_attention
torch.manual_seed(0)
q = torch.randn(1, 32, 16); k = torch.randn(1, 32, 16); v = torch.randn(1, 32, 8)
o_soft = B.softmax_attention(q, k, v, causal=True) # 标准 softmax
o_conf = conformal_attention(q, k, v, JSpaceConfig(alpha=1.0), causal=True)
print((o_soft - o_conf).abs().max().item()) # 两种注意力输出接近签名: JSpaceConfig(weight="newton", alpha=1.0, r_max=0.99999, s=None, gamma=None, eps=1e-12)
| 参数 | 默认值 | 含义 |
|---|---|---|
weight |
"newton" |
共形权重族:"newton"|"poisson"|"jacobian"|"custom",前三者都满足 E_σ[K]=1 |
alpha |
1.0 |
温度增益:beta = alpha * ‖q‖/sqrt(d) 与 softmax 的 logit = q·k/sqrt(d) 精确对齐;alpha=1 复现标准温度 |
r_max |
0.99999 |
半径数值上限,保证 1-r 不下溢 |
s |
None |
仅 weight="custom" 时显式指定指数 s |
gamma |
None |
仅 weight="custom" 时使用(默认按 0 处理) |
eps |
1e-12 |
范数的 clamp 下限 |
方法 exponents(d: int) -> (s, gamma):按 weight 返回 (s, gamma) ——
newton: ((d-2)/2, 0)(d≤2 时为 (1,1));poisson: (d/2, 1);jacobian: (d-1, d-1);custom: (s, gamma or 0)。
import torch
from conformal_attention import JSpaceConfig
cfg = JSpaceConfig(weight="newton", alpha=1.0)
print(cfg.exponents(64)) # (31.0, 0.0)
print(JSpaceConfig("poisson").exponents(64)) # (32.0, 1.0)
print(JSpaceConfig("jacobian").exponents(64)) # (63.0, 63.0)签名: beta_to_radius(beta: Tensor, s: float) -> Tensor;radius_to_beta(r: Tensor, s: float) -> Tensor
温度与半径的闭式互逆映射:
r(β) = (√(s²+β²) − s) / β,β(r) = 2s r / (1−r²)。
无界的温度被一一映射为有界半径(β→0 ⇒ r→0 均匀注意力,β→∞ ⇒ r→1⁻ δ 注意力)。
import torch
from conformal_attention import beta_to_radius, radius_to_beta
s = 31.0
beta = torch.tensor([[4.0]])
r = beta_to_radius(beta, s)
beta_back = radius_to_beta(r, s)
print(float(r), float(beta_back)) # 0.0629... 4.0(互逆)签名: jspace_embed(q, k, cfg=JSpaceConfig()) -> (r, qhat, zeta)
把 (q, k) 嵌入 J-空间。返回三元组:r(形状 (..., n, 1),查询半径,严格 <1)、qhat((..., n, d),查询方向)、zeta((..., m, d),key 的边界点)。
import torch
from conformal_attention import JSpaceConfig, jspace_embed
q = torch.randn(1, 8, 64); k = torch.randn(1, 8, 64)
r, qhat, zeta = jspace_embed(q, k, JSpaceConfig(alpha=1.0))
print(r.shape, qhat.shape, zeta.shape) # torch.Size([1,8,1]) [1,8,64] [1,8,64]签名: conformal_log_weights(qhat, zeta, r, s) -> Tensor;conformal_weights(qhat, zeta, r, s) -> Tensor
计算解析 max-subtraction 形式 K̃ = K/K(u=1) ∈ (0,1]:
log K̃ = −s·log1p( (2r/(1−r)²)·(1−u) ),其中 u = ⟨q̂, ζ⟩。conformal_weights 即其 exp。
import torch
from conformal_attention import JSpaceConfig, jspace_embed, conformal_log_weights, conformal_weights
cfg = JSpaceConfig("newton", alpha=1.0)
s, _ = cfg.exponents(64)
q = torch.randn(1, 8, 64); k = torch.randn(1, 8, 64)
r, qhat, zeta = jspace_embed(q, k, cfg)
lw = conformal_log_weights(qhat, zeta, r, s) # log K~, 形状 (1,8,8)
w = conformal_weights(qhat, zeta, r, s) # K~ ∈ (0,1]
print(w.shape, bool((w <= 1.0).all()))签名: conformal_normalizer(r, d, cfg=JSpaceConfig()) -> Tensor;log_conformal_normalizer(r, d, cfg=JSpaceConfig()) -> Tensor;resolution_limit(n, d, cfg=JSpaceConfig(), delta=1.0) -> float
conformal_normalizer:闭式归一化常数E_σ[K̃],复杂度O(1),不触碰任何 key。对 newton/poisson/jacobian 三种权重,E[K]=1故E[K̃]=1/K(u=1)=(1−r)^{2s}/(1−r²)^γ。log_conformal_normalizer:对数域计算,永不下溢。resolution_limit:J-空间的“奈奎斯特”分辨率上限r_n = 1 − (δ/n)^{1/(2s)}。当所需锐度r超过r_n时,解析常数不再是有限 n 下的好近似,应改用normalize="none"。
import torch
from conformal_attention import (JSpaceConfig, conformal_normalizer,
log_conformal_normalizer, resolution_limit)
d = 64
cfg = JSpaceConfig("newton", alpha=1.0)
r = torch.tensor([[0.3]])
print(float(conformal_normalizer(r, d, cfg))) # 与 key 无关的闭式常数
print(float(log_conformal_normalizer(r, d, cfg))) # 对数域
print(resolution_limit(n=4096, d=d, cfg=cfg)) # 分辨率上限 r_n签名: conformal_attention(q, k, v, cfg=JSpaceConfig(), causal=False, mask=None, normalize="analytic", return_weights=False)
精确共形注意力(O(n²)),drop-in 替换 softmax。q,k: (..., n, d),v: (..., m, dv)。
normalize 三种取值(重点):
"none":完全不归一化。权重∈(0,1],输出≤ Σ|v|有界,恒有限。适合超过resolution_limit的高锐度场景,或后续接 LayerNorm。"analytic"(默认):除以闭式常数cnt·E_σ[K̃](r)。O(1),不对 key 做任何跨-key 规约。这是本方法的核心卖点。"empirical":除以Σ_j K̃。等价 softmax 式的分母规约(O(n)),仅作消融对照,用于验证解析常数。
其他参数:causal=True 施加下三角屏蔽(支持 n_k ≥ n_q 的偏移);mask 是 bool 张量(True=保留);return_weights=True 返回 (out, w)(w 是实际参与 matmul 的权重)。
import torch
from conformal_attention import JSpaceConfig, conformal_attention
q = torch.randn(1, 32, 16); k = torch.randn(1, 32, 16); v = torch.randn(1, 32, 8)
cfg = JSpaceConfig(alpha=1.0)
o_none = conformal_attention(q, k, v, cfg, normalize="none") # 不归一化
o_ana = conformal_attention(q, k, v, cfg, normalize="analytic") # 解析常数
o_emp = conformal_attention(q, k, v, cfg, normalize="empirical") # 经验求和
o, w = conformal_attention(q, k, v, cfg, causal=True, return_weights=True)
print(o.shape, w.shape, o_none.shape, o_ana.shape, o_emp.shape)签名: ConformalAttention(dim, n_heads=8, cfg=JSpaceConfig(), normalize="analytic", learn_alpha=True, bias=False);forward(x, causal=True, mask=None) -> Tensor
多头共形注意力 nn.Module(精确版)。无 softmax、无 1/sqrt(d) 手工缩放、无跨-key 规约。
dim:模型隐藏维;n_heads:头数(须整除dim)。cfg:几何配置;normalize:三种归一化模式之一。learn_alpha:是否逐头学习温度增益(softplus(raw_alpha),初值约cfg.alpha)。bias:qkv与proj线性层是否带偏置。forward(x, causal, mask):x形状(B, N, dim),返回同形状。
import torch
from conformal_attention import ConformalAttention, JSpaceConfig
x = torch.randn(2, 64, 64)
attn = ConformalAttention(dim=64, n_heads=8, cfg=JSpaceConfig(alpha=1.0),
normalize="analytic", learn_alpha=True)
out = attn(x, causal=True)
print(out.shape) # torch.Size([2, 64, 64])签名: LandmarkConformalBasis(xi, r_far, s, ridge=1e-3)
远场可分离基 Ψ: S^{d-1} → R^m,使 K(q,ζ) ≈ a(q)ᵀ Ψ(ζ)。Ψ 与 q 无关 ⇒ 矩 M_B = Σ_{j∈B} Ψ(ζ_j) v_jᵀ 可加,父结点矩 = 子结点矩之和(O(1) 合并)——这是 O(log n) 的来源。
xi:地标,形状(m, d);r_far:远场分辨率上限(coeffs中r会被 clamp 到r_far);s:核指数;ridge:Kxx求逆的岭正则。
方法:
features(zeta) -> (..., n, m):键的基函数值。coeffs(qhat, r) -> (..., n, m):查询的展开系数。
import torch
from conformal_attention import JSpaceConfig, LandmarkConformalBasis
D, M = 64, 32
s, _ = JSpaceConfig("newton").exponents(D)
xi = torch.nn.functional.normalize(torch.randn(M, D), dim=-1)
basis = LandmarkConformalBasis(xi, r_far=0.5, s=s)
zeta = torch.nn.functional.normalize(torch.randn(8, D), dim=-1)
psi = basis.features(zeta) # (8, 32)
qhat = torch.nn.functional.normalize(torch.randn(1, D), dim=-1)
a = basis.coeffs(qhat, torch.tensor([[0.4]])) # (1, 32)
print(psi.shape, a.shape)签名: HierarchicalConformalAttention(n_landmarks=48, window=64, r_far=0.5, cfg=JSpaceConfig(), landmark_source="keys");forward(q, k, v, normalize="analytic") -> Tensor
因果层级共形注意力 = 精确近场(窗口 w)+ O(log n) 个规范块的压缩远场。单头复杂度:建树 O(n·m·dv);每 query O(w·d + log(n/w)·m·dv);并行深度 O(log n)。
n_landmarks(m):远场地标数;window(w):精确近场窗口。r_far:远场分辨率上限;cfg:几何配置。landmark_source:"keys"(从 key 均匀采样)或"random"(随机高斯)。forward(q,k,v,normalize):q,k形状(B,n,d)、v形状(B,n,dv);normalize仅支持"analytic"或"none"("empirical"会抛NotImplementedError,因它需要O(n)规约)。last_stats(dict,每次forward后更新):mean_far_nodes(平均访问的远场结点数)、max_far_nodes(最大远场结点数)、near_ops(近场窗口大小 =window)、n(序列长度)、landmarks(地标数 =n_landmarks)、total_per_query(mean_far_nodes + window,每 query 总操作数的估计)。
import torch
from conformal_attention import HierarchicalConformalAttention, JSpaceConfig
q = torch.randn(2, 128, 32); k = torch.randn(2, 128, 32); v = torch.randn(2, 128, 16)
h = HierarchicalConformalAttention(n_landmarks=32, window=32, r_far=0.5,
cfg=JSpaceConfig(alpha=6.0), landmark_source="keys")
out = h(q, k, v, normalize="analytic") # 因果:只看 j <= i
print(out.shape) # torch.Size([2, 128, 16])
print(h.last_stats) # {'mean_far_nodes': ..., 'max_far_nodes': ..., 'near_ops': 32, ...}签名: ConformalKVTree(basis, dv, d, cfg=JSpaceConfig(), window=64, max_len=1<<22, device="cpu", dtype=torch.float32)
流式共形 KV 树。append O(log n),query O(log n)——对比标准 KV-cache 的 O(n)。
basis:LandmarkConformalBasis实例;dv:值维度;d:key/query 维度。cfg:几何配置;window:精确近场环形缓冲区大小;max_len:最大序列长度;device/dtype:存储张量所在设备与精度。append(k, v) -> int:追加一个 key/value(k形状(d,)、v形状(dv,)),返回本次更新的结点数。query(q, normalize="analytic") -> Tensor:对单个 query(形状(d,))求因果注意力输出(形状(dv,))。last_nodes(int):最近一次query触发的结点数(含近场环形缓冲)。
import torch
from conformal_attention import ConformalKVTree, LandmarkConformalBasis, JSpaceConfig
D, DV, M = 32, 16, 32
s, _ = JSpaceConfig("newton").exponents(D)
xi = torch.nn.functional.normalize(torch.randn(M, D), dim=-1)
basis = LandmarkConformalBasis(xi, r_far=0.5, s=s)
tree = ConformalKVTree(basis, dv=DV, d=D, cfg=JSpaceConfig(alpha=6.0), window=16)
for _ in range(64):
tree.append(torch.randn(D), torch.randn(DV))
out = tree.query(torch.randn(D)) # 自回归式查询
print(out.shape) # torch.Size([16])
print(tree.last_nodes) # 本次查询触发的结点数签名: build_ball_tree(zeta, v, pos, leaf_size=16, depth=0, max_depth=64) -> Node;count_nodes(node) -> int
在单位球面上按主方向二分构建球树。zeta: (n,d) 单位向量;v: (n,dv);pos: (n,) 位置(用于因果前缀)。返回根 Node(含质心方向、角半径、按位置排序的 v 前缀和)。count_nodes 返回树中结点总数。
import numpy as np
from certified import build_ball_tree, count_nodes
rng = np.random.default_rng(0)
n, d, dv = 256, 16, 8
zeta = rng.normal(size=(n, d)); zeta /= np.linalg.norm(zeta, axis=1, keepdims=True)
v = rng.normal(size=(n, dv)); pos = np.arange(n)
root = build_ball_tree(zeta, v, pos, leaf_size=16)
print(count_nodes(root)) # 结点总数签名: certified_attention(qhat, root, kernel, r=0.3, s=15.0, beta=8.0, eps=1e-2, max_nodes=1<<20, causal_pos=None, analytic_den=None) -> Cert;exact_attention(qhat, zeta, v, kernel, r=0.3, s=15.0, beta=8.0, analytic_den=None, pos=None, causal_pos=None) -> np.ndarray
对单个 query 做带证书的注意力求值(最佳优先遍历 + 剪枝)。
qhat:查询方向(单位向量,(d,));root:球树根。kernel:"conformal"(分母取解析常数analytic_den,只需认证分子)或"softmax"(分母必须由遍历本身夹逼到相对精度eps)。r/s:共形核参数;beta:softmax 核逆温度;eps:目标相对误差;max_nodes:结点预算;causal_pos:因果位置上限;analytic_den:共形解析分母(= E_σ[K̃]·n)。
Cert 数据类字段:out(输出向量)、num_bound(分子的剩余不确定度)、den_lo/den_hi(分母上下界)、nodes(访问结点数)、leaves_exact(精确展开的叶子数)、rel_bound(相对误差界)。
import numpy as np, torch
from conformal_attention import conformal_normalizer, JSpaceConfig
from certified import build_ball_tree, certified_attention, exact_attention
rng = np.random.default_rng(0)
n, d, dv = 256, 16, 8
zeta = rng.normal(size=(n, d)); zeta /= np.linalg.norm(zeta, axis=1, keepdims=True)
v = rng.normal(size=(n, dv)); pos = np.arange(n)
root = build_ball_tree(zeta, v, pos, leaf_size=16)
qh = rng.normal(size=d); qh /= np.linalg.norm(qh)
s = (d - 2) / 2; r = 0.3
Z = float(conformal_normalizer(torch.tensor([[r]]), d, JSpaceConfig("newton"))) * n
cert = certified_attention(qh, root, "conformal", r=r, s=s, eps=1e-2, analytic_den=Z)
exact = exact_attention(qh, zeta, v, "conformal", r=r, s=s, analytic_den=Z)
print(cert.out.shape, cert.nodes, cert.rel_bound) # (8,) 结点数 相对误差界
print(np.linalg.norm(cert.out - exact)) # 与精确解一致签名: ktilde_conformal(u, r, s) -> np.ndarray;ktilde_softmax(u, beta) -> np.ndarray
两族核的“解析 max-subtraction”形式,值域均为 (0,1]:
K̃_conformal(u) = (1 + (1−u)/σ_h)^{-s}(σ_h = (1−r)²/(2r),重尾);K̃_softmax(u) = exp(β(u−1))(高斯尾)。
import numpy as np
from certified import ktilde_conformal, ktilde_softmax
u = np.linspace(-1, 1, 5)
print(ktilde_conformal(u, r=0.5, s=15.0)) # 共形核(重尾)
print(ktilde_softmax(u, beta=8.0)) # softmax 核(高斯尾)签名一览:
softmax_attention(q, k, v, causal=False, scale=None, dtype_acc=None)
softmax_attention_naive(q, k, v, causal=False, scale=None)
linear_attention(q, k, v, causal=False, feature="elu", eps=1e-6)
performer_attention(q, k, v, n_features=256, causal=False, seed=0, eps=1e-6)
sparse_attention(q, k, v, pattern="local", window=128, stride=64, n_global=8, topk=64, causal=True) -> (out, allow)
attn_matrix_softmax(q, k, causal=False)
attn_matrix_linear(q, k, causal=False, eps=1e-6)
softmax_attention:标准(数值稳定)softmax,含 max/sum 两次跨-key 规约;scale默认1/sqrt(d),dtype_acc可指定高精度累积。softmax_attention_naive:不做 max-subtraction 的朴素 softmax,用于演示动态范围导致的溢出。linear_attention:Katharopoulos 线性注意力(phi(q)(phi(k)ᵀv)/(phi(q)·Σphi(k))),秩受限。performer_attention:FAVOR+ 正随机特征逼近 softmax。sparse_attention:稀疏注意力;pattern="local"|"strided"|"topk",返回(out, allow)(allow是参与 mask)。attn_matrix_softmax/attn_matrix_linear:返回显式注意力矩阵(用于谱分析等)。
import torch
import baselines as B
q = torch.randn(2, 32, 16); k = torch.randn(2, 32, 16); v = torch.randn(2, 32, 8)
o1 = B.softmax_attention(q, k, v, causal=False)
o2 = B.softmax_attention_naive(q, k, v)
o3 = B.linear_attention(q, k, v)
o4 = B.performer_attention(q, k, v, n_features=64)
o5, allow = B.sparse_attention(q, k, v, pattern="local", window=8, causal=True)
A_soft = B.attn_matrix_softmax(q, k)
A_lin = B.attn_matrix_linear(q, k)
print(o1.shape, o2.shape, o3.shape, o4.shape, o5.shape, A_soft.shape, A_lin.shape)| 模式 | 是否需要跨-key 规约 | 复杂度 | 数值范围 | 推荐场景 |
|---|---|---|---|---|
"none" |
否 | O(1) | 权重 ∈(0,1],输出 ≤ Σ|v| 恒有限 |
高锐度(超过 resolution_limit)、超长序列/流式、后接 LayerNorm |
"analytic" |
否(闭式常数) | O(1) | 对数域计算,与 softmax 同量级 | 默认:常规训练与推理 |
"empirical" |
是(Σ_j K̃) |
O(n) | 与 softmax 相同 | 消融对照,验证解析常数 |
在仓库根目录运行(Windows 路径):
# 运行全部实验 E1–E9
python experiments\run_experiments.py
# 只运行 E4(Fenwick 矩树)与 E8(自回归解码代价)
python experiments\run_experiments.py E4 E8产物:
experiments/results.json:所有实验的结构化结果。figures/*.png:9 张图(fig_normalizer、fig_stability、fig_kernel、fig_nodes、fig_farfield、fig_certified、fig_recall、fig_spectrum、fig_decode)。
补充实验(远场精度、带证书剪枝、检索对比):
python experiments\run_experiments2.py # E4b E5b E6b
python experiments\run_experiments2.py E6b # 只跑检索对比其他脚本:
# 核验 Möbius 公式(球→球、边界共形因子、主归一化恒等式、温度-半径互逆)
python experiments\verify_mobius.py
# 40 位精度独立核验三个经典配平(需要 mpmath)
python experiments\verify_identities.py
# 多极截断率与前渐近"驼峰"位置(任意精度)
python experiments\verify_gegenbauer.py
# 抽取本 README 的全部 python 代码块并实际执行
python experiments\verify_readme.py需要 Microsoft Edge(用其 headless 模式打印 PDF)与 KaTeX 资源。KaTeX 属第三方资源, 未纳入版本库,首次构建前先下载一次:
pwsh -File paper\fetch_assets.ps1 # 下载到 paper/assets/katex(约 3 MB,仅需一次)
python paper\build_paper.py # 读 results.json → 生成 attention_logn_v2.pdf构建后可自查产物:
python paper\audit_pdf.py # 章节、图片、定理编号、占位符残留
python paper\audit_layout.py # 越界与版面挤压检测alpha(温度):与 softmax 温度的对应关系为β = alpha·‖q‖/√d。alpha=1复现标准温度。温度与半径通过r=(√(s²+β²)−s)/β与β=2sr/(1−r²)闭式互换,因此可直接“以半径思考”:小r→ 均匀注意力,大r(→1)→ δ 注意力。window:层级版本的精确近场窗口。越大越接近精确解但近场开销线性增长;典型取 32–128。近场与远场在r_far处无缝衔接。n_landmarks:远场 Nyström 地标数(基的秩)。越大远场逼近越好,但建树/查询开销随m·dv线性增长;典型 32–96。r_far:远场分辨率上限,coeffs中r被 clamp 到r_far,决定远场展开的截断阶一致性。典型0.5;与n_landmarks一起控制远场精度。- J-空间分辨率上限
resolution_limit(n, d):r_n = 1 − (δ/n)^{1/(2s)}。当所需锐度r超过r_n时,解析归一化常数n·E_σ[K̃]不再是有限 n 下的好近似——此时应改用normalize="none"(恒有限)或"empirical"。高维(大s)下r_n会显著偏低,务必先检查。
from conformal_attention import JSpaceConfig, resolution_limit
for d in [8, 16, 32, 64, 128]:
print(f"d={d:3d} n=4096 -> resolution_limit = {resolution_limit(4096, d, JSpaceConfig('newton')):.3f}")Q1:为什么不需要 softmax?
softmax 需要 max_j(数值稳定)与 sum_j(归一化)两次跨-key 全局规约。共形权重由 Newton 壳层定理给出 E_σ[K]=1,归一化常数是仅关于 r 的闭式函数,与 key、与 n 都无关,因此这两次规约被解析消去。这使注意力变成“可加矩”算子,可用 Fenwick 树在 O(log n) 内求值。
Q2:输出量级变化很大怎么办?
共形权重 K̃∈(0,1] 天然有界;若仍需稳定尺度,可在注意力后接 LayerNorm(Transformer 的常规做法),或使用 normalize="analytic" 使输出与 softmax 同量级。
Q3:fp16 会溢出吗?
conformal_log_weights 全程在对数域计算且权重有界,log-weight 动态范围随 β 增大而饱和(见 E2),不像 softmax 的 logit 范围线性发散。极端场景下仍建议 fp32/bf16 累积,或将 dtype_acc 传入对照的 softmax 基线。
Q4:高维下层级版本精度不够怎么办?
增大 n_landmarks(远场秩)、减小 r_far(让更多质量落到精确近场)、或增大 window。注意高维下 resolution_limit 偏低,若解析归一化失效,改用 normalize="none"。
Q5:如何做多头?
直接用 ConformalAttention(dim, n_heads=...),内部已实现 qkv 线性投影 + 逐头可学习温度(learn_alpha)+ 输出投影,与标准多头接口一致。
Q6:如何与 RoPE 位置编码结合?
可以。共形权重只依赖方向夹角 u = ⟨q̂, ζ⟩,而 key 的归一化 ζ = k/‖k‖ 保留方向信息——把 RoPE 旋转作用在 q, k 的方向上(即旋转后再进入 jspace_embed 的归一化)即可照常编码位置,不会破坏 J-空间构造。
@misc{wei2026conformal,
author = {魏勇勤},
title = {共形注意力:J-空间中的免归一化与对数复杂度注意力机制},
year = {2026},
month = {9},
howpublished = {\url{https://github.com/my21cn/attention_logn_v2}},
note = {Conformal Attention: Normalisation-Free, Logarithmic-Complexity Attention in J-Space}
}本仓库采用双许可:
| 内容 | 许可证 | 文件 |
|---|---|---|
源代码(src/、experiments/、paper/ 下的构建与自查脚本) |
MIT | LICENSE |
论文正文与插图(attention_logn_v2.pdf、paper/body_part*.py、figures/) |
CC BY 4.0 | LICENSE-PAPER |
第三方资源:论文渲染使用 KaTeX(MIT),由 paper/fetch_assets.ps1
在构建时下载,不随本仓库分发。
复用论文内容请按 LICENSE-PAPER 中的建议方式署名 魏勇勤。