We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Zero-shot classification pipeline truncation support
Transformers 4.10.0 brought [a change](https://github.com/huggingface/transformers/pull/13299/files#diff-c5af53af9b08fb383b49d7a07c1a56c890198b5cd48adc97aeef753fe2e7d60dR91) that modified the default truncation strategy to TruncationStrategy.DO_NOT_TRUNCATE for the ZeroShotClassificationPipeline.

That uncovered an issue in that the [ZeroShotClassificationPipeline](https://github.com/huggingface/transformers/blob/master/src/transformers/pipelines/zero_shot_classification.py#L217 ) doesn't appear to pass kwargs to the parent's call method. So even when calling the pipeline with truncation=True, it doesn't allow for truncation.

Thank you for the assistance in advance, appreciate all the work you guys do. 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/transformers/pipelines/zero_shot_classification.py`
Content:
```
1 from typing import List, Union
2 
3 import numpy as np
4 
5 from ..file_utils import add_end_docstrings, is_torch_available
6 from ..tokenization_utils import TruncationStrategy
7 from ..utils import logging
8 from .base import PIPELINE_INIT_ARGS, ArgumentHandler, Pipeline
9 
10 
11 if is_torch_available():
12     import torch
13 
14 logger = logging.get_logger(__name__)
15 
16 
17 class ZeroShotClassificationArgumentHandler(ArgumentHandler):
18     """
19     Handles arguments for zero-shot for text classification by turning each possible label into an NLI
20     premise/hypothesis pair.
21     """
22 
23     def _parse_labels(self, labels):
24         if isinstance(labels, str):
25             labels = [label.strip() for label in labels.split(",")]
26         return labels
27 
28     def __call__(self, sequences, labels, hypothesis_template):
29         if len(labels) == 0 or len(sequences) == 0:
30             raise ValueError("You must include at least one label and at least one sequence.")
31         if hypothesis_template.format(labels[0]) == hypothesis_template:
32             raise ValueError(
33                 (
34                     'The provided hypothesis_template "{}" was not able to be formatted with the target labels. '
35                     "Make sure the passed template includes formatting syntax such as {{}} where the label should go."
36                 ).format(hypothesis_template)
37             )
38 
39         if isinstance(sequences, str):
40             sequences = [sequences]
41         labels = self._parse_labels(labels)
42 
43         sequence_pairs = []
44         for sequence in sequences:
45             sequence_pairs.extend([[sequence, hypothesis_template.format(label)] for label in labels])
46 
47         return sequence_pairs
48 
49 
50 @add_end_docstrings(PIPELINE_INIT_ARGS)
51 class ZeroShotClassificationPipeline(Pipeline):
52     """
53     NLI-based zero-shot classification pipeline using a :obj:`ModelForSequenceClassification` trained on NLI (natural
54     language inference) tasks.
55 
56     Any combination of sequences and labels can be passed and each combination will be posed as a premise/hypothesis
57     pair and passed to the pretrained model. Then, the logit for `entailment` is taken as the logit for the candidate
58     label being valid. Any NLI model can be used, but the id of the `entailment` label must be included in the model
59     config's :attr:`~transformers.PretrainedConfig.label2id`.
60 
61     This NLI pipeline can currently be loaded from :func:`~transformers.pipeline` using the following task identifier:
62     :obj:`"zero-shot-classification"`.
63 
64     The models that this pipeline can use are models that have been fine-tuned on an NLI task. See the up-to-date list
65     of available models on `huggingface.co/models <https://huggingface.co/models?search=nli>`__.
66     """
67 
68     def __init__(self, args_parser=ZeroShotClassificationArgumentHandler(), *args, **kwargs):
69         super().__init__(*args, **kwargs)
70         self._args_parser = args_parser
71         if self.entailment_id == -1:
72             logger.warning(
73                 "Failed to determine 'entailment' label id from the label2id mapping in the model config. Setting to "
74                 "-1. Define a descriptive label2id mapping in the model config to ensure correct outputs."
75             )
76 
77     @property
78     def entailment_id(self):
79         for label, ind in self.model.config.label2id.items():
80             if label.lower().startswith("entail"):
81                 return ind
82         return -1
83 
84     def _parse_and_tokenize(
85         self,
86         sequences,
87         candidate_labels,
88         hypothesis_template,
89         padding=True,
90         add_special_tokens=True,
91         truncation=TruncationStrategy.DO_NOT_TRUNCATE,
92         **kwargs
93     ):
94         """
95         Parse arguments and tokenize only_first so that hypothesis (label) is not truncated
96         """
97         sequence_pairs = self._args_parser(sequences, candidate_labels, hypothesis_template)
98         return_tensors = self.framework
99         if getattr(self.tokenizer, "pad_token", None) is None:
100             # XXX some tokenizers do not have a padding token, we use simple lists
101             # and no padding then
102             logger.warning("The tokenizer {self.tokenizer} does not have a pad token, we're not running it as a batch")
103             padding = False
104             inputs = []
105             for sequence_pair in sequence_pairs:
106                 model_input = self.tokenizer(
107                     text=sequence_pair[0],
108                     text_pair=sequence_pair[1],
109                     add_special_tokens=add_special_tokens,
110                     return_tensors=return_tensors,
111                     padding=padding,
112                     truncation=truncation,
113                 )
114                 inputs.append(model_input)
115         else:
116             inputs = self.tokenizer(
117                 sequence_pairs,
118                 add_special_tokens=add_special_tokens,
119                 return_tensors=return_tensors,
120                 padding=padding,
121                 truncation=truncation,
122             )
123 
124         return inputs
125 
126     def _forward(self, inputs, return_tensors=False):
127         """
128         Internal framework specific forward dispatching
129 
130         Args:
131             inputs: dict holding all the keyword arguments for required by the model forward method.
132             return_tensors: Whether to return native framework (pt/tf) tensors rather than numpy array
133 
134         Returns:
135             Numpy array
136         """
137         # Encode for forward
138         with self.device_placement():
139             if self.framework == "tf":
140                 if isinstance(inputs, list):
141                     predictions = []
142                     for input_ in inputs:
143                         prediction = self.model(input_.data, training=False)[0]
144                         predictions.append(prediction)
145                 else:
146                     predictions = self.model(inputs.data, training=False)[0]
147             else:
148                 with torch.no_grad():
149                     if isinstance(inputs, list):
150                         predictions = []
151                         for input_ in inputs:
152                             model_input = self.ensure_tensor_on_device(**input_)
153                             prediction = self.model(**model_input)[0].cpu()
154                             predictions.append(prediction)
155 
156                     else:
157                         inputs = self.ensure_tensor_on_device(**inputs)
158                         predictions = self.model(**inputs)[0].cpu()
159 
160         if return_tensors:
161             return predictions
162         else:
163             if isinstance(predictions, list):
164                 predictions = np.array([p.numpy() for p in predictions])
165             else:
166                 predictions = predictions.numpy()
167             return predictions
168 
169     def __call__(
170         self,
171         sequences: Union[str, List[str]],
172         candidate_labels,
173         hypothesis_template="This example is {}.",
174         multi_label=False,
175         **kwargs,
176     ):
177         """
178         Classify the sequence(s) given as inputs. See the :obj:`~transformers.ZeroShotClassificationPipeline`
179         documentation for more information.
180 
181         Args:
182             sequences (:obj:`str` or :obj:`List[str]`):
183                 The sequence(s) to classify, will be truncated if the model input is too large.
184             candidate_labels (:obj:`str` or :obj:`List[str]`):
185                 The set of possible class labels to classify each sequence into. Can be a single label, a string of
186                 comma-separated labels, or a list of labels.
187             hypothesis_template (:obj:`str`, `optional`, defaults to :obj:`"This example is {}."`):
188                 The template used to turn each label into an NLI-style hypothesis. This template must include a {} or
189                 similar syntax for the candidate label to be inserted into the template. For example, the default
190                 template is :obj:`"This example is {}."` With the candidate label :obj:`"sports"`, this would be fed
191                 into the model like :obj:`"<cls> sequence to classify <sep> This example is sports . <sep>"`. The
192                 default template works well in many cases, but it may be worthwhile to experiment with different
193                 templates depending on the task setting.
194             multi_label (:obj:`bool`, `optional`, defaults to :obj:`False`):
195                 Whether or not multiple candidate labels can be true. If :obj:`False`, the scores are normalized such
196                 that the sum of the label likelihoods for each sequence is 1. If :obj:`True`, the labels are considered
197                 independent and probabilities are normalized for each candidate by doing a softmax of the entailment
198                 score vs. the contradiction score.
199 
200         Return:
201             A :obj:`dict` or a list of :obj:`dict`: Each result comes as a dictionary with the following keys:
202 
203             - **sequence** (:obj:`str`) -- The sequence for which this is the output.
204             - **labels** (:obj:`List[str]`) -- The labels sorted by order of likelihood.
205             - **scores** (:obj:`List[float]`) -- The probabilities for each of the labels.
206         """
207         if "multi_class" in kwargs and kwargs["multi_class"] is not None:
208             multi_label = kwargs.pop("multi_class")
209             logger.warning(
210                 "The `multi_class` argument has been deprecated and renamed to `multi_label`. "
211                 "`multi_class` will be removed in a future version of Transformers."
212             )
213 
214         if sequences and isinstance(sequences, str):
215             sequences = [sequences]
216 
217         outputs = super().__call__(sequences, candidate_labels, hypothesis_template)
218         if isinstance(outputs, list):
219             # XXX: Some tokenizers cannot handle batching because they don't
220             # have pad_token, so outputs will be a list, however, because outputs
221             # is only n logits and sequence_length is not present anymore, we
222             # can recreate a tensor out of outputs.
223             outputs = np.array(outputs)
224         num_sequences = len(sequences)
225         candidate_labels = self._args_parser._parse_labels(candidate_labels)
226         reshaped_outputs = outputs.reshape((num_sequences, len(candidate_labels), -1))
227 
228         if len(candidate_labels) == 1:
229             multi_label = True
230 
231         if not multi_label:
232             # softmax the "entailment" logits over all candidate labels
233             entail_logits = reshaped_outputs[..., self.entailment_id]
234             scores = np.exp(entail_logits) / np.exp(entail_logits).sum(-1, keepdims=True)
235         else:
236             # softmax over the entailment vs. contradiction dim for each label independently
237             entailment_id = self.entailment_id
238             contradiction_id = -1 if entailment_id == 0 else 0
239             entail_contr_logits = reshaped_outputs[..., [contradiction_id, entailment_id]]
240             scores = np.exp(entail_contr_logits) / np.exp(entail_contr_logits).sum(-1, keepdims=True)
241             scores = scores[..., 1]
242 
243         result = []
244         for iseq in range(num_sequences):
245             top_inds = list(reversed(scores[iseq].argsort()))
246             result.append(
247                 {
248                     "sequence": sequences if isinstance(sequences, str) else sequences[iseq],
249                     "labels": [candidate_labels[i] for i in top_inds],
250                     "scores": scores[iseq][top_inds].tolist(),
251                 }
252             )
253 
254         if len(result) == 1:
255             return result[0]
256         return result
257
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/transformers/pipelines/zero_shot_classification.py b/src/transformers/pipelines/zero_shot_classification.py
--- a/src/transformers/pipelines/zero_shot_classification.py
+++ b/src/transformers/pipelines/zero_shot_classification.py
@@ -88,7 +88,7 @@
         hypothesis_template,
         padding=True,
         add_special_tokens=True,
-        truncation=TruncationStrategy.DO_NOT_TRUNCATE,
+        truncation=TruncationStrategy.ONLY_FIRST,
         **kwargs
     ):
         """
@@ -113,13 +113,31 @@
                 )
                 inputs.append(model_input)
         else:
-            inputs = self.tokenizer(
-                sequence_pairs,
-                add_special_tokens=add_special_tokens,
-                return_tensors=return_tensors,
-                padding=padding,
-                truncation=truncation,
-            )
+            try:
+                inputs = self.tokenizer(
+                    sequence_pairs,
+                    add_special_tokens=add_special_tokens,
+                    return_tensors=return_tensors,
+                    padding=padding,
+                    truncation=truncation,
+                )
+            except Exception as e:
+                if "too short" in str(e):
+                    # tokenizers might yell that we want to truncate
+                    # to a value that is not even reached by the input.
+                    # In that case we don't want to truncate.
+                    # It seems there's not a really better way to catch that
+                    # exception.
+
+                    inputs = self.tokenizer(
+                        sequence_pairs,
+                        add_special_tokens=add_special_tokens,
+                        return_tensors=return_tensors,
+                        padding=padding,
+                        truncation=TruncationStrategy.DO_NOT_TRUNCATE,
+                    )
+                else:
+                    raise e
 
         return inputs

{"golden_diff": "diff --git a/src/transformers/pipelines/zero_shot_classification.py b/src/transformers/pipelines/zero_shot_classification.py\n--- a/src/transformers/pipelines/zero_shot_classification.py\n+++ b/src/transformers/pipelines/zero_shot_classification.py\n@@ -88,7 +88,7 @@\n         hypothesis_template,\n         padding=True,\n         add_special_tokens=True,\n-        truncation=TruncationStrategy.DO_NOT_TRUNCATE,\n+        truncation=TruncationStrategy.ONLY_FIRST,\n         **kwargs\n     ):\n         \"\"\"\n@@ -113,13 +113,31 @@\n                 )\n                 inputs.append(model_input)\n         else:\n-            inputs = self.tokenizer(\n-                sequence_pairs,\n-                add_special_tokens=add_special_tokens,\n-                return_tensors=return_tensors,\n-                padding=padding,\n-                truncation=truncation,\n-            )\n+            try:\n+                inputs = self.tokenizer(\n+                    sequence_pairs,\n+                    add_special_tokens=add_special_tokens,\n+                    return_tensors=return_tensors,\n+                    padding=padding,\n+                    truncation=truncation,\n+                )\n+            except Exception as e:\n+                if \"too short\" in str(e):\n+                    # tokenizers might yell that we want to truncate\n+                    # to a value that is not even reached by the input.\n+                    # In that case we don't want to truncate.\n+                    # It seems there's not a really better way to catch that\n+                    # exception.\n+\n+                    inputs = self.tokenizer(\n+                        sequence_pairs,\n+                        add_special_tokens=add_special_tokens,\n+                        return_tensors=return_tensors,\n+                        padding=padding,\n+                        truncation=TruncationStrategy.DO_NOT_TRUNCATE,\n+                    )\n+                else:\n+                    raise e\n \n         return inputs\n", "issue": "Zero-shot classification pipeline truncation support\nTransformers 4.10.0 brought [a change](https://github.com/huggingface/transformers/pull/13299/files#diff-c5af53af9b08fb383b49d7a07c1a56c890198b5cd48adc97aeef753fe2e7d60dR91) that modified the default truncation strategy to TruncationStrategy.DO_NOT_TRUNCATE for the ZeroShotClassificationPipeline.\r\n\r\nThat uncovered an issue in that the [ZeroShotClassificationPipeline](https://github.com/huggingface/transformers/blob/master/src/transformers/pipelines/zero_shot_classification.py#L217 ) doesn't appear to pass kwargs to the parent's call method. So even when calling the pipeline with truncation=True, it doesn't allow for truncation.\r\n\r\nThank you for the assistance in advance, appreciate all the work you guys do. \n", "before_files": [{"content": "from typing import List, Union\n\nimport numpy as np\n\nfrom ..file_utils import add_end_docstrings, is_torch_available\nfrom ..tokenization_utils import TruncationStrategy\nfrom ..utils import logging\nfrom .base import PIPELINE_INIT_ARGS, ArgumentHandler, Pipeline\n\n\nif is_torch_available():\n    import torch\n\nlogger = logging.get_logger(__name__)\n\n\nclass ZeroShotClassificationArgumentHandler(ArgumentHandler):\n    \"\"\"\n    Handles arguments for zero-shot for text classification by turning each possible label into an NLI\n    premise/hypothesis pair.\n    \"\"\"\n\n    def _parse_labels(self, labels):\n        if isinstance(labels, str):\n            labels = [label.strip() for label in labels.split(\",\")]\n        return labels\n\n    def __call__(self, sequences, labels, hypothesis_template):\n        if len(labels) == 0 or len(sequences) == 0:\n            raise ValueError(\"You must include at least one label and at least one sequence.\")\n        if hypothesis_template.format(labels[0]) == hypothesis_template:\n            raise ValueError(\n                (\n                    'The provided hypothesis_template \"{}\" was not able to be formatted with the target labels. '\n                    \"Make sure the passed template includes formatting syntax such as {{}} where the label should go.\"\n                ).format(hypothesis_template)\n            )\n\n        if isinstance(sequences, str):\n            sequences = [sequences]\n        labels = self._parse_labels(labels)\n\n        sequence_pairs = []\n        for sequence in sequences:\n            sequence_pairs.extend([[sequence, hypothesis_template.format(label)] for label in labels])\n\n        return sequence_pairs\n\n\n@add_end_docstrings(PIPELINE_INIT_ARGS)\nclass ZeroShotClassificationPipeline(Pipeline):\n    \"\"\"\n    NLI-based zero-shot classification pipeline using a :obj:`ModelForSequenceClassification` trained on NLI (natural\n    language inference) tasks.\n\n    Any combination of sequences and labels can be passed and each combination will be posed as a premise/hypothesis\n    pair and passed to the pretrained model. Then, the logit for `entailment` is taken as the logit for the candidate\n    label being valid. Any NLI model can be used, but the id of the `entailment` label must be included in the model\n    config's :attr:`~transformers.PretrainedConfig.label2id`.\n\n    This NLI pipeline can currently be loaded from :func:`~transformers.pipeline` using the following task identifier:\n    :obj:`\"zero-shot-classification\"`.\n\n    The models that this pipeline can use are models that have been fine-tuned on an NLI task. See the up-to-date list\n    of available models on `huggingface.co/models <https://huggingface.co/models?search=nli>`__.\n    \"\"\"\n\n    def __init__(self, args_parser=ZeroShotClassificationArgumentHandler(), *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._args_parser = args_parser\n        if self.entailment_id == -1:\n            logger.warning(\n                \"Failed to determine 'entailment' label id from the label2id mapping in the model config. Setting to \"\n                \"-1. Define a descriptive label2id mapping in the model config to ensure correct outputs.\"\n            )\n\n    @property\n    def entailment_id(self):\n        for label, ind in self.model.config.label2id.items():\n            if label.lower().startswith(\"entail\"):\n                return ind\n        return -1\n\n    def _parse_and_tokenize(\n        self,\n        sequences,\n        candidate_labels,\n        hypothesis_template,\n        padding=True,\n        add_special_tokens=True,\n        truncation=TruncationStrategy.DO_NOT_TRUNCATE,\n        **kwargs\n    ):\n        \"\"\"\n        Parse arguments and tokenize only_first so that hypothesis (label) is not truncated\n        \"\"\"\n        sequence_pairs = self._args_parser(sequences, candidate_labels, hypothesis_template)\n        return_tensors = self.framework\n        if getattr(self.tokenizer, \"pad_token\", None) is None:\n            # XXX some tokenizers do not have a padding token, we use simple lists\n            # and no padding then\n            logger.warning(\"The tokenizer {self.tokenizer} does not have a pad token, we're not running it as a batch\")\n            padding = False\n            inputs = []\n            for sequence_pair in sequence_pairs:\n                model_input = self.tokenizer(\n                    text=sequence_pair[0],\n                    text_pair=sequence_pair[1],\n                    add_special_tokens=add_special_tokens,\n                    return_tensors=return_tensors,\n                    padding=padding,\n                    truncation=truncation,\n                )\n                inputs.append(model_input)\n        else:\n            inputs = self.tokenizer(\n                sequence_pairs,\n                add_special_tokens=add_special_tokens,\n                return_tensors=return_tensors,\n                padding=padding,\n                truncation=truncation,\n            )\n\n        return inputs\n\n    def _forward(self, inputs, return_tensors=False):\n        \"\"\"\n        Internal framework specific forward dispatching\n\n        Args:\n            inputs: dict holding all the keyword arguments for required by the model forward method.\n            return_tensors: Whether to return native framework (pt/tf) tensors rather than numpy array\n\n        Returns:\n            Numpy array\n        \"\"\"\n        # Encode for forward\n        with self.device_placement():\n            if self.framework == \"tf\":\n                if isinstance(inputs, list):\n                    predictions = []\n                    for input_ in inputs:\n                        prediction = self.model(input_.data, training=False)[0]\n                        predictions.append(prediction)\n                else:\n                    predictions = self.model(inputs.data, training=False)[0]\n            else:\n                with torch.no_grad():\n                    if isinstance(inputs, list):\n                        predictions = []\n                        for input_ in inputs:\n                            model_input = self.ensure_tensor_on_device(**input_)\n                            prediction = self.model(**model_input)[0].cpu()\n                            predictions.append(prediction)\n\n                    else:\n                        inputs = self.ensure_tensor_on_device(**inputs)\n                        predictions = self.model(**inputs)[0].cpu()\n\n        if return_tensors:\n            return predictions\n        else:\n            if isinstance(predictions, list):\n                predictions = np.array([p.numpy() for p in predictions])\n            else:\n                predictions = predictions.numpy()\n            return predictions\n\n    def __call__(\n        self,\n        sequences: Union[str, List[str]],\n        candidate_labels,\n        hypothesis_template=\"This example is {}.\",\n        multi_label=False,\n        **kwargs,\n    ):\n        \"\"\"\n        Classify the sequence(s) given as inputs. See the :obj:`~transformers.ZeroShotClassificationPipeline`\n        documentation for more information.\n\n        Args:\n            sequences (:obj:`str` or :obj:`List[str]`):\n                The sequence(s) to classify, will be truncated if the model input is too large.\n            candidate_labels (:obj:`str` or :obj:`List[str]`):\n                The set of possible class labels to classify each sequence into. Can be a single label, a string of\n                comma-separated labels, or a list of labels.\n            hypothesis_template (:obj:`str`, `optional`, defaults to :obj:`\"This example is {}.\"`):\n                The template used to turn each label into an NLI-style hypothesis. This template must include a {} or\n                similar syntax for the candidate label to be inserted into the template. For example, the default\n                template is :obj:`\"This example is {}.\"` With the candidate label :obj:`\"sports\"`, this would be fed\n                into the model like :obj:`\"<cls> sequence to classify <sep> This example is sports . <sep>\"`. The\n                default template works well in many cases, but it may be worthwhile to experiment with different\n                templates depending on the task setting.\n            multi_label (:obj:`bool`, `optional`, defaults to :obj:`False`):\n                Whether or not multiple candidate labels can be true. If :obj:`False`, the scores are normalized such\n                that the sum of the label likelihoods for each sequence is 1. If :obj:`True`, the labels are considered\n                independent and probabilities are normalized for each candidate by doing a softmax of the entailment\n                score vs. the contradiction score.\n\n        Return:\n            A :obj:`dict` or a list of :obj:`dict`: Each result comes as a dictionary with the following keys:\n\n            - **sequence** (:obj:`str`) -- The sequence for which this is the output.\n            - **labels** (:obj:`List[str]`) -- The labels sorted by order of likelihood.\n            - **scores** (:obj:`List[float]`) -- The probabilities for each of the labels.\n        \"\"\"\n        if \"multi_class\" in kwargs and kwargs[\"multi_class\"] is not None:\n            multi_label = kwargs.pop(\"multi_class\")\n            logger.warning(\n                \"The `multi_class` argument has been deprecated and renamed to `multi_label`. \"\n                \"`multi_class` will be removed in a future version of Transformers.\"\n            )\n\n        if sequences and isinstance(sequences, str):\n            sequences = [sequences]\n\n        outputs = super().__call__(sequences, candidate_labels, hypothesis_template)\n        if isinstance(outputs, list):\n            # XXX: Some tokenizers cannot handle batching because they don't\n            # have pad_token, so outputs will be a list, however, because outputs\n            # is only n logits and sequence_length is not present anymore, we\n            # can recreate a tensor out of outputs.\n            outputs = np.array(outputs)\n        num_sequences = len(sequences)\n        candidate_labels = self._args_parser._parse_labels(candidate_labels)\n        reshaped_outputs = outputs.reshape((num_sequences, len(candidate_labels), -1))\n\n        if len(candidate_labels) == 1:\n            multi_label = True\n\n        if not multi_label:\n            # softmax the \"entailment\" logits over all candidate labels\n            entail_logits = reshaped_outputs[..., self.entailment_id]\n            scores = np.exp(entail_logits) / np.exp(entail_logits).sum(-1, keepdims=True)\n        else:\n            # softmax over the entailment vs. contradiction dim for each label independently\n            entailment_id = self.entailment_id\n            contradiction_id = -1 if entailment_id == 0 else 0\n            entail_contr_logits = reshaped_outputs[..., [contradiction_id, entailment_id]]\n            scores = np.exp(entail_contr_logits) / np.exp(entail_contr_logits).sum(-1, keepdims=True)\n            scores = scores[..., 1]\n\n        result = []\n        for iseq in range(num_sequences):\n            top_inds = list(reversed(scores[iseq].argsort()))\n            result.append(\n                {\n                    \"sequence\": sequences if isinstance(sequences, str) else sequences[iseq],\n                    \"labels\": [candidate_labels[i] for i in top_inds],\n                    \"scores\": scores[iseq][top_inds].tolist(),\n                }\n            )\n\n        if len(result) == 1:\n            return result[0]\n        return result\n", "path": "src/transformers/pipelines/zero_shot_classification.py"}], "after_files": [{"content": "from typing import List, Union\n\nimport numpy as np\n\nfrom ..file_utils import add_end_docstrings, is_torch_available\nfrom ..tokenization_utils import TruncationStrategy\nfrom ..utils import logging\nfrom .base import PIPELINE_INIT_ARGS, ArgumentHandler, Pipeline\n\n\nif is_torch_available():\n    import torch\n\nlogger = logging.get_logger(__name__)\n\n\nclass ZeroShotClassificationArgumentHandler(ArgumentHandler):\n    \"\"\"\n    Handles arguments for zero-shot for text classification by turning each possible label into an NLI\n    premise/hypothesis pair.\n    \"\"\"\n\n    def _parse_labels(self, labels):\n        if isinstance(labels, str):\n            labels = [label.strip() for label in labels.split(\",\")]\n        return labels\n\n    def __call__(self, sequences, labels, hypothesis_template):\n        if len(labels) == 0 or len(sequences) == 0:\n            raise ValueError(\"You must include at least one label and at least one sequence.\")\n        if hypothesis_template.format(labels[0]) == hypothesis_template:\n            raise ValueError(\n                (\n                    'The provided hypothesis_template \"{}\" was not able to be formatted with the target labels. '\n                    \"Make sure the passed template includes formatting syntax such as {{}} where the label should go.\"\n                ).format(hypothesis_template)\n            )\n\n        if isinstance(sequences, str):\n            sequences = [sequences]\n        labels = self._parse_labels(labels)\n\n        sequence_pairs = []\n        for sequence in sequences:\n            sequence_pairs.extend([[sequence, hypothesis_template.format(label)] for label in labels])\n\n        return sequence_pairs\n\n\n@add_end_docstrings(PIPELINE_INIT_ARGS)\nclass ZeroShotClassificationPipeline(Pipeline):\n    \"\"\"\n    NLI-based zero-shot classification pipeline using a :obj:`ModelForSequenceClassification` trained on NLI (natural\n    language inference) tasks.\n\n    Any combination of sequences and labels can be passed and each combination will be posed as a premise/hypothesis\n    pair and passed to the pretrained model. Then, the logit for `entailment` is taken as the logit for the candidate\n    label being valid. Any NLI model can be used, but the id of the `entailment` label must be included in the model\n    config's :attr:`~transformers.PretrainedConfig.label2id`.\n\n    This NLI pipeline can currently be loaded from :func:`~transformers.pipeline` using the following task identifier:\n    :obj:`\"zero-shot-classification\"`.\n\n    The models that this pipeline can use are models that have been fine-tuned on an NLI task. See the up-to-date list\n    of available models on `huggingface.co/models <https://huggingface.co/models?search=nli>`__.\n    \"\"\"\n\n    def __init__(self, args_parser=ZeroShotClassificationArgumentHandler(), *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._args_parser = args_parser\n        if self.entailment_id == -1:\n            logger.warning(\n                \"Failed to determine 'entailment' label id from the label2id mapping in the model config. Setting to \"\n                \"-1. Define a descriptive label2id mapping in the model config to ensure correct outputs.\"\n            )\n\n    @property\n    def entailment_id(self):\n        for label, ind in self.model.config.label2id.items():\n            if label.lower().startswith(\"entail\"):\n                return ind\n        return -1\n\n    def _parse_and_tokenize(\n        self,\n        sequences,\n        candidate_labels,\n        hypothesis_template,\n        padding=True,\n        add_special_tokens=True,\n        truncation=TruncationStrategy.ONLY_FIRST,\n        **kwargs\n    ):\n        \"\"\"\n        Parse arguments and tokenize only_first so that hypothesis (label) is not truncated\n        \"\"\"\n        sequence_pairs = self._args_parser(sequences, candidate_labels, hypothesis_template)\n        return_tensors = self.framework\n        if getattr(self.tokenizer, \"pad_token\", None) is None:\n            # XXX some tokenizers do not have a padding token, we use simple lists\n            # and no padding then\n            logger.warning(\"The tokenizer {self.tokenizer} does not have a pad token, we're not running it as a batch\")\n            padding = False\n            inputs = []\n            for sequence_pair in sequence_pairs:\n                model_input = self.tokenizer(\n                    text=sequence_pair[0],\n                    text_pair=sequence_pair[1],\n                    add_special_tokens=add_special_tokens,\n                    return_tensors=return_tensors,\n                    padding=padding,\n                    truncation=truncation,\n                )\n                inputs.append(model_input)\n        else:\n            try:\n                inputs = self.tokenizer(\n                    sequence_pairs,\n                    add_special_tokens=add_special_tokens,\n                    return_tensors=return_tensors,\n                    padding=padding,\n                    truncation=truncation,\n                )\n            except Exception as e:\n                if \"too short\" in str(e):\n                    # tokenizers might yell that we want to truncate\n                    # to a value that is not even reached by the input.\n                    # In that case we don't want to truncate.\n                    # It seems there's not a really better way to catch that\n                    # exception.\n\n                    inputs = self.tokenizer(\n                        sequence_pairs,\n                        add_special_tokens=add_special_tokens,\n                        return_tensors=return_tensors,\n                        padding=padding,\n                        truncation=TruncationStrategy.DO_NOT_TRUNCATE,\n                    )\n                else:\n                    raise e\n\n        return inputs\n\n    def _forward(self, inputs, return_tensors=False):\n        \"\"\"\n        Internal framework specific forward dispatching\n\n        Args:\n            inputs: dict holding all the keyword arguments for required by the model forward method.\n            return_tensors: Whether to return native framework (pt/tf) tensors rather than numpy array\n\n        Returns:\n            Numpy array\n        \"\"\"\n        # Encode for forward\n        with self.device_placement():\n            if self.framework == \"tf\":\n                if isinstance(inputs, list):\n                    predictions = []\n                    for input_ in inputs:\n                        prediction = self.model(input_.data, training=False)[0]\n                        predictions.append(prediction)\n                else:\n                    predictions = self.model(inputs.data, training=False)[0]\n            else:\n                with torch.no_grad():\n                    if isinstance(inputs, list):\n                        predictions = []\n                        for input_ in inputs:\n                            model_input = self.ensure_tensor_on_device(**input_)\n                            prediction = self.model(**model_input)[0].cpu()\n                            predictions.append(prediction)\n\n                    else:\n                        inputs = self.ensure_tensor_on_device(**inputs)\n                        predictions = self.model(**inputs)[0].cpu()\n\n        if return_tensors:\n            return predictions\n        else:\n            if isinstance(predictions, list):\n                predictions = np.array([p.numpy() for p in predictions])\n            else:\n                predictions = predictions.numpy()\n            return predictions\n\n    def __call__(\n        self,\n        sequences: Union[str, List[str]],\n        candidate_labels,\n        hypothesis_template=\"This example is {}.\",\n        multi_label=False,\n        **kwargs,\n    ):\n        \"\"\"\n        Classify the sequence(s) given as inputs. See the :obj:`~transformers.ZeroShotClassificationPipeline`\n        documentation for more information.\n\n        Args:\n            sequences (:obj:`str` or :obj:`List[str]`):\n                The sequence(s) to classify, will be truncated if the model input is too large.\n            candidate_labels (:obj:`str` or :obj:`List[str]`):\n                The set of possible class labels to classify each sequence into. Can be a single label, a string of\n                comma-separated labels, or a list of labels.\n            hypothesis_template (:obj:`str`, `optional`, defaults to :obj:`\"This example is {}.\"`):\n                The template used to turn each label into an NLI-style hypothesis. This template must include a {} or\n                similar syntax for the candidate label to be inserted into the template. For example, the default\n                template is :obj:`\"This example is {}.\"` With the candidate label :obj:`\"sports\"`, this would be fed\n                into the model like :obj:`\"<cls> sequence to classify <sep> This example is sports . <sep>\"`. The\n                default template works well in many cases, but it may be worthwhile to experiment with different\n                templates depending on the task setting.\n            multi_label (:obj:`bool`, `optional`, defaults to :obj:`False`):\n                Whether or not multiple candidate labels can be true. If :obj:`False`, the scores are normalized such\n                that the sum of the label likelihoods for each sequence is 1. If :obj:`True`, the labels are considered\n                independent and probabilities are normalized for each candidate by doing a softmax of the entailment\n                score vs. the contradiction score.\n\n        Return:\n            A :obj:`dict` or a list of :obj:`dict`: Each result comes as a dictionary with the following keys:\n\n            - **sequence** (:obj:`str`) -- The sequence for which this is the output.\n            - **labels** (:obj:`List[str]`) -- The labels sorted by order of likelihood.\n            - **scores** (:obj:`List[float]`) -- The probabilities for each of the labels.\n        \"\"\"\n        if \"multi_class\" in kwargs and kwargs[\"multi_class\"] is not None:\n            multi_label = kwargs.pop(\"multi_class\")\n            logger.warning(\n                \"The `multi_class` argument has been deprecated and renamed to `multi_label`. \"\n                \"`multi_class` will be removed in a future version of Transformers.\"\n            )\n\n        if sequences and isinstance(sequences, str):\n            sequences = [sequences]\n\n        outputs = super().__call__(sequences, candidate_labels, hypothesis_template)\n        if isinstance(outputs, list):\n            # XXX: Some tokenizers cannot handle batching because they don't\n            # have pad_token, so outputs will be a list, however, because outputs\n            # is only n logits and sequence_length is not present anymore, we\n            # can recreate a tensor out of outputs.\n            outputs = np.array(outputs)\n        num_sequences = len(sequences)\n        candidate_labels = self._args_parser._parse_labels(candidate_labels)\n        reshaped_outputs = outputs.reshape((num_sequences, len(candidate_labels), -1))\n\n        if len(candidate_labels) == 1:\n            multi_label = True\n\n        if not multi_label:\n            # softmax the \"entailment\" logits over all candidate labels\n            entail_logits = reshaped_outputs[..., self.entailment_id]\n            scores = np.exp(entail_logits) / np.exp(entail_logits).sum(-1, keepdims=True)\n        else:\n            # softmax over the entailment vs. contradiction dim for each label independently\n            entailment_id = self.entailment_id\n            contradiction_id = -1 if entailment_id == 0 else 0\n            entail_contr_logits = reshaped_outputs[..., [contradiction_id, entailment_id]]\n            scores = np.exp(entail_contr_logits) / np.exp(entail_contr_logits).sum(-1, keepdims=True)\n            scores = scores[..., 1]\n\n        result = []\n        for iseq in range(num_sequences):\n            top_inds = list(reversed(scores[iseq].argsort()))\n            result.append(\n                {\n                    \"sequence\": sequences if isinstance(sequences, str) else sequences[iseq],\n                    \"labels\": [candidate_labels[i] for i in top_inds],\n                    \"scores\": scores[iseq][top_inds].tolist(),\n                }\n            )\n\n        if len(result) == 1:\n            return result[0]\n        return result\n", "path": "src/transformers/pipelines/zero_shot_classification.py"}]}