1. 始める前に
この Codelab では、CNN を使用して画像分類モデルを改善する方法を学びます。
前提条件
この Codelab は、これまでの 2 回、コンピュータ ビジョン モデルの構築(コードの一部を紹介します)と畳み込みとプーリングの実行の Codelab で構築されています。この Codelab では畳み込みとプーリングを導入しています。
ラボの内容
- 畳み込みでコンピュータ ビジョンと精度を改善する方法
作成するアプリの概要
- ニューラル ネットワークを強化するレイヤ
必要なもの
Colab で実行する Codelab の残りの部分のコードを確認できます。
TensorFlow と前の Codelab でインストールしたライブラリも必要です。
2. 畳み込みでコンピュータ ビジョンの精度を向上させる
ここでは、入力レイヤ(入力データの形)、出力レイヤ(目的の出力の形状)、隠れレイヤの 3 つのレイヤを含むディープ ニューラル ネットワーク(DNN)を使用して、ファッションな画像認識を行う方法を学習しました。さまざまな隠れ層の各種サイズやトレーニング エポック数など、最終的な精度に影響するいくつかのパラメータを試しました。
便宜上、ここではコード全体を再度取り上げます。テストを実行して、最後に出力されたテスト精度をメモしておきます。
import tensorflow as tf
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images/255.0
test_images=test_images/255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)
test_loss, test_accuracy = model.evaluate(test_images, test_labels)
print ('Test loss: {}, Test accuracy: {}'.format(test_loss, test_accuracy*100))
おそらく精度はトレーニングで約 89%、検証で 87% です。これは、畳み込みを使用してさらに改善できます。畳み込みにより、特定のコンテンツに焦点を当て、画像の内容を絞り込むことができます。
フィルタを使用した画像処理をしたことがあれば、畳み込みに慣れていることがわかります。
簡単に言うと、配列(通常は 3x3 または 5x5)を取り、画像上に渡します。そのマトリックス内の式に基づいて基になるピクセルを変更することで、エッジ検出などのオペレーションを実行できます。たとえば、通常、エッジ検出には中央のセルが 3x3 で、すべての近隣ノードを -1 としています。この場合、ピクセルごとにその値に 8 を掛けた値を、各ネイバーの値から引きます。これをすべてのピクセルに対して実行すると、エッジが補正された新しい画像になります。
これは、コンピュータ ビジョンにも最適です。エッジなどの機能を拡張することで、コンピュータがアイテムを区別するのに役立つからです。さらに、ハイライト表示された特徴だけでトレーニングするので、必要な情報の量はさらに少なくなります。
これが、畳み込みニューラル ネットワークのコンセプトです。レイヤを追加して、高密度レイヤで畳み込みを行うと、高密度レイヤに届く情報がさらにフォーカスされ、精度が向上します。
3. コードを試す
次のコードを実行します。前と同じニューラル ネットワークですが、今回は畳み込み層が最初に追加されています。時間は長くなりますが、精度への影響をご確認ください。
import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(64, (3, 3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.summary()
model.fit(training_images, training_labels, epochs=5)
test_loss, test_accuracy = model.evaluate(test_images, test_labels)
print ('Test loss: {}, Test accuracy: {}'.format(test_loss, test_accuracy*100))
多くの場合、トレーニング データで最大 93%、検証データで 91% まで上昇していると考えられます。
これをエポック(たとえば約 20 個)に実行して結果を確認してみましょう。トレーニングの結果は良好に見えるかもしれませんが、実際には過学習と呼ばれる現象が原因で検証結果が下がる場合があります。
過学習は、ネットワークがトレーニング セットからのデータを認識しすぎると発生します。そのため、過学習は、そのデータのみを認識することを専門としており、一般的な状況では他のデータを見るのに効果的ではありません。たとえば、ハイヒールでのみトレーニングしている場合、ネットワークによってはハイヒールを識別できる「スニーカー」とよく識別されますが、
もう一度コードを見て、畳み込みがどのように構築されているかを確認してください。
4. データを収集する
まず、データを収集します。
変化があったため、トレーニング データを再構成する必要があります。これは、最初の畳み込みにはすべてを含む単一のテンソルが想定されるため、リスト内の 60,000 個の 28x28x1 アイテムではなく、60,000x28x28x1 の単一の 4D リストがあり、テスト画像でも同じです。そうしないと、畳み込みが形状を認識しないため、トレーニング時にエラーが発生します。
import tensorflow as tf
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images = training_images/255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images = test_images/255.0
5. モデルを定義する
次に、モデルを定義します。上部に入力レイヤの代わりに、畳み込みレイヤを追加します。パラメータの意味は次のとおりです。
- 生成する畳み込みの数。32 のような値が出発点として適しています。
- 畳み込み行列のサイズ(この例では 3x3 グリッド)。
- 使用するアクティベーション関数(この場合は
relu
)。 - 最初のレイヤでは、入力データの形状。
最大プーリング層は、畳み込みによって強調された特徴のコンテンツを維持しながら画像を圧縮するように設計されています。最大プーリングに(2,2)を指定すると、イメージのサイズが 4 倍に削減されます。2x2 のピクセル配列が作成され、最大のピクセル値が選択されて 4 ピクセルが 1 に変換されます。画像全体でこの計算を繰り返すことで、水平方向のピクセル数を半分に、垂直方向のピクセル数を半分にします。
model.summary()
を呼び出して、ネットワークのサイズと形状を確認できます。最大プーリング レイヤの後、画像サイズは次のように縮小されます。
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_2 (Conv2D) (None, 26, 26, 64) 640 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 13, 13, 64) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 11, 11, 64) 36928 _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 5, 5, 64) 0 _________________________________________________________________ flatten_2 (Flatten) (None, 1600) 0 _________________________________________________________________ dense_4 (Dense) (None, 128) 204928 _________________________________________________________________ dense_5 (Dense) (None, 10) 1290 =================================================================
CNN の完全なコードは次のとおりです。
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
#Add another convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
#Now flatten the output. After this you'll just have the same DNN structure as the non convolutional version
tf.keras.layers.Flatten(),
#The same 128 dense layers, and 10 output layers as in the pre-convolution example:
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
6. モデルのコンパイルとトレーニング
モデルをコンパイルし、適合性メソッドを呼び出してトレーニングを行い、テストセットからの損失と精度を評価します。
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)
test_loss, test_acc = model.evaluate(test_images, test_labels)
print ('Test loss: {}, Test accuracy: {}'.format(test_loss, test_acc*100))
7. 畳み込みとプールの可視化
このコードは、畳み込みをグラフで表示します。print (test_labels[:100])
はテストセットの最初の 100 個のラベルを示しており、インデックス 0、インデックス 23、インデックス 28 のラベルはすべて同じ値(9)になっています。すべてのシューズです。それぞれの畳み込みの結果を見ると、それらの間に共通する特徴が見え始めます。現在、DNN はそのデータをトレーニングしているとき、はるかに少ない情報で作業を行っています。そしてその畳み込みとプーリングの組み合わせによって、靴の共通点を見つけている可能性があります。
print(test_labels[:100])
[9 2 1 1 6 1 4 6 5 7 4 5 7 3 4 1 2 4 8 0 2 5 7 9 1 4 6 0 9 3 8 8 3 3 8 0 7 5 7 9 6 1 3 7 6 7 2 1 2 2 4 4 5 8 2 2 8 4 8 0 7 7 8 5 1 1 2 3 9 8 7 0 2 6 2 3 1 2 8 4 1 8 5 9 5 0 3 2 0 6 5 3 6 7 1 8 0 1 4 2]
これらのラベルに対応する画像の一部を選択して、畳み込みを通してどのように見えるかをレンダリングできるようになりました。したがって、次のコードでは、FIRST_IMAGE
、SECOND_IMAGE
、THIRD_IMAGE
はすべてアンクルブートである値 9 のインデックスです。
import matplotlib.pyplot as plt
f, axarr = plt.subplots(3,4)
FIRST_IMAGE=0
SECOND_IMAGE=23
THIRD_IMAGE=28
CONVOLUTION_NUMBER = 6
from tensorflow.keras import models
layer_outputs = [layer.output for layer in model.layers]
activation_model = tf.keras.models.Model(inputs = model.input, outputs = layer_outputs)
for x in range(0,4):
f1 = activation_model.predict(test_images[FIRST_IMAGE].reshape(1, 28, 28, 1))[x]
axarr[0,x].imshow(f1[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
axarr[0,x].grid(False)
f2 = activation_model.predict(test_images[SECOND_IMAGE].reshape(1, 28, 28, 1))[x]
axarr[1,x].imshow(f2[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
axarr[1,x].grid(False)
f3 = activation_model.predict(test_images[THIRD_IMAGE].reshape(1, 28, 28, 1))[x]
axarr[2,x].imshow(f3[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
axarr[2,x].grid(False)
以下のように、畳敷きの本質を畳み込み、すべての靴に共通する特徴であることがわかります。
8. 練習
演習 1
畳み込みを編集してみてください。畳み込み数を 32 から 16 または 64 に変更します。正確性とトレーニング時間には、どのような影響がありますか。
演習 2
最終畳み込みを削除します。正確性やトレーニング時間には、どのような影響がありますか。
演習 3
畳み込みを追加します。どのような影響がありますか。
演習 4
最初のものを除くすべての畳み込みを削除します。どのような影響がありますか。実際に試してみてください。
9. 完了
最初の CNN を作成しました。コンピュータ ビジョン モデルをさらに強化する方法については、複雑な画像で畳み込みニューラル ネットワーク(CNN)を使用するをご覧ください。