TensorFlow での CNN 画像分類と手順と例
⚡ スマートサマリー
畳み込みニューラルネットワークは、すべてのピクセルに均等な重み付けをするのではなく、小さなフィルタを使って画像をスキャンするため、コンピュータビジョン分野で主流となっています。このチュートリアルでは、各レイヤーについて説明した後、TensorFlowを使用してMNISTの数字を分類します。
畳み込みニューラルネットワークとは何ですか?
畳み込みニューラルネットワーク畳み込みニューラルネットワーク(CNN)は、コンピュータビジョン分野でよく知られた手法です。これは、視覚イメージの分析に使用される深層ニューラルネットワークの一種です。このタイプのアーキテクチャは、画像や動画から物体を認識する際に主流となっています。画像認識、動画認識、自然言語処理、レコメンデーションシステムなどのアプリケーションで使用されています。
Archi畳み込みニューラル ネットワークの構造
数年前の Facebook を思い出してください。プロフィールに写真をアップロードした後、写真上の顔に名前を手動で追加するように求められました。 現在、Facebook は convnet を使用して、写真内の友達を自動的にタグ付けします。
画像分類用の畳み込みニューラル ネットワークを理解するのはそれほど難しくありません。入力画像は畳み込みフェーズで処理され、その後ラベルが付けられます。
典型的な畳み込みニューラルネットワーク(ConvNet)のアーキテクチャは、以下の図にまとめられます。まず、画像がネットワークに入力されます。これを入力画像と呼びます。次に、入力画像は一連の処理ステップを経て、畳み込み層と呼ばれる部分を通過します。最後に、ニューラルネットワークは画像上の数字を予測します。

画像は、高さと幅を持つピクセルの配列で構成されます。グレースケール画像にはチャンネルが1つしかありませんが、カラー画像には3つのチャンネル(赤、緑、青それぞれに1つずつ)があります。チャンネルは互いに重ね合わされています。このチュートリアルでは、チャンネルが1つだけのグレースケール画像を使用します。各ピクセルには、色の濃淡を表す0から255までの値があります。たとえば、値が0のピクセルは白色を表示し、値が255に近いピクセルはより暗くなります。
に保存されている画像を見てみましょう。 MNISTデータセット下の図は、左側の図をマトリックス形式で表現する方法を示しています。元のマトリックスは、0から1の範囲に標準化されていることに注意してください。濃い色のマトリックスの値は約0.9で、白いピクセルの値は0です。
畳み込み演算
このモデルにおいて最も重要な構成要素は畳み込み層です。この部分は、画像のサイズを縮小することで重みの計算速度を向上させ、汎化性能を高めることを目的としています。
畳み込み部分の間、ネットワークは画像の重要な特徴を維持し、無関係なノイズを除外します。 たとえば、モデルは、山を背景にした写真から象を認識する方法を学習しています。 従来のニューラル ネットワークを使用する場合、モデルはすべてのピクセルに重みを割り当てます。これには、必須ではなくネットワークを誤解させる可能性がある山のピクセルも含まれます。
代わりに、 ケラス 畳み込みニューラルネットワークは数学的手法を用いてtrac最も関連性の高いピクセルのみを抽出します。この数学的演算は畳み込みと呼ばれます。この手法により、ネットワークは各層でますます複雑な特徴を学習できます。畳み込みは行列を小さな断片に分割し、各断片内の最も重要な要素を学習します。
畳み込みニューラル ネットワーク (ConvNet または CNN) のコンポーネント
畳み込みニューラルネットワークは4つの構成要素から成り立っています。
- コンボリューション
- 非線形性 (ReLU)
- Poolingまたはサブサンプリング
- 分類 (完全接続層)
コンボリューション
畳み込みの目的は、tracこれは、画像内のオブジェクトの特徴を局所的に学習することを意味します。つまり、ネットワークは画像内の特定のパターンを学習し、画像内のどこでもそれらを認識できるようになります。
畳み込みは要素ごとの乗算です。その概念は理解しやすいものです。コンピュータは通常3×3の寸法で画像の一部をスキャンし、それをフィルタで乗算します。要素ごとの乗算の出力は特徴マップと呼ばれます。この手順は画像全体がスキャンされるまで繰り返されます。畳み込みの後、画像のサイズが縮小されることに注意してください。
下の図は、画像の一部分(パッチ)をフィルタで乗算して、特徴マップの単一セルを生成する様子を示しています。
以下のアニメーションは、同じ畳み込み演算が画像全体に適用される様子を示しています。
利用可能なフィルターは多数あります。以下にその一部を示します。各フィルターにはそれぞれ特定の目的があることがお分かりいただけるでしょう。なお、下の図ではカーネルはフィルターの同義語です。
畳み込みの背後にある演算
畳み込みフェーズでは、画像内の小さなピクセル配列にフィルタが適用されます。フィルタは、入力画像に沿って3×3または5×5の形状で移動します。つまり、ネットワークはこれらのウィンドウを入力画像全体にスライドさせ、畳み込みを計算します。下の動画は、畳み込みの動作を示しています。パッチのサイズは3×3で、出力行列は画像行列とフィルタ間の要素ごとの演算の結果です。
出力の幅と高さが、入力の幅と高さと異なる場合があることがわかります。 それは境界効果によって起こります。
ボーダー効果
画像には5×5の特徴マップと3×3のフィルタが含まれています。フィルタが3×3のグリッドをフィルタリングできるウィンドウは中央に1つだけあります。出力される特徴マップは各軸で2タイルずつ縮小され、3×3のサイズになります。
入力と同じ出力次元を得るには、パディングを追加する必要があります。パディングとは、行列の両側に適切な数の行と列を追加することです。これにより、畳み込み演算がすべての入力タイルを中央に収めることができます。下の図では、入力行列と出力行列は同じ次元の5×5です。
ネットワークを定義するとき、畳み込み特徴は XNUMX つのパラメーターによって制御されます。
深さ: これは、畳み込み処理中に適用するフィルターの数を定義します。前の例では、深さが1と表示されていましたが、これはフィルターが1つだけ使用されることを意味します。ほとんどの場合、フィルターは複数使用されます。以下の動画は、3つのフィルターを使用した場合の処理を示しています。
ストライド: これは、2つのスライス間の「ピクセル単位の移動量」を定義します。ストライドが1の場合、ウィンドウは1ピクセル分移動します。ストライドが2の場合、ウィンドウは2ピクセル分移動します。ストライドを大きくすると、特徴マップは小さくなります。以下の2つの図は、ストライド1とストライド2を比較したものです。
歩幅例1
ストライド2
ゼロパディング: パディングとは、入力特徴マップの両側に、対応する行数と列数を追加する操作です。この場合、出力は入力と同じ次元になります。
非線形性 (ReLU)
畳み込み演算の最後に、出力は非線形性を可能にするために活性化関数によって処理されます。畳み込みニューラルネットワークで一般的に使用される活性化関数はReLUです。負の値を持つすべてのピクセルはゼロに置き換えられます。
Pooling Opera生産
この手順は理解しやすいものです。プーリングの目的は、入力画像の次元を削減することです。これらの手順は、演算の計算量を減らすために行われます。次元を削減することで、ネットワークが計算する重みが少なくなり、過学習を防ぐことができます。
この段階では、サイズとストライドを定義する必要があります。入力画像をプーリングする標準的な方法は、特徴マップの最大値を使用することです。下の図を見てください。プーリングは、4×4 特徴マップの 4 つのサブマトリックスをスクリーニングし、最大値を返します。プーリングは 2×2 配列の最大値を取得し、このウィンドウを 2 ピクセル移動します。たとえば、最初のサブマトリックスは [3,1,3,2] なので、プーリングは最大値である 3 を返します。
平均などの別のプーリング操作もあります。
この操作は、特徴マップのサイズを大幅に縮小します。
完全に接続されたレイヤー
最後のステップでは、従来の 人工ニューラルネットワーク 前のチュートリアルで行ったように。 前の層のすべてのニューロンを次の層に接続します。 ソフトマックス アクティベーション関数を使用して、入力画像上の数値を分類します。
要約:
TensorFlowの畳み込みニューラルネットワークは、予測を行う前にさまざまな層をコンパイルします。ニューラルネットワークには次の要素があります。
- 畳み込み層
- ReLU活性化機能
- Pooling層
- 密に接続された層
畳み込み層は、画像のサブ領域に異なるフィルターを適用します。ReLU活性化関数は非線形性を加え、プーリング層は特徴マップの次元を削減します。
これらのレイヤーはすべてtrac画像から重要な情報を抽出します。最後に、特徴マップをソフトマックス関数を持つ全結合層に入力して予測を行います。
TensorFlow を使用して CNN をトレーニングする
これで畳み込みニューラルネットワークの構成要素がわかったので、 TensorFlow。 CNN 画像分類には MNIST データセットを使用します。
データの準備は前回のチュートリアルと同じです。コードを実行して、CNN のアーキテクチャに直接ジャンプできます。
CNN を使用して画像を分類するには、次の手順に従います。
- ステップ 1: データセットをアップロードする
- ステップ 2: 入力レイヤー
- ステップ 3: 畳み込み層
- ステップ4: Pooling層
- ステップ 5: XNUMX 番目の畳み込み層と Pooling レイヤー
- ステップ6: 緻密な層
- ステップ 7: ロジット層
バージョンノート: 以下のリストは TensorFlow 1.x を対象としています。TensorFlow 2 では、tf.layers 名前空間と tf.estimator.inputs.numpy_input_fn は存在しなくなりました。同等のものは tf.keras.layers.Conv2D、Max です。Pooling2D、Dense、Dropoutをtf.keras.Modelに組み込み、model.fit()で学習させます。各レイヤーの仕組みについては手順を読み、Keras APIにマッピングしてください。
ステップ 1: データセットをアップロードする
MNISTデータセットはscikit-learnから入手できます。ダウンロードして「ダウンロード」フォルダに保存してください。fetch_mldata('MNIST original')でアップロードできます。
バージョンノート: mldata.org は閉鎖され、scikit-learn 0.22 で fetch_mldata() が削除されました。現在のインストールでは、同じ数字を読み込むには、 fetch_openml 代わりに、fetch_openml('mnist_784', version=1)を使用します。パイプラインの残りの部分は変更されていません。
トレーニング/テスト セットを作成する
train_test_split を使用してデータセットを分割する必要があります。
機能を拡張する
最後に、以下のTensorFlow CNNを使用した画像分類の例に示すように、MinMaxScalerを使用して特徴量をスケーリングできます。
import numpy as np import tensorflow as tf from sklearn.datasets import fetch_mldata #Change USERNAME by the username of your machine ## Windows USER mnist = fetch_mldata('C:\\Users\\USERNAME\\Downloads\\MNIST original') ## Mac User mnist = fetch_mldata('/Users/USERNAME/Downloads/MNIST original') print(mnist.data.shape) print(mnist.target.shape) from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42) y_train = y_train.astype(int) y_test = y_test.astype(int) batch_size =len(X_train) print(X_train.shape, y_train.shape,y_test.shape ) ## resclae from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() # Train X_train_scaled = scaler.fit_transform(X_train.astype(np.float64)) # test X_test_scaled = scaler.fit_transform(X_test.astype(np.float64)) feature_columns = [tf.feature_column.numeric_column('x', shape=X_train_scaled.shape[1:])] X_train_scaled.shape[1:]
CNN を定義する
CNNは、従来のニューラルネットワークが学習するグローバルパターンとは異なり、画像の生ピクセルにフィルタを適用して詳細なパターンを学習します。CNNを構築するには、以下を定義する必要があります。
- 畳み込み層:特徴マップにn個のフィルタを適用します。畳み込みの後、ReLU活性化関数を使用してネットワークに非線形性を追加する必要があります。
- Pooling層:畳み込みの次のステップは、特徴マップをダウンサンプリングすることです。目的は、特徴マップの次元を削減して過学習を防ぎ、計算速度を向上させることです。最大プーリングは従来の手法で、特徴マップをサブ領域(通常は2×2サイズ)に分割し、最大値のみを保持します。
- 完全に接続された層: 前の層のすべてのニューロンが次の層に接続されます。CNN は、畳み込み層からの特徴とプーリング層で削減された特徴に従ってラベルを分類します。
CNNアーキテクチャ
- 畳み込み層: 14個の5×5フィルタを適用します(例)tracReLU活性化関数を用いた5×5ピクセルのサブ領域(5×5ピクセルのサブ領域)
- Pooling レイヤー: 2×2 フィルターとストライド 2 で最大プーリングを実行します (プールされた領域が重複しないように指定します)
- 畳み込み層: 36 個の 5×5 フィルターを適用、ReLU 活性化関数付き
- Pooling レイヤー2: 再び、2×2フィルターとストライド2で最大プーリングを実行します。
- 1,764 個のニューロン、ドロップアウト正則化率は 0.4 (トレーニング中に特定の要素がドロップされる確率は 0.4)
- 密層 (ロジッツ層): 10 個のニューロン (数字のターゲット クラス (0 ~ 9) ごとに XNUMX つずつ)。
CNN の作成に使用する重要なモジュールが XNUMX つあります。
- conv2d()。 フィルター数、フィルターカーネルサイズ、パディング、活性化関数を引数として二次元畳み込み層を構築します。
- max_pooling2d()。最大プーリング アルゴリズムを使用して XNUMX 次元プーリング層を構築します。
- 密集()。 非表示のレイヤーとユニットを使用して高密度のレイヤーを構築します
CNNを構築するための関数を定義します。ラップする前に、各構成要素をどのように構築するかを詳しく見ていきましょう。ping すべてを一つの機能にまとめる。
ステップ 2: 入力レイヤー
def cnn_model_fn(features, labels, mode): input_layer = tf.reshape(tensor = features["x"],shape =[-1, 28, 28, 1])
データの形状を使用してテンソルを定義する必要があります。 そのためには、モジュール tf.reshape を使用できます。 このモジュールでは、再形成するテンソルとテンソルの形状を宣言する必要があります。 最初の引数はデータの特徴であり、関数の引数で定義されます。
画像には高さ、幅、チャンネルがあります。MNISTデータセットは28×28サイズのモノクロ画像です。shape引数でバッチサイズを-1に設定することで、features[“x”]の形状になります。利点は、バッチサイズを調整可能なハイパーパラメータにできることです。バッチサイズを7に設定すると、テンソルには5,488個の値(28×28×7)が供給されます。
ステップ 3: 畳み込み層
# first Convolutional Layer conv1 = tf.layers.conv2d( inputs=input_layer, filters=14, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
最初の畳み込み層は、カーネルサイズが5×5でパディングが同じ14個のフィルタで構成されています。パディングが同じとは、出力テンソルと入力テンソルの高さと幅が同じであることを意味します。TensorFlowは、行と列にゼロを追加してサイズを均一にします。
ReLU活性化関数を使用します。出力サイズは[28, 28, 14]になります。
ステップ4: Pooling層
畳み込みの次のステップはプーリング処理です。プーリング処理によってデータの次元が削減されます。max_pooling2dモジュールをサイズ2×2、ストライド2で使用できます。入力には前のレイヤーを使用します。出力サイズは[batch_size, 14, 14, 14]になります。
# first Pooling Layer
pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)
ステップ 5: XNUMX 番目の畳み込み層と Pooling レイヤー
2番目の畳み込み層では36個のフィルタが適用され、出力サイズは[batch_size, 14, 14, 36]となります。プーリング層では、以前と同じ2×2のウィンドウとストライド2を使用するため、各空間軸が半分になり、出力形状は[batch_size, 7, 7, 36]となります。
conv2 = tf.layers.conv2d(
inputs=pool1,
filters=36,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)
ステップ6: 緻密な層
次に、全結合層を定義する必要があります。特徴マップは、全結合層に接続する前に平坦化する必要があります。モジュールreshapeを7×7×36のサイズで使用できます。
密結合層は 1,764 個のニューロンを接続します。ReLU 活性化関数を追加します。さらに、ドロップアウト正則化項を 0.3 の割合で追加します。これは、活性化の 30 パーセントが 0 に設定されることを意味します。ドロップアウトはトレーニング フェーズでのみ発生することに注意してください。関数 cnn_model_fn には、以下の CNN 画像分類 TensorFlow の例に示すように、モデルをトレーニングするか評価するかを宣言する引数 mode があります。
pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 36])
dense = tf.layers.dense(inputs=pool2_flat, units=7 * 7 * 36, activation=tf.nn.relu)
dropout = tf.layers.dropout(
inputs=dense, rate=0.3, training=mode == tf.estimator.ModeKeys.TRAIN)
ステップ 7: ロジット層
最後に、TensorFlowの画像分類の例では、モデルの予測結果を含む最終層を定義できます。出力形状はバッチサイズと、対象クラスの総数である10に等しくなります。
# Logits Layer
logits = tf.layers.dense(inputs=dropout, units=10)
クラスとその各クラスの確率を含む辞書を作成できます。関数 tf.argmax() は、ロジット層で最も高い値のインデックスを返します。softmax 関数は、各クラスの確率を返します。
predictions = {
# Generate predictions
"classes": tf.argmax(input=logits, axis=1),
"probabilities": tf.nn.softmax(logits, name="softmax_tensor") }
モードが「予測」に設定されている場合にのみ、予測辞書を返すようにします。予測結果を表示するには、このコードを追加します。
if mode == tf.estimator.ModeKeys.PREDICT: return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)
次のステップは、モデルの損失を計算することです。前回のチュートリアルでは、多クラスモデルの損失関数は交差エントロピーであることを学びました。損失は、以下のコードで簡単に計算できます。
# Calculate Loss (for both TRAIN and EVAL modes)
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)
TensorFlow CNNの例の最後のステップは、モデルを最適化すること、つまり重みの最適な値を見つけることです。そのためには、学習率0.001の勾配降下法オプティマイザを使用します。目的は損失を最小化することです。
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
train_op = optimizer.minimize(
loss=loss,
global_step=tf.train.get_global_step())
CNNの処理は完了しました。しかし、評価モード中にパフォーマンス指標を表示したいとします。マルチクラスモデルのパフォーマンス指標は精度です。TensorFlowには、ラベルと予測値の2つの引数を取る精度モジュールが用意されています。
eval_metric_ops = {
"accuracy": tf.metrics.accuracy(labels=labels, predictions=predictions["classes"])}
return tf.estimator.EstimatorSpec(mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)
それでおしまい。 最初の CNN を作成しました。モデルのトレーニングと評価に使用するために、すべてを関数にラップする準備が整いました。
def cnn_model_fn(features, labels, mode): """Model function for CNN.""" # Input Layer input_layer = tf.reshape(features["x"], [-1, 28, 28, 1]) # Convolutional Layer conv1 = tf.layers.conv2d( inputs=input_layer, filters=32, kernel_size=[5, 5], padding="same", activation=tf.nn.relu) # Pooling Layer pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2) # Convolutional Layer #2 and Pooling Layer conv2 = tf.layers.conv2d( inputs=pool1, filters=36, kernel_size=[5, 5], padding="same", activation=tf.nn.relu) pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2) # Dense Layer pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 36]) dense = tf.layers.dense(inputs=pool2_flat, units=7 * 7 * 36, activation=tf.nn.relu) dropout = tf.layers.dropout( inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN) # Logits Layer logits = tf.layers.dense(inputs=dropout, units=10) predictions = { # Generate predictions (for PREDICT and EVAL mode) "classes": tf.argmax(input=logits, axis=1), "probabilities": tf.nn.softmax(logits, name="softmax_tensor") } if mode == tf.estimator.ModeKeys.PREDICT: return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions) # Calculate Loss loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits) # Configure the Training Op (for TRAIN mode) if mode == tf.estimator.ModeKeys.TRAIN: optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001) train_op = optimizer.minimize( loss=loss, global_step=tf.train.get_global_step()) return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op) # Add evaluation metrics Evaluation mode eval_metric_ops = { "accuracy": tf.metrics.accuracy( labels=labels, predictions=predictions["classes"])} return tf.estimator.EstimatorSpec( mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)
組み立て後の機能に関する注記: 上記のラップ版では、最初の畳み込み層を32個のフィルターと0.4のドロップアウトに設定していますが、ステップバイステップのコードスニペットでは14個のフィルターと0.3を使用しています。どちらも実行できますが、いずれかの値のペアを選択して一貫性を保つことで、印刷される形状がレイヤーテーブルと一致するようにします。
以下の手順は前のチュートリアルと同じです。
まず、画像分類用の CNN モデルを使用して推定器を定義します。
# Create the Estimator mnist_classifier = tf.estimator.Estimator( model_fn=cnn_model_fn, model_dir="train/mnist_convnet_model")
CNNの学習には時間がかかるため、50回の反復ごとにソフトマックス層の値を保存するログフックを作成します。
# Set up logging for predictions tensors_to_log = {"probabilities": "softmax_tensor"} logging_hook = tf.train.LoggingTensorHook(tensors=tensors_to_log, every_n_iter=50)
モデルの推定準備が整いました。バッチサイズを100に設定し、データをシャッフルします。トレーニングステップ数を16,000に設定しているため、トレーニングにはかなりの時間がかかる場合があります。しばらくお待ちください。
# Train the model train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"x": X_train_scaled}, y=y_train, batch_size=100, num_epochs=None, shuffle=True) mnist_classifier.train( input_fn=train_input_fn, steps=16000, hooks=[logging_hook])
モデルの学習が完了したので、モデルを評価して結果を出力できます。
# Evaluate the model and print results eval_input_fn = tf.estimator.inputs.numpy_input_fn( x={"x": X_test_scaled}, y=y_test, num_epochs=1, shuffle=False) eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn) print(eval_results)
評価結果は、復元されたチェックポイント、停止したステップ、および最終的なメトリクス辞書を出力します。
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-08-05-12:52:41 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train/mnist_convnet_model/model.ckpt-15652 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Finished evaluation at 2018-08-05-12:52:56 INFO:tensorflow:Saving dict for global step 15652: accuracy = 0.9589286, global_step = 15652, loss = 0.13894269 {'accuracy': 0.9689286, 'loss': 0.13894269, 'global_step': 15652}
現在のアーキテクチャでは、評価辞書は精度0.9689286、つまり約97%を報告しています。アーキテクチャ、バッチサイズ、反復回数を変更することで精度を向上させることができます。CNNは、 人工ニューラルネットワーク またはロジスティック回帰:人工ニューラルネットワークのチュートリアルでは、精度は96%でしたが、これはCNNよりも低い値です。CNNは、より大きな画像セットを使用した場合、計算速度と精度の両面で優れた性能を発揮します。











