【问题标题】:How to use SHAP with SpaCy models?如何将 SHAP 与 SpaCy 模型一起使用?
【发布时间】:2021-07-27 12:47:34
【问题描述】:

我正在尝试提高 SpaCy 二进制文本分类模型的可解释性,该模型是通过使用 SHAP 解释预测来训练的。这是我迄今为止尝试过的(遵循this 教程):

nlp = spacy.load("my_model") # load my model
explainer = shap.Explainer(nlp_predict)
shap_values = explainer(["This is an example"])

但我得到AttributeError: 'str' object has no attribute 'shape'。 nlp_predict 是我编写的一种方法,它采用文本列表并以教程中使用的格式输出每个文本的预测概率。我在这里错过了什么?


这是我的格式化函数:

def nlp_predict(texts):
    result = []
    for text in texts:
        prediction = nlp_fn(text) # This returns label probability but in the wrong format
        sub_result = []
        sub_result.append({'label': 'label1', 'score': prediction["label1"]})
        sub_result.append({'label': 'label2', 'score': prediction["label2"]})
        result.append(sub_result)
    return(result)

这是他们在教程中使用的预测格式(针对 2 个数据点):

[[{'label': 'label1', 'score': 2.850986311386805e-05},
  {'label': 'label2', 'score': 0.9999715089797974}],
 [{'label': 'label1', 'score': 0.00010622951958794147},
  {'label': 'label2', 'score': 0.9998937845230103}]]

我的函数的输出与此匹配,但我仍然得到AttributeError。这是我收到的完整错误消息:。

【问题讨论】:

  • 我认为您在这里没有提供足够的信息来弄清楚发生了什么。你能提供整个堆栈跟踪吗? spaCy 又从何而来?
  • 在本教程中,他们使用了具有特定格式输出的 transformers.pipeline(每个文本的列表 -> 每个类别的列表 -> 具有键类别和值预测的字典),但是 spacy 有不同的预测格式,所以我想如果我把我的预测放在相同的格式中它应该可以工作,但我仍然收到这个错误消息。
  • @GSwart,你最终弄清楚如何在 spaCy 中使用 SHAP 了吗?

标签: python nlp spacy shap


【解决方案1】:

问题在于 shap 只为转换器库的标记器和模型实现了方法。

SpaCy 标记器的工作方式非常不同,特别是不会返回标记 id 作为标记化的结果。

因此,完成这项工作的解决方案需要编写一个函数来包装 spacy 分词器以返回与转换器分词器相同的数据(例如 [{'input_ids': [101, 7592, ...], 'offset_mapping': [(0, 5), (6, 9), ...], ...}] 之类的东西),或者在 shap 中添加对 spacy 分词器/模型的支持。

这是一个例子,我破解了前者的解决方案。

  • 围绕我的 spacy 模型进行预测/标记化的包装器:
import spacy
textcat_spacy = spacy.load("my-model")
tokenizer_spacy = spacy.tokenizer.Tokenizer(textcat_spacy.vocab)

# Run the spacy pipeline on some random text just to retrieve the classes
doc = textcat_spacy("hi")
classes = list(doc.cats.keys())

# Define a function to predict
def predict(texts):
    # convert texts to bare strings
    texts = [str(text) for text in texts]
    results = []
    for doc in textcat_spacy.pipe(texts):
        # results.append([{'label': cat, 'score': doc.cats[cat]} for cat in doc.cats])
        results.append([doc.cats[cat] for cat in classes])
    return results

# Create a function to create a transformers-like tokenizer to match shap's expectations
def tok_adapter(text, return_offsets_mapping=False):
    doc = tokenizer_spacy(text)
    out = {"input_ids": [tok.norm for tok in doc]}
    if return_offsets_mapping:
        out["offset_mapping"] = [(tok.idx, tok.idx + len(tok)) for tok in doc]
    return out
  • 形状解释器配置:
import shap
# Create the Shap Explainer
# - predict is the "model" function, adapted to a transformers-like model
# - masker is the masker used by shap, which relies on a transformers-like tokenizer
# - algorithm is set to permuation, which is the one used for transformers models
# - output_names are the classes (altough it is not propagated to the permutation explainer currently, which is why plots do not have the labels)
# - max_evals is set to a high number to reduce the probability of cases where the explainer fails because there are too many tokens
explainer = shap.Explainer(predict, masker=shap.maskers.Text(tok_adapter), algorithm="permutation", output_names=classes, max_evals=1500)
  • 用法:
sample = "Some text to classify"
# Process the text using SpaCy
doc = textcat_spacy(sample)
# Get the shap values
shap_values = explainer([sample])

【讨论】:

    猜你喜欢
    • 2019-09-15
    • 2021-01-31
    • 2023-01-01
    • 1970-01-01
    • 2015-04-19
    • 2011-01-04
    • 2023-03-17
    • 1970-01-01
    • 2021-10-10
    相关资源
    最近更新 更多