毕业聚餐那晚,三十个同学围坐一桌,服务员递来一张1000元的账单。作为班长的你,必须向每个人说清楚:你该摊多少钱?你翻着点菜单,发现直接“找谁点了什么”根本不可能——有人共享水煮鱼,有人只吃了几口凉菜,还有人把蛋糕上的草莓全挑走了。于是你换了个思路:从1000元总账单出发,先把账单拆成凉菜、热菜、主食、饮品几个小计,再把每个小计细分到具体菜品,最后按“谁吃掉了多少”把每道菜分摊回每个人头上。这个“从最终金额反推每个源头贡献”的过程,就是本期主角——逐层相关性传播(Layer-wise Relevance Propagation,简称 LRP)。深度模型告诉你“有85%概率是猫”时,就像递来一张总额 0.85 的账单;LRP 沿着神经网络的层,把 0.85 反向拆解到每个像素,告诉你哪些像素在证明“猫”,哪些像素在拖后腿。整个拆分严格遵守三条规矩:总额守恒、按比例分摊、特殊项目特殊处理。学会 LRP,你就掌握了给 AI“对账”的本领——面对模型的任何结论,都能逐条查验它的账本。
学会 LRP,你就能在模型审计、AI 安全分析和可信部署中从容回答“为什么”——把黑箱预测变成一份可逐条复核的贡献账本。
可视化演示
展示LRP-0基础分配规则、LRP-ε稳定化抑制噪声及Alpha-Beta正负贡献分离三种核心传播规则。
本节配有交互动效(进入视口后自动加载,约 3KB)。
LRP-0基础传播规则 按权重比例分配相关性:R_j=Σ(x_j*w_j/z_k)*R_k 保守性:ΣR_j(in)=ΣR_k(out)守恒 R_j=Σ_k (x_j·w_jk)/(Σ_j x_j·w_jk)·R_k 按贡献比例反向分配相关性
逐层分解思想
毕业聚餐后,你拿着1000元账单犯愁:30个人的消费交织在一起,直接问“谁知道这道菜是谁点的”会乱成一锅粥。更聪明的做法是先分大类:凉菜、热菜、主食、饮料,每一类的小计加起来刚好等于 1000。这就是“分解”的起点——从总额出发,按结构逐层往下拆,而不是从头累加。LRP 的思想正是如此:把一个“结论”拆成若干层“小计”,再一路拆到最底层的输入。
神经网络同样层层嵌套。最后一层输出预测值 y,它由前一层的加权和组合而来;前一层的每个神经元又由更前一层的多个特征组合。如果 y 是总账单,那么每一层就是账单上的一级类目。LRP 要做的,就是定义一条“反向拆账路径”:从输出 y 出发,逐层反推,最终回答“每个输入特征对 y 贡献了多大一份”。
形式化地说,LRP 为每个神经元分配一个“相关性分数”R。我们希望找到输入层每个特征的相关性 R_i^{(0)},使得它们之和约等于预测值 f(x)。这与梯度显著图完全不同——梯度解释的是“哪个像素如果变化一点会改变结果”,而 LRP 回答的是“哪个像素实际为这个结果出了多少钱”。
这份“分项账单”思维是整篇教程的根基:不管是图像里猫的耳朵,还是文本中的关键词,每个特征都能被标上“贡献金额”。于是你在 AI 面前不再雾里看花,而是手握一纸明细,随时可以对质。
- 模型预测值f(x) 代表模型对输入 x 输出的预测得分,例如“85% 概率是猫”。它相当于聚餐账单的总额 1000 元。
- 输入相关性R_i^{(0)} 表示第 i 个输入特征分配到的相关性分数,例如某个像素贡献了 0.15 的“猫概率”。它相当于某个同学摊到的饭钱。
- 总额守恒所有输入特征的相关性求和约等于预测值,保证解释的总量与结论一致。
守恒性原则
分摊方案刚公布,同桌的莉莉第一个质疑:“我可不想替别人买单!”要想服众,账本必须满足一条铁律:无论你从哪一页看起,所有数字加起来都得等于总账单 1000 元。小明的分摊方案要经得起“逐页复核”。这条铁律在 LRP 中称为“守恒性”(Conservation)。
它要求:对任意相邻的两层,第 l+1 层的相关性总和等于第 l 层的相关性总和,并且逐层相等,最终都等于模型的预测输出 f(x)。换句话说,LRP 输出的解释不是“看法”,而是“账目”——每一层都不多转一笔、不少转一笔,从头到尾只有同一笔钱在换名字。
实现守恒的关键在于“按份额转移”而非“按变化率转移”。梯度方法(如 Saliency Map)把 d f/d x 当作重要性,但梯度只能反映“输入微扰→输出变化”的灵敏度,不保证所有权重加起来等于预测值;LRP 的分配规则却强制每笔相关性从输出到输入完整转手。正是这一点,让 LRP 的解释具有定量的可靠性。
这份“从总额出发、逐层对账”的守恒性,正是 LRP 与朴素梯度方法最根本的分水岭。它让你有了和模型“对质”的底气:任何一层、任何一页账都可以逐条核对,找出模型偷藏私房钱的地方。
- 高层相关性R_j^{(l+1)} 是第 l+1 层第 j 个神经元的相关性,代表靠近输出一侧的账目小计。
- 低层相关性R_i^{(l)} 是第 l 层第 i 个神经元的相关性,代表靠近输入一侧的账目小计。
- 逐层等值相邻两层的小计必须相等,一路下推到输入层,每一页账都对得上。
Z规则传播
一人吃独食好算账,但聚餐的真正麻烦是“共享菜”。水煮鱼 58 元,三个人都吃了,怎么分?小明的办法简单公正:统计每个人夹了几筷子,用“人均夹菜量 / 总夹菜量”来分配这道菜的价格。全连接层的相关性传播,就是这盘“共享菜”的数学版本。
设输入层有激活值 a_i,它与输出神经元 j 之间有权重 w_{ij}。输出神经元 j“这盘菜”的总输入是 z_j = \sum_k a_k w_{kj};而输入 i“夹到的那筷子”贡献是 a_i w_{ij}。于是输入 i 从输出 j 分到的相关性比例是 a_i w_{ij} / z_j。把所有输出端分来的比例乘以对应相关性 R_j 再相加,就得到输入 i 的总相关性 R_i。
这就是 LRP 最经典的“Z 规则”。它看起来像神经网络的加权求和,但方向和角色完全反过来:反向传播的不是梯度,而是“贡献账单”。Z 规则的优点在于天然满足守恒——因为在每个输出端,所有输入份额比例之和恒为 1。
Z 规则把“夹菜量占比”变成了可解释性的核心算子:谁吃得多、谁贡献大,账目精确到每一块钱。而且它是比例型的,永远不多出一分、不少转一笔,这正是 LRP 名字里“传播”二字的底气。
- 贡献分子a_i w_{ij} 表示输入 i 通过权重 w_{ij} 对输出 j “付出”的贡献量,相当于某个人夹走某道菜的量。
- 归一化分母\sum_k a_k w_{kj} 是输出 j 从所有输入获得的总输入,相当于整道菜被分食的总量。
- 分配比例两者相除得到第 i 个输入在第 j 个输出处获得的贡献份额。
- 汇总所有输出把第 i 个输入从各个输出分摊到的相关性相加,就得到它的最终相关性。
卷积层适配
共享菜的另一形态是“整桌拼盘”:一个大盘子转在桌上,谁都能伸筷子。卷积层就像这个转盘——一个卷积核权重在整张特征图上“滑动”,不同位置共享同一组参数。分摊时不能只盯着一道菜,而要看每个局部窗口“桌面”上的分配。
卷积层本质上是“局部连接 + 权重共享”的全连接层。因此 Z 规则依然适用,但要调整其结构:对输出特征图上的某个位置 j,它的归一化分母只累加该位置感受野(局部窗口)内的输入与对应卷积核权重的乘积,分子则取该输入与其卷积核权重的乘积。窗口外的一切不参与这盘菜的分配,这正是“拼桌只在面前这一小块区域分摊”。
池化层更直白:最大池化相当于“这桌菜只有吃得最多的人买单”——相关性全部传给窗口中激活值最大的位置,其他位置相关性归零;平均池化则把相关性均匀分给窗口里的每个位置。这样,卷积神经网络的每一层都有了明确的 LRP 传播方式。
拼盘转桌看似复杂,但规则依然一条:谁在局部窗口里贡献大,谁就多分账。卷积层的 LRP 正是通过这样的“局部对账”,让深层卷积网络也能一张张呈现出可解释的热力图——哪怕层数再深,账目始终清晰。
- 局部邻域j \in \mathcal{N}(i) 表示与输入位置 i 相邻的输出位置集合,即局部感受野窗口。
- 局部归一化分母只在感受野窗口内求和,模拟“拼盘只在自己面前一圈分摊”。
- 池化层传递最大池化把相关性只传给窗口中激活值最大的位置,其余位置贡献归零。
激活层处理
账单上的“服务费 10%”是分摊时最让人头疼的一项:它不属于任何一道菜,却必须摊到每个人头上。神经网络里的激活函数、偏置项就扮演着这种“特殊费用”。要处理它们,LRP 需要专门的“附加规则”。
先看 ReLU。ReLU 把负输入直接截断为 0,等于“这道菜没上桌”,因此被截断的路径在 LRP 中自然分不到相关性(分子为 0),无需额外处理。真正的问题出在分母:Z 规则中的分母 z_j 可能为零或极小,一旦出现,分配比例就会爆炸,导致相关性溢出成 NaN。
解决方案是“ε 规则”:在分母上添加一个 ε·sign(z_j),ε 是非常小的正数(如 1e-6),符号函数保证分母与 z_j 同号。这样分母永远不会精确为 0,同时 ε 数值极小,不会破坏守恒性的账目。进阶玩家还可以使用 α-β 规则:把正权重贡献和负权重贡献分开计算,分别配比后作差,从而在 ReLU 网络中生成更锐利的解释图。
ε 规则像在账单上多留 1 元“找零缓冲”,钱数不变,但让每一笔分摊都能平稳落地。激活层有了“特殊费用处理章程”,LRP 才真正能在深度网络里一路稳定回传,跑出既稳定又清晰的证据图。
- 加权总输入z_j 表示输出神经元 j 从所有输入处获得的加权总输入,即一道菜的总食量。
- ε 补偿项ε·sign(z_j) 在分母上添加一个与 z_j 同号的极小量,防止分母归零。
- 完整 ε 规则用修正后的分母替换原始分母,完成稳定且守恒的相关性传播。
可视化应用
分摊完成,小明画了一张“座位贡献图”:吃得多的人头顶标红,吃得少的标绿,几乎没动的标灰。大家路过这张图,一眼就看出“谁把账单吃成了这样”。深度学习的可视化,就是这张座位贡献图的数字版本。
将 LRP 得到的输入特征相关性 R_i 映射到颜色,就得到热力图:正值用热色标注(模型认为是“猫”的区域),负值用警示色标注(抑制“猫”的区域),接近 0 用中性灰。NLP 任务中则把句子中的每个词按照 LRP 分数涂上深浅色,形成词语级别的归因标签。
为了显示稳定,通常对相关性做最大绝对值归一化:S_i = R_i / \max_j |R_j|,把所有分数压缩到 [-1, 1] 区间。正数越大说明该特征对最终预测的“支持力度”越强,负数越大说明“反向证据”越强。这类可视化常用于模型调试(例如发现模型在识别 X 光片时不是在“看肺”而是在“看边角文字”)、偏置检测与对抗样本分析。
当模型变成“一张可对账的座位图”,可信 AI 才真正落地。让每个数据点都为预测“签字画押”,这就是 LRP 给模型可解释性与可信度带来的核心价值——模型不再是黑箱,而是一本公开、可复核、逐层透明的账本。
- 最大绝对值取所有输入特征相关性的绝对值的最大值,用它做归一化因子,保证热力图颜色范围稳定。
- 归一化映射每个特征的相关性除以该最大值,得到 [-1, 1] 区间内的分数,正值表示支持预测、负值表示抑制预测。
AI 应用场景
医学影像诊断辅助
阶段:模型部署与事后解释(post-hoc 解释)
解决的问题:放射科医生面对 AI 的“92% 概率肺炎”提示时常有疑虑,尤其在病例复杂时不敢采纳。传统上只有准确率、召回率这类“平均信心”,无法解释单张 X 光片“为什么”。LRP 把预测得分反推回每个像素,生成热力图,让医生一眼看到模型是依据肺野纹理,还是错误地看了肋骨、文字标记等无关区域。
具体案例:某医院 AI 辅助读片,影像科医生用 LRP 热力图复核 AI 的肺炎提示,发现在部分真阳性病例中,模型主要依据图像角落的“床头板文字”而非肺野,于是下线该版本并重新清洗训练数据,使模型真正聚焦病灶区域。
信贷风控拒绝理由
阶段:模型审计与合规解释
解决的问题:银行因客户贷款申请被拒,需给出可解释的拒绝理由,监管要求“可解释且可复核”。LRP 按客户各特征(收入、负债率、历史逾期次数……)分配贡献,算出一份“负向贡献排名”,把模型预测的违约风险拆成每个特征的“应付款”。
具体案例:某持牌消金公司使用 LRP 为每次拒贷生成特征归因报告:模型预测“违约风险 72%”,LRP 显示“近 6 个月逾期次数”贡献了其中 35% 的风险,“收入负债比”贡献 28%,据此向客户出具合规的拒绝原因说明。
NLP 情感分析调试
阶段:模型调试与数据质量分析
解决的问题:电商评论情感分类模型把“这家店烂得可以”判断为正向,原因是语料中“可以”经常与好评共现。传统误差分析需抽样子集人工查看,效率低。LRP 对每个词计算相关性,一眼看出模型在关键词“可以”上分配了超高正贡献,从而定位歧义词与标注偏差。
具体案例:NLP 团队在 BERT 情感模型上接入 LRP,对 1000 条误判评论做词级归因,统计出 Top 贡献词表,发现“便宜”“可以”“不错”等歧义词的分布异常,重新评估后修正了训练语料标注。
Python 演示
import numpy as np def forward(x, W1, W2): """两层网络前向传播,返回隐藏层激活和输出预测。""" a1 = np.maximum(0, x @ W1) # ReLU 隐藏层 y = a1 @ W2 # 线性输出层 return a1, y def lrp_dense(act_in, W, R_out, eps=1e-9): """全连接层 LRP-Z 规则传播。 参数说明: act_in : 本层输入激活,形状 (n_in,) W : 权重矩阵,形状 (n_in, n_out) R_out : 输出层相关性,形状 (n_out,) """ z = act_in[:, None] * W # 每个连接的贡献量 denom = z.sum(axis=0) + eps * np.sign(z.sum(axis=0)) # 分母加ε保护 ratio = z / denom[None, :] # 每个连接的分配比例 return np.sum(ratio * R_out[None, :], axis=1) # 汇总到输入 def main(): rng = np.random.default_rng(42) n_in, n_h = 6, 4 W1 = rng.normal(0, 1, (n_in, n_h)) * 0.5 W2 = rng.normal(0, 1, (n_h, 1)) * 0.5 x = np.array([2.0, -1.5, 0.5, 3.0, -2.0, 1.0]) a1, y = forward(x, W1, W2) print("模型输出值:", float(y[0])) R_out = np.array([float(y[0])]) # 输出相关性设为预测值 R_hidden = lrp_dense(a1, W2, R_out) # 第1层:输出 -> 隐藏 R_input = lrp_dense(x, W1, R_hidden) # 第2层:隐藏 -> 输入 print("隐藏层相关性:", np.round(R_hidden, 4)) print("输入特征相关性:", np.round(R_input, 4)) print("输入相关性总和:", round(float(np.sum(R_input)), 4)) print("预测值对比 :", round(float(y[0]), 4)) if __name__ == "__main__": main()
a1 = np.maximum(0, x @ W1)ReLU 让负激活归零,模拟“没上桌的菜不参与分摊”。z = act_in[:, None] * W把激活展成列与权重逐元素相乘,得到每个连接“夹的那筷子”贡献量。denom = z.sum(axis=0) + eps * np.sign(z.sum(axis=0))每道菜的总食量,加上 ε 做防爆炸保护。ratio = z / denom[None, :]计算每个连接在对应输出中的分配比例。R_out = np.array([float(y[0])])从输出预测值出发,把它当作需要摊分的“总账单”。R_hidden = lrp_dense(a1, W2, R_out)第一次回传:把输出相关性分给隐藏神经元。print("输入相关性总和:", ...)验证守恒性:输入相关性之和应约等于输出预测。
常见误区
误区“LRP 和梯度显著图(Saliency Map)不是一回事吗?都是把输出对输入求导吧?”
正解梯度反映的是“输入变化一点点,输出会变多少”,即敏感度;LRP 反映的是“输入实际贡献了多少”,且满足守恒性——所有特征相关性加起来等于预测值。两者在数学上不同,只在某些条件(如 ReLU 网络局部线性且无偏置)下可能近似一致。用“夹菜量占比”来比喻,梯度问的是“再夹一筷子会多花多少钱”,LRP 问的是“你刚才那筷子吃掉了多少钱”。
为何常见:因为反向传播梯度的可视化方法流行更早,人们容易把“从输出往回算”一律理解成梯度。
误区“热力图中红色(正)意味着模型喜欢这个区域,蓝色(负)意味着模型在这里犯了错。”
正解正负只表示对当前预测“支持”还是“抑制”,二者都是模型决策的正常组成。比如“猫”的分类中,猫耳轮廓是正贡献,背景草可能抑制“猫”,但这不代表模型出错;负贡献可能是在对抗“狗”的证据。LRP 热力图是“支持/抑制”编码,不是“对/错”编码。
为何常见:人习惯把红色/热色联想为“危险/错误”,把绿色联想为“安全/正确”,但 LRP 颜色编码的语义完全不同。
误区“反正只是可视化,大致看看热点在哪里就行,不守恒也无所谓。”
正解守恒是 LRP 的核心性质,正是它让解释有量化意义(“3 号像素贡献了 0.2 的预测概率”)。如果舍弃守恒,解释分数与预测值脱钩,既无法定量分析,也无法做严格的对账式调试。ε 规则只是微扰,并不会破坏守恒。
为何常见:不少简化实现(比如只取 ReLU 的 gradient×input)会悄悄丢失守恒性,使用者只盯着热力图看,没有检查相关性总和。
误区“拿到训练好的模型,跑一个成熟的 LRP 库,出来的图就一定是可信的解释。”
正解LRP 的正确性依赖模型结构:需要适配不同层(卷积、池化、残差连接),需要针对激活函数选择规则(Z、ε、α-β),而且输入预处理方式会显著影响结果。直接“无脑默认”常常得到噪声图。就像同一张账单,家常菜馆和大酒店的计价规则不同,得先看清“菜品结构”再动手分摊。
为何常见:现成库封装得太黑盒,使用者不知道底层规则选择与模型结构强相关。
面试题
Q1. LRP 的全称是什么?
- A.Layer-wise Relevance Propagation(逐层相关性传播)← 正确答案
- B.Local Regression Prediction(局部回归预测)
- C.Large Random Propagation(大随机传播算法)
- D.Low Rank Pooling(低秩池化操作)
答案:A。LRP 全称为 Layer-wise Relevance Propagation,中文是逐层相关性传播。它像从账单总额反推每个食客的贡献一样,把输出预测逐层分回输入特征。B 是干扰项,LRP 与回归预测无关;C、D 也是虚构概念。
Q2. LRP 核心的“守恒性”指的是什么?
- A.每层相关性总和保持不变且等于输出预测← 正确答案
- B.每层权重绝对值之和永远为 1
- C.所有输入像素的颜色保持守恒
- D.每层偏置总量保持严格不变
答案:A。守恒性指任意相邻两层相关性总和相等,并最终等于模型输出预测值,好比账单每一页小计都与总账一致。B 描述的是权重的归一化性质,C 与图像处理无关,D 中的偏置在 LRP 中通常被吸收或忽略。
Q3. 在 LRP 的 Z 规则中,分母的作用是什么?
- A.对输出神经元的总输入做归一化汇总← 正确答案
- B.对输出激活值做概率归一化处理
- C.让权重矩阵自动完成转置操作
- D.把输入数据压缩到 0 到 1 之间
答案:A。Z 规则的分母 \sum_k a_k w_{kj} 是输出 j 从所有输入获得的总输入量,用来归一化每个连接的贡献占比,相当于算出整道菜的总食量。B 是 softmax 的功能,C、D 与 LRP 无关。
Q4. 与梯度显著图相比,LRP 的关键区别是什么?
- A.两者在数学定义上完全一致
- B.LRP 的贡献总和不等于模型预测值
- C.LRP 强调按比例分配而非局部敏感度← 正确答案
- D.LRP 只能应用于线性回归模型
答案:C。梯度显著图衡量的是“输入扰动→输出变化”的敏感度,而 LRP 强调按连接贡献比例分配相关性,且总和守恒。A 错误,两者数学定义不同;B 与守恒性相反;D 错误,LRP 适用于深度神经网络。
Q5. 卷积层应用 Z 规则时,分母的求和范围是什么?
- A.前一层全部神经元贡献求和
- B.对应感受野窗口内的局部输入求和← 正确答案
- C.整个验证集样本的平均贡献
- D.卷积核参数之外的区域求和
答案:B。卷积层是局部连接结构,LRP 的归一化分母只在输出位置对应的感受野窗口内累加,就像拼盘只在面前一圈分摊。A 是全连接层的做法,C 与单个样本解释无关,D 中的区域不参与该输出的计算。
Q6. 最大池化层在 LRP 中的相关性应该传给哪个位置?
- A.将相关性平均分给窗口内所有位置
- B.只传给窗口内激活值最大的位置← 正确答案
- C.只传给窗口内激活值最小的位置
- D.传给窗口正中心的位置
答案:B。最大池化在前向传播中只有最大值“存活”,因此 LRP 把相关性全部传给窗口内激活最大的位置,其余位置贡献归零,类似于“只有吃得最多的人买单”。A 是平均池化的策略,C、D 与最大池化的语义不符。
Q7. ε 规则在 LRP 中的主要目的是什么?
- A.避免分母为零时数值产生爆炸← 正确答案
- B.让模型的训练过程更快收敛
- C.让卷积核的感受野变得更大
- D.减小图像输入的分辨率
答案:A。Z 规则分母可能为 0 导致相关性溢出,ε 规则在分母上添加 ε·sign(z_j) 的极小同号补偿,防止数值爆炸,同时不破坏守恒。B 涉及优化器,C、D 与数值稳定性无关。
Q8. LRP 的守恒性体现在哪些层间关系上?
- A.输出层相关性总和等于模型预测值← 正确答案
- B.中间层相关性总和逐层保持相等← 正确答案
- C.输入层所有特征相关性之和等于预测值← 正确答案
- D.每一层权重之和必须为常数 1
答案:ABC。守恒性要求输出层、每个中间层、输入层的相关性总和都相等且等于预测值 f(x),如同账本每一页小计都相等。D 描述的是权重的范数约束,与相关性传播的守恒无关。
Q9. 以下哪些措施可以提升 LRP 的数值稳定性?
- A.在分母中添加 ε·sign(z_j) 补偿项← 正确答案
- B.在每一层施加学习率衰减策略
- C.使用 α-β 规则分开处理正负贡献← 正确答案
- D.把模型预测值强制设置为零
答案:AC。ε 规则通过在分母添加同号极小量防止除零爆炸,α-β 规则通过分离正负贡献并分别归一化来增强稳定性与解释清晰度。B 是训练阶段的优化策略,与解释传播无关;D 会摧毁守恒性,完全错误。
Q10. LRP 可视化可以应用于哪些实际任务?
- A.生成图像分类的像素级热力图← 正确答案
- B.对 NLP 词语重要性进行标注← 正确答案
- C.辅助模型调试与偏置检测← 正确答案
- D.直接扩大训练数据集的规模
答案:ABC。LRP 可把预测分数映射到图像像素(热力图)或 NLP 词元(词级归因),并用于模型调试、偏置检测和对抗样本分析。D 属于数据增强,与解释模型决策无关。