Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/pt-br/datasets/tfless_tfds.ipynb
25115 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

TFDS para Jax e PyTorch

O TFDS sempre foi independente de framework. Por exemplo, você pode carregar facilmente datasets no formato NumPy para uso em Jax e PyTorch.

O TensorFlow e sua solução de carregamento de dados (tf.data) são cidadãos de primeira classe em nossa API por design.

Estendemos o TFDS para oferecer suporte ao carregamento de dados em NumPy puro sem TensorFlow. Isto pode ser conveniente para uso em estruturas de aprendizado de máquina, como Jax e PyTorch. Na verdade, para esses últimos usuários, o TensorFlow pode:

  • reservar memória GPU/TPU;

  • aumentar o tempo de construção em CI/CD;

  • levar um tempo para importar em tempo de execução.

O TensorFlow não é mais uma dependência para a leitura de datasets.

Os pipelines de aprendizado de máquina precisam de um carregador de dados para carregar exemplos, decodificá-los e apresentá-los ao modelo. Os carregadores de dados usam o paradigma "fonte/amostrador/carregador":

TFDS dataset ┌────────────────┐ on disk │ │ ┌──────────►│ Data │ |..|... │ | │ source ├─┐ ├──┼────┴─────┤ │ │ │ │12│image12 │ └────────────────┘ │ ┌────────────────┐ ├──┼──────────┤ │ │ │ │13│image13 │ ├───►│ Data ├───► ML pipeline ├──┼──────────┤ │ │ loader │ │14│image14 │ ┌────────────────┐ │ │ │ ├──┼──────────┤ │ │ │ └────────────────┘ |..|... | │ Index ├─┘ │ sampler │ │ │ └────────────────┘
  • A fonte de dados é responsável por acessar e decodificar exemplos de um dataset TFDS em tempo real.

  • O amostrador de índice é responsável por determinar a ordem em que os registros são processados. Isto é importante para implementar transformações globais (por exemplo, embaralhamento global, fragmentação, repetição para múltiplas épocas) antes de ler quaisquer registros.

  • O carregador de dados orquestra o carregamento aproveitando a fonte de dados e o amostrador de índice. Permite otimização de desempenho (por exemplo, pré-busca, multiprocessamento ou multithreading).

Resumo

tfds.data_source é uma API para criar fontes de dados:

  1. para prototipagem rápida em pipelines de Python puro;

  2. para gerenciar pipelines de aprendizagem de máquina com uso intensivo de dados em escala.

Configuração

Vamos instalar e importar as dependências necessárias:

!pip install array_record !pip install tfds-nightly import os os.environ.pop('TFDS_DATA_DIR', None) import tensorflow_datasets as tfds

Fontes de dados

Fontes de dados são basicamente sequências Python. Portanto, elas precisam implementar o seguinte protocolo:

class RandomAccessDataSource(Protocol): """Interface for datasources where storage supports efficient random access.""" def __len__(self) -> int: """Number of records in the dataset.""" def __getitem__(self, record_key: int) -> Sequence[Any]: """Retrieves records for the given record_keys."""

Aviso: a API ainda está em desenvolvimento. Neste ponto em particular, __getitem__ deve suportar int e list[int] em entradas. No futuro, provavelmente só suportará int conformeo padrão.

O formato de arquivo subjacente precisa suportar acesso aleatório eficiente. No momento, o TFDS depende de array_record.

array_record é um novo formato de arquivo derivado de Riegeli, atingindo uma nova fronteira de eficiência em entrada e saída. O ArrayRecord suporta leitura paralela, gravação e acesso aleatório por índice de registros. ArrayRecord é baseado em Riegeli e oferece suporte aos mesmos algoritmos de compactação.

fashion_mnist é um dataset comum para visão computacional. Para recuperar uma fonte de dados baseada em ArrayRecord com TFDS, basta usar:

ds = tfds.data_source('fashion_mnist')

tfds.data_source é um wrapper conveniente. É equivalente a:

builder = tfds.builder('fashion_mnist', file_format='array_record') builder.download_and_prepare() ds = builder.as_data_source()

Isso gera como saída um dicionário de fontes de dados:

{ 'train': DataSource(name=fashion_mnist, split='train', decoders=None), 'test': DataSource(name=fashion_mnist, split='test', decoders=None), }

Depois que download_and_prepare for executado e você gerar os arquivos de registro, não precisaremos mais do TensorFlow. Tudo acontecerá em Python/NumPy!

Vamos verificar isso desinstalando o TensorFlow e recarregando a fonte de dados em outro subprocesso:

!pip uninstall -y tensorflow
%%writefile no_tensorflow.py import os os.environ.pop('TFDS_DATA_DIR', None) import tensorflow_datasets as tfds try: import tensorflow as tf except ImportError: print('No TensorFlow found...') ds = tfds.data_source('fashion_mnist') print('...but the data source could still be loaded...') ds['train'][0] print('...and the records can be decoded.')
!python no_tensorflow.py

Em versões futuras, também faremos com que a preparação do dataset seja independente do TensorFlow.

Uma fonte de dados tem um comprimento:

len(ds['train'])

Acessar o primeiro elemento do dataset:

%%timeit ds['train'][0]

...é tão barato quanto acessar qualquer outro elemento. Esta é a definição de acesso aleatório:

%%timeit ds['train'][1000]

Características agora usam o NumPy DTypes (em vez de TensorFlow DTypes). Você pode inspecionar as características com:

features = tfds.builder('fashion_mnist').info.features

Você encontrará mais informações sobre as características na nossa documentação. Aqui podemos recuperar a forma das imagens e o número de classes:

shape = features['image'].shape num_classes = features['label'].num_classes

Uso em Python puro

Você pode consumir fontes de dados em Python iterando sobre elas:

for example in ds['train']: print(example) break

Se você inspecionar elementos, também perceberá que todas as características já estão decodificadas usando NumPy. Nos bastidores, usamos OpenCV por padrão porque é rápido. Se você não tiver o OpenCV instalado, usaremos como padrão o Pillow para obter decodificação de imagem leve e rápida.

{ 'image': array([[[0], [0], ..., [0]], [[0], [0], ..., [0]]], dtype=uint8), 'label': 2, }

Observação: Atualmente, o recurso está disponível apenas para características de Tensor, Image e Scalar. As características de Audio e Video chegarão em breve. Fique atento!

Uso com PyTorch

O PyTorch usa o paradigma fonte/amostrador/carregador. No Torch, as "fontes de dados" são chamadas de "datasets". torch.utils.data contém todos os detalhes que você precisa saber para construir pipelines de entrada eficientes no Torch.

As fontes de dados TFDS podem ser usadas como datasets em estilo de mapa comuns.

Primeiro instalamos e importamos o Torch:

!pip install torch from tqdm import tqdm import torch

Já definimos fontes de dados para treinamento e teste (respectivamente, ds['train'] e ds['test']). Agora podemos definir o amostrador e os carregadores:

batch_size = 128 train_sampler = torch.utils.data.RandomSampler(ds['train'], num_samples=5_000) train_loader = torch.utils.data.DataLoader( ds['train'], sampler=train_sampler, batch_size=batch_size, ) test_loader = torch.utils.data.DataLoader( ds['test'], sampler=None, batch_size=batch_size, )

Usando o PyTorch, treinamos e avaliamos uma regressão logística simples nos primeiros exemplos:

class LinearClassifier(torch.nn.Module): def __init__(self, shape, num_classes): super(LinearClassifier, self).__init__() height, width, channels = shape self.classifier = torch.nn.Linear(height * width * channels, num_classes) def forward(self, image): image = image.view(image.size()[0], -1).to(torch.float32) return self.classifier(image) model = LinearClassifier(shape, num_classes) optimizer = torch.optim.Adam(model.parameters()) loss_function = torch.nn.CrossEntropyLoss() print('Training...') model.train() for example in tqdm(train_loader): image, label = example['image'], example['label'] prediction = model(image) loss = loss_function(prediction, label) optimizer.zero_grad() loss.backward() optimizer.step() print('Testing...') model.eval() num_examples = 0 true_positives = 0 for example in tqdm(test_loader): image, label = example['image'], example['label'] prediction = model(image) num_examples += image.shape[0] predicted_label = prediction.argmax(dim=1) true_positives += (predicted_label == label).sum().item() print(f'\nAccuracy: {true_positives/num_examples * 100:.2f}%')

Em breve: uso com JAX

Estamos trabalhando em estreita colaboração com o Grain. O Grain é um carregador de dados de código aberto, rápido e determinístico para Python. Então fique ligado!

Saiba mais

Para mais informações, consulte o documento da API tfds.data_source.