基于PyTorch微调BERT情感分析模型后,如何通过SHAP绕过WordPiece分词实现预测解释?
如何在SHAP中使用预分词输入并禁用BERT的WordPiece拆分?
当然可以做到!而且不需要用到你提到的论文里的复杂方法,只需要对tokenizer和预测函数做一点简单包装,就能让SHAP直接基于你的预分词结果计算贡献值。下面是具体的实现步骤和代码修改:
核心思路
我们要绕开BERT tokenizer的自动拆分逻辑,直接把预分词后的token列表传给模型,同时让SHAP明确知晓我们的token边界,这样它就会基于完整的词(而非WordPiece子词)来计算每个token的预测贡献。
具体代码修改
1. 准备预分词的输入数据
首先把你的测试文本改成预分词后的列表格式:
test = {'label': [1], 'text': [['this', 'is', 'a', 'lovely', 'movie']]}
2. 自定义预分词处理函数
这个函数会把预分词的token列表转换成模型需要的input_ids和attention_mask,同时保留原始token文本供SHAP展示:
def custom_tokenizer(x): # x是预分词的batch,比如[[token1, token2], [token3, token4]] # 将每个预分词转换为对应的token ID input_ids = [tokenizer.convert_tokens_to_ids(tokens) for tokens in x] # 统一序列长度(padding) max_seq_len = max(len(ids) for ids in input_ids) padded_input_ids = [ids + [tokenizer.pad_token_id] * (max_seq_len - len(ids)) for ids in input_ids] attention_mask = [[1] * len(ids) + [0] * (max_seq_len - len(ids)) for ids in input_ids] # 返回模型需要的输入格式,同时携带原始token文本 return { "input_ids": torch.tensor(padded_input_ids), "attention_mask": torch.tensor(attention_mask), "text": x }
3. 调整预测函数
修改predictor和f_batch,让它们直接接收预分词的输入,并用我们的自定义函数处理:
def predictor(x): # x是预分词的batch列表 inputs = custom_tokenizer(x) outputs = model(**inputs) # 注意要取模型的logits输出,再做softmax probas = F.softmax(outputs.logits, dim=1).detach().numpy() val = sp.special.logit(probas[:, 1]) return val def f_batch(x): # 现在predictor已经支持批量处理,直接调用即可 return predictor(x)
4. 创建SHAP Explainer并生成解释
我们需要指定一个基于预分词的masker,告诉SHAP如何对token进行掩码操作:
from shap.maskers import Text # 用自定义的逻辑处理mask,掩码token用BERT的[MASK] masker = Text(tokenizer=lambda x: x, mask_token=tokenizer.mask_token) explainer_bert = shap.Explainer(f_batch, masker=masker, output_names=["Negative", "Positive"]) # 计算SHAP值并可视化 shap_values = explainer_bert(test['text']) shap.plots.text(shap_values)
注意事项
- 如果你的预分词中有不在BERT词汇表中的词,
convert_tokens_to_ids会返回unk_token_id,这时候你可以选择替换为[UNK],或者调整预分词策略匹配BERT的词汇表。 - 确保
custom_tokenizer返回的input_ids和attention_mask形状符合模型要求(batch_size × seq_len)。 - 之前的代码中直接对
outputs做softmax是不准确的,模型的原始输出是logits,需要取outputs.logits再计算概率。
这样修改后,SHAP就会基于你提供的预分词(比如lovely作为一个完整token)来计算每个词的情感贡献,不会再拆分成WordPiece子词啦。
内容的提问来源于stack exchange,提问作者Maria
相关产品推荐
相关产品推荐

