<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Copyright 2020 The TensorFlow Authors.
Step1:  データ増強
<table class="tfo-notebook-buttons" align="left">
  <td><a target="_blank" href="https
Step2:  データセットをダウンロードする
このチュートリアルでは、tf_flowers データセットを使用します。便宜上、TensorFlow Dataset を使用してデータセットをダウンロードします。他のデータインポート方法に関する詳細は、画像読み込みのチュートリアルをご覧ください。
Step3:  花のデータセットには 5 つのクラスがあります。
Step4:  データセットから画像を取得し、それを使用してデータ増強を実演してみましょう。
Step5:  Keras 前処理レイヤーを使用する
リサイズとリスケール
Keras 前処理レイヤーを使用して、画像を一定の形状にサイズ変更し（tf.keras.layers.Resizing）、ピクセル値を再スケールする（tf.keras.layers.Rescaling）ことができます。
Step6:  注意
Step7:  ピクセルが [0, 1] の範囲にあることを確認します。
Step8:  データ増強
tf.keras.layers.RandomFlip や tf.keras.layers.RandomRotation などの Keras 前処理レイヤーをデータ拡張に使用することができます。
前処理レイヤーをいくつか作成し、同じ画像に繰り返して適用してみましょう。
Step9:  データ拡張には、tf.keras.layers.RandomContrast、tf.keras.layers.RandomCrop、tf.keras.layers.RandomZoom など、様々な前処理レイヤーを使用できます。
Keras 前処理レイヤーを使用するための 2 つのオプション
これらの前処理レイヤーを使用できる方法には 2 つありませうが、これらには重要なトレードオフが伴います。
オプション 1
Step10:  この場合、2 つの重要なポイントがあります。
データ増強はデバイス上で他のレイヤーと同期して実行されるため、GPU アクセラレーションの恩恵を受けることができます。
model.saveを使用してモデルをエクスポートすると、前処理レイヤーはモデルの残りの部分と一緒に保存されます。後でこのモデルをデプロイする場合、画像は自動的に（レイヤーの設定に従い）標準化されます。これにより、サーバーサイドでロジックを再実装する手間が省けます。
注意
Step11:  このアプローチでは、Dataset.map を使用して、拡張画像のバッチを生成するデータセットを作成します。この場合は、
データ拡張は CPU 上で非同期に行われ、ノンブロッキングです。以下に示すように、Dataset.prefetch を使用して GPU 上でのモデルのトレーニングをデータの前処理にオーバーラップさせることができます。
この場合、Model.save を呼び出しても、前処理レイヤーはモデルと一緒にエクスポートされません。保存前にモデルに前処理レイヤーをアタッチするか、サーバー側で前処理レイヤーを再実装する必要があります。トレーニングの後、エクスポートする前に前処理レイヤーをアタッチすることができます。
1 番目のオプションの例については、画像分類チュートリアルをご覧ください。次に、2 番目のオプションを見てみましょう。
前処理レイヤーをデータセットに適用する
前に作成した前処理レイヤーを使用して、トレーニング、検証、テスト用のデータセットを構成します。また、パフォーマンス向上のために、並列読み取りとバッファ付きプリフェッチを使用してデータセットを構成し、I/O がブロックされることなくディスクからバッチを生成できるようにします。（データセットのパフォーマンスに関する詳細は、tf.data API によるパフォーマンス向上ガイドをご覧ください。）
注意
Step12:  モデルをトレーニングする
完全を期すために、準備したデータセットを使用してモデルをトレーニングします。
Sequential モデルは、それぞれに最大プールレイヤー（tf.keras.layers.MaxPooling2D）を持つ3つの畳み込みブロック（tf.keras.layers.Conv2D）で構成されます。ReLU 活性化関数（'relu'）により活性化されたユニットが 128 個ある完全に接続されたレイヤー（tf.keras.layers.Dense）があります。このモデルの精度は調整されていません（このチュートリアルの目的は、標準的なアプローチを示すことであるため）。
Step13:  tf.keras.optimizers.Adam オプティマイザとtf.keras.losses.SparseCategoricalCrossentropy 損失関数を選択します。各トレーニングエポックのトレーニングと検証の精度を表示するには、Model.compile に metrics 引数を渡します。
Step14:  数エポック、トレーニングします。
Step15:  カスタムデータ増強
また、カスタムデータ拡張レイヤーを作成することもできます。
このセクションでは、これを行うための 2 つの方法を説明します。
まず、tf.keras.layers.Lambda レイヤーを作成します。簡潔なコードを書くには良い方法です。
次に、subclassing を介して新しいレイヤーを記述します。こうすることで、さらに制御できるようになります。
どちらのレイヤーも、確率に従って、画像の色をランダムに反転します。
Step16:  次に、サブクラス化してカスタムレイヤーを実装します。
Step17:  どちらのレイヤーも、上記 1 と 2 のオプションで説明した使用が可能です。
tf.image を使用する
上記の Keras 前処理ユーティリティは便利ではありますが、より細かい制御には、tf.data や tf.image を使用して独自のデータ拡張パイプラインやレイヤーを書くことができます。（また、<a>TensorFlow Addons 画像
Step18:  作業に必要な画像を取得します。
Step19:  以下の関数を使用して元の画像と拡張画像を並べて視覚化し、比較してみましょう。
Step20:  データ増強
画像をフリップする
tf.image.flip_left_right を使って、画像を縦方向または横方向に反転します。
Step21:  画像をグレースケールにする
tf.image.rgb_to_grayscale を使って、画像をグレースケールにできます。
Step22:  画像の彩度を処理する
tf.image.adjust_saturation を使用し、彩度係数を指定して画像の彩度を操作します。
Step23:  画像の明るさを変更する
tf.image.adjust_brightness を使用し、明度係数を指定して画像の明度を変更します。
Step24:  画像を中央でトリミングする
tf.image.central_crop を使用して、画像の中央から希望する部分までをトリミングします。
Step25:  画像を回転させる
tf.image.rot90 を使用して、画像を 90 度回転させます。
Step26:  ランダム変換
警告
Step27:  画像のコントラストをランダムに変更する
tf.image.stateless_random_contrast を使用し、コントラスト範囲と seed を指定して、image のコントラストをランダムに変更します。コントラスト範囲は、[lower, upper] の間隔でランダムに選択され、指定された seed に関連付けられます。
Step28:  ランダムに画像をトリミングする
tf.image.stateless_random_crop を使用し、ターゲットの size と seed を指定して image をランダムにトリミングします。image から切り取られる部分は、ランダムに選択されたオフセットにあり、指定された seed に関連付けられています。
Step29:  データ増強をデータセットに適用する
前に説明したように、Dataset.map を使用してデータセットにデータ拡張を適用します。
Step30:  次に、画像のサイズ変更と再スケーリングのためのユーティリティ関数を定義します。この関数は、データセット内の画像のサイズとスケールを統一するために使用されます。
Step31:  また、画像にランダム変換を適用できる augment 関数も定義します。この関数は、次のステップのデータセットで使用されます。
Step32:  オプション 1
Step33:  augment 関数をトレーニングデータセットにマッピングします。
Step34:  オプション 2
Step35:  ラッパー関数 f をトレーニングデータセットにマッピングし、resize_and_rescale 関数を検証セットとテストセットにマッピングします。
<ASSISTANT_TASK:>
Python Code:
#@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.
Explanation: Copyright 2020 The TensorFlow Authors.
End of explanation
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds
from tensorflow.keras import layers
Explanation: データ増強
<table class="tfo-notebook-buttons" align="left">
  <td><a target="_blank" href="https://www.tensorflow.org/tutorials/images/data_augmentation"><img src="https://www.tensorflow.org/images/tf_logo_32px.png">TensorFlow.org で表示</a></td>
  <td><a target="_blank" href="https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/tutorials/images/data_augmentation.ipynb"><img src="https://www.tensorflow.org/images/colab_logo_32px.png">Google Colab で実行</a></td>
  <td><a target="_blank" href="https://github.com/tensorflow/docs-l10n/blob/master/site/ja/tutorials/images/data_augmentation.ipynb"><img src="https://www.tensorflow.org/images/GitHub-Mark-32px.png">GitHub でソースを表示</a></td>
  <td><a href="https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/tutorials/images/data_augmentation.ipynb"><img src="https://www.tensorflow.org/images/download_logo_32px.png">ノートブックをダウンロード</a></td>
</table>
概要
このチュートリアルでは、データ拡張を説明します。これは、画像の回転といったランダム（ただし現実的）な変換を適用することで、トレーニングセットの多様性を拡大する手法です。
データ拡張を次の 2 つの方法で適用する方法を学習します。
tf.keras.layers.Resizing、tf.keras.layers.Rescaling、tf.keras.layers.RandomFlip、および tf.keras.layers.RandomRotation などの Keras 前処理レイヤーを使用します。
tf.image.flip_left_right、tf.image.rgb_to_grayscale、tf.image.adjust_brightness、tf.image.central_crop、および tf.image.stateless_random* などの tf.image メソッドを使用します。
セットアップ
End of explanation
(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,
)
Explanation: データセットをダウンロードする
このチュートリアルでは、tf_flowers データセットを使用します。便宜上、TensorFlow Dataset を使用してデータセットをダウンロードします。他のデータインポート方法に関する詳細は、画像読み込みのチュートリアルをご覧ください。
End of explanation
num_classes = metadata.features['label'].num_classes
print(num_classes)
Explanation: 花のデータセットには 5 つのクラスがあります。
End of explanation
get_label_name = metadata.features['label'].int2str
image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
Explanation: データセットから画像を取得し、それを使用してデータ増強を実演してみましょう。
End of explanation
IMG_SIZE = 180
resize_and_rescale = tf.keras.Sequential([
  layers.Resizing(IMG_SIZE, IMG_SIZE),
  layers.Rescaling(1./255)
])
Explanation: Keras 前処理レイヤーを使用する
リサイズとリスケール
Keras 前処理レイヤーを使用して、画像を一定の形状にサイズ変更し（tf.keras.layers.Resizing）、ピクセル値を再スケールする（tf.keras.layers.Rescaling）ことができます。
End of explanation
result = resize_and_rescale(image)
_ = plt.imshow(result)
Explanation: 注意: 上記のリスケーリングレイヤーは、ピクセル値を [0,1] の範囲に標準化します。代わりに [-1,1] を用いる場合には、tf.keras.layers.Rescaling(1./127.5, offset=-1) と記述します。
次のようにして、これらのレイヤーを画像に適用した結果を可視化します。
End of explanation
print("Min and max pixel values:", result.numpy().min(), result.numpy().max())
Explanation: ピクセルが [0, 1] の範囲にあることを確認します。
End of explanation
data_augmentation = tf.keras.Sequential([
  layers.RandomFlip("horizontal_and_vertical"),
  layers.RandomRotation(0.2),
])
# Add the image to a batch.
image = tf.cast(tf.expand_dims(image, 0), tf.float32)
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")
Explanation: データ増強
tf.keras.layers.RandomFlip や tf.keras.layers.RandomRotation などの Keras 前処理レイヤーをデータ拡張に使用することができます。
前処理レイヤーをいくつか作成し、同じ画像に繰り返して適用してみましょう。
End of explanation
model = tf.keras.Sequential([
  # Add the preprocessing layers you created earlier.
  resize_and_rescale,
  data_augmentation,
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  # Rest of your model.
])
Explanation: データ拡張には、tf.keras.layers.RandomContrast、tf.keras.layers.RandomCrop、tf.keras.layers.RandomZoom など、様々な前処理レイヤーを使用できます。
Keras 前処理レイヤーを使用するための 2 つのオプション
これらの前処理レイヤーを使用できる方法には 2 つありませうが、これらには重要なトレードオフが伴います。
オプション 1: 前処理レイヤーをモデルの一部にする
End of explanation
aug_ds = train_ds.map(
  lambda x, y: (resize_and_rescale(x, training=True), y))
Explanation: この場合、2 つの重要なポイントがあります。
データ増強はデバイス上で他のレイヤーと同期して実行されるため、GPU アクセラレーションの恩恵を受けることができます。
model.saveを使用してモデルをエクスポートすると、前処理レイヤーはモデルの残りの部分と一緒に保存されます。後でこのモデルをデプロイする場合、画像は自動的に（レイヤーの設定に従い）標準化されます。これにより、サーバーサイドでロジックを再実装する手間が省けます。
注意: データ拡張はテスト時には非アクティブなので、(Model.evaluate や Model.predict ではなく)  Model.fit への呼び出し時にのみ、入力画像を拡張します。
オプション 2: 前処理レイヤーをデータセットに適用する
End of explanation
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 prefetching 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)
Explanation: このアプローチでは、Dataset.map を使用して、拡張画像のバッチを生成するデータセットを作成します。この場合は、
データ拡張は CPU 上で非同期に行われ、ノンブロッキングです。以下に示すように、Dataset.prefetch を使用して GPU 上でのモデルのトレーニングをデータの前処理にオーバーラップさせることができます。
この場合、Model.save を呼び出しても、前処理レイヤーはモデルと一緒にエクスポートされません。保存前にモデルに前処理レイヤーをアタッチするか、サーバー側で前処理レイヤーを再実装する必要があります。トレーニングの後、エクスポートする前に前処理レイヤーをアタッチすることができます。
1 番目のオプションの例については、画像分類チュートリアルをご覧ください。次に、2 番目のオプションを見てみましょう。
前処理レイヤーをデータセットに適用する
前に作成した前処理レイヤーを使用して、トレーニング、検証、テスト用のデータセットを構成します。また、パフォーマンス向上のために、並列読み取りとバッファ付きプリフェッチを使用してデータセットを構成し、I/O がブロックされることなくディスクからバッチを生成できるようにします。（データセットのパフォーマンスに関する詳細は、tf.data API によるパフォーマンス向上ガイドをご覧ください。）
注意: データ拡張はトレーニングセットのみに適用されます。
End of explanation
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)
])
Explanation: モデルをトレーニングする
完全を期すために、準備したデータセットを使用してモデルをトレーニングします。
Sequential モデルは、それぞれに最大プールレイヤー（tf.keras.layers.MaxPooling2D）を持つ3つの畳み込みブロック（tf.keras.layers.Conv2D）で構成されます。ReLU 活性化関数（'relu'）により活性化されたユニットが 128 個ある完全に接続されたレイヤー（tf.keras.layers.Dense）があります。このモデルの精度は調整されていません（このチュートリアルの目的は、標準的なアプローチを示すことであるため）。
End of explanation
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
Explanation: tf.keras.optimizers.Adam オプティマイザとtf.keras.losses.SparseCategoricalCrossentropy 損失関数を選択します。各トレーニングエポックのトレーニングと検証の精度を表示するには、Model.compile に metrics 引数を渡します。
End of explanation
epochs=5
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
Explanation: 数エポック、トレーニングします。
End of explanation
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")
Explanation: カスタムデータ増強
また、カスタムデータ拡張レイヤーを作成することもできます。
このセクションでは、これを行うための 2 つの方法を説明します。
まず、tf.keras.layers.Lambda レイヤーを作成します。簡潔なコードを書くには良い方法です。
次に、subclassing を介して新しいレイヤーを記述します。こうすることで、さらに制御できるようになります。
どちらのレイヤーも、確率に従って、画像の色をランダムに反転します。
End of explanation
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])
Explanation: 次に、サブクラス化してカスタムレイヤーを実装します。
End of explanation
(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,
)
Explanation: どちらのレイヤーも、上記 1 と 2 のオプションで説明した使用が可能です。
tf.image を使用する
上記の Keras 前処理ユーティリティは便利ではありますが、より細かい制御には、tf.data や tf.image を使用して独自のデータ拡張パイプラインやレイヤーを書くことができます。（また、<a>TensorFlow Addons 画像: 演算</a>および TensorFlow I/O: 色空間の変換もご覧ください。）
花のデータセットは、前にデータ拡張で構成したので、再インポートして最初からやり直しましょう。
End of explanation
image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
Explanation: 作業に必要な画像を取得します。
End of explanation
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)
Explanation: 以下の関数を使用して元の画像と拡張画像を並べて視覚化し、比較してみましょう。
End of explanation
flipped = tf.image.flip_left_right(image)
visualize(image, flipped)
Explanation: データ増強
画像をフリップする
tf.image.flip_left_right を使って、画像を縦方向または横方向に反転します。
End of explanation
grayscaled = tf.image.rgb_to_grayscale(image)
visualize(image, tf.squeeze(grayscaled))
_ = plt.colorbar()
Explanation: 画像をグレースケールにする
tf.image.rgb_to_grayscale を使って、画像をグレースケールにできます。
End of explanation
saturated = tf.image.adjust_saturation(image, 3)
visualize(image, saturated)
Explanation: 画像の彩度を処理する
tf.image.adjust_saturation を使用し、彩度係数を指定して画像の彩度を操作します。
End of explanation
bright = tf.image.adjust_brightness(image, 0.4)
visualize(image, bright)
Explanation: 画像の明るさを変更する
tf.image.adjust_brightness を使用し、明度係数を指定して画像の明度を変更します。
End of explanation
cropped = tf.image.central_crop(image, central_fraction=0.5)
visualize(image, cropped)
Explanation: 画像を中央でトリミングする
tf.image.central_crop を使用して、画像の中央から希望する部分までをトリミングします。
End of explanation
rotated = tf.image.rot90(image)
visualize(image, rotated)
Explanation: 画像を回転させる
tf.image.rot90 を使用して、画像を 90 度回転させます。
End of explanation
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)
Explanation: ランダム変換
警告: ランダム画像演算には tf.image.random* および tf.image.stateless_random* の 2 つのセットがあります。tf.image.random* 演算は、TF 1.x の古い RNG を使用するため、使用することは強くお勧めしません。代わりに、このチュートリアルで紹介したランダム画像演算を使用してください。詳細については、乱数の生成を参照してください。
画像にランダムな変換を適用すると、データセットの一般化と拡張にさらに役立ちます。現在の tf.image は、次の 8 つのランダム画像演算 (ops) を提供します。
tf.image.stateless_random_brightness
tf.image.stateless_random_contrast
tf.image.stateless_random_crop
tf.image.stateless_random_flip_left_right
tf.image.stateless_random_flip_up_down
tf.image.stateless_random_hue
tf.image.stateless_random_jpeg_quality
tf.image.stateless_random_saturation
これらのランダム画像演算は機能的であり、出力は入力にのみ依存します。これにより、高性能で決定論的な入力パイプラインで簡単に使用できるようになります。各ステップで seed 値を入力する必要があります。同じ seedを指定すると、呼び出された回数に関係なく、同じ結果が返されます。
注意: seed は、形状が (2,)  の Tensor で、値は任意の整数です。
以降のセクションでは、次のことを行います。
ランダム画像演算を使用して画像を変換する例を見る。
ランダム変換をトレーニングデータセットに適用する方法を示す。
画像の明るさをランダムに変更する
tf.image.stateless_random_brightness を使用し、明度係数と seed を指定して、image の明度をランダムに変更します。明度係数は、[-max_delta, max_delta) の範囲でランダムに選択され、指定された seed に関連付けられます。
End of explanation
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)
Explanation: 画像のコントラストをランダムに変更する
tf.image.stateless_random_contrast を使用し、コントラスト範囲と seed を指定して、image のコントラストをランダムに変更します。コントラスト範囲は、[lower, upper] の間隔でランダムに選択され、指定された seed に関連付けられます。
End of explanation
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)
Explanation: ランダムに画像をトリミングする
tf.image.stateless_random_crop を使用し、ターゲットの size と seed を指定して image をランダムにトリミングします。image から切り取られる部分は、ランダムに選択されたオフセットにあり、指定された seed に関連付けられています。
End of explanation
(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,
)
Explanation: データ増強をデータセットに適用する
前に説明したように、Dataset.map を使用してデータセットにデータ拡張を適用します。
End of explanation
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
Explanation: 次に、画像のサイズ変更と再スケーリングのためのユーティリティ関数を定義します。この関数は、データセット内の画像のサイズとスケールを統一するために使用されます。
End of explanation
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
Explanation: また、画像にランダム変換を適用できる augment 関数も定義します。この関数は、次のステップのデータセットで使用されます。
End of explanation
# Create a `Counter` object and `Dataset.zip` it together with the training set.
counter = tf.data.experimental.Counter()
train_ds = tf.data.Dataset.zip((train_datasets, (counter, counter)))
Explanation: オプション 1: tf.data.experimental.Counte を使用する
tf.data.experimental.Counter オブジェクト (counter と呼ぶ) を作成し、(counter, counter) を含むデータセットを zip します。これにより、データセット内の各画像が、counter に基づいて（一意の値形状 (2,)）に関連付けられるようになります。これは後で、ランダム変換の seed 値として augment 関数に渡されます。
End of explanation
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)
)
Explanation: augment 関数をトレーニングデータセットにマッピングします。
End of explanation
# Create a generator.
rng = tf.random.Generator.from_seed(123, alg='philox')
# Create 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
Explanation: オプション 2: tf.random.Generator を使用する
seed の初期値で tf.random.Generator オブジェクトを作成します。同じジェネレータオブジェクトに make_seeds 関数を呼び出すと、必ず新しい一意の seed 値が返されます。
ラッパー関数を 1) make_seeds 関数を呼び出し、2) 新たに生成された seed 値を augment 関数に渡してランダム変換を行うように定義します。
注意: tf.random.Generator オブジェクトは RNG 状態を tf.Variable に格納するため、checkpoint または  SavedModel として保存できます。詳細につきましては、乱数の生成を参照してください。
End of explanation
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)
)
Explanation: ラッパー関数 f をトレーニングデータセットにマッピングし、resize_and_rescale 関数を検証セットとテストセットにマッピングします。
End of explanation
<END_TASK>