Postępuj zgodnie z tym przewodnikiem, aby utworzyć nowy zbiór danych (w TFDS lub we własnym repozytorium).
Sprawdź naszą listę zbiorów danych , aby sprawdzić, czy żądany zbiór danych już istnieje.
TL;DR
Najłatwiejszym sposobem napisania nowego zestawu danych jest użycie interfejsu CLI TFDS :
cd path/to/my/project/datasets/
tfds new my_dataset # Create `my_dataset/my_dataset.py` template files
# [...] Manually modify `my_dataset/my_dataset_dataset_builder.py` to implement your dataset.
cd my_dataset/
tfds build # Download and prepare the dataset to `~/tensorflow_datasets/`
Aby użyć nowego zestawu danych za pomocą tfds.load('my_dataset')
:
-
tfds.load
automatycznie wykryje i załaduje zestaw danych wygenerowany w~/tensorflow_datasets/my_dataset/
(np. przeztfds build
). - Alternatywnie możesz jawnie
import my.project.datasets.my_dataset
aby zarejestrować swój zbiór danych:
import my.project.datasets.my_dataset # Register `my_dataset`
ds = tfds.load('my_dataset') # `my_dataset` registered
Przegląd
Zbiory danych są dystrybuowane w różnych formatach i w różnych miejscach i nie zawsze są przechowywane w formacie gotowym do wprowadzenia do potoku uczenia maszynowego. Wejdź do TFDS.
TFDS przetwarza te zbiory danych do standardowego formatu (dane zewnętrzne -> pliki serializowane), który można następnie załadować jako potok uczenia maszynowego (pliki serializowane -> tf.data.Dataset
). Serializacja jest wykonywana tylko raz. Późniejszy dostęp spowoduje bezpośredni odczyt z tych wstępnie przetworzonych plików.
Większość przetwarzania wstępnego odbywa się automatycznie. Każdy zestaw danych implementuje podklasę tfds.core.DatasetBuilder
, która określa:
- Skąd pochodzą dane (tj. ich adresy URL);
- Jak wygląda zbiór danych (tj. jego cechy);
- Jak należy podzielić dane (np.
TRAIN
iTEST
); - oraz poszczególne przykłady w zbiorze danych.
Zapisz swój zbiór danych
Domyślny szablon: tfds new
Użyj interfejsu TFDS CLI , aby wygenerować wymagane pliki Pythona z szablonami.
cd path/to/project/datasets/ # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset
To polecenie wygeneruje nowy folder my_dataset/
o następującej strukturze:
my_dataset/
__init__.py
README.md # Markdown description of the dataset.
CITATIONS.bib # Bibtex citation for the dataset.
TAGS.txt # List of tags describing the dataset.
my_dataset_dataset_builder.py # Dataset definition
my_dataset_dataset_builder_test.py # Test
dummy_data/ # (optional) Fake data (used for testing)
checksum.tsv # (optional) URL checksums (see `checksums` section).
Wyszukaj tutaj TODO(my_dataset)
i odpowiednio zmodyfikuj.
Przykład zbioru danych
Wszystkie zestawy danych są zaimplementowanymi podklasami tfds.core.DatasetBuilder
, który zajmuje się większością schematów. Obsługuje:
- Małe/średnie zbiory danych, które można wygenerować na jednym komputerze (ten samouczek).
- Bardzo duże zbiory danych, które wymagają generacji rozproszonej (przy użyciu Apache Beam , zobacz nasz obszerny przewodnik po zbiorach danych )
Oto minimalny przykład kreatora zbiorów danych opartego na tfds.core.GeneratorBasedBuilder
:
class Builder(tfds.core.GeneratorBasedBuilder):
"""DatasetBuilder for my_dataset dataset."""
VERSION = tfds.core.Version('1.0.0')
RELEASE_NOTES = {
'1.0.0': 'Initial release.',
}
def _info(self) -> tfds.core.DatasetInfo:
"""Dataset metadata (homepage, citation,...)."""
return self.dataset_info_from_configs(
features=tfds.features.FeaturesDict({
'image': tfds.features.Image(shape=(256, 256, 3)),
'label': tfds.features.ClassLabel(
names=['no', 'yes'],
doc='Whether this is a picture of a cat'),
}),
)
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
"""Download the data and define splits."""
extracted_path = dl_manager.download_and_extract('http://data.org/data.zip')
# dl_manager returns pathlib-like objects with `path.read_text()`,
# `path.iterdir()`,...
return {
'train': self._generate_examples(path=extracted_path / 'train_images'),
'test': self._generate_examples(path=extracted_path / 'test_images'),
}
def _generate_examples(self, path) -> Iterator[Tuple[Key, Example]]:
"""Generator of examples for each split."""
for img_path in path.glob('*.jpeg'):
# Yields (key, example)
yield img_path.name, {
'image': img_path,
'label': 'yes' if img_path.name.startswith('yes_') else 'no',
}
Należy pamiętać, że w przypadku niektórych określonych formatów danych udostępniamy gotowe do użycia narzędzia do tworzenia zbiorów danych , które obsługują większość procesów przetwarzania danych.
Przyjrzyjmy się szczegółowo 3 abstrakcyjnym metodom nadpisywania.
_info
: metadane zbioru danych
_info
zwraca tfds.core.DatasetInfo
zawierający metadane zestawu danych .
def _info(self):
# The `dataset_info_from_configs` base method will construct the
# `tfds.core.DatasetInfo` object using the passed-in parameters and
# adding: builder (self), description/citations/tags from the config
# files located in the same package.
return self.dataset_info_from_configs(
homepage='https://dataset-homepage.org',
features=tfds.features.FeaturesDict({
'image_description': tfds.features.Text(),
'image': tfds.features.Image(),
# Here, 'label' can be 0-4.
'label': tfds.features.ClassLabel(num_classes=5),
}),
# If there's a common `(input, target)` tuple from the features,
# specify them here. They'll be used if as_supervised=True in
# builder.as_dataset.
supervised_keys=('image', 'label'),
# Specify whether to disable shuffling on the examples. Set to False by default.
disable_shuffling=False,
)
Większość pól powinna być oczywista. Kilka doprecyzowań:
-
features
: Określa strukturę zbioru danych, kształt,... Obsługuje złożone typy danych (audio, wideo, sekwencje zagnieżdżone,...). Aby uzyskać więcej informacji, zobacz dostępne funkcje lub przewodnik po złączach funkcji . -
disable_shuffling
: Zobacz sekcję Utrzymuj porządek zestawu danych .
Zapisywanie pliku BibText
CITATIONS.bib
:
- Wyszukaj w witrynie zbioru danych instrukcje dotyczące cytowań (użyj ich w formacie BibTex).
- W przypadku artykułów arXiv : znajdź artykuł i kliknij łącze
BibText
po prawej stronie. - Znajdź artykuł w Google Scholar i kliknij cudzysłów pod tytułem, a następnie w wyskakującym okienku kliknij
BibTeX
. - Jeśli nie ma powiązanej publikacji (na przykład jest tylko witryna internetowa), możesz użyć Edytora BibTeX Online, aby utworzyć niestandardowy wpis BibTeX (w menu rozwijanym znajduje się typ wpisu
Online
).
Aktualizacja pliku TAGS.txt
:
- Wszystkie dozwolone tagi są wstępnie wypełnione w wygenerowanym pliku.
- Usuń wszystkie tagi, które nie mają zastosowania do zbioru danych.
- Prawidłowe tagi są wymienione w tensorflow_datasets/core/valid_tags.txt .
- Aby dodać tag do tej listy, wyślij wiadomość PR.
Zachowaj porządek zbioru danych
Domyślnie rekordy zbiorów danych są tasowane podczas przechowywania, aby rozkład klas był bardziej równomierny w zbiorze danych, ponieważ często rekordy należące do tej samej klasy sąsiadują ze sobą. Aby określić, że zbiór danych powinien być sortowany według klucza wygenerowanego dostarczonego przez _generate_examples
pole disable_shuffling
powinno być ustawione na True
. Domyślnie jest ustawiona na False
.
def _info(self):
return self.dataset_info_from_configs(
# [...]
disable_shuffling=True,
# [...]
)
Należy pamiętać, że wyłączenie tasowania ma wpływ na wydajność, ponieważ fragmentów nie można już czytać równolegle.
_split_generators
: pobiera i dzieli dane
Pobieranie i wyodrębnianie danych źródłowych
Większość zbiorów danych wymaga pobierania danych z Internetu. Odbywa się to za pomocą argumentu wejściowego tfds.download.DownloadManager
_split_generators
. dl_manager
ma następujące metody:
-
download
: obsługujehttp(s)://
,ftp(s)://
-
extract
: obecnie obsługuje pliki.zip
,.gz
i.tar
. -
download_and_extract
: To samo codl_manager.extract(dl_manager.download(urls))
Wszystkie te metody zwracają tfds.core.Path
(aliasy dla epath.Path
), które są obiektami podobnymi do pathlib.Path .
Metody te obsługują dowolną strukturę zagnieżdżoną ( list
, dict
), na przykład:
extracted_paths = dl_manager.download_and_extract({
'foo': 'https://example.com/foo.zip',
'bar': 'https://example.com/bar.zip',
})
# This returns:
assert extracted_paths == {
'foo': Path('/path/to/extracted_foo/'),
'bar': Path('/path/extracted_bar/'),
}
Ręczne pobieranie i wyodrębnianie
Niektórych danych nie można pobrać automatycznie (np. wymagają logowania). W takim przypadku użytkownik ręcznie pobierze dane źródłowe i umieści je w manual_dir/
(domyślnie jest to ~/tensorflow_datasets/downloads/manual/
).
Dostęp do plików można następnie uzyskać poprzez dl_manager.manual_dir
:
class MyDataset(tfds.core.GeneratorBasedBuilder):
MANUAL_DOWNLOAD_INSTRUCTIONS = """
Register into https://example.org/login to get the data. Place the `data.zip`
file in the `manual_dir/`.
"""
def _split_generators(self, dl_manager):
# data_path is a pathlib-like `Path('<manual_dir>/data.zip')`
archive_path = dl_manager.manual_dir / 'data.zip'
# Extract the manually downloaded `data.zip`
extracted_path = dl_manager.extract(archive_path)
...
Położenie manual_dir
można dostosować za pomocą tfds build --manual_dir=
lub za pomocą tfds.download.DownloadConfig
.
Przeczytaj archiwum bezpośrednio
dl_manager.iter_archive
czyta archiwa sekwencyjnie, bez ich rozpakowywania. Może to zaoszczędzić miejsce na dysku i poprawić wydajność w niektórych systemach plików.
for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
...
fobj
ma te same metody, co with open('rb') as fobj:
(np. fobj.read()
)
Określanie podziałów zbioru danych
Jeśli zbiór danych ma wstępnie zdefiniowane podziały (np. MNIST
ma podziały train
i test
), zachowaj je. W przeciwnym razie określ tylko pojedynczy podział all
. Użytkownicy mogą dynamicznie tworzyć własne podpodziały za pomocą interfejsu API subsplit (np. split='train[80%:]'
). Należy pamiętać, że jako nazwę rozdzieloną można użyć dowolnego ciągu alfabetycznego, z wyjątkiem wyżej wymienionych all
.
def _split_generators(self, dl_manager):
# Download source data
extracted_path = dl_manager.download_and_extract(...)
# Specify the splits
return {
'train': self._generate_examples(
images_path=extracted_path / 'train_imgs',
label_path=extracted_path / 'train_labels.csv',
),
'test': self._generate_examples(
images_path=extracted_path / 'test_imgs',
label_path=extracted_path / 'test_labels.csv',
),
}
_generate_examples
: Generator przykładów
_generate_examples
generuje przykłady dla każdego podziału z danych źródłowych.
Ta metoda zazwyczaj odczytuje artefakty źródłowego zestawu danych (np. plik CSV) i generuje krotki (key, feature_dict)
:
-
key
: Przykładowy identyfikator. Służy do deterministycznego tasowania przykładów za pomocąhash(key)
lub do sortowania według klucza, gdy tasowanie jest wyłączone (patrz sekcja Utrzymywanie porządku zbioru danych ). Powinno być:- unikalny : Jeśli dwa przykłady używają tego samego klucza, zostanie zgłoszony wyjątek.
- deterministyczny : Nie powinien zależeć od
download_dir
, kolejnościos.path.listdir
,... Dwukrotne wygenerowanie danych powinno dać ten sam klucz. - porównywalne : Jeśli mieszanie jest wyłączone, klucz zostanie użyty do sortowania zbioru danych.
-
feature_dict
:dict
zawierający przykładowe wartości.- Struktura powinna być zgodna ze strukturą
features=
zdefiniowaną wtfds.core.DatasetInfo
. - Złożone typy danych (obraz, wideo, audio,...) będą kodowane automatycznie.
- Każda funkcja często akceptuje wiele typów danych wejściowych (np. wideo akceptowane
/path/to/vid.mp4
,np.array(shape=(l, h, w, c))
,List[paths]
,List[np.array(shape=(h, w, c)]
,List[img_bytes]
,...) - Więcej informacji można znaleźć w przewodniku po złączu funkcji .
- Struktura powinna być zgodna ze strukturą
def _generate_examples(self, images_path, label_path):
# Read the input data out of the source files
with label_path.open() as f:
for row in csv.DictReader(f):
image_id = row['image_id']
# And yield (key, feature_dict)
yield image_id, {
'image_description': row['description'],
'image': images_path / f'{image_id}.jpeg',
'label': row['label'],
}
Dostęp do plików i tf.io.gfile
Aby obsługiwać systemy przechowywania w chmurze, unikaj używania wbudowanych operacji we/wy Pythona.
Zamiast tego dl_manager
zwraca obiekty podobne do pathlib bezpośrednio kompatybilne z pamięcią masową Google Cloud:
path = dl_manager.download_and_extract('http://some-website/my_data.zip')
json_path = path / 'data/file.json'
json.loads(json_path.read_text())
Alternatywnie użyj interfejsu API tf.io.gfile
zamiast wbudowanego do operacji na plikach:
-
open
->tf.io.gfile.GFile
-
os.rename
->tf.io.gfile.rename
- ...
Pathlib powinien być preferowany zamiast tf.io.gfile
(patrz racjonalny plik .
Dodatkowe zależności
Niektóre zestawy danych wymagają dodatkowych zależności w języku Python tylko podczas generowania. Na przykład zestaw danych SVHN używa scipy
do ładowania niektórych danych.
Jeśli dodajesz zestaw danych do repozytorium TFDS, użyj tfds.core.lazy_imports
aby pakiet tensorflow-datasets
był mały. Użytkownicy będą instalować dodatkowe zależności tylko w razie potrzeby.
Aby użyć lazy_imports
:
- Dodaj wpis dla swojego zestawu danych do
DATASET_EXTRAS
wsetup.py
. Dzięki temu użytkownicy mogą na przykład wykonaćpip install 'tensorflow-datasets[svhn]'
, aby zainstalować dodatkowe zależności. - Dodaj wpis dotyczący importu do
LazyImporter
i doLazyImportsTest
. - Użyj
tfds.core.lazy_imports
aby uzyskać dostęp do zależności (na przykładtfds.core.lazy_imports.scipy
) wDatasetBuilder
.
Uszkodzone dane
Niektóre zbiory danych nie są idealnie czyste i zawierają pewne uszkodzone dane (na przykład obrazy znajdują się w plikach JPEG, ale niektóre mają nieprawidłowy format JPEG). Te przykłady należy pominąć, ale w opisie zbioru danych zostaw notatkę, ile przykładów zostało pominiętych i dlaczego.
Konfiguracja/warianty zbioru danych (tfds.core.BuilderConfig)
Niektóre zbiory danych mogą mieć wiele wariantów lub opcji wstępnego przetwarzania danych i zapisywania ich na dysku. Na przykład cykl_gan ma jedną konfigurację na parę obiektów ( cycle_gan/horse2zebra
, cycle_gan/monet2photo
,...).
Odbywa się to poprzez tfds.core.BuilderConfig
s:
Zdefiniuj obiekt konfiguracyjny jako podklasę
tfds.core.BuilderConfig
. Na przykładMyDatasetConfig
.@dataclasses.dataclass class MyDatasetConfig(tfds.core.BuilderConfig): img_size: Tuple[int, int] = (0, 0)
Zdefiniuj element klasy
BUILDER_CONFIGS = []
wMyDataset
, który zawiera listęMyDatasetConfig
s udostępnianych przez zestaw danych.class MyDataset(tfds.core.GeneratorBasedBuilder): VERSION = tfds.core.Version('1.0.0') # pytype: disable=wrong-keyword-args BUILDER_CONFIGS = [ # `name` (and optionally `description`) are required for each config MyDatasetConfig(name='small', description='Small ...', img_size=(8, 8)), MyDatasetConfig(name='big', description='Big ...', img_size=(32, 32)), ] # pytype: enable=wrong-keyword-args
Użyj
self.builder_config
wMyDataset
, aby skonfigurować generowanie danych (np.shape=self.builder_config.img_size
). Może to obejmować ustawienie różnych wartości w_info()
lub zmianę dostępu do pobieranych danych.
Uwagi:
- Każda konfiguracja ma unikalną nazwę. Pełna nazwa konfiguracji to
dataset_name/config_name
(np.coco/2017
). - Jeśli nie określono, zostanie użyta pierwsza konfiguracja w
BUILDER_CONFIGS
(np.tfds.load('c4')
domyślniec4/en
)
Zobacz anli
aby zapoznać się z przykładem zestawu danych używającego BuilderConfig
s.
Wersja
Wersja może odnosić się do dwóch różnych znaczeń:
- „Zewnętrzna” oryginalna wersja danych: np. COCO v2019, v2017,...
- „Wewnętrzna” wersja kodu TFDS: np. zmień nazwę funkcji w
tfds.features.FeaturesDict
, napraw błąd w_generate_examples
Aby zaktualizować zbiór danych:
- W przypadku „zewnętrznej” aktualizacji danych: wielu użytkowników może chcieć jednocześnie uzyskać dostęp do określonego roku/wersji. Odbywa się to poprzez użycie jednego
tfds.core.BuilderConfig
na wersję (np.coco/2017
,coco/2019
) lub jednej klasy na wersję (np.Voc2007
,Voc2012
). - W przypadku „wewnętrznej” aktualizacji kodu: użytkownicy pobierają tylko najnowszą wersję. Każda aktualizacja kodu powinna zwiększyć atrybut klasy
VERSION
(np. z1.0.0
doVERSION = tfds.core.Version('2.0.0')
) po wersjonowaniu semantycznym .
Dodaj import do rejestracji
Nie zapomnij zaimportować modułu zestawu danych do swojego projektu __init__
, aby został on automatycznie zarejestrowany w tfds.load
i tfds.builder
.
import my_project.datasets.my_dataset # Register MyDataset
ds = tfds.load('my_dataset') # MyDataset available
Na przykład, jeśli współtworzysz tensorflow/datasets
, dodaj import modułu do __init__.py
jego podkatalogu (np. image/__init__.py
.
Sprawdź typowe problemy związane z implementacją
Sprawdź typowe problemy związane z implementacją .
Przetestuj swój zbiór danych
Pobierz i przygotuj: tfds build
Aby wygenerować zbiór danych, uruchom tfds build
z katalogu my_dataset/
:
cd path/to/datasets/my_dataset/
tfds build --register_checksums
Kilka przydatnych flag do programowania:
-
--pdb
: Przejdź do trybu debugowania, jeśli zostanie zgłoszony wyjątek. -
--overwrite
: Usuń istniejące pliki, jeśli zbiór danych został już wygenerowany. -
--max_examples_per_split
: Generuj tylko pierwsze X przykładów (domyślnie 1), a nie pełny zestaw danych. -
--register_checksums
: Zapisz sumy kontrolne pobranych adresów URL. Należy go używać wyłącznie w fazie rozwoju.
Pełną listę flag znajdziesz w dokumentacji CLI .
Sumy kontrolne
Zalecane jest zapisywanie sum kontrolnych zbiorów danych, aby zagwarantować determinizm, pomóc w dokumentacji,... Dokonuje się tego poprzez wygenerowanie zbioru danych z --register_checksums
(patrz poprzednia sekcja).
Jeśli udostępniasz swoje zbiory danych poprzez PyPI, nie zapomnij wyeksportować plików checksums.tsv
(np. w package_data
pliku setup.py
).
Przetestuj jednostkowo swój zbiór danych
tfds.testing.DatasetBuilderTestCase
to podstawowy TestCase
umożliwiający pełne wykorzystanie zbioru danych. Wykorzystuje „dane fikcyjne” jako dane testowe, które naśladują strukturę źródłowego zbioru danych.
- Dane testowe należy umieścić w katalogu
my_dataset/dummy_data/
i powinny naśladować artefakty źródłowego zestawu danych po pobraniu i rozpakowaniu. Można go utworzyć ręcznie lub automatycznie za pomocą skryptu ( przykładowy skrypt ). - Upewnij się, że w podziałach danych testowych używasz różnych danych, ponieważ test zakończy się niepowodzeniem, jeśli podziały zestawu danych będą się nakładać.
- Dane testowe nie powinny zawierać żadnych materiałów objętych prawami autorskimi . W razie wątpliwości nie twórz danych przy użyciu materiału z oryginalnego zbioru danych.
import tensorflow_datasets as tfds
from . import my_dataset_dataset_builder
class MyDatasetTest(tfds.testing.DatasetBuilderTestCase):
"""Tests for my_dataset dataset."""
DATASET_CLASS = my_dataset_dataset_builder.Builder
SPLITS = {
'train': 3, # Number of fake train example
'test': 1, # Number of fake test example
}
# If you are calling `download/download_and_extract` with a dict, like:
# dl_manager.download({'some_key': 'http://a.org/out.txt', ...})
# then the tests needs to provide the fake output paths relative to the
# fake data directory
DL_EXTRACT_RESULT = {
'name1': 'path/to/file1', # Relative to my_dataset/dummy_data dir.
'name2': 'file2',
}
if __name__ == '__main__':
tfds.testing.test_main()
Uruchom następujące polecenie, aby przetestować zestaw danych.
python my_dataset_test.py
Prześlij nam swoją opinię
Nieustannie staramy się udoskonalać proces tworzenia zestawu danych, ale możemy to zrobić tylko wtedy, gdy jesteśmy świadomi problemów. Jakie problemy lub błędy napotkałeś podczas tworzenia zbioru danych? Czy była jakaś część, która była myląca lub nie działała za pierwszym razem?
Podziel się swoją opinią na GitHubie .