一棵家谱变成 0/1 矩阵,再叠成张量 左边写着 einsum、"xy,yz->xz" 和 :- Sister, Parent。右边一棵三代的小家谱,其中一个节点是强调色;虚线通往一个 4×4 的方格矩阵,几个格子点亮;再通往一个立方体张量,表面有两个点亮的小块。 einsum "xy,yz->xz" :- Sister, Parent

逻辑编程里有一条教科书式的规则:x 是 y 的姐妹,y 是 z 的父母,那么 x 是 z 的姑姑或姨妈。用 Datalog 写出来是这样:

Aunt(x, z) :- Sister(x, y), Parent(y, z).

而用 numpy 写,是这样一行:

Python
Aunt = np.einsum("xy,yz->xz", Sister, Parent) > 0

华盛顿大学的 Pedro Domingos 在 2025 年 10 月的论文《Tensor Logic: The Language of AI》里说,这两行不只是“结果碰巧一样”,它们本来就是同一种运算;而且神经网络、逻辑推理、核方法、概率图模型,全都可以只用这一种语句写出来1。他据此提出一门新语言,名字就叫张量逻辑(tensor logic),并且说它能在嵌入空间里做“可靠、透明、不会幻觉”的推理。

这话听上去很大。逻辑规则和矩阵乘法真的是一回事吗?如果是,为什么符号 AI 和神经网络各走各路走了几十年?只剩一种语句的语言长什么样,能不能真把规则学出来、真不幻觉?我们就从上面这一行 einsum 开始,边跑代码边往下看。

一、规则与 einsum 的对应

先认识两边

Datalog 是最简单的逻辑编程语言,可以看成去掉函数符号的 Prolog。一个 Datalog 程序由两样东西组成:事实,比如 Parent(舅舅, 表妹),说的是“舅舅是表妹的父母”;规则,比如上面那条 Aunt,箭头(:-)左边叫头,右边叫体,体里的逗号是“并且”。规则的意思是:只要能找到一组取值,让体里的每一项都是已知事实,头就成立。

einsum(爱因斯坦求和)是一种写张量运算的记号。张量就是多维数组:向量有一个下标,矩阵有两个。"xy,yz->xz" 的意思是:第一个矩阵的下标叫 x、y,第二个叫 y、z,结果保留 x、z;在箭头右边没出现的下标 y,要被求和掉。所以它就是矩阵乘法 Cxz=∑yAxyByzC_{xz} = \sum_y A_{xy} B_{yz}。

现象:两边算出同样的五条

我们拿一个七口之家试一下:外婆有三个孩子,妈妈、小姨和舅舅;妈妈有“我”,舅舅有表妹和表弟。把 Sister 和 Parent 各写成一个 7×7 的 0/1 矩阵,第 x 行第 y 列是 1 就表示这条事实成立,再跑上面那行 einsum:

einsum[妈妈,表妹] = 1 经由 y = ['舅舅'] -> Aunt = 1
einsum[妈妈,表弟] = 1 经由 y = ['舅舅'] -> Aunt = 1
einsum[小姨,我] = 1 经由 y = ['妈妈'] -> Aunt = 1
einsum[小姨,表妹] = 1 经由 y = ['舅舅'] -> Aunt = 1
einsum[小姨,表弟] = 1 经由 y = ['舅舅'] -> Aunt = 1

五条结果,和按 Datalog 规则一条条推出来的完全一样2。

原因:关系就是布尔张量

为什么会一样?把规则拆开看,每一部分都能在 einsum 里找到对应。

同一条姑姨规则的 Datalog 写法和 einsum 写法 上半部分是 Datalog 规则和六条事实。下半部分是 Sister 矩阵乘 Parent 矩阵:两者共享的下标 y(妈妈、舅舅)被求和,得到每对 x、z 之间有几个 y 能连起来的计数矩阵,再经过阶跃函数 H 得到 Aunt 矩阵。小姨对我、表妹、表弟都是 1,妈妈对表妹、表弟是 1。 Datalog 写法 Aunt(x, z) :- Sister(x, y), Parent(y, z). Sister(小姨, 妈妈) Sister(小姨, 舅舅) Sister(妈妈, 舅舅) Parent(妈妈, 我) Parent(舅舅, 表妹) Parent(舅舅, 表弟) 逗号是“并且”,y 只在体里出现, 意思是“存在某个 y” einsum 写法 Aunt[x,z] = H( Sister[x,y] Parent[y,z] ) Σ y H × 妈妈 舅舅 小姨 妈妈 1 1 0 1 我 表妹 表弟 妈妈 舅舅 1 0 0 0 1 1 我 表妹 表弟 小姨 妈妈 1 1 1 0 1 1 我 表妹 表弟 小姨 妈妈 1 1 1 0 1 1 Sister[x,y] Parent[y,z] 计数:有几个 y Aunt[x,z] 每一格数的是“有几个 y 能把 x 和 z 连起来”。这家人每格最多 1 个,计数和结果看不出差别; 若再加一条 Parent(妈妈, 表妹),小姨→表妹 这格会数出 2,H 把它压回 1。
图 1 · 关系是 0/1 矩阵,“并且”是相乘,只在体里出现的变量被求和,阶跃函数把路径计数压回真假

关系就是布尔张量。 一个二元关系 Parent(y, z) 等价于一个 0/1 矩阵,三元关系就是一个三维的 0/1 数组。论文把这句话反过来说:关系是稀疏布尔张量的一种紧凑写法,只列出值为 1 的那些格子。

体里的逗号是乘法,共享的变量是共享的下标。 两个 0/1 数相乘,只有都为 1 时才是 1,正好是“并且”。Sister(x, y) 和 Parent(y, z) 用的是同一个 y,对应到 einsum 里就是两边用同一个下标 y。数据库里把这叫连接(join):把两张表里 y 相同的行拼起来。

只在体里出现的变量被求和。 头里只有 x 和 z,y 没出现,einsum 就把 y 求和掉。数据库里这叫投影(projection):把不需要的列扔掉。逻辑上,它对应的是“存在某个 y”。

最后套一个阶跃函数。 求和得到的是“有几个 y 能连起来”,可能大于 1;比如表妹若同时是妈妈和舅舅的孩子,小姨就能经由两条路成为她的姨妈,这一格会数出 22。逻辑只关心真假,所以论文在外面套了一个阶跃函数 H(x)H(x):大于 0 就是 1,否则是 0。写成公式就是:

Auntxz=H(∑ySisterxy Parentyz)\text{Aunt}_{xz} = H\Big(\sum_y \text{Sister}_{xy}\,\text{Parent}_{yz}\Big)

这就是论文的核心观察:一条 Datalog 规则,等于在布尔张量上做一次 einsum,再逐元素过一个阶跃函数。体里有几项就是几个张量相乘,关系有几元就是几维;对应关系对任意多项、任意元数都成立。

递归规则:反复做到不动点

再看一条递归的规则,祖先:父母是祖先,祖先的孩子的祖先也是祖先。

Ancestor(x, y) :- Parent(x, y).
Ancestor(x, z) :- Ancestor(x, y), Parent(y, z).

Datalog 的标准算法叫前向链:把所有规则拿到已知事实上反复用,推出新事实,加进去,再用,直到一轮下来什么新东西都推不出为止。这个“推不出新东西”的状态叫不动点。换成矩阵,就是反复算 A←H(A+AP)A \leftarrow H(A + A P),直到 AA 不再变化。在那个七口之家上,第一轮新增了外婆是“我”、表妹、表弟的祖先这三条,第二轮什么也没新增,停下2。

到这里,“规则就是 einsum”是站得住的。而 einsum 本来就是神经网络里最常用的运算:全连接层、卷积、注意力,几乎都能写成 einsum3。那么,能不能干脆只保留这一种语句,用它把两边都写出来?

二、只有一种语句的语言

张量方程

论文的回答是能,并且把这当成整门语言的定义。张量逻辑程序就是一组张量方程,每条方程长这样:

Aunt[x, z] = H(Sister[x, y] Parent[y, z])

左边是要算的张量,右边是几个张量的连接,加一个可选的逐元素非线性函数(阶跃、sigmoid、ReLU 都行)。规则只有这么几条:右边有、左边没有的下标被求和;没算出来的元素默认是 0;左边相同的几条方程结果相加(这正好对应 Datalog 里同名的几条规则取“或”)。用圆括号写的张量表示布尔张量,所以任何 Datalog 程序原样就是合法的张量逻辑程序1。

论文说这就是全部定义:没有关键字,没有别的语句。为了方便,可以加一些语法糖,比如下标里写 t+1、用 max= 代替默认的求和、softmax,但它们不增加表达能力。

现象:神经网络和图模型都写得进去

有了这一种语句,论文第 4 节把几类 AI 方法挨个写了一遍。挑几条放在一起看:

几种 AI 方法写成张量方程(摘自论文第 3、4 节)
方法张量方程说明
感知机Y = step(W[i] X[i])i 被求和,就是点积
多层感知机X[i,j] = sig(W[i,j,k] X[i-1,k])i 是层号,一条方程写完所有层
卷积层F[x,y] = relu(K[dx,dy,ch] Img[x+dx,y+dy,ch])下标里可以写加法
图神经网络聚合Agg[n,l,d] = Neig(n,n') Z[n',l,d]邻接关系是布尔张量,乘上就把非邻居清零
注意力Comp[p,p'.] = softmax(Q[p,dk] K[p',dk] / sqrt(Dk))
Attn[p,dv] = Comp[p,p'] V[p',dv]
整个 Transformer 约十几条方程
核机器Y[Q] = f(A[i] Y[i] K[Q,i] + B)核函数另写一条方程
贝叶斯网络P_X[x] = CPT[x,p1,p2] P_1[p1] P_2[p2]边缘化是投影,因子相乘是连接
Datalog 规则Aunt(x,z) = Sister(x,y) Parent(y,z)布尔张量,原样可用

论文还用带“虚拟下标”的 RNN 推出张量逻辑是图灵完备的。

图 2 · 神经网络、核方法、概率图模型和逻辑规则,写出来都是同一种“连接 + 求和 + 非线性”

这张表里,左边那一列来自完全不同的几个学派,右边的写法却是同一个模子。

推理和学习也只有一套

推理有两种方式,都是从 Datalog 搬过来的。前向链把方程当成一段顺序代码,挨个执行,能算的元素都算出来,重复到不动点或满足停止条件;后向链把每条方程当成函数,从要问的那个张量出发,递归地去调右边那些张量的方程,只算用得到的元素。

学习靠求导。因为只有一种语句,求导规则也只有一条:不看非线性,方程左边对右边某个张量的导数,就是右边其余张量的乘积。比如 Yij=MikXkjY_{ij} = M_{ik} X_{kj},∂Yij/∂Mik=Xkj\partial Y_{ij}/\partial M_{ik} = X_{kj}。所以一个张量逻辑程序的梯度,本身也是一个张量逻辑程序。第六节学规则时,我们会用数值差分核对这一点。

第一次尝试的疑问:这不就是 einsum 吗

读到这里,很自然会有一个疑问:PyTorch 和 numpy 里早就有 einsum,上面那张表的每一行都能直接用它写出来,张量逻辑多了什么?

论文的回答是,Python 的张量库只管求导和 GPU,不管推理和知识;逻辑语言只管推理,不管学习和扩展。张量逻辑想做的是让同一个程序里,布尔的事实和规则、实数的权重和嵌入可以混在一起写、一起推理、一起求导。

可是反过来想,既然 einsum 在每个深度学习框架里都有,为什么没人拿它来跑 Datalog?用矩阵跑规则,代价在哪里?

三、稀疏关系的代价

现象:结果一样,速度差了上千倍

我们生成一个随机家谱:N 个人,每人平均有一个更早出生的父母,然后用两种办法算出全部祖先关系。一种是 Datalog 引擎常用的半朴素求值:存一个事实集合,每一轮只拿上一轮新推出的事实去连接;另一种是上面的稠密矩阵写法,每一轮做一次 N×N 的矩阵乘法。

随机家谱上求全部祖先关系:集合求值 vs 稠密矩阵
人数 N父子事实推出祖先集合求值稠密矩阵矩阵里非零的比例
5005094,1336.4 ms189 ms1.65%
1,0009356,1593.6 ms407 ms0.62%
2,0001,98016,61311.8 ms2.7 s0.42%
4,0004,04945,55527.6 ms24.4 s0.28%

两种办法推出的祖先关系逐条比对完全一致。迭代轮数相同(4000 人时 40 轮)。numpy float32,4 核 CPU。

图 3 · 结果完全一样,但矩阵里 99% 以上是 0,稠密写法把时间花在了乘 0 上

原因:矩阵要为不存在的事实付钱

原因就在最后一列。4000 个人的祖先关系有 4.5 万条,可 4000×4000 的矩阵有 1600 万个格子,99.7% 是 0。集合求值只碰真实存在的事实,事实多一倍,时间大约多一倍;矩阵乘法每轮要做 N3N^3 次乘加,人数翻倍,每轮就慢 8 倍,加上轮数也在增加,总时间涨了约 9 倍。

换到 GPU 上,常数会小很多,但阶数不变。更麻烦的是维数:一个三元关系是 N3N^3 个格子,论文自己也说,用元组列表代替稠密张量,省下的空间随元数指数增长。所以用稠密 einsum 跑规则,在“几个人的家谱”上很优雅,在真实的知识库上走不通。

论文给的两条路

论文第 6 节承认了这一点,给了两条路1。

第一条是分工:稠密的部分交给 GPU,稀疏的部分当成关系交给数据库查询引擎,用上数据库几十年的查询优化。这条路靠得住,但它其实就是今天大家在做的事:向量算在框架里,关系存在数据库里,中间写胶水代码。张量逻辑在这里的作用,是把两边写成同一种记号。

第二条是论文更看好的:把稀疏张量分解成稠密的小张量,全部放到 GPU 上算。论文说这比直接操作稀疏张量“指数级更高效”,而且随机的分解就够用,代价是有一点出错的概率。这条路通向论文第 5 节,也是论文自己说最有意思的部分:在嵌入空间里推理。把关系压进嵌入以后,推出来的东西还对吗?

四、在嵌入空间里推理

先从一个集合开始

嵌入就是给每个对象分配一个 D 维向量。论文先考虑最简单的情况:每个对象一个随机的单位向量。D 足够大时,两个随机单位向量几乎正交,点积在 0 附近,标准差约 1/D1/\sqrt{D};一个向量和自己的点积是 1。

想存一个集合,比如“哪些人喜欢猫”,就把集合里每个人的向量加起来,得到一个向量 SS。问某人 A 在不在集合里,算 S⋅eAS \cdot e_A:A 在里面,结果约等于 1;不在,约等于 0。噪声来自集合里另外 N 个向量和 eAe_A 的点积,标准差约 N/D\sqrt{N/D}。取 ½ 当阈值,就能判断在不在,出错的概率随 D 增大而减小。论文把它比作 Bloom filter:一种用固定大小的位数组判断“是否在集合里”的数据结构,可能误报,不会漏报4。

我们用 5000 个对象试了一下,集合外得分的标准差和 N/D\sqrt{N/D} 吻合得很好:D=1024、N=50 时实测 0.211,理论 0.221;这时错判率 0.92%。集合放到 200 个,错判率涨到 12%2。

再存一个关系

同样的办法可以存关系。一条事实 Parent(Bob, Carl) 用两个向量的外积 eBob⊗eCarle_{Bob} \otimes e_{Carl} 表示,得到一个 D×D 的矩阵;把所有事实的外积加起来,就是整个关系的嵌入:

EmbRij=∑(x,y)∈Rex,i ey,j\text{EmbR}_{ij} = \sum_{(x,y) \in R} e_{x,i}\, e_{y,j}

这是 Smolensky 在 1990 年提出的张量积表示5。查询 Parent(A, B) 时,用 eAe_A 和 eBe_B 从两边各点一次:DAB=eA⊤ EmbR eBD_{AB} = e_A^\top\, \text{EmbR}\, e_B。展开后,每条事实贡献 (ex⋅eA)(ey⋅eB)(e_x \cdot e_A)(e_y \cdot e_B),只有 x=Ax=A、y=By=B 那条贡献约 1,其余都是接近 0 的噪声。

把关系叠加进一个 D×D 矩阵,再用两次点积取回 左边是存:1000 条 Parent 事实,每条是两个 256 维随机向量的外积,全部加成一个 256×256 的 EmbR。右边是取:对 2000 个对象的 400 万个候选对算 e_A·EmbR·e_B,不在关系里的对得分集中在 0 附近,标准差 0.139;真事实集中在 1 附近。阈值 0.5 处有一条虚线,越过它的假事实约 1122 条,比真事实还多。 存 · 每条事实一个外积,叠成一块 取 · 两次点积,得分 = 信号 + 噪声 EmbR[i,j] 256 × 256 + e_Bob ⊗ e_Carl Parent(Bob, Carl) + e_Ann ⊗ e_Dan Parent(Ann, Dan) + … 共 1000 条事实 65,536 个实数 对象一共 2000 个,向量是随机的单位向量, 两两点积在 0 附近抖动,标准差约 1/√256。 存同样 1000 条事实,元组列表只要 2000 个整数; 稠密的 2000×2000 矩阵要 400 万格。 D[A,B] = e_A · EmbR · e_B 400 万个候选对,每对一个得分 0 0.5 1 不在关系里:std 0.139 1000 条真事实 越过 0.5 的假事实 ≈ 1122 条 两条曲线各自缩放;左边那条的面积是右边的 4000 倍。
图 4 · 误判率只有 0.028%,可分母是 400 万个候选对,冒出来的假事实比真事实还多

现象:误判率很低,假事实却很多

我们在 2000 个对象上扫了一遍维度 D 和事实数 |R|,阈值取 ½:

关系叠加的错判(2000 个对象,400 万个候选对)
维度 DD²事实数 |R|漏判误判率误判条数
644,0961000%0.148%≈ 5,932
12816,3841000%0.000%≈ 5
12816,3841,0003.8%2.79%≈ 111,701
25665,5361,0000.10%0.028%≈ 1,122
25665,5364,0003.5%3.57%≈ 142,438

误判条数 = 误判率 × 不在关系里的候选对数。

图 5 · 要让假事实少于真事实,D² 得比事实数大两个数量级以上

看百分比,D=256 存 1000 条事实只误判 0.028%,好像很准了。可换成条数就是另一回事:多出来约 1122 条假事实,比 1000 条真事实还多。逻辑推理里,一条假事实接着往下推,可能带出一串假结论。

问题出在分母上。这个误差和 Bloom filter 一样,单次查询出错的概率小,但“把整个关系取回来”要查 N2N^2 次。实验里要让假事实降到个位数,D² 大约要比事实数大两个数量级(D=128 存 100 条,误判约 5 条)。而 D×D 的稠密矩阵本身并不比元组列表省地方:存 1000 条事实,列表是 2000 个整数,D=256 的 EmbR 是 6.5 万个实数。嵌入真正省下的是相对 N2N^2 的稠密矩阵,以及“全部在 GPU 上做稠密运算”这件事。

规则在嵌入空间里连着用

规则也能搬进嵌入空间。Ancestor(x, z) :- Ancestor(x, y), Parent(y, z) 里,共享变量 y 在嵌入空间里变成共享的下标,两个关系嵌入直接做矩阵乘法:EmbAnc′=EmbAnc⋅EmbP\text{EmbAnc}' = \text{EmbAnc} \cdot \text{EmbP}。展开后,中间多出来的是 ey⋅ey′e_y \cdot e_{y'} 这一项,y 和 y′ 相同时约为 1,不同时约为 0,所以近似成立。

每多连一次,就多一层近似。我们用 1000 个对象、611 条父子事实(含一条 12 代的长链),D=512,算“恰好 k 代”的祖先关系,看错判怎么随跳数变化。论文还建议了一个降噪办法:每推一步就把结果取出来、按 ½ 阈值化、再重新嵌入。两种做法都试了:

嵌入空间里连乘 k 次 Parent(D=512,100 万个候选对)
跳数真事实直接连乘,最后读出每步阈值化再重嵌
漏判误判漏判误判
16110%00%0
23770.3%780.3%78
32870.3%1,3510.7%340
42134.2%7,3760.5%1,780
516210.5%25,1634.9%26,592
613622.1%61,93217.6%337,792

D=128 时,直接连乘第 2 跳就有约 16 万条误判。

图 6 · 噪声随跳数累积;每步阈值化在前几跳有用,但混进去的假事实一旦被当成真的重新嵌入,就会扩散

直接连乘时,第 1 跳完全正确,到第 6 跳漏掉了 22% 的真事实,还多出 6 万多条假的。每步阈值化在第 3、4 跳确实把误判压了下来,但到第 6 跳反而更糟:早期混进去的少量假事实被当成真事实重新嵌入,下一跳从它们出发又推出一批,越滚越多。

所以论文说的“出错概率随嵌入维度下降”是对的,但要读全:维度要跟着事实数、对象数和推理深度一起涨,降噪也只能延缓误差累积,挡不住它。随机嵌入下的“可靠”,是一个有代价的概率保证。

不过随机嵌入只是第一步,它和查表没有本质区别。论文真正想要的是学出来的嵌入:相似的对象向量相近,可以互相“借”结论。这时候,论文说的“不会幻觉”还成立吗?

五、温度与“不会幻觉”

论文的主张

嵌入是学出来的时候,Sim=Emb Emb⊤\text{Sim} = \text{Emb}\,\text{Emb}^\top 不再接近单位阵,而是一个衡量对象两两相似度的 Gram 矩阵。查询 Parent(Rob, Carl) 时,即使库里只有 Parent(Bob, Carl),只要 Rob 和 Bob 的向量相近,也会得到一个不小的分数。论文把这叫类比推理:相似的对象按相似程度分享推论。

接着论文在每条方程外面套一个带温度 T 的 sigmoid:σ(x,T)=1/(1+e−x/T)\sigma(x, T) = 1/(1+e^{-x/T})。T 越大,曲线越平缓;T 趋于 0,曲线变成阶跃。论文的说法是:T 设为 0,等于把 Gram 矩阵变成单位阵,推理就成了纯演绎;“这和 LLM 不同,LLM 即使在 T=0 时也会幻觉”。T 调高,推理就越来越偏类比;每条规则还可以有自己的 T,数学定理用 0,积累弱证据的规则用高温1。

现象:T 趋于 0,相似的对象照样“借”到结论

我们用一个最小的例子检查。D=256,库里只存一条事实 Parent(Bob, Carl)。另造三个对象:Rob 和 Bob 余弦相似度 0.8(像学出来的近义对象),Bobby 是 0.4,Alice 和 Zed 是无关的随机向量。原始得分分别是:Bob 1.0、Rob 0.8、Bobby 0.4,无关的在 ±0.02 附近。再把得分过 sigmoid,看 T 变小时会怎样:

只存 Parent(Bob, Carl),查询结果随温度 T 的变化
查询Bob → CarlRob → CarlBobby → CarlZed → Alice
原始得分1.0000.8000.4000.005
论文原式 σ(x/T),阈值在 0
T = 0.30.9660.9350.7910.504
T = 0.00011111
阈值挪到 ½:σ((x − ½)/T)
T = 0.30.8410.7310.4170.161
T = 0.00011100

按原式,2000 个无关对象在 T=0.0001 时有 50.5% 被判成 Carl 的父母;阈值挪到 ½ 后是 0%。

图 7 · 温度只决定曲线有多陡,决定真假的是阈值和嵌入之间的相似度

先看论文原式。阈值在 0,T 趋于 0 时得分只要大于 0 就判真,而无关对象的得分是围着 0 抖动的噪声,于是一半无关对象都被判成了 Carl 的父母。这显然不是论文本意,应该理解成方程里还有一个偏置,把阈值放在 ½,就像第四节的 Bloom filter 那样。

阈值挪到 ½ 以后,T 趋于 0 确实把弱相似(Bobby)和噪声都清掉了,但 Rob 仍然是 1。原因很简单:Rob 的原始得分是 0.8,已经越过了阈值,曲线再陡也只会把它推向 1,不会推向 0。

原因:演绎和类比的冲突在嵌入里,不在温度里

所以“T=0 让 Gram 矩阵变成单位阵”需要一个前提:任意两个不同对象的相似度都低于阈值。这在随机嵌入下成立(这就是第四节),而学出来的嵌入恰恰是要让相似的对象靠近,余弦 0.8 很平常。下面这段是我的推断,论文没有讨论:想要同一套嵌入既能类比又能在需要时严格演绎,可能得给演绎用的规则单独一套近乎正交的嵌入,或者在读出时把“是不是同一个对象”和“像不像”分开判断,光调 T 做不到。

再说和 LLM 的比较。张量逻辑的推理过程里,每一步推出的张量都能取出来看,这一点确实比 LLM 的推理过程透明。但“T=0 不会幻觉”成立的那个区间,正好是随机嵌入、不做类比的区间,而在那个区间里,它仍然有第四节看到的、随维度和推理深度变化的误判。把它说成“免疫幻觉”,是把一个概率保证说成了绝对保证。

前面讨论的都是事实和嵌入怎么存、怎么推。张量逻辑另一半的卖点是学习:规则本身能不能也学出来?

六、规则的学习

归纳逻辑编程与一条带权重的方程

从数据里学出逻辑规则,有一个专门的领域,叫归纳逻辑编程(ILP)。它难在搜索:可能的规则组合是天文数字。论文的思路是,把“候选规则”写成一条带权重的张量方程,让梯度下降来挑。论文原话是,一条方程可以表示连接结构相同的所有规则。

我们照这个思路,在家庭数据上学“姑姨”关系。候选方程是:

Aunt[x, z] = sig(W[r, s] Rel[r, x, y] Rel[s, y, z] + b)

Rel 把四种基本关系(Parent、Sister、Brother、Spouse)叠成一个三维张量,r、s 取遍这四种。所以这一条方程同时代表了 16 条形如 Aunt(x, z) :- r(x, y), s(y, z) 的候选规则,W[r, s] 就是每条候选规则的权重。

现象:权重自己挑出了正确的规则

随机生成 40 个家庭(452 人,195 条真的姑姨关系)训练,20 个新家庭(232 人,84 条)测试。训练完的权重是这样的:

学到的 W[r, s](行是第一段关系 r,列是第二段关系 s,偏置 b = −10.1)
r \ sParentSisterBrotherSpouse
Parent−0.06−0.04−0.03−0.04
Sister20.60−0.01−0.04−0.03
Brother−0.02−0.02−0.03−0.02
Spouse−0.08−0.01−0.01−0.03

阈值化(W + b > 0)后只剩 Aunt(x,z) :- Sister(x,y), Parent(y,z)。新家庭上 84 条全中,误判 0。

图 8 · 16 条候选规则同时训练,梯度把权重集中到了唯一正确的那一条上

16 个权重里,只有 W[Sister, Parent] 长到了 20.6,其余都在 0 附近。阈值化以后,留下的正是 Aunt(x, z) :- Sister(x, y), Parent(y, z),拿到没见过的新家庭上 84 条全中,没有误判。学出来的不是一个黑盒,而是一条能读、能拿去推理任何家庭的规则。

顺便核对第二节说的求导规则。损失对 W[r, s] 的梯度写出来也是一个 einsum:∂L/∂Wrs=∑Gxz Relrxy Relsyz\partial L/\partial W_{rs} = \sum G_{xz}\,\text{Rel}_{rxy}\,\text{Rel}_{syz},其中 GG 是损失对 sigmoid 输入的导数。和数值差分比,W[Sister, Parent] 这一格是 −2.742338e-05 对 −2.742324e-05,前五位一致2。

不足:权重能学,结构要先写对

真实的“姑姨”还包括姻亲:舅舅的妻子是舅妈,叔叔的妻子是婶婶。这类关系是三段连接,Spouse(x, w), Brother(w, y), Parent(y, z)。我们把舅妈也加进训练目标(训练集里 134 条),候选方程仍然只有两段,再训一次:模型还是只学出了 Sister∘Parent,新家庭上 80 条舅妈全部漏掉。

这不是训练不够,而是两段连接的方程里根本没有三段的规则,权重怎么调都补不上。论文那句“一条方程表示连接结构相同的所有规则”,反过来读就是:连接结构得由人先写好。ILP 最难的那部分,正是在不同的结构之间搜索。论文提到可以用张量分解来“发明”新的中间谓词(比如自动发现“兄弟姐妹”这个概念),这是一个有意思的方向,但论文没有给出实验,我们也没有验证。

到这里,论文的几个主张都摸了一遍。最后还剩一个问题:这些想法里,哪些是新的?

七、这篇论文的位置

这个观察并不新

“规则就是矩阵乘法加阈值”这个观察,在 2013 到 2017 年之间就有好几个人写过,论文几乎都没有引用:

和张量逻辑相关的前人工作
年份工作和本文的关系
1990Smolensky,张量积表示引第四节关系嵌入的来源,论文引用了
2011Nickel 等,RESCAL每个关系一个矩阵,三元组打分 e_hᵀ M_r e_t,就是嵌入空间里的关系
2013Grefenstette,用张量模拟逻辑演算把谓词逻辑的真值计算写成张量运算
2016Cohen,TensorLog把一类概率 Datalog 编译成可微的矩阵运算,交给 TensorFlow 训练;名字几乎一样
2016Sato,线性代数方法求值 Datalog矩阵乘法加阈值算传递闭包,就是第一节的 Ancestor
2017Rocktäschel 与 Riedel,神经定理证明器用嵌入相似度代替符号匹配,第五节的“类比推理”
2026Shah 与 Zadrozny,第三方复现按论文实现并在家谱和 FB15k-237 上做了实验

“引”表示 Domingos 的论文引用了这项工作。

图 9 · 规则与张量运算的对应、关系嵌入、软匹配,都早有人做过

具体来说,Smolensky 1990 年就用外积叠加表示符号结构5;RESCAL 用每个关系一个矩阵打分6;Grefenstette 2013 年把逻辑演算写成张量运算7;Cohen 2016 年的 TensorLog 把 Datalog 编译成可微的矩阵运算8;Sato 同年用矩阵乘法加阈值求值 Datalog9;神经定理证明器用嵌入相似度做软匹配10。

新的是什么,缺的是什么

论文新的地方,是把这个对应关系推到了极致:张量方程是整门语言唯一的语句,并且把神经网络、核方法、概率图模型、逻辑程序都写成这一种形式;再加上第五节“学出来的嵌入 + 温度”这个统一演绎与类比的设想。作为一种看问题的视角,这很有启发:GNN 的聚合就是“邻居关系”和特征的连接,贝叶斯网络的边缘化就是投影,读完再看这些模型,确实会觉得它们是一家人。

缺的东西也很明显。论文 17 页,没有图,没有一个实验;项目网站上只有论文、幻灯片和访谈,截至本文写作时没有官方实现11。语言层面也有不少空白,比如 Datalog 里很重要的否定(“x 没有孩子”)怎么写、递归和否定混在一起时怎么分层,论文都没讲。

目前能看到的实验来自第三方。2026 年 1 月 Shah 和 Zadrozny 按论文实现了一版:在 1972 人的圣经家谱上,用矩阵乘法加阶跃 74 轮算出 33945 条祖先关系;在知识图谱数据集 FB15k-237 上,按论文的关系矩阵写法做链接预测,MRR 0.3068,去掉直连边后的组合推理 MRR 0.33461213。前者验证的正是第一节的对应关系,后者是一个合格但不算突出的知识图谱嵌入结果。“嵌入空间里可靠推理”“治好 LLM 的幻觉”这些更大的主张,还没有实验支撑。

小结

  1. 逻辑规则和 einsum 是同一种运算吗? 在布尔张量上是。关系是 0/1 张量,体里的“并且”是相乘,共享变量是共享下标,只在体里出现的变量被求和,最后用阶跃函数把路径计数压回真假。递归规则就是反复做到不动点。
  2. 只有一种语句的语言长什么样? 一组张量方程。感知机、卷积、注意力、核机器、贝叶斯网络和 Datalog 都能写进去,推理是前向链和后向链,梯度也是张量方程。
  3. 直接用稠密矩阵跑规则行不行? 结果对,但稀疏关系里 99% 以上是 0。4000 人的家谱,集合求值 28 ms,稠密矩阵 24 s。论文的出路是交给数据库,或者压进嵌入。
  4. 压进嵌入以后推理还对吗? 近似对。误差随维度下降,但要和事实数、对象数、推理深度一起看:D=256 存 1000 条事实,多出约 1122 条假事实;连乘 6 跳,漏判 22%。每步阈值化只能延缓累积。
  5. 温度调到 0 就不会幻觉吗? 不能这么说。温度只管曲线陡不陡;相似度 0.8 的对象在任何温度下都会“借”到结论。纯演绎要求不同对象的相似度都低于阈值,这和学出来的嵌入的目的相冲突。
  6. 规则能学出来吗? 在给定的连接结构里能:16 条候选规则同时训练,权重集中到了正确的 Sister∘Parent,新家庭全中。结构之外的规则(三段的舅妈)学不出来。
  7. 哪些是新的? 对应关系本身 2016 年前后就有人写过;新的是把它当作唯一的语言构造、统一几大范式,以及嵌入空间推理的设想。论文没有实验和实现,更大的主张还有待验证。

本文所有实验都是几十行 numpy,可以在调研笔记目录里找到2。想自己体会一下,最短的版本就是这几行:

Python
import numpy as np
rng = np.random.default_rng(0)
N, D = 2000, 256
E = rng.standard_normal((N, D)); E /= np.linalg.norm(E, axis=1, keepdims=True)
R = np.zeros((N, N)); R[rng.integers(0, N, 1000), rng.integers(0, N, 1000)] = 1
EmbR = E.T @ R @ E # EmbR[i,j] = R(x,y) Emb[x,i] Emb[y,j]
Score = E @ EmbR @ E.T # D[x,y] = EmbR[i,j] Emb[x,i] Emb[y,j]
print("真事实", int(R.sum()), "判真", int((Score > 0.5).sum()),
"其中假的", int(((Score > 0.5) & (R == 0)).sum()))
# 真事实 1000 判真 2171 其中假的 1171

参考资料

Footnotes

  1. Tensor Logic: The Language of AIPedro Domingos · arXiv · 2025-10-14arxiv.org ↗文中引用的是 v3(2025-10-16),17 页,没有图,也没有实验。第 3 节定义语言,第 4 节实现各范式,第 5 节讲嵌入空间推理,第 6 节讲扩展。https://arxiv.org/abs/2510.12269 ↩ ↩2 ↩3 ↩4

  2. 本文的实验代码与调研笔记/mnt/project-files/tensor-logic-research/:experiment/exp1_datalog.py 到 exp4_learn_rule.py,输出在 logs/。numpy 2.5.3,4 核 CPU。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  3. Einsum is all you need: Einstein summation in deep learningTim Rocktäschel · 2018-04-30rockt.ai ↗论文引用它来说明“神经网络里几乎所有线性和多线性运算都能写成 einsum”。https://rockt.ai/2018/04/30/einsum ↩

  4. Space/time trade-offs in hash coding with allowable errorsBurton H. Bloom · Communications of the ACM 13(7) · 1970doi.org ↗https://doi.org/10.1145/362686.362692 ↩

  5. Tensor product variable binding and the representation of symbolic structures in connectionist systemsPaul Smolensky · Artificial Intelligence 46 · 1990doi.org ↗张量积表示:用向量外积把“角色”和“填充物”绑在一起,再叠加起来。论文第 5 节的关系嵌入就是这种表示。https://doi.org/10.1016/0004-3702(90)90007-M ↩ ↩2

  6. A Three-Way Model for Collective Learning on Multi-Relational DataMaximilian Nickel, Volker Tresp, Hans-Peter Kriegel · ICML 2011 · 2011icml.cc ↗RESCAL:每个关系一个矩阵 M_r,三元组打分 e_hᵀ M_r e_t。凭领域知识整理,发文前需要核对。https://icml.cc/2011/papers/438_icmlpaper.pdf ↩

  7. Towards a Formal Distributional Semantics: Simulating Logical Calculi with TensorsEdward Grefenstette · arXiv · 2013-04-22arxiv.org ↗https://arxiv.org/abs/1304.5823 ↩

  8. TensorLog: A Differentiable Deductive DatabaseWilliam W. Cohen · arXiv · 2016-05-20arxiv.org ↗把一类概率 Datalog 编译成可微的矩阵运算,交给 TensorFlow / Theano 训练。名字和 Tensor Logic 几乎一样,论文没有引用。https://arxiv.org/abs/1605.06523 ↩

  9. A Linear Algebraic Approach to Datalog EvaluationTaisuke Sato · arXiv(后刊于 TPLP 2017) · 2016-07-30arxiv.org ↗在向量空间里求值 Datalog:矩阵乘法加阈值算传递闭包。https://arxiv.org/abs/1608.00139 ↩

  10. End-to-End Differentiable ProvingTim Rocktäschel, Sebastian Riedel · arXiv · 2017-05-31arxiv.org ↗神经定理证明器:用嵌入的相似度代替符号合一,相似的符号可以“软”匹配。https://arxiv.org/abs/1705.11040 ↩

  11. tensor-logic.orgtensor-logic.orgtensor-logic.org ↗截至 2026-10-24,站上只有论文、ECML/PKDD 2025 开幕报告的幻灯片、一个访谈视频和邮件订阅,没有官方实现。https://tensor-logic.org/ ↩

  12. Implementing Tensor Logic: Unifying Datalog and Neural Reasoning via Tensor ContractionSwapn Shah, Wlodek Zadrozny · arXiv · 2026-01-23arxiv.org ↗第三方复现:圣经家谱 1972 人、1727 条父子关系,74 轮收敛出 33945 条祖先关系;FB15k-237 上链接预测 MRR 0.3068,去掉直连边的组合推理 MRR 0.3346。https://arxiv.org/abs/2601.17188 ↩

  13. sshah100-clt/tensor_logic_implementationGitHubgithub.com ↗上一篇复现论文的代码。https://github.com/sshah100-clt/tensor_logic_implementation ↩

延伸阅读