Postępuj zgodnie z tym przewodnikiem, aby utworzyć nowy zestaw danych (w TFDS lub we własnym repozytorium).
Sprawdź naszą listę zestawów danych , aby zobaczyć, czy żądany zestaw danych już istnieje.
TL;DR
Najłatwiejszym sposobem napisania nowego zestawu danych jest użycie TFDS CLI :
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 zestaw danych:
import my.project.datasets.my_dataset # Register `my_dataset`
ds = tfds.load('my_dataset') # `my_dataset` registered
Przegląd
Zestawy danych są dystrybuowane w różnych formatach iw różnych miejscach i nie zawsze są przechowywane w formacie, który jest gotowy do wprowadzenia do potoku uczenia maszynowego. Wpisz TFDS.
TFDS przetwarza te zestawy 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średnie odczytanie z tych wstępnie przetworzonych plików.
Większość wstępnego przetwarzania 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.
Napisz swój zestaw danych
Domyślny szablon: tfds new
Użyj TFDS CLI , aby wygenerować wymagane pliki szablonów Pythona.
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 TODO(my_dataset)
tutaj i odpowiednio zmodyfikuj.
Przykład zbioru danych
Wszystkie zestawy danych są zaimplementowanymi podklasami tfds.core.DatasetBuilder
, który zajmuje się większością szablonów. To wspiera:
- Małe/średnie zestawy danych, które można wygenerować na jednym komputerze (ten samouczek).
- Bardzo duże zbiory danych, które wymagają generowania rozproszonego (przy użyciu Apache Beam , zobacz nasz przewodnik po ogromnych zbiorach danych )
Oto minimalny przykład konstruktora zestawu danych, który jest oparty 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',
}
Pamiętaj, że w przypadku niektórych określonych formatów danych udostępniamy gotowe do użycia narzędzia do tworzenia zestawów danych, które zajmują się przetwarzaniem większości danych.
Przyjrzyjmy się szczegółowo 3 abstrakcyjnym metodom nadpisywania.
_info
: metadane zestawu 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 precyzji:
-
features
: określają strukturę zbioru danych, kształt, ... Obsługa złożonych typów danych (audio, wideo, sekwencje zagnieżdżone, ...). Więcej informacji można znaleźć w dostępnych funkcjach lub w przewodniku dotyczącym łącznika funkcji . -
disable_shuffling
: Zobacz sekcję Zachowaj kolejność zestawów danych .
Zapisywanie pliku BibText
CITATIONS.bib
:
- Przeszukaj witrynę zestawu danych w celu znalezienia instrukcji cytowania (użyj jej w formacie BibTex).
- W przypadku dokumentów arXiv : znajdź artykuł i kliknij link
BibText
po prawej stronie. - Znajdź artykuł w Google Scholar i kliknij podwójny cudzysłów pod tytułem, a następnie w wyskakującym okienku kliknij
BibTeX
. - Jeśli nie ma powiązanego artykułu (na przykład jest tylko strona internetowa), możesz użyć Edytora BibTeX Online , aby utworzyć niestandardowy wpis BibTeX (menu rozwijane zawiera typ wpisu
Online
).
Aktualizowanie 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 pliku tensorflow_datasets/core/valid_tags.txt .
- Aby dodać tag do tej listy, wyślij PR.
Zachowaj kolejność zbiorów danych
Domyślnie rekordy zestawów danych są tasowane podczas przechowywania w celu ujednolicenia rozkładu klas w zbiorze danych, ponieważ często rekordy należące do tej samej klasy są ciągłe. Aby określić, że zbiór danych ma być sortowany według klucza wygenerowanego przez _generate_examples
należy ustawić pole disable_shuffling
na True
. Domyślnie jest ustawiony na False
.
def _info(self):
return self.dataset_info_from_configs(
# [...]
disable_shuffling=True,
# [...]
)
Pamiętaj, że wyłączenie mieszania ma wpływ na wydajność, ponieważ fragmentów nie można już odczytywać równolegle.
_split_generators
: pobiera i dzieli dane
Pobieranie i wyodrębnianie danych źródłowych
Większość zestawó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ą dowolne zagnieżdżone struktury ( list
, dict
), takie jak:
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 ekstrakcja
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 ~/tensorflow_datasets/downloads/manual/
).
Dostęp do plików można następnie uzyskać za pomocą 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 tfds.download.DownloadConfig
.
Czytaj archiwum bezpośrednio
dl_manager.iter_archive
odczytuje archiwa sekwencyjnie bez ich rozpakowywania. Może to zaoszczędzić miejsce w pamięci masowej i poprawić wydajność w niektórych systemach plików.
for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
...
fobj
ma takie same metody jak with open('rb') as fobj:
(np fobj.read()
)
Określanie podziałów zbioru danych
Jeśli zestaw danych zawiera wstępnie zdefiniowane podziały (np. MNIST
ma podział na train
i test
), zachowaj je. W przeciwnym razie określ tylko jeden podział tfds.Split.TRAIN
. Użytkownicy mogą dynamicznie tworzyć własne podpodziały za pomocą interfejsu API podpodziałów (np. split='train[80%:]'
).
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
: Przykładowy generator
_generate_examples
generuje przykłady dla każdego podziału z danych źródłowych.
Ta metoda zwykle odczytuje artefakty źródłowego zestawu danych (np. plik CSV) i zwraca 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 (zobacz sekcję Utrzymanie kolejności zestawu danych ). Powinien być:- unique : Jeśli dwa przykłady używają tego samego klucza, zostanie zgłoszony wyjątek.
- deterministic : nie powinien zależeć od
download_dir
,os.path.listdir
order,... Dwukrotne wygenerowanie danych powinno dać ten sam klucz. - porównywalny : Jeśli tasowanie jest wyłączone, klucz będzie używany do sortowania zestawu 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,...) zostaną automatycznie zakodowane.
- Każda funkcja często akceptuje wiele typów danych wejściowych (np. video accept
/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 dotyczącym łącznika 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 pamięci masowej w chmurze, unikaj korzystania z wbudowanych operacji wejścia/wyjścia Pythona.
Zamiast tego dl_manager
zwraca obiekty podobne do pathlib bezpośrednio kompatybilne z pamięcią 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())
Ewentualnie użyj 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 niż tf.io.gfile
(patrz .
Dodatkowe zależności
Niektóre zestawy danych wymagają dodatkowych zależności języka 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
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 dla swojego 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 zestawy danych nie są idealnie czyste i zawierają uszkodzone dane (na przykład obrazy są w plikach JPEG, ale niektóre są nieprawidłowymi plikami JPEG). Te przykłady należy pominąć, ale w opisie zestawu danych należy zostawić informację, ile przykładów zostało usuniętych i dlaczego.
Konfiguracja/warianty zestawu danych (tfds.core.BuilderConfig)
Niektóre zestawy danych mogą mieć wiele wariantów lub opcji dotyczących sposobu wstępnego przetwarzania danych i zapisywania ich na dysku. Na przykład cycle_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 członkowski klasy
BUILDER_CONFIGS = []
wMyDataset
, który zawiera listęMyDatasetConfig
s, które uwidacznia 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 innych wartości w_info()
lub zmianę dostępu do pobieranych danych.
Uwagi:
- Każda konfiguracja ma unikalną nazwę. W pełni kwalifikowana nazwa konfiguracji to
dataset_name/config_name
(np.coco/2017
). - Jeśli nie zostanie określony, zostanie użyta pierwsza konfiguracja w
BUILDER_CONFIGS
(nptfds.load('c4')
domyślniec4/en
)
Zobacz anli
, aby zapoznać się z przykładem zestawu danych, który używa BuilderConfig
s.
Wersja
Wersja może odnosić się do dwóch różnych znaczeń:
- Oryginalna wersja danych „zewnętrzna”: 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ć zestaw danych:
- W przypadku „zewnętrznej” aktualizacji danych: wielu użytkowników może jednocześnie chcieć uzyskać dostęp do określonego roku/wersji. Odbywa się to za pomocą 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ększać 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
, 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 moduł import do jego podkatalogu __init__.py
(np. image/__init__.py
.
Sprawdź typowe problemy z implementacją
Proszę sprawdzić typowe błędy implementacji .
Przetestuj swój zestaw danych
Pobierz i przygotuj: tfds build
Aby wygenerować zestaw danych, uruchom tfds build
z katalogu my_dataset/
:
cd path/to/datasets/my_dataset/
tfds build --register_checksums
Kilka przydatnych flag do programowania:
-
--pdb
: Wejdź w tryb debugowania, jeśli zostanie zgłoszony wyjątek. -
--overwrite
: Usuń istniejące pliki, jeśli zestaw danych został już wygenerowany. -
--max_examples_per_split
: Generuj tylko pierwsze X przykładów (domyślnie 1), zamiast pełnego zestawu danych. -
--register_checksums
: Zapisz sumy kontrolne pobranych adresów URL. Powinien być używany tylko podczas opracowywania.
Zobacz dokumentację interfejsu CLI, aby uzyskać pełną listę flag.
Sumy kontrolne
Zaleca się zapisywanie sum kontrolnych zestawów danych, aby zagwarantować determinizm, pomoc w dokumentacji,... Odbywa się to poprzez wygenerowanie zestawu danych za pomocą opcji --register_checksums
(patrz poprzednia sekcja).
Jeśli udostępniasz swoje zestawy danych przez PyPI, nie zapomnij wyeksportować plików checksums.tsv
(np. w package_data
twojego setup.py
).
Przetestuj swój zestaw danych
tfds.testing.DatasetBuilderTestCase
to podstawowy TestCase
do pełnego sprawdzenia zestawu danych. Używa „fikcyjnych danych” jako danych testowych, które naśladują strukturę źródłowego zestawu danych.
- Dane testowe należy umieścić w
my_dataset/dummy_data/
i powinny naśladować artefakty źródłowego zestawu danych w postaci pobranej i wyodrębnionej. Można go utworzyć ręcznie lub automatycznie za pomocą skryptu ( przykładowy skrypt ). - Pamiętaj, aby używać różnych danych w testowych podziałach danych, ponieważ test zakończy się niepowodzeniem, jeśli podziały zbiorów danych będą się pokrywać.
- Dane testowe nie powinny zawierać żadnych materiałów chronionych prawem autorskim . 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
Wyślij nam opinie
Nieustannie staramy się ulepszyć przepływ pracy 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 GitHub .