データ拡張

TensorFlow.orgで表示 GoogleColabで実行 GitHubでソースを表示 ノートブックをダウンロード

概要

このチュートリアルでは、データ拡張について説明します。これは、画像の回転などのランダムな(ただし現実的な)変換を適用することにより、トレーニングセットの多様性を高める手法です。 2つの方法でデータ拡張を適用する方法を学習します。まず、あなたが使用するKeras前処理レイヤーを。次に、あなたが使用するtf.image

設定

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds

from tensorflow.keras import layers
2021-07-31 01:20:29.398577: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0

データセットをダウンロードする

このチュートリアルでは使用していますtf_flowersのデータセットを。便宜上、使用してデータセットをダウンロードしTensorFlowデータセットを。あなたがデータをインポートする他の方法について学習したい場合は、参照負荷イメージがチュートリアル。

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)
2021-07-31 01:20:32.658409: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
2021-07-31 01:20:33.245494: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.246357: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-31 01:20:33.246390: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-31 01:20:33.249453: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-07-31 01:20:33.249541: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
2021-07-31 01:20:33.250610: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcufft.so.10
2021-07-31 01:20:33.250929: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcurand.so.10
2021-07-31 01:20:33.251983: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusolver.so.11
2021-07-31 01:20:33.252852: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusparse.so.11
2021-07-31 01:20:33.253031: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-07-31 01:20:33.253121: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.253980: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.254770: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-07-31 01:20:33.255502: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-07-31 01:20:33.256126: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.256945: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-31 01:20:33.257035: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.257857: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.258642: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-07-31 01:20:33.258683: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-31 01:20:33.827497: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1258] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-07-31 01:20:33.827531: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1264]      0 
2021-07-31 01:20:33.827538: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1277] 0:   N 
2021-07-31 01:20:33.827734: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.828649: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.829480: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.830357: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1418] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14646 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)

花のデータセットには5つのクラスがあります。

num_classes = metadata.features['label'].num_classes
print(num_classes)
5

データセットから画像を取得し、それを使用してデータ拡張を示しましょう。

get_label_name = metadata.features['label'].int2str

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2021-07-31 01:20:33.935374: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
2021-07-31 01:20:33.935908: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2000160000 Hz
2021-07-31 01:20:34.470092: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

Keras前処理レイヤーを使用する

サイズ変更と再スケーリング

あなたはする前処理層を使用することができますサイズを変更一貫した形状、およびにあなたのイメージを再スケールピクセル値。

IMG_SIZE = 180

resize_and_rescale = tf.keras.Sequential([
  layers.experimental.preprocessing.Resizing(IMG_SIZE, IMG_SIZE),
  layers.experimental.preprocessing.Rescaling(1./255)
])

これらのレイヤーを画像に適用した結果を確認できます。

result = resize_and_rescale(image)
_ = plt.imshow(result)

png

あなたはピクセルがであることを確認することができます[0-1]

print("Min and max pixel values:", result.numpy().min(), result.numpy().max())
Min and max pixel values: 0.0 1.0

データ拡張

データ拡張のために前処理レイヤーを使用することもできます。

いくつかの前処理レイヤーを作成し、それらを同じ画像に繰り返し適用してみましょう。

data_augmentation = tf.keras.Sequential([
  layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
  layers.experimental.preprocessing.RandomRotation(0.2),
])
# Add the image to a batch
image = tf.expand_dims(image, 0)
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = data_augmentation(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0])
  plt.axis("off")

png

前処理の様々ながある、あなたが含むデータの増強のために使用することができますlayers.RandomContrastlayers.RandomCroplayers.RandomZoom 、そして他の人が。

前処理レイヤーを使用する2つのオプション

これらの前処理レイヤーを使用するには2つの方法がありますが、重要なトレードオフがあります。

オプション1:前処理レイヤーをモデルの一部にする

model = tf.keras.Sequential([
  resize_and_rescale,
  data_augmentation,
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  # Rest of your model
])

この場合、注意すべき2つの重要なポイントがあります。

  • データ拡張は、デバイス上で他のレイヤーと同期して実行され、GPUアクセラレーションの恩恵を受けます。

  • あなたが使用してモデルをエクスポートする場合model.save 、前処理層は、モデルの残りの部分と一緒に保存されます。後でこのモデルをデプロイすると、(レイヤーの構成に従って)イメージが自動的に標準化されます。これにより、そのロジックをサーバー側で再実装する手間を省くことができます。

オプション2:前処理レイヤーをデータセットに適用する

aug_ds = train_ds.map(
  lambda x, y: (resize_and_rescale(x, training=True), y))

このアプローチでは、使用Dataset.mapデータセットを作成するために、拡張画像の利回りバッチいます。この場合:

  • データ拡張はCPUで非同期に行われ、非ブロッキングです。あなたは使用して、データを前処理とGPUのモデルの訓練を重ねることができDataset.prefetchの下に表示し、。
  • この場合、prepreprocessing層が呼び出すモデルにエクスポートされませんmodel.save 。モデルを保存する前、またはサーバー側で再実装する前に、モデルにアタッチする必要があります。トレーニング後、エクスポートする前に前処理レイヤーをアタッチできます。

あなたは、最初のオプションの例を見つけることができます画像分類のチュートリアルを。ここで2番目のオプションを示しましょう。

前処理レイヤーをデータセットに適用します

上で作成した前処理レイヤーを使用して、トレーニング、検証、およびテストのデータセットを構成します。また、並列読み取りとバッファー付きプリフェッチを使用してデータセットのパフォーマンスを構成し、I / Oがブロックされることなくディスクからバッチを生成します。あなたは、よりデータセットのパフォーマンスを学ぶことができtf.dataのAPIとのより良い性能をガイド。

batch_size = 32
AUTOTUNE = tf.data.AUTOTUNE

def prepare(ds, shuffle=False, augment=False):
  # Resize and rescale all datasets
  ds = ds.map(lambda x, y: (resize_and_rescale(x), y), 
              num_parallel_calls=AUTOTUNE)

  if shuffle:
    ds = ds.shuffle(1000)

  # Batch all datasets
  ds = ds.batch(batch_size)

  # Use data augmentation only on the training set
  if augment:
    ds = ds.map(lambda x, y: (data_augmentation(x, training=True), y), 
                num_parallel_calls=AUTOTUNE)

  # Use buffered prefecting on all datasets
  return ds.prefetch(buffer_size=AUTOTUNE)
train_ds = prepare(train_ds, shuffle=True, augment=True)
val_ds = prepare(val_ds)
test_ds = prepare(test_ds)

モデルをトレーニングする

完全を期すために、これらのデータセットを使用してモデルをトレーニングします。このモデルは精度が調整されていません(目標はメカニズムを示すことです)。

model = tf.keras.Sequential([
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
epochs=5
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
Epoch 1/5
2021-07-31 01:20:39.448244: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-07-31 01:20:41.475212: I tensorflow/stream_executor/cuda/cuda_dnn.cc:359] Loaded cuDNN version 8100
2021-07-31 01:20:46.496035: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-07-31 01:20:46.860481: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
92/92 [==============================] - 17s 66ms/step - loss: 1.3434 - accuracy: 0.4271 - val_loss: 1.1534 - val_accuracy: 0.5368
Epoch 2/5
92/92 [==============================] - 3s 27ms/step - loss: 1.0960 - accuracy: 0.5565 - val_loss: 1.0718 - val_accuracy: 0.5695
Epoch 3/5
92/92 [==============================] - 3s 26ms/step - loss: 1.0115 - accuracy: 0.5988 - val_loss: 1.0322 - val_accuracy: 0.6022
Epoch 4/5
92/92 [==============================] - 3s 27ms/step - loss: 0.9503 - accuracy: 0.6202 - val_loss: 0.8811 - val_accuracy: 0.6730
Epoch 5/5
92/92 [==============================] - 3s 27ms/step - loss: 0.8758 - accuracy: 0.6570 - val_loss: 0.8760 - val_accuracy: 0.6485
loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
12/12 [==============================] - 1s 13ms/step - loss: 0.8319 - accuracy: 0.6812
Accuracy 0.6811988949775696

カスタムデータ拡張

カスタムデータ拡張レイヤーを作成することもできます。このチュートリアルでは、そのための2つの方法を示します。まず、あなたが作成されますlayers.Lambda層を。これは簡潔なコードを書くための良い方法です。次に、あなたが経て、新たな層書き込みますサブクラスあなたより詳細に制御できます。両方のレイヤーは、ある程度の確率に従って、画像の色をランダムに反転します。

def random_invert_img(x, p=0.5):
  if  tf.random.uniform([]) < p:
    x = (255-x)
  else:
    x
  return x
def random_invert(factor=0.5):
  return layers.Lambda(lambda x: random_invert_img(x, factor))

random_invert = random_invert()
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = random_invert(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0].numpy().astype("uint8"))
  plt.axis("off")

png

次は、することにより、カスタム層を実装するサブクラス化

class RandomInvert(layers.Layer):
  def __init__(self, factor=0.5, **kwargs):
    super().__init__(**kwargs)
    self.factor = factor

  def call(self, x):
    return random_invert_img(x)
_ = plt.imshow(RandomInvert()(image)[0])

png

これらのレイヤーは両方とも、上記のオプション1と2で説明したように使用できます。

tf.imageを使用する

上記layers.preprocessingユーティリティが便利です。より細かく制御するために、あなたが使用して独自のデータ増強パイプラインまたは層を書くことができますtf.datatf.image 。また、チェックアウトすることがありTensorFlowアドオンイメージを:オペレーションおよびTensorFlow I / O:カラースペース変換

花のデータセットは以前にデータ拡張を使用して構成されていたため、再インポートして最初からやり直してみましょう。

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

使用する画像を取得します。

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2021-07-31 01:21:08.829596: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

次の関数を使用して、元の画像と拡張された画像を並べて視覚化して比較してみましょう。

def visualize(original, augmented):
  fig = plt.figure()
  plt.subplot(1,2,1)
  plt.title('Original image')
  plt.imshow(original)

  plt.subplot(1,2,2)
  plt.title('Augmented image')
  plt.imshow(augmented)

データ拡張

画像を反転する

画像を垂直または水平に反転します。

flipped = tf.image.flip_left_right(image)
visualize(image, flipped)

png

画像をグレースケール

画像をグレースケールします。

grayscaled = tf.image.rgb_to_grayscale(image)
visualize(image, tf.squeeze(grayscaled))
_ = plt.colorbar()

png

画像を飽和させる

飽和係数を指定して画像を飽和させます。

saturated = tf.image.adjust_saturation(image, 3)
visualize(image, saturated)

png

画像の明るさを変更する

明るさ係数を指定して、画像の明るさを変更します。

bright = tf.image.adjust_brightness(image, 0.4)
visualize(image, bright)

png

画像を中央でトリミング

画像を中央から目的の画像部分まで切り抜きます。

cropped = tf.image.central_crop(image, central_fraction=0.5)
visualize(image,cropped)

png

画像を回転させる

画像を90度回転します。

rotated = tf.image.rot90(image)
visualize(image, rotated)

png

ランダム変換

画像にランダムな変換を適用すると、データセットの一般化と拡張にさらに役立ちます。現在tf.image APIは、8つの、ランダム画像操作(オペレーション)を提供しています。

これらのランダムな画像操作は純粋に機能的です。出力は入力にのみ依存します。これにより、高性能で決定論的な入力パイプラインで簡単に使用できるようになります。これらは、必要seed入力される値の各ステップを。同じ与えられたseed 、彼らは呼ばれている回数のと同じ結果が独立して返します。

次のセクションでは、次のことを行います。

  1. ランダムな画像操作を使用して画像を変換する例を確認してください。と
  2. ランダム変換をトレーニングデータセットに適用する方法を示します。

画像の明るさをランダムに変更する

無作為の明るさ変更image輝度係数及び提供することにより、 seed 。輝度係数の範囲でランダムに選択されている[-max_delta, max_delta)所与の関連付けられているseed

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_brightness = tf.image.stateless_random_brightness(
      image, max_delta=0.95, seed=seed)
  visualize(image, stateless_random_brightness)

png

png

png

画像のコントラストをランダムに変更する

無作為のコントラスト変更imageコントラスト範囲と提供することにより、 seed 。コントラスト範囲が間隔でランダムに選択されている[lower, upper]所与の関連付けられているseed

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_contrast = tf.image.stateless_random_contrast(
      image, lower=0.1, upper=0.9, seed=seed)
  visualize(image, stateless_random_contrast)

png

png

png

画像をランダムに切り抜く

ランダムトリミングimageターゲット提供することによって、 size及びseed 。トリミングされます部分imageランダムオフセット選択されると、所与の関連付けられているseed

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_crop = tf.image.stateless_random_crop(
      image, size=[210, 300, 3], seed=seed)
  visualize(image, stateless_random_crop)

png

png

png

データセットに拡張を適用する

前のセクションで変更された場合に備えて、最初に画像データセットを再度ダウンロードしましょう。

(train_datasets, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

画像のサイズ変更と再スケーリングのためのユーティリティ関数を定義しましょう。この関数は、データセット内の画像のサイズとスケールを統一するために使用されます。

def resize_and_rescale(image, label):
  image = tf.cast(image, tf.float32)
  image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])
  image = (image / 255.0)
  return image, label

レッツも定義augment画像にランダムな変形を適用することができます機能を。この関数は、次のステップでデータセットで使用されます。

def augment(image_label, seed):
  image, label = image_label
  image, label = resize_and_rescale(image, label)
  image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6)
  # Make a new seed
  new_seed = tf.random.experimental.stateless_split(seed, num=1)[0, :]
  # Random crop back to the original size
  image = tf.image.stateless_random_crop(
      image, size=[IMG_SIZE, IMG_SIZE, 3], seed=seed)
  # Random brightness
  image = tf.image.stateless_random_brightness(
      image, max_delta=0.5, seed=new_seed)
  image = tf.clip_by_value(image, 0, 1)
  return image, label

オプション1:使用tf.data.experimental.Counter()

作成tf.data.experimental.Counter()オブジェクトを(せのはそれを呼び出すcounter )とzipでデータセットを(counter, counter) 。これは、データセット内の各画像は、(形状の固有の値に関連付けされることを保証する(2,)に基づいて) counter後に渡されることができるaugmentとして機能seedランダム変換の値。

# Create counter and zip together with train dataset
counter = tf.data.experimental.Counter()
train_ds = tf.data.Dataset.zip((train_datasets, (counter, counter)))

マップaugmentトレーニングデータセットに関数を。

train_ds = (
    train_ds
    .shuffle(1000)
    .map(augment, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

オプション2:使用tf.random.Generator

作成tf.random.Generator intialでオブジェクトをseed値。呼び出しmake_seeds同じジェネレータオブジェクトの機能は、新しい、ユニークな返しseed常に値を。 1)呼び出すラッパー関数を定義make_seeds機能とその2)新たに生成された通過seedに値をaugmentランダム変換する機能。

# Create a generator
rng = tf.random.Generator.from_seed(123, alg='philox')
# A wrapper function for updating seeds
def f(x, y):
  seed = rng.make_seeds(2)[0]
  image, label = augment((x, y), seed)
  return image, label

ラッパー関数の地図fトレーニングデータセットへ。

train_ds = (
    train_datasets
    .shuffle(1000)
    .map(f, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

これらのデータセットを使用して、前に示したようにモデルをトレーニングできるようになりました。

次のステップ

このチュートリアルでは、使用して、データの増強を実証しKeras前処理層tf.image 。お使いのモデル内の前処理層を含める方法については、参照画像分類のチュートリアルを。あなたはまたに示すように、前処理層は、あなたがテキストを分類することができますどのように学習に興味がある可能性があり、基本的なテキスト分類のチュートリアル。あなたは、詳細について学ぶことができtf.dataこの中でガイド、そしてあなたは、パフォーマンスのために、あなたの入力パイプラインを構成する方法を学ぶことができ、ここで