关于百度搜索技术大赛:PaddleNLP如何自定义数据集

38次阅读

共计 4335 个字符,预计需要花费 11 分钟才能阅读完成。

============

如何自定义数据集

通过应用 PaddleNLP 提供的 :func:load_dataset,:class:MapDataset 和 :class:IterDataset。任何人都能够不便的定义属于本人的数据集。

从本地文件创建数据集

从本地文件创建数据集时,咱们 举荐 依据本地数据集的格局给出读取 function 并传入 :func:load_dataset 中创立数据集。

waybill_ie <https://github.com/PaddlePaddle/PaddleNLP/tree/develop/examples/information_extraction/waybill_ie>__ 快递单信息抽取工作中的数据为例:

.. code-block::

from paddlenlp.datasets import load_dataset

def read(data_path):
    with open(data_path, 'r', encoding='utf-8') as f:
        # 跳过列名
        next(f)
        for line in f:
            words, labels = line.strip('\n').split('\t')
            words = words.split('\002')
            labels = labels.split('\002')
            yield {'tokens': words, 'labels': labels}

# data_path 为 read()办法的参数
map_ds = load_dataset(read, data_path='train.txt',lazy=False) 
iter_ds = load_dataset(read, data_path='train.txt',lazy=True) 

咱们举荐将数据读取代码写成生成器 (generator) 的模式,这样能够更好的构建 :class:MapDataset 和 :class:IterDataset 两种数据集。同时咱们也举荐将单条数据写成字典的格局,这样能够更不便的监测数据流向。

事实上,:class:MapDataset 在绝大多数时候都能够满足要求。个别只有在数据集过于宏大无奈一次性加载进内存的时候咱们才思考应用 :class:IterDataset。任何人都能够不便的定义属于本人的数据集。

.. note::

须要留神的是,只有 PaddleNLP 内置的数据集具备将数据中的 label 主动转为 id 的性能(具体条件参见 :doc:` 创立 DatasetBuilder <../community/contribute_datasets/how_to_write_a_DatasetBuilder>`)。像上例中的自定义数据集须要在自定义的 convert to feature 办法中增加 label 转 id 的性能。自定义数据读取 function 中的参数能够间接以关键字参数的的形式传入 :func:`load_dataset` 中。而且对于自定义数据集,:attr:`lazy` 参数是 ** 必须 ** 传入的。

从 :class:paddle.io.Dataset/IterableDataset 创立数据集

尽管 PaddlePddle 内置的 :class:Dataset 和 :class:IterableDataset 是能够间接接入 :class:DataLoader 用于模型训练的,但有时咱们心愿更不便的应用一些数据处理(例如 convert to feature, 数据荡涤,数据加强等)。而 PaddleNLP 内置的 :class:MapDataset 和 :class:IterDataset 正好提供了能实现以上性能的 API。

所以如果您习惯应用 :class:paddle.io.Dataset/IterableDataset 创立数据集的话。只须要在原来的数据集上套上一层 :class:MapDataset 或 :class:IterDataset 就能够把原来的数据集对象转换成 PaddleNLP 的数据集。

上面举一个简略的小例子。:class:IterDataset 的用法基本相同。

.. code-block::

from paddle.io import Dataset
from paddlenlp.datasets import MapDataset

class MyDataset(Dataset):
    def __init__(self, path):

        def load_data_from_source(path):
            ...
            ...
            return data

        self.data = load_data_from_source(path)

    def __getitem__(self, idx):
        return self.data[idx]

    def __len__(self):
        return len(self.data)

ds = MyDataset(data_path)  # paddle.io.Dataset
new_ds = MapDataset(ds)    # paddlenlp.datasets.MapDataset

从其余 python 对象创立数据集

实践上,咱们能够应用任何蕴含 :func:__getitem__ 办法和 :func:__len__ 办法的 python 对象创立 :class:MapDataset。包含 :class:List,:class:Tuple,:class:DataFrame 等。只有将符合条件的 python 对象作为初始化参数传入 :class:MapDataset 即可实现创立。

.. code-block::

from paddlenlp.datasets import MapDataset

data_source_1 = [1,2,3,4,5]
data_source_2 = ('a', 'b', 'c', 'd')

list_ds = MapDataset(data_source_1)
tuple_ds = MapDataset(data_source_2)

print(list_ds[0])  # 1
print(tuple_ds[0]) # a

同样的,咱们也能够应用蕴含 :func:__iter__ 办法的 python 对象创立 :class:IterDataset。例如 :class:List,:class:Generator 等。创立办法与 :class:MapDataset 雷同。

.. code-block::

from paddlenlp.datasets import IterDataset

data_source_1 = ['a', 'b', 'c', 'd']
data_source_2 = (i for i in range(5))

list_ds = IterDataset(data_source_1)
gen_ds = IterDataset(data_source_2)

print([data for data in list_ds]) # ['a', 'b', 'c', 'd']
print([data for data in gen_ds])  # [0, 1, 2, 3, 4]

.. note::

须要留神,像上例中间接将 ** 生成器 ** 对象传入 :class:`IterDataset` 所生成的数据集。其数据只能迭代 ** 一次 **。

与惯例的 python 对象一样,只有满足以上的条件,咱们也能够应用同样的办法从第三方数据集创立 PaddleNLP 数据集。

例如 HuggingFace Dataset:

.. code-block::

from paddlenlp.datasets import MapDataset
from datasets import load_dataset

hf_train_ds = load_dataset('msra_ner', split='train')
print(type(train_ds)) # <class 'datasets.arrow_dataset.Dataset'>

train_ds = MapDataset(train_ds)
print(type(train_ds)) # <class 'paddlenlp.datasets.dataset.MapDataset'>

print(train_ds[2]) # {'id': '2', 
                   #  'ner_tags': [0, 0, 0, 5, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                   #               0, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
                   #  'tokens': ['因', '有', '关', '日', '寇', '在', '京', '掠', '夺', '文', '物',
                   #             '详', '情', ',', '藏', '界', '较', '为', '重', '视', ',', '也', 
                   #             '是', '我', '们', '收', '藏', '北', '京', '史', '料', '中', '的',
                   #             '要', '件', '之', '一', '。']}

hf_train_ds = load_dataset('cmrc2018', split='train')
train_ds = MapDataset(hf_train_ds)
print(train_ds[1818]) # {'answers': {'answer_start': [9], 'text': ['字仲可']}, 
                      #  'context': ' 徐珂(),原名昌,字仲可,浙江杭县(今属杭州市)人。光绪举人。#              前任商务印书馆编辑。加入南社。1901 年在上海负责了《内政报》、#《西方杂志》的编辑,1911 年,接管《西方杂志》的“杂纂部”。与潘仕成、#              王晋卿、王辑塘、冒鹤亭等敌对。编有《清稗类钞》、《历代白话诗选》、#《古今词全集评》等。光绪十五年(1889 年)举人。前任商务印书馆编辑。#              加入南社。曾负责袁世凯在天津小站练兵时的幕僚,不久离去。', 
                      #  'id': 'TRAIN_113_QUERY_0', 
                      #  'question': '徐珂字什么?'}

hf_train_ds = load_dataset('glue', 'sst2', split='train')
train_ds = MapDataset(hf_train_ds)
print(train_ds[0]) # {'idx': 0, 'label': 0, 'sentence': 'hide new secretions from the parental units'}

hf_train_ds = load_dataset('ptb_text_only', split='train')
train_ds = MapDataset(hf_train_ds)
print(train_ds[1]) # {'sentence': 'pierre <unk> N years old will join the board as a nonexecutive director nov. N'}

正文完
 0