Viết bộ dữ liệu tùy chỉnh

Làm theo hướng dẫn này để tạo tập dữ liệu mới (trong TFDS hoặc trong kho lưu trữ của riêng bạn).

Kiểm tra danh sách tập dữ liệu của chúng tôi để xem liệu tập dữ liệu bạn muốn đã có chưa.

TL; DR

Cách dễ nhất để viết một tập dữ liệu mới là sử dụng 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.py` to implement your dataset.
cd my_dataset/
tfds build  # Download and prepare the dataset to `~/tensorflow_datasets/`

Để sử dụng tập dữ liệu mới với tfds.load('my_dataset') :

  • tfds.load sẽ tự động phát hiện và tải tập dữ liệu được tạo trong ~/tensorflow_datasets/my_dataset/ (ví dụ: bởi tfds build ).
  • Ngoài ra, bạn có thể import my.project.datasets.my_dataset để đăng ký tập dữ liệu của mình:
import my.project.datasets.my_dataset  # Register `my_dataset`

ds = tfds.load('my_dataset')  # `my_dataset` registered

Tổng quat

Tập dữ liệu được phân phối ở mọi loại định dạng và ở mọi nơi, và chúng không phải lúc nào cũng được lưu trữ ở định dạng sẵn sàng cung cấp vào đường dẫn máy học. Nhập TFDS.

TFDS xử lý các tập dữ liệu đó thành một định dạng chuẩn (dữ liệu bên ngoài -> các tệp được tuần tự hóa), sau đó có thể được tải dưới dạng đường ống học máy (các tệp được tuần tự hóa -> tf.data.Dataset ). Việc tuần tự hóa chỉ được thực hiện một lần. Quyền truy cập tiếp theo sẽ đọc trực tiếp từ các tệp được xử lý trước đó.

Hầu hết quá trình tiền xử lý được thực hiện tự động. Mỗi tập dữ liệu thực hiện một lớp con của tfds.core.DatasetBuilder , chỉ định:

  • Dữ liệu đến từ đâu (tức là các URL của nó);
  • Tập dữ liệu trông như thế nào (tức là các tính năng của nó);
  • Dữ liệu nên được phân chia như thế nào (ví dụ: TRAINTEST );
  • và các ví dụ riêng lẻ trong tập dữ liệu.

Viết tập dữ liệu của bạn

Mẫu mặc định: tfds new

Sử dụng TFDS CLI để tạo tệp python mẫu được yêu cầu.

cd path/to/project/datasets/  # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset

Lệnh này sẽ tạo một thư mục my_dataset/ mới với cấu trúc sau:

my_dataset/
    __init__.py
    my_dataset.py # Dataset definition
    my_dataset_test.py # (optional) Test
    dummy_data/ # (optional) Fake data (used for testing)
    checksum.tsv # (optional) URL checksums (see `checksums` section).

Tìm kiếm TODO(my_dataset) tại đây và sửa đổi cho phù hợp.

Ví dụ về tập dữ liệu

Tất cả các tập dữ liệu được triển khai dưới dạng tfds.core.GeneratorBasedBuilder , một lớp con của tfds.core.DatasetBuilder , quản lý hầu hết các bản trình bày. Nó hỗ trợ:

Đây là một ví dụ tối thiểu về lớp tập dữ liệu:

class MyDataset(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 tfds.core.DatasetInfo(
        builder=self,
        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',
      }

Chúng ta hãy xem chi tiết 3 phương thức trừu tượng để ghi đè.

_info : siêu dữ liệu tập dữ liệu

_info trả về tfds.core.DatasetInfo chứa siêu dữ liệu tập dữ liệu .

def _info(self):
  return tfds.core.DatasetInfo(
      builder=self,
      # Description and homepage used for documentation
      description="""
      Markdown description of the dataset. The text will be automatically
      stripped and dedent.
      """,
      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,
      # Bibtex citation for the dataset
      citation=r"""
      @article{my-awesome-dataset-2020,
               author = {Smith, John},}
      """,
  )

Hầu hết các lĩnh vực nên tự giải thích. Một số khu vực:

  • features : Điều này chỉ định cấu trúc tập dữ liệu, hình dạng, ... Hỗ trợ các kiểu dữ liệu phức tạp (âm thanh, video, chuỗi lồng nhau, ...). Xem các tính năng có sẵn hoặc hướng dẫn trình kết nối tính năng để biết thêm thông tin.
  • disable_shuffling : Xem phần Duy trì thứ tự tập dữ liệu .
  • citation : Để tìm trích dẫn BibText :
    • Tìm kiếm trên trang web tập dữ liệu để biết hướng dẫn trích dẫn (sử dụng ở định dạng BibTex).
    • Đối với giấy arXiv : tìm giấy và nhấp vào liên kết BibText ở phía bên tay phải.
    • Tìm bài báo trên Google Scholar và nhấp vào dấu ngoặc kép bên dưới tiêu đề và trên cửa sổ bật lên, nhấp vào BibTeX .
    • Nếu không có tài liệu liên quan (ví dụ: chỉ có một trang web), bạn có thể sử dụng Trình chỉnh sửa trực tuyến BibTeX để tạo mục nhập BibTeX tùy chỉnh (trình đơn thả xuống có loại mục nhập Online ).

Duy trì thứ tự tập dữ liệu

Theo mặc định, các bản ghi của tập dữ liệu được xáo trộn khi được lưu trữ để làm cho việc phân bố các lớp đồng nhất hơn trên tập dữ liệu, vì thường các bản ghi thuộc cùng một lớp sẽ liền kề nhau. Để chỉ định rằng tập dữ liệu phải được sắp xếp theo khóa được tạo bởi _generate_examples , trường disable_shuffling phải được đặt thành True . Theo mặc định, nó được đặt thành False .

def _info(self):
  return tfds.core.DatasetInfo(
    # [...]
    disable_shuffling=True,
    # [...]
  )

Hãy nhớ rằng việc tắt xáo trộn có ảnh hưởng đến hiệu suất vì các phân đoạn không thể đọc song song được nữa.

_split_generators : tải xuống và phân chia dữ liệu

Tải xuống và trích xuất dữ liệu nguồn

Hầu hết các bộ dữ liệu cần tải xuống dữ liệu từ web. Điều này được thực hiện bằng cách sử dụng đối số đầu vào tfds.download.DownloadManager của _split_generators . dl_manager có các phương thức sau:

  • download : hỗ trợ http(s):// , ftp(s)://
  • extract : hiện hỗ trợ các .zip , .gz.tar .
  • download_and_extract : Giống như dl_manager.extract(dl_manager.download(urls))

Tất cả các phương thức đó trả về tfds.core.Path (bí danh cho epath.Path ), là các đối tượng giống như pathlib.Path .

Các phương thức đó hỗ trợ cấu trúc lồng nhau tùy ý ( list , dict ), như:

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/'),
}

Tải xuống và trích xuất thủ công

Một số dữ liệu không thể được tải xuống tự động (ví dụ: yêu cầu đăng nhập), trong trường hợp này, người dùng sẽ tải xuống thủ công dữ liệu nguồn và đặt nó trong manual_dir/ (mặc định là ~/tensorflow_datasets/downloads/manual/ ).

Các tệp sau đó có thể được truy cập thông qua 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)
    ...

Vị trí manual_dir có thể được tùy chỉnh bằng tfds build --manual_dir= hoặc sử dụng tfds.download.DownloadConfig .

Đọc trực tiếp kho lưu trữ

dl_manager.iter_archive đọc tuần tự các kho lưu trữ mà không cần giải nén chúng. Điều này có thể tiết kiệm không gian lưu trữ và cải thiện hiệu suất trên một số hệ thống tệp.

for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
  ...

fobj có các phương thức tương tự như with open('rb') as fobj: (ví dụ: fobj.read() )

Chỉ định phân chia tập dữ liệu

Nếu tập dữ liệu đi kèm với các phần tách được xác định trước (ví dụ: MNIST có phần tách traintest ), hãy giữ những phần đó. Nếu không, chỉ xác định một phần tách tfds.Split.TRAIN duy nhất. Người dùng có thể tự động tạo các phân vùng con của họ bằng API subsplit (ví dụ: 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 : Trình tạo mẫu

_generate_examples tạo các ví dụ cho mỗi phần tách từ dữ liệu nguồn.

Phương pháp này thường sẽ đọc các tạo tác tập dữ liệu nguồn (ví dụ: tệp CSV) và các bộ giá trị sản lượng (key, feature_dict) :

  • key : Định danh mẫu. Được sử dụng để xáo trộn một cách xác định các ví dụ bằng cách sử dụng hash(key) hoặc để sắp xếp theo khóa khi xáo trộn bị tắt (xem phần Duy trì thứ tự tập dữ liệu ). Nên là:
    • duy nhất : Nếu hai ví dụ sử dụng cùng một khóa, một ngoại lệ sẽ được đưa ra.
    • xác định : Không nên phụ thuộc vào thứ tự download_dir , os.path.listdir , ... Tạo dữ liệu hai lần nên mang lại cùng một khóa.
    • so sánh được : Nếu xáo trộn bị tắt, khóa sẽ được sử dụng để sắp xếp tập dữ liệu.
  • feature_dict : Một dict lệnh chứa các giá trị ví dụ.
    • Cấu trúc phải khớp với cấu trúc features= được định nghĩa trong tfds.core.DatasetInfo .
    • Các loại dữ liệu phức tạp (hình ảnh, video, âm thanh, ...) sẽ được mã hóa tự động.
    • Mỗi tính năng thường chấp nhận nhiều kiểu đầu vào (ví dụ: chấp nhận video /path/to/vid.mp4 , np.array(shape=(l, h, w, c)) , List[paths] , List[np.array(shape=(h, w, c)] , List[img_bytes] , ...)
    • Xem hướng dẫn trình kết nối tính năng để biết thêm thông tin.
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'],
      }

Quyền truy cập tệp và tf.io.gfile

Để hỗ trợ hệ thống lưu trữ đám mây, hãy tránh sử dụng các hoạt động I / O tích hợp sẵn trong Python.

Thay vào đó, dl_manager trả về các đối tượng giống như pathlib tương thích trực tiếp với bộ nhớ 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())

Ngoài ra, hãy sử dụng API tf.io.gfile thay vì tích hợp sẵn cho các hoạt động tệp:

Pathlib nên được ưu tiên hơn tf.io.gfile (xem phần hợp lý .

Phụ thuộc bổ sung

Một số bộ dữ liệu chỉ yêu cầu các phụ thuộc Python bổ sung trong quá trình tạo. Ví dụ: tập dữ liệu SVHN sử dụng scipy để tải một số dữ liệu.

Nếu bạn đang thêm tập dữ liệu vào kho lưu trữ TFDS, vui lòng sử dụng tfds.core.lazy_imports để giữ gói tensorflow-datasets nhỏ. Người dùng sẽ chỉ cài đặt các phần phụ thuộc bổ sung khi cần thiết.

Để sử dụng lazy_imports :

  • Thêm mục nhập cho tập dữ liệu của bạn vào DATASET_EXTRAS trong setup.py . Điều này giúp người dùng có thể thực hiện, ví dụ: pip install 'tensorflow-datasets[svhn]' để cài đặt các phụ thuộc bổ sung.
  • Thêm một mục nhập để nhập của bạn vào LazyImporter và vào LazyImportsTest .
  • Sử dụng tfds.core.lazy_imports để truy cập phần phụ thuộc (ví dụ: tfds.core.lazy_imports.scipy ) trong DatasetBuilder của bạn.

Dữ liệu bị hỏng

Một số bộ dữ liệu không hoàn toàn sạch và chứa một số dữ liệu bị hỏng (ví dụ: hình ảnh nằm trong tệp JPEG nhưng một số bộ dữ liệu là JPEG không hợp lệ). Nên bỏ qua các ví dụ này, nhưng hãy để lại ghi chú trong phần mô tả tập dữ liệu có bao nhiêu ví dụ bị loại bỏ và tại sao.

Cấu hình / biến thể tập dữ liệu (tfds.core.BuilderConfig)

Một số bộ dữ liệu có thể có nhiều biến thể hoặc các tùy chọn về cách dữ liệu được xử lý trước và ghi vào đĩa. Ví dụ: cycle_gan có một cấu hình cho mỗi cặp đối tượng ( cycle_gan/horse2zebra , cycle_gan/monet2photo , ...).

Điều này được thực hiện thông qua tfds.core.BuilderConfig s:

  1. Xác định đối tượng cấu hình của bạn như một lớp con của tfds.core.BuilderConfig . Ví dụ, MyDatasetConfig .

    @dataclasses.dataclass
    class MyDatasetConfig(tfds.core.BuilderConfig):
      img_size: Tuple[int, int] = (0, 0)
    
  2. Xác định thành viên lớp BUILDER_CONFIGS = [] trong MyDataset liệt kê các MyDatasetConfig mà tập dữ liệu hiển thị.

    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
    
  3. Sử dụng self.builder_config trong MyDataset để định cấu hình tạo dữ liệu (ví dụ: shape=self.builder_config.img_size ). Điều này có thể bao gồm việc đặt các giá trị khác nhau trong _info() hoặc thay đổi quyền truy cập dữ liệu tải xuống.

Ghi chú:

  • Mỗi cấu hình có một tên duy nhất. Tên đủ điều kiện của cấu hình là dataset_name/config_name (ví dụ: coco/2017 ).
  • Nếu không được chỉ định, cấu hình đầu tiên trong BUILDER_CONFIGS sẽ được sử dụng (ví dụ: tfds.load('c4') mặc định thành c4/en )

Xem anli để biết ví dụ về tập dữ liệu sử dụng BuilderConfig s.

Phiên bản

Phiên bản có thể đề cập đến hai nghĩa khác nhau:

  • Phiên bản dữ liệu gốc "bên ngoài": ví dụ: COCO v2019, v2017, ...
  • Phiên bản mã TFDS "nội bộ": ví dụ: đổi tên tính năng trong tfds.features.FeaturesDict , sửa lỗi trong _generate_examples

Để cập nhật tập dữ liệu:

  • Đối với cập nhật dữ liệu "bên ngoài": Nhiều người dùng có thể muốn truy cập đồng thời vào một năm / phiên bản cụ thể. Điều này được thực hiện bằng cách sử dụng một tfds.core.BuilderConfig cho mỗi phiên bản (ví dụ: coco/2017 , coco/2019 ) hoặc một lớp cho mỗi phiên bản (ví dụ: Voc2007 , Voc2012 ).
  • Đối với cập nhật mã "nội bộ": Người dùng chỉ tải xuống phiên bản mới nhất. Bất kỳ bản cập nhật mã nào cũng phải tăng thuộc tính lớp VERSION (ví dụ: từ 1.0.0 lên VERSION = tfds.core.Version('2.0.0') ) sau khi lập phiên bản ngữ nghĩa .

Thêm một mục nhập để đăng ký

Đừng quên nhập mô-đun tập dữ liệu vào dự án __init__ của bạn để được đăng ký tự động trong tfds.load , tfds.builder .

import my_project.datasets.my_dataset  # Register MyDataset

ds = tfds.load('my_dataset')  # MyDataset available

Ví dụ: nếu bạn đang đóng góp vào tensorflow/datasets , hãy thêm nhập mô-đun vào __init__.py của thư mục con của nó (ví dụ: image/__init__.py .

Kiểm tra các lỗi triển khai phổ biến

Vui lòng kiểm tra các lỗi triển khai phổ biến .

Kiểm tra tập dữ liệu của bạn

Tải xuống và chuẩn bị: tfds build

Để tạo tập dữ liệu, hãy chạy tfds build từ thư mục my_dataset/ :

cd path/to/datasets/my_dataset/
tfds build --register_checksums

Một số cờ hữu ích để phát triển:

  • --pdb : Vào chế độ gỡ lỗi nếu một ngoại lệ được đưa ra.
  • --overwrite : Xóa các tệp hiện có nếu tập dữ liệu đã được tạo.
  • --max_examples_per_split : Chỉ tạo X ví dụ đầu tiên (mặc định là 1), thay vì tập dữ liệu đầy đủ.
  • --register_checksums : Ghi lại tổng kiểm tra của các url đã tải xuống. Chỉ nên được sử dụng khi đang trong quá trình phát triển.

Xem tài liệu CLI để biết danh sách đầy đủ các cờ.

Kiểm tra

Bạn nên ghi lại tổng kiểm tra của tập dữ liệu để đảm bảo tính xác định, trợ giúp về tài liệu, ... Điều này được thực hiện bằng cách tạo tập dữ liệu với --register_checksums (xem phần trước).

Nếu bạn đang phát hành tập dữ liệu của mình thông qua PyPI, đừng quên xuất các tệp checksums.tsv (ví dụ: trong package_data của setup.py ).

Unit-test tập dữ liệu của bạn

tfds.testing.DatasetBuilderTestCase là một TestCase cơ sở để thực hiện đầy đủ một tập dữ liệu. Nó sử dụng "dữ liệu giả" làm dữ liệu thử nghiệm bắt chước cấu trúc của tập dữ liệu nguồn.

  • Dữ liệu thử nghiệm nên được đặt trong my_dataset/dummy_data/ và phải bắt chước các tạo tác của tập dữ liệu nguồn khi được tải xuống và giải nén. Nó có thể được tạo thủ công hoặc tự động với một script ( script ví dụ ).
  • Đảm bảo sử dụng dữ liệu khác nhau trong phần tách dữ liệu thử nghiệm của bạn, vì thử nghiệm sẽ không thành công nếu phần tách tập dữ liệu của bạn chồng chéo lên nhau.
  • Dữ liệu thử nghiệm không được chứa bất kỳ tài liệu có bản quyền nào . Nếu nghi ngờ, không tạo dữ liệu bằng cách sử dụng tài liệu từ tập dữ liệu gốc.
import tensorflow_datasets as tfds
from . import my_dataset


class MyDatasetTest(tfds.testing.DatasetBuilderTestCase):
  """Tests for my_dataset dataset."""
  DATASET_CLASS = my_dataset.MyDataset
  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()

Chạy lệnh sau để kiểm tra tập dữ liệu.

python my_dataset_test.py

Gửi phản hồi cho chúng tôi

Chúng tôi liên tục cố gắng cải thiện quy trình tạo tập dữ liệu, nhưng chỉ có thể làm như vậy nếu chúng tôi nhận thức được các vấn đề. Bạn đã gặp phải sự cố, lỗi nào khi tạo tập dữ liệu? Có một phần nào đó gây nhầm lẫn, viết sẵn hoặc không hoạt động trong lần đầu tiên? Vui lòng chia sẻ phản hồi của bạn trên github .