线性代数
这一部分落在 TRG 主线的「一步 SVD 截断加收缩」和「分段求导得内能」上。TRG 每一步做两次 SVD,留前 k 个奇异值和奇异向量,再收缩成新的局部张量;求内能时,反向要穿过每一次 SVD。JAX 的 jnp.linalg 和 tenferro 的 TracedTensorLinalgExt 在普通矩阵上给出同样的梯度,差别出在三处:奇异向量的符号,奇异值重复或为 0 时的求导规则,以及截断 SVD 输出时的形状元数据。每页都是同一个任务的两份程序(有的地方加一份 PyTorch),数字从实测输出里贴。分解怎么落到 faer、反向规则怎么写,见 tenferro 卷的线性代数。
- 分解的梯度:svd、eigh、qr、solve 四个损失,两边对中心差分都在 1e-9 量级,彼此差 1e-15 量级;奇异向量、特征向量的符号不同,所以损失要和符号无关,
SvdGauge::CanonicalPivot能定一个符号;秩亏的测试矩阵两边都对不上差分,恰好为 0 的奇异值两边都给 NaN;solve的右端项必须是二维的。 - 简并奇异值:TRG 从第 5 步起,JAX 内置
jnp.linalg.svd和 PyTorch 的梯度是 NaN,因为第 4 步的矩阵里有成对相等的奇异值,1/(s_j² − s_i²)除以 0;tenferro 默认的展宽规则给出有限、正确的梯度;JAX 里用custom_jvp补上同样的规则,以及jit把s_j**2 - s_i**2融合成 FMA、梯度变成 1e120 的坑。 - SVD 的输出:
jnp.linalg.svd默认返回满矩阵,tenferro 默认是薄的;对 SVD、QR 的输出直接切片再求导会报slice input requires constant exact or upper-bound extents,先 reshape、用掩码或take_axis都能绕开;k 由数据决定时两边的写法;faer 给出恰好为 −0 的奇异值,sqrt(s)的梯度是 NaN。
flowchart TB t["局部张量 T"] --> m["transpose reshape"] m --> svd["SVD"] svd --> sign["符号 规范"] svd --> deg["简并 求导规则"] svd --> cut["截断 前 k 个"] cut --> sq["sqrt s"] sq --> c["收缩成 T'"] c --> t
💬 关联讨论
发起讨论加载中...