Merci de vous être connecté à Google I/O. Voir toutes les sessions à la demande Regarder à la demande

Générateurs d'ensembles de données spécifiques au format

Ce guide documente tous les générateurs de jeux de données spécifiques au format actuellement disponibles dans TFDS.

Les générateurs d'ensembles de données spécifiques au format sont des sous-classes de tfds.core.GeneratorBasedBuilder qui prennent en charge la plupart des traitements de données pour un format de données spécifique.

Jeux de données basés sur tf.data.Dataset

Si vous souhaitez créer un jeu de données TFDS à partir d'un jeu de données au tf.data.Dataset ( référence ), vous pouvez utiliser tfds.dataset_builders.TfDataBuilder (voir API docs ).

Nous envisageons deux utilisations typiques de cette classe :

  • Création d'ensembles de données expérimentaux dans un environnement de type bloc-notes
  • Définir un générateur de jeu de données dans le code

Créer un nouvel ensemble de données à partir d'un bloc-notes

Supposons que vous travaillez dans un bloc-notes, que vous chargez des données en tant que tf.data.Dataset , que vous appliquez diverses transformations (carte, filtre, etc.) et que vous souhaitez maintenant stocker ces données et les partager facilement avec vos coéquipiers ou les charger dans d'autres blocs-notes. Au lieu d'avoir à définir une nouvelle classe de générateur d'ensemble de données, vous pouvez également instancier un tfds.dataset_builders.TfDataBuilder et appeler download_and_prepare pour stocker votre ensemble de données en tant qu'ensemble de données TFDS.

Comme il s'agit d'un jeu de données TFDS, vous pouvez le versionner, utiliser des configurations, avoir différentes divisions et le documenter pour une utilisation ultérieure plus facile. Cela signifie que vous devez également indiquer à TFDS quelles sont les fonctionnalités de votre jeu de données.

Voici un exemple factice de la façon dont vous pouvez l'utiliser.

import tensorflow as tf
import tensorflow_datasets as tfds

my_ds_train = tf.data.Dataset.from_tensor_slices({"number": [1, 2, 3]})
my_ds_test = tf.data.Dataset.from_tensor_slices({"number": [4, 5]})

# Optionally define a custom `data_dir`.
# If None, then the default data dir is used.
custom_data_dir = "/my/folder"

# Define the builder.
single_number_builder = tfds.dataset_builders.TfDataBuilder(
    name="my_dataset",
    config="single_number",
    version="1.0.0",
    data_dir=custom_data_dir,
    split_datasets={
        "train": my_ds_train,
        "test": my_ds_test,
    },
    features=tfds.features.FeaturesDict({
        "number": tfds.features.Scalar(dtype=tf.int64),
    }),
    description="My dataset with a single number.",
    release_notes={
        "1.0.0": "Initial release with numbers up to 5!",
    }
)

# Make the builder store the data as a TFDS dataset.
single_number_builder.download_and_prepare()

La méthode download_and_prepare itérera sur l'entrée tf.data.Dataset s et stockera l'ensemble de données TFDS correspondant dans /my/folder/my_dataset/single_number/1.0.0 , qui contiendra à la fois les fractionnements d'entraînement et de test.

L'argument config est facultatif et peut être utile si vous souhaitez stocker différentes configurations sous le même jeu de données.

L'argument data_dir peut être utilisé pour stocker l'ensemble de données TFDS généré dans un dossier différent, par exemple dans votre propre bac à sable si vous ne souhaitez pas (encore) le partager avec d'autres. Notez que lors de cette opération, vous devez également transmettre le data_dir à tfds.load . Si l'argument data_dir n'est pas spécifié, le répertoire de données TFDS par défaut sera utilisé.

Chargement de votre ensemble de données

Une fois l'ensemble de données TFDS stocké, il peut être chargé à partir d'autres scripts ou par des coéquipiers s'ils ont accès aux données :

# If no custom data dir was specified:
ds_test = tfds.load("my_dataset/single_number", split="test")

# When there are multiple versions, you can also specify the version.
ds_test = tfds.load("my_dataset/single_number:1.0.0", split="test")

# If the TFDS was stored in a custom folder, then it can be loaded as follows:
custom_data_dir = "/my/folder"
ds_test = tfds.load("my_dataset/single_number:1.0.0", split="test", data_dir=custom_data_dir)

Ajout d'une nouvelle version ou configuration

Après avoir itéré davantage sur votre jeu de données, vous avez peut-être ajouté ou modifié certaines des transformations des données source. Pour stocker et partager cet ensemble de données, vous pouvez facilement le stocker en tant que nouvelle version.

def add_one(example):
  example["number"] = example["number"] + 1
  return example

my_ds_train_v2 = my_ds_train.map(add_one)
my_ds_test_v2 = my_ds_test.map(add_one)

single_number_builder_v2 = tfds.dataset_builders.TfDataBuilder(
    name="my_dataset",
    config="single_number",
    version="1.1.0",
    data_dir=custom_data_dir,
    split_datasets={
        "train": my_ds_train_v2,
        "test": my_ds_test_v2,
    },
    features=tfds.features.FeaturesDict({
        "number": tfds.features.Scalar(dtype=tf.int64, doc="Some number"),
    }),
    description="My dataset with a single number.",
    release_notes={
        "1.1.0": "Initial release with numbers up to 6!",
        "1.0.0": "Initial release with numbers up to 5!",
    }
)

# Make the builder store the data as a TFDS dataset.
single_number_builder_v2.download_and_prepare()

Définition d'une nouvelle classe de générateur d'ensemble de données

Vous pouvez également définir un nouveau DatasetBuilder basé sur cette classe.

import tensorflow as tf
import tensorflow_datasets as tfds

class MyDatasetBuilder(tfds.dataset_builders.TfDataBuilder):
  def __init__(self):
    ds_train = tf.data.Dataset.from_tensor_slices([1, 2, 3])
    ds_test = tf.data.Dataset.from_tensor_slices([4, 5])
    super().__init__(
        name="my_dataset",
        version="1.0.0",
        split_datasets={
            "train": ds_train,
            "test": ds_test,
        },
        features=tfds.features.FeaturesDict({
            "number": tfds.features.Scalar(dtype=tf.int64),
        }),
        config="single_number",
        description="My dataset with a single number.",
        release_notes={
            "1.0.0": "Initial release with numbers up to 5!",
        })

ConNLL

Le format

CoNLL est un format populaire utilisé pour représenter des données textuelles annotées.

Les données au format CoNLL contiennent généralement un jeton avec ses annotations linguistiques par ligne ; au sein d'une même ligne, les annotations sont généralement séparées par des espaces ou des tabulations. Les lignes vides représentent les limites des phrases.

Prenons comme exemple la phrase suivante du jeu de données conll2003 , qui suit le format d'annotation CoNLL :

U.N. NNP I-NP I-ORG official
NN I-NP O
Ekeus NNP I-NP I-PER
heads VBZ I-VP O
for IN I-PP O
Baghdad NNP I-NP
I-LOC . . O O

ConllDatasetBuilder

Pour ajouter un nouvel ensemble de données basé sur CoNLL à TFDS, vous pouvez baser votre classe de générateur d'ensemble de données sur tfds.dataset_builders.ConllDatasetBuilder . Cette classe de base contient du code commun pour traiter les spécificités des jeux de données CoNLL (itération sur le format basé sur les colonnes, listes précompilées de fonctionnalités et de balises, ...).

tfds.dataset_builders.ConllDatasetBuilder implémente un GeneratorBasedBuilder spécifique à CoNLL. Reportez-vous à la classe suivante comme exemple minimal d'un générateur d'ensemble de données CoNLL :

from tensorflow_datasets.core.dataset_builders.conll import conll_dataset_builder_utils as conll_lib
import tensorflow_datasets.public_api as tfds

class MyCoNNLDataset(tfds.dataset_builders.ConllDatasetBuilder):
  VERSION = tfds.core.Version('1.0.0')
  RELEASE_NOTES = {'1.0.0': 'Initial release.'}

  # conllu_lib contains a set of ready-to-use CONLL-specific configs.
  BUILDER_CONFIGS = [conll_lib.CONLL_2003_CONFIG]

  def _info(self) -> tfds.core.DatasetInfo:
    return self.create_dataset_info(
        # ...
    )

  def _split_generators(self, dl_manager):
    path = dl_manager.download_and_extract('https://data-url')

    return {'train': self._generate_examples(path=path / 'train.txt'),
            'test': self._generate_examples(path=path / 'train.txt'),
    }

Comme pour les constructeurs de jeux de données standard, il faut écraser les méthodes de classe _info et _split_generators . Selon le jeu de données, vous devrez peut-être également mettre à jour conll_dataset_builder_utils.py pour inclure les fonctionnalités et la liste des balises spécifiques à votre jeu de données.

La méthode _generate_examples ne devrait pas nécessiter d'écrasement supplémentaire, sauf si votre jeu de données nécessite une implémentation spécifique.

Exemples

Considérez conll2003 comme un exemple d'ensemble de données implémenté à l'aide du générateur d'ensemble de données spécifique à CoNLL.

CLI

Le moyen le plus simple d'écrire un nouvel ensemble de données basé sur CoNLL consiste à utiliser l'interface de ligne de commande TFDS :

cd path/to/my/project/datasets/
tfds new my_dataset --format=conll   # Create `my_dataset/my_dataset.py` CoNLL-specific template files

CoNLL-U

Le format

CoNLL-U est un format populaire utilisé pour représenter des données textuelles annotées.

CoNLL-U améliore le format CoNLL en ajoutant un certain nombre de fonctionnalités, telles que la prise en charge des mots à plusieurs jetons . Les données au format CoNLL-U contiennent généralement un jeton avec ses annotations linguistiques par ligne ; dans la même ligne, les annotations sont généralement séparées par des tabulations simples. Les lignes vides représentent les limites des phrases.

Typiquement, chaque ligne de mot annotée CoNLL-U contient les champs suivants, comme indiqué dans la documentation officielle :

  • ID : Index de mots, entier commençant à 1 pour chaque nouvelle phrase ; peut être une plage pour les jetons multimots ; peut être un nombre décimal pour les nœuds vides (les nombres décimaux peuvent être inférieurs à 1 mais doivent être supérieurs à 0).
  • FORME : forme de mot ou symbole de ponctuation.
  • LEMMA : Lemme ou racine d'une forme de mot.
  • UPOS : étiquette universelle de partie du discours.
  • XPOS : étiquette de partie du discours spécifique à la langue ; soulignement si non disponible.
  • FEATS : liste des caractéristiques morphologiques de l'inventaire universel des caractéristiques ou d'une extension spécifique à la langue définie ; soulignement si non disponible.
  • HEAD : En-tête du mot courant, qui est soit une valeur ID soit zéro (0).
  • DEPREL : Relation de dépendance universelle à HEAD (racine si HEAD = 0) ou à un sous-type défini spécifique à la langue de celui-ci.
  • DEPS : graphe de dépendance amélioré sous la forme d'une liste de paires head-deprel.
  • MISC : Toute autre annotation.

Considérons comme exemple la phrase annotée CoNLL-U suivante de la documentation officielle :

1-2    vámonos   _
1      vamos     ir
2      nos       nosotros
3-4    al        _
3      a         a
4      el        el
5      mar       mar

ConllUDatasetBuilder

Pour ajouter un nouvel ensemble de données basé sur CoNLL-U à TFDS, vous pouvez baser votre classe de générateur d'ensemble de données sur tfds.dataset_builders.ConllUDatasetBuilder . Cette classe de base contient du code commun pour traiter les spécificités des jeux de données CoNLL-U (itération sur le format basé sur les colonnes, listes précompilées de fonctionnalités et de balises, ...).

tfds.dataset_builders.ConllUDatasetBuilder implémente un GeneratorBasedBuilder spécifique à CoNLL-U. Reportez-vous à la classe suivante comme exemple minimal d'un générateur d'ensemble de données CoNLL-U :

from tensorflow_datasets.core.dataset_builders.conll import conllu_dataset_builder_utils as conllu_lib
import tensorflow_datasets.public_api as tfds

class MyCoNNLUDataset(tfds.dataset_builders.ConllUDatasetBuilder):
  VERSION = tfds.core.Version('1.0.0')
  RELEASE_NOTES = {'1.0.0': 'Initial release.'}

  # conllu_lib contains a set of ready-to-use features.
  BUILDER_CONFIGS = [
      conllu_lib.get_universal_morphology_config(
          language='en',
          features=conllu_lib.UNIVERSAL_DEPENDENCIES_FEATURES,
      )
  ]

  def _info(self) -> tfds.core.DatasetInfo:
    return self.create_dataset_info(
        # ...
    )

  def _split_generators(self, dl_manager):
    path = dl_manager.download_and_extract('https://data-url')

    return {
        'train':
            self._generate_examples(
                path=path / 'train.txt',
                # If necessary, add optional custom processing (see conllu_lib
                # for examples).
                # process_example_fn=...,
            )
    }

Comme pour les constructeurs de jeux de données standard, il faut écraser les méthodes de classe _info et _split_generators . Selon le jeu de données, vous devrez peut-être également mettre à jour conllu_dataset_builder_utils.py pour inclure les fonctionnalités et la liste des balises spécifiques à votre jeu de données.

La méthode _generate_examples ne devrait pas nécessiter d'écrasement supplémentaire, sauf si votre jeu de données nécessite une implémentation spécifique. Notez que, si votre jeu de données nécessite un prétraitement spécifique - par exemple s'il prend en compte des fonctionnalités de dépendance universelle non classiques - vous devrez peut-être mettre à jour l'attribut process_example_fn de votre fonction generate_examples (voir le daset xtreme_pos comme exemple).

Exemples

Considérez les ensembles de données suivants, qui utilisent le générateur d'ensembles de données spécifique CoNNL-U, comme exemples :

CLI

Le moyen le plus simple d'écrire un nouvel ensemble de données basé sur CoNLL-U consiste à utiliser la CLI TFDS :

cd path/to/my/project/datasets/
tfds new my_dataset --format=conllu   # Create `my_dataset/my_dataset.py` CoNLL-U specific template files