Keras 2 : examples : リサイズの学習 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/26/2021 (keras 2.7.0)
* 本ページは、Keras の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
- Code examples : Computer Vision : Learning to Resize in Computer Vision (Author: Sayak Paul)
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- 人工知能研究開発支援
- 人工知能研修サービス(経営者層向けオンサイト研修)
- テクニカルコンサルティングサービス
- 実証実験(プロトタイプ構築)
- アプリケーションへの実装
- 人工知能研修サービス
- PoC(概念実証)を失敗させないための支援
- テレワーク & オンライン授業を支援
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- ウェビナー運用には弊社製品「ClassCat® Webinar」を利用しています。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
- 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
- E-Mail:sales-info@classcat.com ; WebSite: www.classcat.com ; Facebook
Keras 2 : examples : リサイズの学習
Description: 与えられた解像度に対して画像の表現をどのように最適に学習するか。
人間が行なうように物事を知覚するようにビジョンモデルを制約すれば、パフォーマンスが向上できるというのが一般的な考え方です。例えば このワーク で Geirhos et al. は、ImageNet-1k データセット上で事前訓練されたビジョンモデルがテキスチャ寄りである一方で、人間は共通の知覚を得るために殆ど形状 (= shape) 記述子を使用していることを示しています。しかしこの信念は、特にビジョンモデルの性能を向上させるとき、常に当てはまるのでしょうか?
それは常に真実であるとは言えないことが判明しています。ビジョンモデルを訓練するとき、ミニバッチ学習を可能にして計算制限を維持するために画像を低次元 ((224 x 224), (299 x 299), 等) にリサイズすることが一般的です。このステップのためには bilinear 補間 のような画像リサイズ法を一般に使用し、リサイズされた画像は人間の目への知覚的特質の多くを失わないません。Learning to Resize Images for Computer Vision Tasks で、Talebi et al. は、画像の知覚的品質を人間の目よりもビジョンモデルのために最適化することを試みれば、パフォーマンスは更に改良できることを示しています。これらは次の質問を調査しています :
与えられた解像度とモデルのために、与えられた画像をどのように最善にリサイズするか?
論文で示されているように、このアイデアは、DenseNet-121, ResNet-50, MobileNetV2 と EfficientNets のような、(ImageNet-1k で事前訓練済みの) 一般的なビジョンモデルのパフォーマンスを一貫して向上させるのに役立ちます。このサンプルでは、論文で提案されている学習可能な画像リサイズモジュールを実装して、DenseNet-121 アーキテクチャを使用して Cats and Dogs データセット 上でそれを実演します。
このサンプルは TensorFlow 2.4 またはそれ以上を必要とします。
セットアップ
from tensorflow.keras import layers
from tensorflow import keras
import tensorflow as tf
import tensorflow_datasets as tfds
tfds.disable_progress_bar()
import matplotlib.pyplot as plt
import numpy as np
ハイパーパラメータの定義
ミニバッチ学習を容易にするため、与えられたバッチ内の画像のために固定 shape を持つ必要があります。これが初期リサイズが何故必要かです。最初に総ての画像を (300 x 300) shape にリサイズしてから (150 x 150) 解像度に対する最適な表現を学習します。
INP_SIZE = (300, 300)
TARGET_SIZE = (150, 150)
INTERPOLATION = "bilinear"
AUTO = tf.data.AUTOTUNE
BATCH_SIZE = 64
EPOCHS = 5
このサンプルでは、bilinear 補間を使用しますが、学習可能な画像リサイザー・モジュールは特定の補間法には依存しません。bicubic のような他のものも使用できます。
データセットをロードして準備する
このサンプルのために、訓練データセット全体の 40% だけを使用します。
train_ds, validation_ds = tfds.load(
"cats_vs_dogs",
# Reserve 10% for validation
split=["train[:40%]", "train[40%:50%]"],
as_supervised=True,
)
def preprocess_dataset(image, label):
image = tf.image.resize(image, (INP_SIZE[0], INP_SIZE[1]))
label = tf.one_hot(label, depth=2)
return (image, label)
train_ds = (
train_ds.shuffle(BATCH_SIZE * 100)
.map(preprocess_dataset, num_parallel_calls=AUTO)
.batch(BATCH_SIZE)
.prefetch(AUTO)
)
validation_ds = (
validation_ds.map(preprocess_dataset, num_parallel_calls=AUTO)
.batch(BATCH_SIZE)
.prefetch(AUTO)
)
[1mDownloading and preparing dataset 786.68 MiB (download: 786.68 MiB, generated: Unknown size, total: 786.68 MiB) to /home/jupyter/tensorflow_datasets/cats_vs_dogs/4.0.0...[0m WARNING:absl:1738 images were corrupted and were skipped [1mDataset cats_vs_dogs downloaded and prepared to /home/jupyter/tensorflow_datasets/cats_vs_dogs/4.0.0. Subsequent calls will reuse this data.[0m
学習可能なリサイザー・ユティリティ
下図 (courtesy: Learning to Resize Images for Computer Vision Tasks ) は学習可能なリサイズ・モジュールの構造を表しています :
def conv_block(x, filters, kernel_size, strides, activation=layers.LeakyReLU(0.2)):
x = layers.Conv2D(filters, kernel_size, strides, padding="same", use_bias=False)(x)
x = layers.BatchNormalization()(x)
if activation:
x = activation(x)
return x
def res_block(x):
inputs = x
x = conv_block(x, 16, 3, 1)
x = conv_block(x, 16, 3, 1, activation=None)
return layers.Add()([inputs, x])
def get_learnable_resizer(filters=16, num_res_blocks=1, interpolation=INTERPOLATION):
inputs = layers.Input(shape=[None, None, 3])
# First, perform naive resizing.
naive_resize = layers.Resizing(
*TARGET_SIZE, interpolation=interpolation
)(inputs)
# First convolution block without batch normalization.
x = layers.Conv2D(filters=filters, kernel_size=7, strides=1, padding="same")(inputs)
x = layers.LeakyReLU(0.2)(x)
# Second convolution block with batch normalization.
x = layers.Conv2D(filters=filters, kernel_size=1, strides=1, padding="same")(x)
x = layers.LeakyReLU(0.2)(x)
x = layers.BatchNormalization()(x)
# Intermediate resizing as a bottleneck.
bottleneck = layers.Resizing(
*TARGET_SIZE, interpolation=interpolation
)(x)
# Residual passes.
for _ in range(num_res_blocks):
x = res_block(bottleneck)
# Projection.
x = layers.Conv2D(
filters=filters, kernel_size=3, strides=1, padding="same", use_bias=False
)(x)
x = layers.BatchNormalization()(x)
# Skip connection.
x = layers.Add()([bottleneck, x])
# Final resized image.
x = layers.Conv2D(filters=3, kernel_size=7, strides=1, padding="same")(x)
final_resize = layers.Add()([naive_resize, x])
return tf.keras.Model(inputs, final_resize, name="learnable_resizer")
learnable_resizer = get_learnable_resizer()
学習可能なリサイズ・モジュールの出力の可視化
ここでは、リサイザーのランダムな重みを通過した後でリサイズされた画像がどのように見えるか可視化します。
sample_images, _ = next(iter(train_ds))
plt.figure(figsize=(16, 10))
for i, image in enumerate(sample_images[:6]):
image = image / 255
ax = plt.subplot(3, 4, 2 * i + 1)
plt.title("Input Image")
plt.imshow(image.numpy().squeeze())
plt.axis("off")
ax = plt.subplot(3, 4, 2 * i + 2)
resized_image = learnable_resizer(image[None, ...])
plt.title("Resized Image")
plt.imshow(resized_image.numpy().squeeze())
plt.axis("off")
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
(訳者注: 実験結果)
モデル構築ユティリティ
def get_model():
backbone = tf.keras.applications.DenseNet121(
weights=None,
include_top=True,
classes=2,
input_shape=((TARGET_SIZE[0], TARGET_SIZE[1], 3)),
)
backbone.trainable = True
inputs = layers.Input((INP_SIZE[0], INP_SIZE[1], 3))
x = layers.Rescaling(scale=1.0 / 255)(inputs)
x = learnable_resizer(x)
outputs = backbone(x)
return tf.keras.Model(inputs, outputs)
学習可能な画像リサイザー・モジュールの構造は様々なビジョンモデルとの柔軟な統合を可能にします。
学習可能なリサイザーでモデルをコンパイルして訓練する
model = get_model()
model.compile(
loss=keras.losses.CategoricalCrossentropy(label_smoothing=0.1),
optimizer="sgd",
metrics=["accuracy"],
)
model.fit(train_ds, validation_data=validation_ds, epochs=EPOCHS)
Epoch 1/5 146/146 [==============================] - 49s 247ms/step - loss: 0.6956 - accuracy: 0.5697 - val_loss: 0.6958 - val_accuracy: 0.5103 Epoch 2/5 146/146 [==============================] - 33s 216ms/step - loss: 0.6685 - accuracy: 0.6117 - val_loss: 0.6955 - val_accuracy: 0.5387 Epoch 3/5 146/146 [==============================] - 33s 216ms/step - loss: 0.6542 - accuracy: 0.6190 - val_loss: 0.7410 - val_accuracy: 0.5684 Epoch 4/5 146/146 [==============================] - 33s 216ms/step - loss: 0.6357 - accuracy: 0.6576 - val_loss: 0.9322 - val_accuracy: 0.5314 Epoch 5/5 146/146 [==============================] - 33s 215ms/step - loss: 0.6224 - accuracy: 0.6745 - val_loss: 0.6526 - val_accuracy: 0.6672 <tensorflow.python.keras.callbacks.History at 0x7f4433a79a50>
Epoch 1/5 146/146 [==============================] - 50s 245ms/step - loss: 0.6839 - accuracy: 0.5817 - val_loss: 0.7042 - val_accuracy: 0.5052 Epoch 2/5 146/146 [==============================] - 33s 216ms/step - loss: 0.6633 - accuracy: 0.6158 - val_loss: 0.7250 - val_accuracy: 0.5107 Epoch 3/5 146/146 [==============================] - 33s 216ms/step - loss: 0.6501 - accuracy: 0.6387 - val_loss: 0.7147 - val_accuracy: 0.5641 Epoch 4/5 146/146 [==============================] - 33s 217ms/step - loss: 0.6465 - accuracy: 0.6440 - val_loss: 0.8562 - val_accuracy: 0.5176 Epoch 5/5 146/146 [==============================] - 33s 216ms/step - loss: 0.6239 - accuracy: 0.6736 - val_loss: 1.2449 - val_accuracy: 0.5064 CPU times: user 5min 44s, sys: 15.7 s, total: 5min 59s Wall time: 3min 5s
訓練済みのビジュアライザーの出力の可視化
plt.figure(figsize=(16, 10))
for i, image in enumerate(sample_images[:6]):
image = image / 255
ax = plt.subplot(3, 4, 2 * i + 1)
plt.title("Input Image")
plt.imshow(image.numpy().squeeze())
plt.axis("off")
ax = plt.subplot(3, 4, 2 * i + 2)
resized_image = learnable_resizer(image[None, ...])
plt.title("Resized Image")
plt.imshow(resized_image.numpy().squeeze() / 10)
plt.axis("off")
プロットは画像のビジュアルが訓練により改善していることを示しています。以下の表は bilinear 補間を使用する場合と比較してリサイズ・モジュールを使用することの利点を示しています :
モデル | パラメータ数 (100 万) | Top-1 精度 |
---|---|---|
With 学習可能なリサイザー | 7.051717 | 67.67% |
Without 学習可能なリサイザー | 7.039554 | 60.19% |
詳細は、このレポジトリ を確認できます。上のレポートされたモデルは、このサンプルとは違って Cats and Dogs の訓練セットの 90% 上で 10 エポック訓練されたことに注意してください。また、リサイズ・モジュールによるパラメータ数の増加は殆ど無視できることにも注意してください。パフォーマンスの改善が確率的な性質によらないことを確認するため、モデルは同じ初期ランダム重みを使用して訓練されました。
さて、ここで尋ねる価値がある質問は – 改善された精度は単に、ベースラインに比べて、モデルにより多くの層を追加した結果ではないか?です (結局のところ、リサイザーはミニネットワークです) 。
それが当てはまらないことを示すため、著者は以下の実験を実行しています :
- あるサイズで訓練された事前訓練済みモデルを取ります、例えば (224 x 224) です。
- そして最初は、より低い解像度にリサイズされた画像上で予測を推論するためにそれを使用します。性能を記録します。
- 2 番目の実験については、事前訓練されたモデルの上にリサイザー・モジュールをプラグインして訓練をウォームスタートします。性能を記録します。
そして著者は 2 番目のオプションの使用が、与えられた解像度に関してモデルが表現をより良く調整することを学習するのに役立つため、より良いと主張しています。この結果は純粋に実験に基づいているので、cross-channel 相互作用を分析するような幾つかの更なる実験がより良かったでしょう。注目すべき点は、Squeeze and Excitation (SE) ブロック, グローバル・コンテキスト (GC) ブロック のような要素は既存のネットワークに幾つかのパラメータを追加もしますが、それらはネットワークが情報をシステマティックな方法で処理して全体的なパフォーマンスを改善するのに役立つことが知られています。
ノート
- ビジョンモデル内に shape バイアスを課すため、Geirhos et al. は自然で様式化された画像の組合せでそれらを訓練しました。出力はテキスチャ情報を破棄しているように見えるので、この学習可能なリサイズ・モジュールが同様の何かを実現できるか調べることは興味深いかもしれません。
- リサイザー・モジュールは任意の解像度とアスペクト比を処理できます、これはオブジェクト検出とセグメンテーションのようなタスクのためには重要です。
- 訓練の間に画像/特徴マップを適応的にリサイズすることを試みる、適応可能な画像リサイズ (= adaptive image resizing) に関する別の近い関連トピックがあります。EfficientV2 はこのアイデアを使用しています。
以上