资讯动态

深度神经网络可解释性:遮挡分析定位模型决策依据的实操指南

发布时间:2026/10/17 7:41:43 来源:尧图企业网站定制
深度神经网络在图像识别任务里跑出高准确率早已不是新鲜事但要把模型为什么做出这个判断讲清楚却一直是落地过程中最让人头疼的环节。我最近在做一个图像分类项目的可解释性分析用遮挡分析Occlusion Analysis来定位模型决策依据踩了不少坑也积累了一些实操经验。这篇文章就把整个思路、实现细节和踩坑过程完整梳理一遍适合正在做模型可解释性、需要向业务方解释模型行为、或者单纯想搞清楚DNN看哪里的从业者参考。遮挡分析的核心思想其实很朴素把输入图像的一部分遮住看模型输出会掉多少掉得越多说明那块区域越关键。听起来简单但真正做起来遮挡窗口大小、步长、遮挡值、评估指标的选择每一步都会影响最终热力图的可信度。下面我按实际操作的顺序把这件事从头到尾讲透。1. 遮挡分析到底在解决什么问题1.1 从模型准不准到模型看哪里做图像分类项目时业务方最常问的两个问题是这个模型准确率多少和它凭什么这么判断第一个问题好回答跑个验证集就有数字。第二个问题就麻烦了尤其是当模型把一张明显是猫的图判成狗或者把背景里的雪地当成了哈士奇的特征时你很难用一句话解释清楚。传统的评估指标只能告诉你模型整体表现如何但没法告诉你模型是看对了地方还是蒙对了答案。我见过不少模型在测试集上准确率很高但热力图一画出来发现它关注的是图像角落的水印或者背景纹理而不是目标物体本身。这种模型一旦换到真实场景遇到没有水印的图表现就会断崖式下跌。遮挡分析就是用来回答模型看哪里这个问题的。它的逻辑是如果我把图像中某个区域遮住模型的预测置信度大幅下降那说明这个区域对模型的判断很重要反之如果遮住某块区域后模型预测几乎不变那这块区域对模型来说就是无关紧要的。把所有区域的重要性拼起来就得到了一张重要性热力图。1.2 遮挡分析和其他可解释性方法的区别市面上可解释性方法不少梯度类方法如Grad-CAM、扰动类方法如遮挡分析、RISE、代理模型方法如LIME各有各的适用场景。我选遮挡分析主要是因为它有几个很实在的优点。第一它不依赖模型内部结构。梯度类方法需要拿到模型的梯度信息对于某些封装好的模型或者黑盒API梯度根本拿不到。遮挡分析只需要模型的输入输出你把图传进去、拿到预测概率就行模型内部怎么算的完全不关心。这一点在工程落地时特别重要因为很多生产环境的模型是封装好的你没法轻易改内部逻辑。第二它的解释直观。遮挡分析的结果直接对应到图像的像素区域这块区域重要这个结论不需要额外的数学转换就能理解。相比之下梯度类方法得到的热力图有时候会有很多噪点需要额外的平滑和后处理才能看。第三它容易实现。核心逻辑就是一个双层循环遍历所有遮挡位置每次遮挡后跑一次前向推理记录输出变化。没有复杂的数学推导代码量也不大。当然遮挡分析也有明显的缺点。最大的问题是计算量大因为每个遮挡位置都要跑一次前向推理。如果图像是224x224遮挡窗口是16x16步长是8那大概要跑几百次推理。对于大模型来说这个开销不小。另外遮挡窗口的大小和步长会显著影响结果窗口太小容易碎片化窗口太大又会丢失细节。这些参数怎么选后面会详细讲。1.3 适用场景与不适用场景遮挡分析不是万能的它有明确的适用边界。我总结下来它最适合这几类场景图像分类模型的决策依据分析想知道模型判断某张图属于某个类别时到底关注了哪些区域。模型调试与数据质量检查发现模型关注了不该关注的区域比如背景、水印、边框说明训练数据可能有偏。向非技术方解释模型行为热力图比梯度、权重这些概念直观得多业务方更容易接受。黑盒模型的可解释性分析拿不到模型内部信息时遮挡分析是少数能用的方法之一。但它不太适合这些场景需要实时解释的场景每次解释要跑几百次推理实时性要求高的场景扛不住。目标检测和分割任务遮挡分析最初是为分类任务设计的直接套到检测任务上遮挡一个区域可能影响多个目标的预测解释起来会很混乱。超大规模模型如果单次推理就要几秒几百次推理的时间成本太高需要先做模型压缩或者用更高效的替代方法。提示如果你的模型推理一次要500毫秒以上做遮挡分析前先算一下总耗时。224x224图像、16x16窗口、8像素步长大概要跑约700次推理总耗时接近6分钟。这个时间能不能接受取决于你的分析频率。2. 遮挡分析的核心原理拆解2.1 遮挡与预测变化的因果逻辑遮挡分析的底层逻辑是因果推断里的干预思想我把某个变量图像区域干预掉遮住观察结果模型预测怎么变。如果遮住某块区域后预测概率大幅下降说明这块区域是模型做出当前判断的因果因素之一。这里有个关键点容易被忽略遮挡分析衡量的是充分性还是必要性严格来说它衡量的是必要性——如果这块区域不存在模型的判断会不会改变。但它不能证明充分性也就是说即使某块区域很重要单独把它露出来也不一定能让模型做出同样的判断。这个区别在解释结果时要注意别把重要区域理解成充分条件。实际操作中我们通常用预测概率的变化量作为重要性分数。假设原始图像对类别c的预测概率是p_c遮住区域r后的预测概率是p_c^r那区域r的重要性分数可以定义为importance(r) p_c - p_c^r分数越高说明遮住这块区域后模型越不确定这块区域越重要。也可以用其他指标比如log odds变化、预测类别的排名变化等后面会详细对比。2.2 遮挡窗口大小对结果的影响遮挡窗口大小是影响结果最关键的参数没有之一。窗口太小比如4x4遮挡一块区域对模型预测的影响可能微乎其微因为模型可以从周围像素推断出被遮住的内容热力图会显得很碎、很分散。窗口太大比如64x64一次遮住一大片虽然能看出大致的关注区域但细节全丢了而且可能把多个重要区域一起遮住导致重要性分数被平均掉。我实测下来的经验是窗口大小取图像短边的5%到15%比较合适。对于224x224的输入窗口取16x16到32x32之间。如果目标物体比较大窗口可以取大一点如果目标物体小且细节多窗口要取小一点。还有一个技巧是多尺度遮挡用不同大小的窗口各跑一遍然后把结果融合。小窗口捕捉细节大窗口捕捉整体关注区域。融合方式可以是加权平均也可以是小窗口结果作为大窗口结果的细化。这个方法计算量会翻倍但结果更稳健。2.3 步长选择与计算量权衡步长决定了遮挡窗口滑动的密度。步长等于窗口大小时窗口之间不重叠计算量最小但热力图会有明显的网格感相邻窗口之间的过渡不自然。步长小于窗口大小时窗口之间有重叠热力图更平滑但计算量成倍增加。计算量的估算公式很简单推理次数 ((图像宽 - 窗口宽) / 步长 1) * ((图像高 - 窗口高) / 步长 1)以224x224图像、16x16窗口为例步长推理次数热力图平滑度适用场景16196网格感明显快速预览8729较平滑常规分析42704很平滑精细分析210609极平滑论文级可视化我一般先用步长16快速跑一遍看大致趋势确认模型关注区域合理后再用步长8跑精细版。步长4以上基本只在需要出论文图或者给客户做正式报告时才用日常调试没必要。2.4 遮挡值的选取策略遮挡值就是被遮住区域填充什么。常见的选择有零值黑色最简单但黑色本身可能是一个有意义的颜色模型可能把黑色区域当成某个物体的一部分。均值填充用数据集的像素均值填充相对中性但均值图像看起来是一片灰色模型可能对灰色有特殊反应。随机噪声用随机噪声填充避免模型对特定颜色产生偏好但每次结果会有随机性。模糊填充把被遮区域做高斯模糊保留部分纹理信息更接近自然遮挡。我实测下来均值填充和模糊填充的结果最稳定。零值填充有时候会让模型把黑色区域识别成阴影或者背景导致重要性分数被低估。随机噪声填充虽然理论上最中性但需要多次采样取平均计算量又上去了。注意遮挡值的选择没有绝对最优关键是要在报告中说明你用了什么值。不同遮挡值得到的热力图可能有差异但重要区域的大致位置通常是一致的。如果换了遮挡值后重要区域完全变了那说明模型本身不稳定这才是更需要关注的问题。3. 从零实现遮挡分析的完整步骤3.1 环境准备与依赖选择实现遮挡分析不需要什么特殊库核心依赖就是深度学习框架本身加上图像处理库。我用的是PyTorch加OpenCV这两个组合最顺手。如果你用的是TensorFlow逻辑完全一样只是API调用方式不同。import torch import torch.nn.functional as F import numpy as np import cv2 from PIL import Image import matplotlib.pyplot as plt模型加载部分假设你已经有一个训练好的分类模型这里用torchvision里的预训练模型做示例import torchvision.models as models import torchvision.transforms as transforms model models.resnet50(pretrainedTrue) model.eval()图像预处理要注意遮挡分析是在预处理后的图像上做的还是在原始图像上做的我的建议是在预处理后的图像上做因为模型看到的就是预处理后的图。如果你在原始图像上遮挡再预处理遮挡区域经过归一化后可能变成奇怪的值影响结果。preprocess transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])3.2 单次遮挡与预测变化计算先实现最核心的单次遮挡逻辑。给定一张预处理后的图像张量、遮挡窗口位置和大小、遮挡值返回遮挡后的图像。def occlude_image(image_tensor, top, left, height, width, fill_value0.0): occluded image_tensor.clone() occluded[:, top:topheight, left:leftwidth] fill_value return occluded然后计算遮挡前后的预测概率变化def get_prediction(model, image_tensor): with torch.no_grad(): output model(image_tensor.unsqueeze(0)) probs F.softmax(output, dim1) return probs.squeeze(0) def compute_importance(model, image_tensor, target_class, top, left, height, width, fill_value0.0): original_probs get_prediction(model, image_tensor) original_score original_probs[target_class].item() occluded occlude_image(image_tensor, top, left, height, width, fill_value) occluded_probs get_prediction(model, occluded) occluded_score occluded_probs[target_class].item() importance original_score - occluded_score return importance这里有个细节要注意fill_value在归一化后的图像上应该填什么如果你用的是ImageNet的均值和标准差归一化那均值填充对应的填充值应该是0因为归一化后均值是0。但如果你想让填充区域在视觉上呈现灰色那填充值应该是归一化后的均值也就是0。这个容易搞混我一开始就填错了导致热力图完全不对。3.3 滑动窗口遍历与热力图生成有了单次遮挡的逻辑接下来就是滑动窗口遍历整张图记录每个位置的重要性分数。def occlusion_analysis(model, image_tensor, target_class, window_size16, stride8, fill_value0.0): _, H, W image_tensor.shape heatmap np.zeros((H, W)) count_map np.zeros((H, W)) for top in range(0, H - window_size 1, stride): for left in range(0, W - window_size 1, stride): importance compute_importance( model, image_tensor, target_class, top, left, window_size, window_size, fill_value ) heatmap[top:topwindow_size, left:leftwindow_size] importance count_map[top:topwindow_size, left:leftwindow_size] 1 count_map[count_map 0] 1 heatmap heatmap / count_map return heatmap这段代码里有个容易被忽略的点边缘区域的处理。如果图像尺寸不能被步长整除最后几行几列可能覆盖不到。我的处理方式是只遍历能完整放下窗口的位置边缘区域用最近邻填充或者直接留空。更严谨的做法是允许窗口超出边界超出部分忽略但这样边缘区域的重要性分数会基于更少的采样需要做归一化。热力图生成后通常要做归一化到0-1区间方便可视化def normalize_heatmap(heatmap): heatmap heatmap - heatmap.min() if heatmap.max() 0: heatmap heatmap / heatmap.max() return heatmap3.4 热力图叠加与可视化最后把热力图叠加到原图上生成直观的可视化结果。我用的是OpenCV的applyColorMap加透明度混合。def visualize_heatmap(image_path, heatmap, alpha0.5): img cv2.imread(image_path) img cv2.resize(img, (heatmap.shape[1], heatmap.shape[0])) heatmap_uint8 np.uint8(255 * heatmap) heatmap_color cv2.applyColorMap(heatmap_uint8, cv2.COLORMAP_JET) overlay cv2.addWeighted(img, 1 - alpha, heatmap_color, alpha, 0) return overlay这里有个实用技巧热力图的颜色映射选择会影响可读性。JET色图对比度高但红色和蓝色在灰度打印时区分度不够。如果报告需要打印建议用VIRIDIS或INFERNO色图它们在灰度下也有较好的区分度。另外叠加时alpha值取0.4到0.6比较合适。太低看不清热力图太高原图细节被盖住。我一般用0.5然后根据实际效果微调。4. 实操中踩过的坑与排查过程4.1 热力图全图均匀归一化位置搞错了第一次跑通代码后我得到的热力图几乎是一片均匀的颜色看不出任何重点区域。排查了半天发现是归一化位置搞错了。我一开始在预处理阶段做了归一化然后在遮挡分析时又对热力图做了一次归一化。问题在于预处理阶段的归一化把像素值映射到了均值0、标准差1的分布而遮挡时我填的fill_value0这个0在归一化后的空间里代表的是均值像素也就是灰色。但模型在训练时看到的图像是归一化后的它对灰色区域的处理和原始图像中的灰色区域是一样的。这本身没问题。真正的问题是我在计算重要性分数时用的是softmax后的概率差。对于ResNet50这种模型即使遮住一大块区域预测概率的变化也可能很小因为模型有很强的鲁棒性。结果就是所有位置的重要性分数都在0.01到0.05之间归一化后看起来就很均匀。解决办法是改用log odds作为重要性指标或者对重要性分数做非线性放大。我最后用的是log oddsdef compute_importance_logodds(model, image_tensor, target_class, top, left, height, width, fill_value0.0): original_probs get_prediction(model, image_tensor) original_logit torch.log(original_probs[target_class] / (1 - original_probs[target_class] 1e-8)) occluded occlude_image(image_tensor, top, left, height, width, fill_value) occluded_probs get_prediction(model, occluded) occluded_logit torch.log(occluded_probs[target_class] / (1 - occluded_probs[target_class] 1e-8)) return (original_logit - occluded_logit).item()log odds对概率变化更敏感尤其是当概率接近0或1时。改用这个指标后热力图的对比度明显提升重要区域清晰可见。4.2 重要区域出现在图像边缘padding的锅第二个坑是热力图的重要区域总是出现在图像边缘尤其是上下边缘。一开始我以为是模型真的关注边缘后来发现是padding的问题。预处理时用了transforms.Resize(256)然后CenterCrop(224)这个操作会在图像周围产生一些填充区域。如果原始图像的长宽比和224x224差距较大填充区域会很明显。模型在这些填充区域上学到了一些虚假特征遮挡分析就把这些区域标成了重要区域。解决办法有两个一是改用Resize((224, 224))直接拉伸避免填充二是如果必须保持长宽比在遮挡分析时把填充区域排除掉不参与重要性计算。我最后用的是第一种方案虽然会轻微变形但避免了填充带来的干扰。提示如果你的任务对长宽比敏感可以用Resize加CenterCrop但在分析结果时要意识到边缘区域可能是填充产生的不要过度解读。4.3 推理速度太慢批处理与半精度优化前面提到遮挡分析的计算量很大。我一开始用单张推理224x224图像、16x16窗口、8像素步长跑了将近8分钟。这个速度没法接受后来做了两个优化。第一个优化是批处理。把所有遮挡后的图像攒成一个batch一次性推理。这样能充分利用GPU的并行能力速度提升非常明显。def batch_occlusion_analysis(model, image_tensor, target_class, window_size16, stride8, fill_value0.0, batch_size64): _, H, W image_tensor.shape positions [] for top in range(0, H - window_size 1, stride): for left in range(0, W - window_size 1, stride): positions.append((top, left)) original_probs get_prediction(model, image_tensor) original_score original_probs[target_class].item() heatmap np.zeros((H, W)) count_map np.zeros((H, W)) for i in range(0, len(positions), batch_size): batch_positions positions[i:ibatch_size] batch_images [] for top, left in batch_positions: occluded occlude_image(image_tensor, top, left, window_size, window_size, fill_value) batch_images.append(occluded) batch_tensor torch.stack(batch_images) with torch.no_grad(): outputs model(batch_tensor) probs F.softmax(outputs, dim1) for j, (top, left) in enumerate(batch_positions): importance original_score - probs[j, target_class].item() heatmap[top:topwindow_size, left:leftwindow_size] importance count_map[top:topwindow_size, left:leftwindow_size] 1 count_map[count_map 0] 1 heatmap heatmap / count_map return heatmap第二个优化是半精度推理。把模型和输入都转成float16速度能再提升30%到50%精度损失几乎可以忽略。model model.half() image_tensor image_tensor.half()这两个优化做完同样的分析从8分钟降到了40秒左右完全可以接受。4.4 不同遮挡值结果差异大稳定性检查前面提到遮挡值会影响结果我实测发现对于某些模型零值填充和均值填充得到的热力图差异能达到30%以上。这时候不能简单选一个值就完事要做稳定性检查。我的做法是用三种遮挡值零值、均值、随机噪声各跑一遍然后计算三个热力图之间的相关性。如果相关性都在0.8以上说明结果稳定可以放心用。如果相关性低于0.6说明模型对遮挡值敏感这时候要么换更中性的遮挡值要么在报告中说明这个局限性。def stability_check(heatmaps): from scipy.stats import pearsonr n len(heatmaps) correlations [] for i in range(n): for j in range(i1, n): corr, _ pearsonr(heatmaps[i].flatten(), heatmaps[j].flatten()) correlations.append(corr) return np.mean(correlations)这个检查虽然增加了计算量但对于需要出正式报告的场景我觉得是值得的。毕竟可解释性分析的可信度比速度更重要。5. 结果解读与常见误判5.1 热力图不是模型注意力很多人把遮挡分析的热力图直接理解成模型注意力图这个理解有偏差。热力图反映的是必要性——遮住这块区域后模型预测会变差但不代表模型在正常推理时看的就是这块区域。模型可能通过多条路径做出判断遮挡分析只能揭示其中一部分。举个例子如果模型判断一张图是狗可能同时依赖狗的耳朵、鼻子和尾巴。遮住耳朵后模型还能靠鼻子和尾巴判断所以耳朵区域的重要性分数不会特别高。但这不代表耳朵不重要只是说明模型有冗余。这种情况下热力图会显示多个中等重要的区域而不是一个高亮区域。解读时要注意高亮区域是必要但不充分的多个中等重要区域可能共同构成模型的判断依据。5.2 背景高亮数据偏差的信号如果热力图显示模型主要关注背景而不是目标物体这通常是一个危险信号。说明训练数据中背景和目标存在虚假相关模型学到了捷径而不是真正的特征。我遇到过一个案例模型在区分两种鸟类时热力图显示它关注的是背景的树枝而不是鸟本身。排查后发现训练数据中一种鸟总是出现在枯树枝上另一种总是出现在绿叶上。模型学会了用背景区分而不是用鸟的形态特征。这种模型换到新场景就会失效。解决办法是数据增强比如随机裁剪、背景替换打破背景和类别的虚假相关。或者用遮挡分析作为数据质量检查工具在训练前就发现这类问题。5.3 多类别场景下的分析策略对于多类别分类遮挡分析需要针对每个类别单独做。因为遮住同一块区域对类别A可能是重要区域对类别B可能无关紧要。我的做法是先对模型预测的top-1类别做分析看模型判断的主要依据。如果top-1和top-2的置信度接近再对top-2做一次分析对比两个类别的关注区域差异。如果两个类别的关注区域高度重叠说明模型对这两个类别的区分能力可能不足需要检查训练数据或模型结构。对于类别数很多的情况比如1000类ImageNet不可能每个类别都分析。我的策略是选几个代表性类别模型表现最好的、表现最差的、以及业务最关心的。这样既能了解模型的整体行为又能聚焦关键问题。5.4 定量评估不只是看图热力图是定性分析但可解释性也需要定量指标。常用的定量评估方法有删除曲线Deletion Curve按重要性从高到低逐步删除像素观察模型预测概率的下降速度。下降越快说明重要性排序越准确。插入曲线Insertion Curve按重要性从高到低逐步插入像素观察预测概率的上升速度。上升越快说明重要区域找得越准。AUC对比计算删除曲线和插入曲线的AUC和随机基线对比。AUC越高解释质量越好。def deletion_curve(model, image_tensor, target_class, heatmap, steps20): _, H, W image_tensor.shape flat_heatmap heatmap.flatten() sorted_indices np.argsort(flat_heatmap)[::-1] scores [] for i in range(1, steps 1): num_pixels int(len(sorted_indices) * i / steps) mask np.ones(H * W, dtypebool) mask[sorted_indices[:num_pixels]] False modified image_tensor.clone().flatten() modified[~torch.tensor(mask)] 0 modified modified.reshape(1, H, W) with torch.no_grad(): prob F.softmax(model(modified.unsqueeze(0)), dim1) scores.append(prob[0, target_class].item()) return scores这个定量评估能帮你判断热力图是否真的反映了模型行为而不是看起来好看但实际没用的图。我一般会在正式报告中附上删除曲线的AUC作为解释质量的量化证据。6. 工程化落地的几个实用建议6.1 封装成可复用工具遮挡分析的代码逻辑不复杂但每次重新写一遍很浪费时间。我把它封装成了一个类支持不同的模型、不同的参数配置用起来方便很多。class OcclusionAnalyzer: def __init__(self, model, window_size16, stride8, fill_value0.0, batch_size64, use_logoddsTrue): self.model model self.window_size window_size self.stride stride self.fill_value fill_value self.batch_size batch_size self.use_logodds use_logodds def analyze(self, image_tensor, target_class): # 核心分析逻辑 pass def visualize(self, image_path, heatmap, alpha0.5): # 可视化逻辑 pass def quantitative_eval(self, image_tensor, target_class, heatmap): # 定量评估逻辑 pass封装成类的好处是参数集中管理换模型、换参数只需要改初始化参数不用改分析逻辑。另外把可视化、定量评估也封装进去形成一个完整的分析流水线。6.2 参数配置的经验值经过多个项目的积累我总结了一套参数配置的经验值可以作为起点参数推荐值说明窗口大小图像短边的8%-12%224图像用16-24步长窗口大小的1/216窗口用8步长遮挡值归一化后的均值通常为0或高斯模糊重要性指标log odds比概率差更敏感批大小64-128根据显存调整精度float16速度优先时使用这套配置在ResNet、VGG、EfficientNet上都跑过结果稳定。如果你的模型比较特殊比如输入尺寸很大或者很小窗口大小按比例调整即可。6.3 和业务方沟通的技巧可解释性分析的最终目的是让人理解模型行为所以沟通方式和结果本身一样重要。我总结了几条和业务方沟通的经验第一不要一上来就讲方法原理。业务方不关心你用的是遮挡分析还是梯度方法他们关心的是模型为什么这么判断和这个判断可不可靠。先给结论再解释方法。第二热力图要配文字说明。光给一张热力图业务方可能看不懂。要在图上标注出关键区域用文字说明模型主要关注了这块区域因为遮住它后预测概率下降了XX%。第三主动说明局限性。遮挡分析不是万能的它有计算量大、参数敏感等局限。主动说出来比被问出来要好。业务方知道方法的边界后对结果的信任度反而更高。第四用对比案例增强说服力。找一个模型判断正确的案例和一个判断错误的案例对比它们的热力图差异。正确的案例通常关注目标物体错误的案例往往关注了背景或无关区域。这种对比比单纯讲方法更有说服力。6.4 性能优化的进阶思路如果遮挡分析的速度还是不够快有几个进阶优化思路GPU并行把滑动窗口的位置生成也放到GPU上用张量操作一次性生成所有遮挡图像避免Python循环的开销。模型蒸馏用一个更小的代理模型来做遮挡分析然后把结果迁移到大模型上。前提是代理模型和大模型的行为足够相似。采样策略不是所有位置都需要分析。可以先用低分辨率快速扫描找出候选重要区域再对这些区域做精细分析。缓存机制如果同一张图需要多次分析比如不同类别可以缓存中间结果避免重复推理。这些优化思路各有适用场景我一般先用批处理加半精度如果还不够快再考虑其他方案。大多数情况下批处理加半精度已经能把时间控制在可接受范围内。遮挡分析这个工具用好了能帮你真正理解模型行为发现数据偏差和模型缺陷用不好就是一张好看但没用的热力图。关键还是要把参数选对、结果解读对、和业务方沟通对。我在实际项目中的体会是可解释性分析的价值不在于方法多高级而在于能不能真正回答模型为什么这么判断这个问题并且让非技术方也能理解。遮挡分析在这两点上做得都不错值得花时间掌握。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑