如何获得 Huggingface Transformer 模型预测 [零样本分类] 的 SHAP 值?
Posted
技术标签:
【中文标题】如何获得 Huggingface Transformer 模型预测 [零样本分类] 的 SHAP 值?【英文标题】:How to get SHAP values for Huggingface Transformer Model Prediction [Zero-Shot Classification]? 【发布时间】:2021-12-06 05:48:12 【问题描述】:通过 Huggingface 给定一个零样本分类任务,如下所示:
from transformers import pipeline
classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
example_text = "This is an example text about snowflakes in the summer"
labels = ["weather", "sports", "computer industry"]
output = classifier(example_text, labels, multi_label=True)
output
'sequence': 'This is an example text about snowflakes in the summer',
'labels': ['weather', 'sports'],
'scores': [0.9780895709991455, 0.021910419687628746]
我正在尝试提取 SHAP 值来为预测结果生成基于文本的解释,如下所示:SHAP for Transformers
我已经根据上面的网址尝试了以下方法:
from transformers import AutoModelForSequenceClassification, AutoTokenizer, ZeroShotClassificationPipeline
model = AutoModelForSequenceClassification.from_pretrained('facebook/bart-large-mnli')
tokenizer = AutoTokenizer.from_pretrained('facebook/bart-large-mnli')
pipe = ZeroShotClassificationPipeline(model=model, tokenizer=tokenizer, return_all_scores=True)
def score_and_visualize(text):
prediction = pipe([text])
print(prediction[0])
explainer = shap.Explainer(pipe)
shap_values = explainer([text])
shap.plots.text(shap_values)
score_and_visualize(example_text)
有什么建议吗?提前感谢您的帮助!
除了上述管道之外,以下方法也可以使用:
from transformers import AutoModelForSequenceClassification, AutoTokenizer, ZeroShotClassificationPipeline
model = AutoModelForSequenceClassification.from_pretrained('facebook/bart-large-mnli')
tokenizer = AutoTokenizer.from_pretrained('facebook/bart-large-mnli')
classifier = ZeroShotClassificationPipeline(model=model, tokenizer=tokenizer, return_all_scores=True)
example_text = "This is an example text about snowflakes in the summer"
labels = ["weather", "sports"]
output = classifier(example_text, labels)
output
'sequence': 'This is an example text about snowflakes in the summer',
'labels': ['weather', 'sports'],
'scores': [0.9780895709991455, 0.021910419687628746]
【问题讨论】:
【参考方案1】:shap 目前不支持ZeroShotClassificationPipeline,但您可以使用解决方法。需要解决方法是因为:
-
shap Explainer 仅将一个参数转发给模型(在本例中为管道),但 ZeroShotClassificationPipeline 需要两个参数,即文本和标签。
shap Explainer 将访问模型的配置并使用其
label2id
和id2label
属性。它们与 ZeroShotClassificationPipeline 返回的标签不匹配,将导致错误。
以下是对一种可能的解决方法的建议。我建议在 shap 打开一个问题,并请求官方支持 huggingface 的 ZeroShotClassificationPipeline。
import shap
from transformers import AutoModelForSequenceClassification, AutoTokenizer, ZeroShotClassificationPipeline
from typing import Union, List
weights = "valhalla/distilbart-mnli-12-3"
model = AutoModelForSequenceClassification.from_pretrained(weights)
tokenizer = AutoTokenizer.from_pretrained(weights)
# Create your own pipeline that only requires the text parameter
# for the __call__ method and provides a method to set the labels
class MyZeroShotClassificationPipeline(ZeroShotClassificationPipeline):
# Overwrite the __call__ method
def __call__(self, *args):
o = super().__call__(args[0], self.workaround_labels)[0]
return [["label":x[0], "score": x[1] for x in zip(o["labels"], o["scores"])]]
def set_labels_workaround(self, labels: Union[str,List[str]]):
self.workaround_labels = labels
example_text = "This is an example text about snowflakes in the summer"
labels = ["weather","sports"]
# In the following, we address issue 2.
model.config.label2id.update(v:k for k,v in enumerate(labels))
model.config.id2label.update(k:v for k,v in enumerate(labels))
pipe = MyZeroShotClassificationPipeline(model=model, tokenizer=tokenizer, return_all_scores=True)
pipe.set_labels_workaround(labels)
def score_and_visualize(text):
prediction = pipe([text])
print(prediction[0])
explainer = shap.Explainer(pipe)
shap_values = explainer([text])
shap.plots.text(shap_values)
score_and_visualize(example_text)
输出:
【讨论】:
您正在丢弃原始的'contradiction': 0, 'entailment': 2, 'neutral': 1
并用任意所需的标签代替。你能解释一下这在模型级别是如何工作的吗?
底层模型经过训练可以预测 3 个类别。您是说无需重新训练模型即可任意更改标签的数量和含义?
不,你不能。扔掉原来的标签是我的一个复制和粘贴错误。 ZeroShotClassificationPipeline
需要 entailment
标签。我已经更正了我的答案。谢谢你的评论。 @SergeyBushmanov
仍然不是很有说服力。句子/标签对是他们客厅中的premise/hypothesis
。完全不清楚是否可以将假设作为预训练的标签传递。
ZeroShotClassificationPipeline
创建了premise/hypothesis
。它将以下句子"[CLS] This is an example text about snowflakes in the summer" [SEP] This example is sports. [SEP]".
传递给标记化后的模型,并使用entailment
logits 进行预测。这就是为什么它被称为零射击。 @SergeyBushmanov【参考方案2】:
这是与@cronoik 讨论的后续内容,这可能有助于其他人理解为什么修补label2id
的魔力会起作用。
ZeroShotClassificationPipeline 状态的文档:
使用在 NLI(自然语言推理)任务上训练的
ModelForSequenceClassification
的基于 NLI 的零样本分类管道。可以传递序列和标签的任何组合,并且每个组合都将作为前提/假设对并传递给预训练模型。然后,
entailment
的 logit 被视为候选标签有效的 logit。可以使用任何 NLI 模型,但entailment
标签的 id 必须包含在模型配置的~transformers.PretrainedConfig.label2id
中。
这意味着(参见随附的源代码):
通过__call__
方法提供的标签将被传递到基础训练模型(通过label2id
),并将在前提/蕴含句对中进行尝试
如果您手动覆盖label2id
,则应将entailment
标签添加到label2id
(否则会收到警告)。无需添加任何其他内容。
一旦满足这些条件,模型将返回所提供标签的字典,分类中的 sigmoid/softmax logits 为 entailment
,如
"<cls> sequence to classify <sep> This example is label . <sep>"
作为label
的蕴涵概率。
对于这种类型的分类器,管道label2id's
只是用作一个占位符来保存标签并将它们传递给管道的其他部分。
【讨论】:
以上是关于如何获得 Huggingface Transformer 模型预测 [零样本分类] 的 SHAP 值?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Huggingface 中从 CSV 加载自定义数据集
Huggingface 微调 - 如何在预训练的基础上构建自定义模型
使用 Huggingface TFTrainer 类微调模型时如何指定损失函数?