anli.py 4.34 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
"""
Adversarial NLI: A New Benchmark for Natural Language Understanding
https://arxiv.org/pdf/1910.14599.pdf

Adversarial NLI (ANLI) is a dataset collected via an iterative, adversarial
human-and-model-in-the-loop procedure. It consists of three rounds that progressively
increase in difficulty and complexity, and each question-answer includes annotator-
provided explanations.

Homepage: "https://github.com/facebookresearch/anli"
11
12
"""
import numpy as np
Jonathan Tow's avatar
Jonathan Tow committed
13
14
from lm_eval.base import rf, Task
from lm_eval.metrics import mean
15

16
17

_CITATION = """
18
19
20
21
22
23
24
25
26
27
28
29
30
@inproceedings{nie-etal-2020-adversarial,
    title = "Adversarial {NLI}: A New Benchmark for Natural Language Understanding",
    author = "Nie, Yixin  and
      Williams, Adina  and
      Dinan, Emily  and
      Bansal, Mohit  and
      Weston, Jason  and
      Kiela, Douwe",
    booktitle = "Proceedings of the 58th Annual Meeting of the Association for Computational Linguistics",
    year = "2020",
    publisher = "Association for Computational Linguistics",
}
"""
Leo Gao's avatar
Leo Gao committed
31

32

Jonathan Tow's avatar
Jonathan Tow committed
33
class ANLIBase(Task):
Leo Gao's avatar
Leo Gao committed
34
    VERSION = 0
Leo Gao's avatar
Leo Gao committed
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    DATASET_PATH = "anli"
    DATASET_NAME = None
    SPLIT = None

    def has_training_docs(self):
        return True

    def has_validation_docs(self):
        return True

    def has_test_docs(self):
        return True

    def training_docs(self):
        if self.has_training_docs():
            if self._training_docs is None:
Jonathan Tow's avatar
Jonathan Tow committed
51
                self._training_docs = list(self.dataset["train_r" + str(self.SPLIT)])
Leo Gao's avatar
Leo Gao committed
52
53
54
55
            return self._training_docs

    def validation_docs(self):
        if self.has_validation_docs():
Jonathan Tow's avatar
Jonathan Tow committed
56
            return self.dataset["dev_r" + str(self.SPLIT)]
Leo Gao's avatar
Leo Gao committed
57
58
59

    def test_docs(self):
        if self.has_test_docs():
Jonathan Tow's avatar
Jonathan Tow committed
60
            return self.dataset["test_r" + str(self.SPLIT)]
Leo Gao's avatar
Leo Gao committed
61

62
    def doc_to_text(self, doc):
Leo Gao's avatar
Leo Gao committed
63
64
65
66
        # OA does this a bit weirdly: they prepend "anli 1:  anli 1:  " to the beginning
        # of the prompt (yes, repeating it!). also, " True, False, or Neither?" is directly 
        # appended onto the question, with no "Answer:" or even a newline. Do we *really* 
        # want to do it exactly as OA did?
Leo Gao's avatar
Leo Gao committed
67
        return doc['premise'] + '\nQuestion: ' + doc['hypothesis'] + ' True, False, or Neither?\nAnswer:'
Leo Gao's avatar
Leo Gao committed
68

69
    def doc_to_target(self, doc):
Jonathan Tow's avatar
Jonathan Tow committed
70
71
72
        # True = entailment
        # False = contradiction
        # Neither = neutral
73
        return " " + ["True", "Neither", "False"][doc['label']]
Leo Gao's avatar
Leo Gao committed
74

Leo Gao's avatar
Leo Gao committed
75
76
77
78
79
80
81
82
83
84
85
    def construct_requests(self, doc, ctx):
        """ Uses RequestFactory to construct Requests and returns an iterable of 
        Requests which will be sent to the LM.

        :param doc:
            The document as returned from training_docs, validation_docs, or test_docs.
        :param ctx: str
            The context string, generated by fewshot_context. This includes the natural 
            language description, as well as the few shot examples, and the question
            part of the document for `doc`. 
        """
Jonathan Tow's avatar
Jonathan Tow committed
86
87
88
89
        ll_true, _ = rf.loglikelihood(ctx, " True") 
        ll_neither, _ = rf.loglikelihood(ctx, " Neither") 
        ll_false, _ = rf.loglikelihood(ctx, " False") 
        return ll_true, ll_neither, ll_false
Leo Gao's avatar
Leo Gao committed
90
91
92
93
94
95
96
97
98
99
100
    
    def process_results(self, doc, results):
        """Take a single document and the LM results and evaluates, returning a 
        dict where keys are the names of submetrics and values are the values of 
        the metric for that one document

        :param doc:
            The document as returned from training_docs, validation_docs, or test_docs.
        :param results:
            The results of the requests created in construct_requests.
        """
Jonathan Tow's avatar
Jonathan Tow committed
101
102
103
104
105
        gold = doc["label"]
        pred = np.argmax(results)
        return {
            "acc": pred == gold
        }
Leo Gao's avatar
Leo Gao committed
106
107
108
109
110
111
112

    def aggregation(self):
        """
        :returns: {str: [float] -> float}
            A dictionary where keys are the names of submetrics and values are 
            functions that aggregate a list of metrics
        """
Jonathan Tow's avatar
Jonathan Tow committed
113
114
115
        return {
            "acc": mean
        }
Leo Gao's avatar
Leo Gao committed
116
117
118
119
120
121
122

    def higher_is_better(self):
        """
        :returns: {str: bool}
            A dictionary where keys are the names of submetrics and values are 
            whether a higher value of the submetric is better
        """
Jonathan Tow's avatar
Jonathan Tow committed
123
124
125
        return {
            "acc": True
        }
Leo Gao's avatar
Leo Gao committed
126

Jonathan Tow's avatar
Jonathan Tow committed
127

Leo Gao's avatar
Leo Gao committed
128
129
130
class ANLIRound1(ANLIBase):
    SPLIT = 1

Jonathan Tow's avatar
Jonathan Tow committed
131

Leo Gao's avatar
Leo Gao committed
132
133
134
class ANLIRound2(ANLIBase):
    SPLIT = 2

Jonathan Tow's avatar
Jonathan Tow committed
135

Leo Gao's avatar
Leo Gao committed
136
class ANLIRound3(ANLIBase):
Jonathan Tow's avatar
Jonathan Tow committed
137
    SPLIT = 3