truthfulqa.py 6.46 KB
Newer Older
Jonathan Tow's avatar
Jonathan Tow committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# Copyright 2020 The HuggingFace Datasets Authors and the current dataset script contributor.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""TruthfulQA dataset."""


import csv
import json

import datasets


_CITATION = """\
@misc{lin2021truthfulqa,
    title={TruthfulQA: Measuring How Models Mimic Human Falsehoods},
    author={Stephanie Lin and Jacob Hilton and Owain Evans},
    year={2021},
    eprint={2109.07958},
    archivePrefix={arXiv},
    primaryClass={cs.CL}
}
"""

_DESCRIPTION = """\
TruthfulQA is a benchmark to measure whether a language model is truthful in
generating answers to questions. The benchmark comprises 817 questions that
span 38 categories, including health, law, finance and politics. Questions are
crafted so that some humans would answer falsely due to a false belief or
misconception. To perform well, models must avoid generating false answers
learned from imitating human texts.
"""

_HOMEPAGE = "https://github.com/sylinrl/TruthfulQA"

# TODO: Add the licence for the dataset here if you can find it
_LICENSE = ""


class TruthfulqaConfig(datasets.BuilderConfig):
    """BuilderConfig for TruthfulQA."""

    def __init__(self, url, features, **kwargs):
        """BuilderConfig for TruthfulQA.

        Args:
        url: *string*, the url to the specific subset of the GPT3 Arithmetic dataset.
        features: *list[string]*, list of the features that will appear in the
            feature dict.
        """
        # Version history:
        super().__init__(version=datasets.Version("0.0.1"), **kwargs)
        self.url = url
        self.features = features


class Truthfulqa(datasets.GeneratorBasedBuilder):
    """TruthfulQA is a benchmark to measure whether a language model is truthful in
Fabrizio Milo's avatar
Fabrizio Milo committed
68
    generating answers to questions."""
Jonathan Tow's avatar
Jonathan Tow committed
69
70
71
72
73

    BUILDER_CONFIGS = [
        TruthfulqaConfig(
            name="multiple_choice",
            url="https://raw.githubusercontent.com/sylinrl/TruthfulQA/013686a06be7a7bde5bf8223943e106c7250123c/data/mc_task.json",
Fabrizio Milo's avatar
Fabrizio Milo committed
74
75
76
77
78
79
80
81
82
83
84
            features=datasets.Features(
                {
                    "question": datasets.Value("string"),
                    "mc1_targets": {
                        "choices": datasets.features.Sequence(datasets.Value("string")),
                        "labels": datasets.features.Sequence(datasets.Value("int32")),
                    },
                    "mc2_targets": {
                        "choices": datasets.features.Sequence(datasets.Value("string")),
                        "labels": datasets.features.Sequence(datasets.Value("int32")),
                    },
Jonathan Tow's avatar
Jonathan Tow committed
85
                }
Fabrizio Milo's avatar
Fabrizio Milo committed
86
87
            ),
            description="The multiple choice TruthfulQA task",
Jonathan Tow's avatar
Jonathan Tow committed
88
89
90
91
        ),
        TruthfulqaConfig(
            name="generation",
            url="https://raw.githubusercontent.com/sylinrl/TruthfulQA/013686a06be7a7bde5bf8223943e106c7250123c/TruthfulQA.csv",
Fabrizio Milo's avatar
Fabrizio Milo committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
            features=datasets.Features(
                {
                    "category": datasets.Value("string"),
                    "question": datasets.Value("string"),
                    "best_answer": datasets.Value("string"),
                    "correct_answers": datasets.features.Sequence(
                        datasets.Value("string")
                    ),
                    "incorrect_answers": datasets.features.Sequence(
                        datasets.Value("string")
                    ),
                    "source": datasets.Value("string"),
                }
            ),
            description="The generative TruthfulQA task",
        ),
Jonathan Tow's avatar
Jonathan Tow committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    ]

    def _info(self):
        return datasets.DatasetInfo(
            description=f"{_DESCRIPTION}\n{self.config.description}",
            features=self.config.features,
            homepage=_HOMEPAGE,
            license=_LICENSE,
            citation=_CITATION,
        )

    def _split_generators(self, dl_manager):
        urls = self.config.url
        data_dir = dl_manager.download_and_extract(urls)
        return [
            datasets.SplitGenerator(
                name=datasets.Split.VALIDATION,
                # These kwargs will be passed to _generate_examples
                gen_kwargs={
                    "filepath": data_dir,
                    "split": "validation",
                },
            ),
        ]

    # method parameters are unpacked from `gen_kwargs` as given in `_split_generators`
    def _generate_examples(self, filepath, split):
        if self.config.name == "multiple_choice":
            # Multiple choice data is in a `JSON` file.
            with open(filepath, encoding="utf-8") as f:
                contents = json.load(f)
                for key, row in enumerate(contents):
                    yield key, {
                        "question": row["question"],
                        "mc1_targets": {
                            "choices": row["mc1_targets"].keys(),
                            "labels": row["mc1_targets"].values(),
                        },
                        "mc2_targets": {
                            "choices": row["mc2_targets"].keys(),
                            "labels": row["mc2_targets"].values(),
Fabrizio Milo's avatar
Fabrizio Milo committed
149
                        },
Jonathan Tow's avatar
Jonathan Tow committed
150
151
152
                    }
        else:
            # Generation data is in a `CSV` file.
Fabrizio Milo's avatar
Fabrizio Milo committed
153
            with open(filepath, newline="") as f:
Jonathan Tow's avatar
Jonathan Tow committed
154
155
156
                contents = csv.DictReader(f)
                for key, row in enumerate(contents):
                    # Ensure that references exist.
Fabrizio Milo's avatar
Fabrizio Milo committed
157
                    if not row["Correct Answers"] or not row["Incorrect Answers"]:
Jonathan Tow's avatar
Jonathan Tow committed
158
159
160
161
162
163
164
                        continue
                    yield key, {
                        "category": row["Category"],
                        "question": row["Question"],
                        "best_answer": row["Best Answer"],
                        # split on ";"
                        "correct_answers": row["Correct Answers"].strip().split(";"),
Fabrizio Milo's avatar
Fabrizio Milo committed
165
166
167
                        "incorrect_answers": row["Incorrect Answers"]
                        .strip()
                        .split(";"),
Jonathan Tow's avatar
Jonathan Tow committed
168
169
                        "source": row["Source"],
                    }