次はmaxプーリングをみます。この記事はKaggleのイントロを色々みてますが、画像認識の三回目になります。
https://www.kaggle.com/code/ryanholbrook/maximum-pooling
ほぼコピペです。
今回学ぶのは、KerasではMaxPool2Dレイヤーによって行われる、最大値プーリングによる凝縮です。
最大プーリングでの凝縮
前に持っていたモデルに凝縮ステップを追加すると、次のようになります:
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Conv2D(filters=64, kernel_size=3), # activation is None
layers.MaxPool2D(pool_size=2),
# More layers follow
])
MaxPool2DレイヤーはConv2Dレイヤーに非常に似ていますが、kernel_sizeに対応するpool_sizeパラメータを使用してカーネルの代わりに単純な最大関数を使用します。ただし、MaxPool2Dレイヤーには、カーネルにあるような学習可能な重みは存在しません。
ReLU関数(検出)を適用した後、特徴マップには多くの「死んだ空間」、つまり0のみを含む大きなエリア(画像の黒いエリア)が出現することに注意してください。これらの0の活性化をネットワーク全体に運ぶことは、モデルのサイズを増加させるだけで、役立つ情報はあまり追加されません。代わりに、特徴マップを凝縮して、最も有用な部分、つまり特徴自体のみを保持したいと考えます。
実際、これは最大プーリングが行うことです。最大プーリングは、元の特徴マップの活性化のパッチを取り、そのパッチの最大活性化でそれらを置き換えます。
ReLU活性化の後に適用すると、特徴を「強化する」効果があります。プーリングステップは、アクティブピクセルとゼロピクセルの比率を増加させます。
早速例題です:最大値プーリングの適用
レッスン2の例で行った特徴抽出に「凝縮」ステップを追加しましょう。
import tensorflow as tf
import matplotlib.pyplot as plt
import warnings
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
titleweight='bold', titlesize=18, titlepad=10)
plt.rc('image', cmap='magma')
warnings.filterwarnings("ignore") # to clean up output cells
Read image
image_path = '../input/computer-vision-resources/car_feature.jpg'
image = tf.io.read_file(image_path)
image = tf.io.decode_jpeg(image)
Define kernel
kernel = tf.constant([
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1],
], dtype=tf.float32)
Reformat for batch compatibility.
image = tf.image.convert_image_dtype(image, dtype=tf.float32)
image = tf.expand_dims(image, axis=0)
kernel = tf.reshape(kernel, [*kernel.shape, 1, 1])
Filter step
image_filter = tf.nn.conv2d(
input=image,
filters=kernel,
# we'll talk about these two in the next lesson!
strides=1,
padding='SAME'
)
Detect step
image_detect = tf.nn.relu(image_filter)
Show what we have so far
plt.figure(figsize=(12, 6))
plt.subplot(131)
plt.imshow(tf.squeeze(image), cmap='gray')
plt.axis('off')
plt.title('Input')
plt.subplot(132)
plt.imshow(tf.squeeze(image_filter))
plt.axis('off')
plt.title('Filter')
plt.subplot(133)
plt.imshow(tf.squeeze(image_detect))
plt.axis('off')
plt.title('Detect')
plt.show();
ここまでは前回の説明で出てきました。
プーリングステップを適用するために、tf.nn内の別の関数、tf.nn.poolを使用します。これは、モデル構築時に使用するMaxPool2Dレイヤーと同じことをするPython関数ですが、単純な関数であるため、直接使用するのが簡単です。
import tensorflow as tf
image_condense = tf.nn.pool(
input=image_detect, # image in the Detect step above
window_shape=(2, 2),
pooling_type='MAX',
# we'll see what these do in the next lesson!
strides=(2, 2),
padding='SAME',
)
plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_condense))
plt.axis('off')
plt.show();
プーリングステップが最も活動的なピクセルの周りで画像を凝縮することで、特徴を強化することができました。
変換不変性
私たちはゼロピクセルを「重要ではない」と呼びました。これは、それらがまったく情報を持たないことを意味するのでしょうか?実際には、ゼロピクセルは位置情報を持っています。空白のスペースはまだ特徴を画像内に配置しています。MaxPool2Dがこれらのピクセルの一部を取り除くと、特徴マップの位置情報の一部も取り除かれます。これにより、convnetには変換不変性と呼ばれるプロパティが付与されます。これは、最大プーリングを持つconvnetは、画像内の位置によって特徴を区別しない傾向があることを意味します。(「変換」とは、何かを回転させたり、形状やサイズを変更せずに位置を変更するための数学的な言葉です。)
次の特徴マップに最大プーリングを繰り返し適用すると、何が起こるかを見てみましょう。
元の画像の2つの点は、繰り返しのプーリングの後に区別できなくなりました。言い換えれば、プーリングによって彼らの位置情報の一部が破壊されました。ネットワークは特徴マップでそれらを区別できなくなったので、元の画像でもそれらを区別できなくなりました:それは位置の違いに対して不変になりました。
実際、プーリングは画像内の2つの点のように、小さな距離でのみネットワークに変換不変性を作り出します。はじめから離れた場所にある特徴は、プーリングの後も明瞭に残ります。位置情報の一部のみが失われたので、すべてが失われたわけではありません。
特徴の位置の小さな違いに対するこの不変性は、画像分類器が持っていると便利なプロパティです。視点やフレーミングの違いのために、同じ種類の特徴が元の画像のさまざまな部分に配置されているかもしれませんが、分類器がそれらが同じであると認識することを望んでいます。この不変性がネットワークに組み込まれているので、訓練に使用するデータをはるかに少なくすることができます:もはやその違いを無視する方法を教える必要がありません。これにより、畳み込みネットワークは、密なレイヤーのみを持つネットワークよりも大きな効率の利点を持ちます。
結論
このレッスンでは、特徴抽出の最後のステップ、MaxPool2Dを使用して凝縮する方法について学びました。