3.5. O Dataset de Classificação de Imagens¶ Open the notebook in SageMaker Studio Lab
Um dos datasets amplamente usados para classificação de imagens é o conjunto de dados MNIST [LeCun et al., 1998]. Embora tenha tido uma boa execução como um conjunto de dados de referência, mesmo os modelos simples pelos padrões atuais alcançam uma precisão de classificação acima de 95%, tornando-o inadequado para distinguir entre modelos mais fortes e mais fracos. Hoje, o MNIST serve mais como verificação de sanidade do que como referência. Para aumentar um pouco a aposta, concentraremos nossa discussão nas próximas seções no dataset Fashion-MNIST, qualitativamente semelhante, mas comparativamente complexo [Xiao et al., 2017], que foi lançado em 2017.
%matplotlib inline
import sys
from mxnet import gluon
from d2l import mxnet as d2l
d2l.use_svg_display()
%matplotlib inline
import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l
d2l.use_svg_display()
%matplotlib inline
import tensorflow as tf
from d2l import tensorflow as d2l
d2l.use_svg_display()
3.5.1. Lendo o Dataset¶
Nós podemos baixar e ler o dataset Fashion-MNIST na memória por meio das funções integradas na estrutura.
mnist_train = gluon.data.vision.FashionMNIST(train=True)
mnist_test = gluon.data.vision.FashionMNIST(train=False)
# `ToTensor` converts the image data from PIL type to 32-bit floating point
# tensors. It divides all numbers by 255 so that all pixel values are between
# 0 and 1
trans = transforms.ToTensor()
mnist_train = torchvision.datasets.FashionMNIST(
root="../data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
root="../data", train=False, transform=trans, download=True)
mnist_train, mnist_test = tf.keras.datasets.fashion_mnist.load_data()
O Fashion-MNIST consiste em imagens de 10 categorias, cada uma representada por 6.000 imagens no conjunto de dados de treinamento e por 1.000 no conjunto de dados de teste. Um dataset de teste (ou conjunto de teste) é usado para avaliar o desempenho do modelo e não para treinamento. Consequentemente, o conjunto de treinamento e o conjunto de teste contém 60.000 e 10.000 imagens, respectivamente.
len(mnist_train), len(mnist_test)
(60000, 10000)
len(mnist_train), len(mnist_test)
(60000, 10000)
len(mnist_train[0]), len(mnist_test[0])
(60000, 10000)
A altura e a largura de cada imagem de entrada são 28 pixels. Observe que o dataset consiste em imagens em tons de cinza, cujo número de canais é 1. Para resumir, ao longo deste livro armazenamos a forma de qualquer imagem com altura \(h\) largura \(w\) pixels como \(h \times w\) or (\(h\), \(w\)).
mnist_train[0][0].shape
(28, 28, 1)
mnist_train[0][0].shape
torch.Size([1, 28, 28])
mnist_train[0][0].shape
(28, 28)
As imagens no Fashion-MNIST estão associadas às seguintes categorias: t-shirt, calças, pulôver, vestido, casaco, sandália, camisa, tênis, bolsa e bota. A função a seguir converte entre índices de rótulos numéricos e seus nomes em texto.
def get_fashion_mnist_labels(labels): #@save
"""Return text labels for the Fashion-MNIST dataset."""
text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
return [text_labels[int(i)] for i in labels]
Agora podemos criar uma função para visualizar esses exemplos.
def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5): #@save
"""Plot a list of images."""
figsize = (num_cols * scale, num_rows * scale)
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
axes = axes.flatten()
for i, (ax, img) in enumerate(zip(axes, imgs)):
ax.imshow(img.asnumpy())
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
if titles:
ax.set_title(titles[i])
return axes
def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5): #@save
"""Plot a list of images."""
figsize = (num_cols * scale, num_rows * scale)
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
axes = axes.flatten()
for i, (ax, img) in enumerate(zip(axes, imgs)):
if torch.is_tensor(img):
# Tensor Image
ax.imshow(img.numpy())
else:
# PIL Image
ax.imshow(img)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
if titles:
ax.set_title(titles[i])
return axes
def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5): #@save
"""Plot a list of images."""
figsize = (num_cols * scale, num_rows * scale)
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
axes = axes.flatten()
for i, (ax, img) in enumerate(zip(axes, imgs)):
ax.imshow(img.numpy())
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
if titles:
ax.set_title(titles[i])
return axes
Aqui estão as imagens e seus labels correspondentes (no texto) para os primeiros exemplos nodataset* de treinamento.
X, y = mnist_train[:18]
print(X.shape)
show_images(X.squeeze(axis=-1), 2, 9, titles=get_fashion_mnist_labels(y));
(18, 28, 28, 1)
X, y = next(iter(data.DataLoader(mnist_train, batch_size=18)))
show_images(X.reshape(18, 28, 28), 2, 9, titles=get_fashion_mnist_labels(y));
X = tf.constant(mnist_train[0][:18])
y = tf.constant(mnist_train[1][:18])
show_images(X, 2, 9, titles=get_fashion_mnist_labels(y));
3.5.2. Lendo um Minibatch¶
Para tornar nossa vida mais fácil ao ler os conjuntos de treinamento e
teste, usamos o iterador de dados integrado em vez de criar um do zero.
Lembre-se de que a cada iteração, um carregador de dados lê um minibatch
de dados com tamanho batch_size
cada vez. Também misturamos
aleatoriamente os exemplos para o iterador de dados de treinamento.
batch_size = 256
def get_dataloader_workers(): #@save
"""Use 4 processes to read the data except for Windows."""
return 0 if sys.platform.startswith('win') else 4
# `ToTensor` converts the image data from uint8 to 32-bit floating point. It
# divides all numbers by 255 so that all pixel values are between 0 and 1
transformer = gluon.data.vision.transforms.ToTensor()
train_iter = gluon.data.DataLoader(mnist_train.transform_first(transformer),
batch_size, shuffle=True,
num_workers=get_dataloader_workers())
batch_size = 256
def get_dataloader_workers(): #@save
"""Use 4 processes to read the data."""
return 4
train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=get_dataloader_workers())
batch_size = 256
train_iter = tf.data.Dataset.from_tensor_slices(
mnist_train).batch(batch_size).shuffle(len(mnist_train[0]))
Vejamos o tempo que leva para ler os dados de treinamento.
timer = d2l.Timer()
for X, y in train_iter:
continue
f'{timer.stop():.2f} sec'
'2.02 sec'
timer = d2l.Timer()
for X, y in train_iter:
continue
f'{timer.stop():.2f} sec'
'1.96 sec'
timer = d2l.Timer()
for X, y in train_iter:
continue
f'{timer.stop():.2f} sec'
'0.17 sec'
3.5.3. Juntando Tudo¶
Agora definimos a função load_data_fashion_mnist
que obtém e lê o
dataset Fashion-MNIST. Ele retorna os iteradores de dados para o
conjunto de treinamento e o conjunto de validação. Além disso, ele
aceita um argumento opcional para redimensionar imagens para outra
forma.
def load_data_fashion_mnist(batch_size, resize=None): #@save
"""Download the Fashion-MNIST dataset and then load it into memory."""
dataset = gluon.data.vision
trans = [dataset.transforms.ToTensor()]
if resize:
trans.insert(0, dataset.transforms.Resize(resize))
trans = dataset.transforms.Compose(trans)
mnist_train = dataset.FashionMNIST(train=True).transform_first(trans)
mnist_test = dataset.FashionMNIST(train=False).transform_first(trans)
return (gluon.data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=get_dataloader_workers()),
gluon.data.DataLoader(mnist_test, batch_size, shuffle=False,
num_workers=get_dataloader_workers()))
def load_data_fashion_mnist(batch_size, resize=None): #@save
"""Download the Fashion-MNIST dataset and then load it into memory."""
trans = [transforms.ToTensor()]
if resize:
trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
mnist_train = torchvision.datasets.FashionMNIST(
root="../data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
root="../data", train=False, transform=trans, download=True)
return (data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=get_dataloader_workers()),
data.DataLoader(mnist_test, batch_size, shuffle=False,
num_workers=get_dataloader_workers()))
def load_data_fashion_mnist(batch_size, resize=None): #@save
"""Download the Fashion-MNIST dataset and then load it into memory."""
mnist_train, mnist_test = tf.keras.datasets.fashion_mnist.load_data()
# Divide all numbers by 255 so that all pixel values are between
# 0 and 1, add a batch dimension at the last. And cast label to int32
process = lambda X, y: (tf.expand_dims(X, axis=3) / 255,
tf.cast(y, dtype='int32'))
resize_fn = lambda X, y: (
tf.image.resize_with_pad(X, resize, resize) if resize else X, y)
return (
tf.data.Dataset.from_tensor_slices(process(*mnist_train)).batch(
batch_size).shuffle(len(mnist_train[0])).map(resize_fn),
tf.data.Dataset.from_tensor_slices(process(*mnist_test)).batch(
batch_size).map(resize_fn))
Abaixo testamos o recurso de redimensionamento de imagem da função
load_data_fashion_mnist
especificando o argumento resize
.
train_iter, test_iter = load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:
print(X.shape, X.dtype, y.shape, y.dtype)
break
(32, 1, 64, 64) <class 'numpy.float32'> (32,) <class 'numpy.int32'>
train_iter, test_iter = load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:
print(X.shape, X.dtype, y.shape, y.dtype)
break
torch.Size([32, 1, 64, 64]) torch.float32 torch.Size([32]) torch.int64
train_iter, test_iter = load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:
print(X.shape, X.dtype, y.shape, y.dtype)
break
(32, 64, 64, 1) <dtype: 'float32'> (32,) <dtype: 'int32'>
Agora estamos prontos para trabalhar com o dataset Fashion-MNIST nas seções a seguir.
3.5.4. Resumo¶
Fashion-MNIST é um dataset de classificação de vestuário que consiste em imagens que representam 10 categorias. Usaremos esse conjunto de dados nas seções e capítulos subsequentes para avaliar vários algoritmos de classificação.
Armazenamos a forma de qualquer imagem com altura \(h\) largura \(w\) pixels como \(h \times w\) or (\(h\), \(w\)).
Os iteradores de dados são um componente chave para um desempenho eficiente. Conte com iteradores de dados bem implementados que exploram a computação de alto desempenho para evitar desacelerar o ciclo de treinamento.
3.5.5. Exercícios¶
A redução de
batch_size
(por exemplo, para 1) afeta o desempenho de leitura?O desempenho do iterador de dados é importante. Você acha que a implementação atual é rápida o suficiente? Explore várias opções para melhorá-lo.
Verifique a documentação online da API do framework. Quais outros conjuntos de dados estão disponíveis?