Files
wehub-resource-sync 2aaeece67c
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
Pipelines-Test / Pipelines-Test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

497 lines
16 KiB
Python

# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
#
# 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.
import csv
import json
import os
from abc import abstractmethod
from collections import defaultdict
from dataclasses import dataclass, field
import paddle
import pandas as pd
from paddle.metric import Accuracy
from paddlenlp.datasets import MapDataset
from paddlenlp.metrics import AccuracyAndF1, Mcc, PearsonAndSpearman
@dataclass
class InputExample(object):
"""Data structure of every example in datasets."""
uid: str = field(default=None, metadata={"help": "A unique identifier of the example."})
text_a: str = field(default=None, metadata={"help": "The first text sequence in each example."})
text_b: str = field(default=None, metadata={"help": "The other text sequences in each example."})
cls_label: int = field(default=None, metadata={"help": "The label of classification tasks."})
seq_label: list = field(default=None, metadata={"help": "The label of generation tasks."})
meta: dict = field(default=None, metadata={"help": "An optional dictionary of other data for each example."})
def __repr__(self):
content = {k: v for k, v in self.__dict__.items() if v is not None}
content = json.dumps(content, indent=2, sort_keys=True) + "\n"
return str(content)
def keys(self, keep_none=False):
return [key for key in self.__dict__.keys() if getattr(self, key) is not None]
class InputFeatures(dict):
"""
Data structure of every wrapped example or a batch of examples as the input of model.
Args:
input_ids (paddle.Tensor):
The token ids.
attention_mask (paddle.Tensor):
The mask ids.
token_type_ids (paddle.Tensor, optional):
The token type ids.
input_embeds (paddle.Tensor, optional):
The embeddings of soft tokens.
mask_ids (paddle.Tensor, optional):
The mask ids where 1 denotes that a token is a mask, 0 denotes it is not a mask.
cls_label (list, optional):
The label of classification task.
seq_label (list, optional):
The label of generation task.
uid (list, optional):
The unique id(s) for example(s).
"""
input_keys = [
"input_ids",
"attention_mask",
"token_type_ids",
"input_embeds",
"cls_label",
"seq_label",
"label",
"uid",
"mask_ids",
"soft_token_ids",
]
def __init__(
self,
input_ids=None,
attention_mask=None,
token_type_ids=None,
input_embeds=None,
mask_ids=None,
label=None,
cls_label=None,
seq_label=None,
uid=None,
soft_token_ids=None,
):
self.input_ids = input_ids
self.attention_mask = attention_mask
self.token_type_ids = token_type_ids
self.input_embeds = input_embeds
self.label = label
self.cls_label = cls_label
self.seq_label = seq_label
self.mask_ids = mask_ids
self.uid = uid
self.soft_token_ids = soft_token_ids
@classmethod
def add_keys(cls, *args):
cls.input_keys.extend(args)
def keys(self, keep_none=False):
if keep_none:
return self.input_keys
else:
return [key for key in self.input_keys if getattr(self, key) is not None]
def values(self, keep_none=False):
return [getattr(self, key) for key in self.keys(keep_none=keep_none)]
def items(self):
return [(key, getattr(self, key)) for key in self.keys()]
def __len__(self):
return len(self.keys())
def __repr__(self):
return str(json.dumps(self.items()) + "\n")
def __getitem__(self, key):
return getattr(self, key)
def __iter__(self):
return iter(self.keys())
def __contains__(self, key, keep_none):
return key in self.keys(keep_none)
def __setitem__(self, key, value):
if key not in self.input_keys:
raise KeyError("{} not in predefined keys, use add_keys to add it.".format(key))
setattr(self, key, value)
@staticmethod
def collate_fn(batch):
"""Collate batch data in form of InputFeatures."""
new_batch = {}
for key in batch[0]:
values = [b[key] for b in batch]
try:
new_batch[key] = paddle.to_tensor(values)
except ValueError:
new_batch[key] = values
return InputFeatures(**new_batch)
class DataProcessor(object):
"""Base class for reading datasets from files."""
def __init__(self, labels=None):
self._labels = labels
if labels is not None:
self._labels = sorted(labels)
@property
def labels(self):
if not getattr(self, "_labels"):
raise ValueError("labels and label_mappings are not set yet.")
return self._labels
@labels.setter
def labels(self, labels):
if labels is not None:
self._labels = sorted(labels)
@property
def label_mapping(self):
if not getattr(self, "_labels"):
raise ValueError("labels and label_mappings are not set yet.")
if not getattr(self, "_label_mapping"):
self._label_mapping = {k: i for i, k in enumerate(self._labels)}
return self._label_mapping
@label_mapping.setter
def label_mapping(self, label_mapping):
if getattr(self, "_labels"):
assert self._labels == sorted(list(label_mapping.keys()))
self._label_mapping = label_mapping
@abstractmethod
def get_examples(self, data_dir, split):
raise NotImplementedError
def get_train_examples(self, data_dir):
return self.get_examples(data_dir, "train")
def get_dev_examples(self, data_dir):
return self.get_examples(data_dir, "dev")
def get_test_exaples(self, data_dir):
return self.get_examples(data_dir, "test")
@classmethod
def read_tsv(cls, input_file, quotechar=None):
with open(input_file, "r", encoding="utf-8-sig") as f:
data = csv.reader(f, delimiter="\t", quotechar=quotechar)
return [x for x in data]
@classmethod
def read_csv(cls, input_file, header=None):
data = pd.read_csv(input_file, header=header)
return data.values.tolist()
@classmethod
def read_json(cls, input_file):
with open(input_file, "r") as f:
data = [json.loads(x) for x in f.readlines()]
return data
class BoolQProcessor(DataProcessor):
def __init__(self):
super().__init__(["False", "True"])
self.split_map = {"train": "train", "dev": "dev32", "test": "val"}
def get_examples(self, data_dir, split):
split = self.split_map[split]
raw_data = self.read_json(os.path.join(data_dir, split + ".jsonl"))
examples = []
for i, line in enumerate(raw_data):
examples.append(
InputExample(
uid="%s-%d" % (split, i),
text_a=line["passage"],
text_b=line["question"],
cls_label=str(line["label"]),
)
)
return examples
class MrpcProcesser(DataProcessor):
def __init__(self):
super().__init__(["0", "1"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(InputExample(uid="%s-%d" % (split, i), text_a=line[3], text_b=line[4], cls_label=line[0]))
return examples
class MnliProcessor(DataProcessor):
def __init__(self):
super().__init__(["contradiction", "entailment", "neutral"])
def _process_file(self, split):
if split in ["dev", "test"]:
return split + "_matched"
return split
def get_examples(self, data_dir, split):
split = self._process_file(split)
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(
InputExample(uid="%s-%s" % (split, line[0]), text_a=line[8], text_b=line[9], cls_label=line[-1])
)
return examples
class MnliMismatchedProcessor(MnliProcessor):
def _process_file(self, split):
if split == "dev":
return split + "_matched"
if split == "test":
return split + "_mismatched"
return split
class SnliProcessor(DataProcessor):
def __init__(self):
super().__init__(["contradiction", "entailment", "neutral"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(
InputExample(uid="%s-%s" % (split, line[0]), text_a=line[7], text_b=line[8], cls_label=line[-1])
)
return examples
class ColaProcessor(DataProcessor):
def __init__(self):
super().__init__(["0", "1"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
examples.append(InputExample(uid="%s-%d" % (split, i), text_a=line[3], text_b=None, cls_label=line[1]))
return examples
class Sst2Processor(DataProcessor):
def __init__(self):
super().__init__(["0", "1"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(InputExample(uid="%s-%d" % (split, i), text_a=line[0], text_b=None, cls_label=line[1]))
return examples
class StsbProcessor(DataProcessor):
def __init__(self):
super().__init__(["0", "1"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(
InputExample(uid="%s-%s" % (split, line[0]), text_a=line[7], text_b=line[8], cls_label=line[-1])
)
return examples
class QqpProcessor(DataProcessor):
def __init__(self):
super().__init__(["0", "1"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
try:
examples.append(
InputExample(uid="%s-%s" % (split, line[0]), text_a=line[3], text_b=line[4], cls_label=line[5])
)
except IndexError:
continue
return examples
class QnliProcessor(DataProcessor):
def __init__(self):
super().__init__(["entailment", "not_entailment"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(
InputExample(uid="%s-%s" % (split, line[0]), text_a=line[1], text_b=line[2], cls_label=line[-1])
)
return examples
class RteProcessor(DataProcessor):
def __init__(self):
super().__init__(["entailment", "not_entailment"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(
InputExample(uid="%s-%s" % (split, line[0]), text_a=line[1], text_b=line[2], cls_label=line[-1])
)
return examples
class WnliProcessor(DataProcessor):
def __init__(self):
super().__init__(["0", "1"])
def get_examples(self, data_dir, split):
raw_data = self.read_tsv(os.path.join(data_dir, split + ".tsv"))
examples = []
for i, line in enumerate(raw_data):
if i == 0:
continue
examples.append(
InputExample(uid="%s-%s" % (split, line[0]), text_a=line[1], text_b=line[2], cls_label=line[-1])
)
return examples
class TextClassificationProcessor(DataProcessor):
def __init__(self, task_name):
NUM_LABELS = {"mr": 2, "sst-5": 5, "subj": 2, "trec": 6, "cr": 2, "mpqa": 2}
assert task_name in NUM_LABELS, "task_name not supported."
self.task_name = task_name
self._labels = list(range(NUM_LABELS[self.task_name]))
def get_examples(self, data_dir, split):
raw_data = self.read_csv(os.path.join(data_dir, split + ".csv"))
examples = []
for i, line in enumerate(raw_data):
examples.append(InputExample(uid="%s-%d" % (split, i), text_a=line[1], cls_label=line[0]))
return examples
# The processor mapping for datasets in RGL paper.
PROCESSOR_MAPPING = {
"mrpc": MrpcProcesser(),
"mnli": MnliProcessor(),
"mnli-mm": MnliMismatchedProcessor(),
"snli": SnliProcessor(),
"cola": ColaProcessor(),
"sst-2": Sst2Processor(),
"sts-b": StsbProcessor(),
"qqp": QqpProcessor(),
"qnli": QnliProcessor(),
"rte": RteProcessor(),
"wnli": WnliProcessor(),
"cr": TextClassificationProcessor("cr"),
"mr": TextClassificationProcessor("mr"),
"sst-5": TextClassificationProcessor("sst-5"),
"subj": TextClassificationProcessor("subj"),
"mpqa": TextClassificationProcessor("mpqa"),
"trec": TextClassificationProcessor("trec"),
"boolq": BoolQProcessor(),
}
# The task mapping for datasets.
TASK_MAPPING = defaultdict(lambda: "classification")
TASK_MAPPING["sts-b"] = "regression"
# The metric mapping for datasets.
METRIC_MAPPING = defaultdict(Accuracy)
METRIC_MAPPING.update(
{
"mrpc": AccuracyAndF1(name=["acc", "precision", "recall", "f1", "acc_and_f1"]),
"qqp": AccuracyAndF1(name=["acc", "precision", "recall", "f1", "acc_and_f1"]),
"cola": Mcc(),
"sts-b": PearsonAndSpearman(name=["pearson", "spearman", "corr"]),
}
)
def load_dataset(dataset, data_path=None, splits=[]):
"""
Read datasets from files.
Args:
dataset (str):
The dataset name in lowercase.
data_path (str):
The path to the dataset directory, including train, dev or test file.
splits (list):
Which file(s) of dataset to read, such as ['train', 'dev', 'test'].
"""
assert len(splits) > 0, "No splits, can not load dataset {}".format(dataset)
processor = PROCESSOR_MAPPING[dataset]
data = []
if "train" in splits:
train_examples = processor.get_train_examples(data_path)
data.append(MapDataset(train_examples))
if "dev" in splits:
dev_examples = processor.get_dev_examples(data_path)
data.append(MapDataset(dev_examples))
if "test" in splits:
test_examples = processor.get_test_exaples(data_path)
data.append(MapDataset(test_examples))
data.append(processor.labels)
return data