Pythonでの機械学習による画像認識、畳み込みニューラルネットワーク

出典:アイルランドタイムズ、ポルó muirí

データを前処理した後、画像認識タスクを実行するためのモデルを構築します。 この手法の一つは畳み込みニューラルネットワークを用いたものである。この記事は、私が画像処理に書いた記事に続きます。 画像認識タスクにデータを使用できるようにした後、タスクを実行するアルゴリズムを作成します。 画像を多層パーセプトロンモデルとして認識するために使用される多くの技術の中で,畳み込みニューラルネットワーク(CNN)は非常に効率的なものとして現れる。 この記事では、CNNを構築する方法と、それを画像のデータセットに適用する方法について説明します。

初めて画像認識モデルの構築を開始するときは、通常、比較的単純なデータセットでそれを訓練して評価することをお勧めします。

私たちが実行できる最も簡単なタスクの一つは、手書きの数字認識です。 手書きの数字の画像が与えられた場合(すなわち、, 0, 1, …, 9), モデルがその数値を正しく分類できるようにしたいと考えています。 このタスクは比較的簡単なようですが、実際には、画像からクレジットカード番号を自動的に抽出するなど、実際の生活の中でかなり頻繁に使用され 数字認識に使用するデータセットは、機械学習ベースの数字認識に使用されるデータセットであるMNISTデータセットです。

MNIST(Modified National Institute of Standards and Technology)データベースには、60,000のトレーニング例と10,000のテスト例が含まれています。 データベースには、20×20ピクセルのボックスに収まるようにサイズ変更されたグレースケールの手書きの数字が含まれており、28×28画像の中央に配置され MnistデータベースはPython経由でアクセスできます。この記事では、TensorFlowの高レベルAPIであるkerasを使用してたたみ込みニューラルネットワークをコーディングする方法を紹介します。 この記事ではtensorflow2.0を使用しています。

1-初期化

各グレースケールイメージの寸法は28×28であるため、画像あたり784ピクセルがあります。 したがって、各入力イメージは、0.0~1.0の間の784個の正規化された浮動小数点値のテンソルに対応します。 画像のラベルは、10個のクラス(各クラスは数字を表します)を持つワンホットテンソルです。 私たちのコードの面では、img_rows=28、img_cols=28、num_classes=10があります。 したがって、入力は形状(number_examples、img_rows、img_cols)を持つため、60000x28x28になります。
コンピュータが乱数列を生成するときに開始点を維持したいので、セットアップするもう一つの重要な要素は、ランダムシードです。

MNISTデータセットもインポートします。前のセクションで説明したように、入力は形状(number_examples、img_rows、img_cols)を持ちます。 しかし、畳み込みニューラルネットワークでデータを使用するには、それをNHWC形式にする必要があります。

NHWC形式は、四つの次元を持つ形状を持っています:

  1. 画像データサンプル数(バッチサイズ)
  2. 各画像の高さ
  3. 各画像の幅
  4. 画像ごとのチャンネル

データセットからの各画像の高さと幅はimg_rows

また、各ピクセルには0と255の間の整数で定量化されたグレースケール値が含まれています。 したがって、データベースは0.0と1.0の間の浮動小数点値を持つように正規化されます。 この場合、0.0は255(純白)のグレースケールピクセル値に対応し、1に相当します。0は、グレースケールピクセル値0(純粋な黒)に対応します。

X_train = X_train.reshape(X_train.shape, img_rows, img_cols, 1) 
X_test = X_test.reshape(X_test.shape, img_rows, img_cols, 1)input_shape = (img_rows, img_cols, 1)# cast floats to single precision
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')# rescale data in interval
X_train /= 255
X_test /= 255

3-ラベルベクトルYをキャスト

クラスをベクトルに変換する必要があります。 これを行うには、次の行をタップします。

Y_train = keras.utils.to_categorical(Y_train, num_classes)
Y_test = keras.utils.to_categorical(Y_test, num_classes)

このステップのより良い説明をするには、この記事を参照する必要があります。

データを処理したので、モデルの構築を開始できます。

畳み込みニューラルネットワークモデル

私が画像処理に書いた記事の最後に述べたように、フィルタは画像認識に大きな役割を果たします。 フィルタを使用して入力を変換し、モデルが特定の画像を認識できるようにする特徴を抽出します。 これの非常に高レベルの例は、曲線検出フィルタであり、このモデルは曲線を持つ数字と曲線を持たない数字を区別することを可能にする。

1-Filters

すべてのニューラルネットワークの重みと同様に、フィルタの重みは学習可能な変数です。 最も有用な隠れた特徴を抽出できるフィルタを生成するために、(カーネル行列の重みを介して)ニューラルネットワークを訓練します。

入力データに複数のチャネルがある場合、フィルタはチャネルごとに別々のカーネル行列を持ちます。 MNISTデータセットには1つのチャネルしかありませんが、他のタイプの画像データ(RGBなど)では、各チャネルのカーネル行列の最適な重みを得るためにモデ

2-畳み込み

畳み込みニューラルネットワークの焦点に達しました。 畳み込みは、入力データにフィルターの重みをどのように適用するかを表します。 畳み込みによって使用される主な演算は、行列の内積、すなわち2つの行列の要素ごとの積の合計です。み込みにおける行列内積の次元は、入力データとカーネル行列の次元、およびストライドサイズに依存します。 ストライドサイズは、入力データに沿って移動するカーネル行列の垂直/水平オフセットです。

3-Padding

時には、前に見たように内積演算を行うとき、行または列を使用しないことがあります。 この現象を避けるために、パディングを使用できます。

したがって、畳み込みですべての入力データを使用する場合は、入力データ行列に0を埋め込むことができます。 0を任意の数で乗算すると0になるため、パディングは行列の内積には影響しません。 畳み込みに歪みを追加したくないので、これは重要です。

4畳み込み層

CNNの畳み込み層は、入力テンソルに複数のフィルタを適用します。 各フィルターには入力チャンネルごとに個別のカーネル行列がありますが、フィルターの畳み込みの全体的な結果は、すべての入力チャンネルの畳み込みの和になります。

畳み込みレイヤーにフィルターを追加すると、レイヤーは非表示のフィーチャをより適切に抽出できます。 しかし、これは、フィルターがモデルに余分な重みを追加するため、追加のトレーニング時間と計算の複雑さを犠牲にして発生します。 出力データのチャンネル数は、畳み込みレイヤーが使用するフィルターの数と同じです。

Pooling

畳み込みレイヤーは重要な非表示フィーチャを抽出しますが、フィーチャの数はまだかなり大きくなる可能性があります。 プールを使用して、高さと幅の次元でデータのサイズを小さくすることができます。 これにより、モデルはより少ない計算を実行し、最終的にはより高速に学習することができます。 また、最も顕著な特徴のみを抽出し、いくつかの例で見つかった潜在的な歪みや珍しい特徴を無視することによって、過剰適合を防止します。p>

プーリングはどのように機能しますか?

畳み込みと同様に、プーリングにフィルタ行列を使用します。 ただし、プーリングフィルターには重みがなく、行列内積も実行されません。 代わりに、入力データのサブセクションにリダクション操作が適用されます。Cnnで通常使用されるプーリングのタイプは、最大プーリングと呼ばれます。

Max poolingのフィルターは、max演算を使用して、入力データの各部分行列の最大数を取得します。

複数の層

1-余分な層を追加する

すべてのニューラルネットワークと同様に、Cnnは追加の層の恩恵を受けることができます。 追加の層は、CNNが、画像データ上で使用するために、本質的に複数のフィルタを一緒に積み重ねることを可能にする。 しかし、ニューラルネットワークを構築するのと同様に、追加するレイヤーの数に注意する必要があります。 モデルに多すぎるレイヤーを追加すると、トレーニングデータに過度に適合し、一般化が非常に不十分になるリスクがあります。 さらに、各追加の層は計算の複雑さを追加し、モデルのトレーニング時間を増加させます。

2-フィルターの増加

通常、畳み込み層のフィルターの数は、モデルの中で深くなるほど増加します。 この場合、第二の畳み込み層には64個のフィルタがあり、第一の畳み込み層の32個のフィルタと比較しています。 畳み込み層が深ければ深いほど、抽出されたフィーチャはより詳細になります。 例えば、第1の畳み込み層は、線、エッジ、および曲線などの特徴を抽出するフィルタを有してもよい。 第二のレベルに到達すると、畳み込み層のフィルタは、77の鋭い角度や88の交差する曲線など、より際立った特徴を抽出することができます。

Fully-connected layer

1-Fully-connected layer

サイズ1024のfully-connected layer(レイヤー内のニューロンの数)を第二のプーリングレイヤーの出力データに適用します。 ユニットの数はやや任意です。 強力であるには十分ですが、あまりにもリソース集約的であるほどではありません。 完全に接続されたレイヤーの目的は、データフィーチャをクラスに変換する前にデータフィーチャを集約することです。 これにより、プール出力を直接クラスに変換した場合よりも、モデルがより良い予測を行うことができます。

2-平坦化

私たちのモデルで使用しているデータはNHWC形式です。 ただし、完全に接続されたレイヤーを使用するには、行の数がバッチサイズを表し、列がデータフィーチャを表す行列であるデータが必要です。 今回は反対方向に形状を変更し、NHWCから2次元行列に変換する必要があります。

ドロップアウト

1-Co-adaptation

Co-adaptationは、レイヤー内の複数のニューロンが入力データから同じ、または非常に類似した隠された特徴を抽出するとき これは、二つの異なるニューロンの接続重みがほぼ同一である場合に発生する可能性があります。

完全に接続された層に多数のニューロンがある場合、共適応が起こる可能性が高くなります。 これは2つの理由で問題になる可能性があります。 まず、同じ出力を計算する冗長なニューロンがある場合、それは計算の無駄です。 第二に、多くのニューロンが同じ特徴を抽出している場合、それは私たちのモデルのためにそれらの特徴に多くの重要性を追加します。 これは、重複した抽出された特徴がトレーニングセットのみに固有のものである場合に過剰適合につながります。

2-ドロップアウト

私たちは、多くのニューロンと完全に接続された層のための共適応を最小限に抑える方法は、トレーニング中にドロップアウ ドロップアウトでは、ニューロンの値をゼロにすることによって、各トレーニングステップで層のニューロンの一部をランダムにシャッ

ソフトマックス層

MNIST画像には10個の可能な桁があるので、10個のニューロン完全接続層を使用して各桁クラスのクラスを取得します。 関数Softmaxはクラスに適用され、クラスごとの確率に変換されます。

モデルの構築

これで、モデルの構築の準備が整いました。 ここにコードがあります:

from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten
from keras.layers import MaxPooling2D, Dropoutmodel = Sequential()#add model layers
model.add(Conv2D(32, kernel_size=(5, 5),
activation='relu',
input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))# add second convolutional layer with 20 filters
model.add(Conv2D(64, (5, 5), activation='relu'))
# add 2D pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))
# flatten data
model.add(Flatten())
# add a dense all-to-all relu layer
model.add(Dense(1024, activation='relu'))
# apply dropout with rate 0.5
model.add(Dropout(0.5))
# soft-max layer
model.add(Dense(num_classes, activation='softmax'))

使用するモデルタイプはシーケンシャルです。 Sequentialは、Kerasでモデルを構築する最も簡単な方法です。 それはあなたが層ごとにモデル層を構築することができます。

モデルにレイヤーをアタッチするには、add()メソッドを使用します。 入門例の目的のために、簡潔にするために密な層に焦点を当てるだけで十分です。 すべてのDense()層は、最初に必要な引数として、ニューロンの数を指定する整数を受け入れます。 レイヤーのアクティブ化関数のタイプは、アクティブ化オプションの引数を使用して定義され、その入力は文字列形式のアクティブ化関数の名前です。 例としては、relu、tanh、elu、sigmoid、softmaxが挙げられる。

このニューラルネットワークでは、毎回2つの畳み込み層に続いてプーリング層があります。 次に、データをフラット化して、0.5のレートでドロップアウトを適用する高密度レイヤーを追加します。 最後に、正しいクラスで各画像を割り当てるために密なレイヤーを追加します。

モデルのコンパイル

次に、モデルをコンパイルする必要があります。 モデルのコンパイルには、オプティマイザ、損失、メトリクスの三つのパラメータが必要です。

オプティマイザは学習率を制御します。 私たちはオプティマイザとして’adam’を使用します。 Adamは、一般的に、多くの場合に使用するのに適したオプティマイザです。 Adamオプティマイザは、トレーニング全体で学習率を調整します。学習率は、モデルの最適な重みの計算速度を決定します。

学習率は、モデルの最適な重みの計算速度を決定します。 学習率を小さくすると、より正確な重み(特定のポイントまで)につながる可能性がありますが、サイズの縮小は計算時間です。

損失関数には’categorical_crossentropy’を使用します。 これは分類のための最も一般的な選択です。 スコアが低い場合は、モデルのパフォーマンスが向上していることを示します。

解釈をさらに簡単にするために、モデルをトレーニングするときに検証セットの精度スコアを確認するために’精度’メトリックを使用します。

#compile model using accuracy to measure model performance
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=)

モデルのトレーニング

今、私たちは私たちのモデルを訓練します。 トレーニングするには、トレーニングデータ(X_Train)、ターゲットデータ(Y_Train)、検証データ、エポック数のパラメータを使用して、モデル上で’fit()’関数を使用します。

検証データには、データセットで提供されたテストセットを使用します。X_TestとY_Testに分割しました。

エポックの数は、モデルがデータを循環させる回数です。 私たちが実行するエポックが多ければ多いほど、モデルは特定のポイントまで改善されます。 その時点以降、モデルは各エポックの間に改善を停止します。 このモデルでは、エポックの数を3に設定します。P>

#train the model
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=3)

モデルを評価する

今、私たちは、そのパフォーマンスを評価することができます私たちのモデルを訓練している:

# evaluate the model
score = model.evaluate(X_test, Y_test, verbose=1)
# print performance
print()
print('Test loss:', score)
print('Test accuracy:', score)

したがって、テストセットでは99,3%の精度と0.025の損失があり、非常に優れています。 エポックの数を増やし、バッチサイズを導入することで、モデルを改善することができます。モデルがテストデータに対して行った実際の予測を確認したい場合は、predict_classes関数を使用できます。 これには、predict関数を使用して10個の数値を持つ配列を与えることもできます。 これらの数値は、入力イメージが各桁(0-9)を表す確率です。 最も高い数値を持つ配列インデックスは、モデル予測を表します。 各配列の合計は1に等しくなります(各数値は確率であるため)。これを表示するには、テストセット内の最初の4つの画像の予測を表示します。

これを表示するには、テストセット内の最初の4つの画像の予注:新しいデータがある場合は、新しいデータをpredict関数に入力して、モデルが新しいデータで行う予測を確認できます。 新しい目に見えないデータはないので、今のところテストセットを使用して予測を表示します。

#predict first 4 images in the test set
model.predict_classes(X_test)

#predict first 4 images in the test set
model.predict(X_test)

We can see that our model predicted 7, 2, 1 and 0 for the first four images.

Let’s compare this with the actual results.div>

実際の結果は、最初の四つの画像も7、2,1、0であることを示しています。 私たちのモデルは正しく予測しました!

モデル全体

import tensorflow as tf # tensorflow 2.0
from keras.datasets import mnist
import numpy as np
seed=0
np.random.seed(seed) # fix random seed
tf.random.set_seed(seed)
# input image dimensions
num_classes = 10 # 10 digitsimg_rows, img_cols = 28, 28 # number of pixels# the data, shuffled and split between train and test sets
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()X_train = X_train.reshape(X_train.shape, img_rows, img_cols, 1)
X_test = X_test.reshape(X_test.shape, img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)# cast floats to single precision
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')# rescale data in interval
X_train /= 255
X_test /= 255Y_train = keras.utils.to_categorical(Y_train, num_classes)
Y_test = keras.utils.to_categorical(Y_test, num_classes)from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten
from keras.layers import MaxPooling2D, Dropout
model = Sequential()#add model layers
model.add(Conv2D(32, kernel_size=(5, 5),
activation='relu',
input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
# add second convolutional layer with 20 filters
model.add(Conv2D(64, (5, 5), activation='relu'))
# add 2D pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))
# flatten data
model.add(Flatten())
# add a dense all-to-all relu layer
model.add(Dense(1024, activation='relu'))
# apply dropout with rate 0.5
model.add(Dropout(0.5))
# soft-max layer
model.add(Dense(num_classes, activation='softmax'))#compile model using accuracy to measure model performance
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=)#train the model
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=3)# evaluate the model
score = model.evaluate(X_test, Y_test, verbose=1)# print performance
print()
print('Test loss:', score)
print('Test accuracy:', score)#predict first 4 images in the test set
model.predict(X_test)model.predict_classes(X_test)#actual results for first 4 images in test set
Y_test

続きを読む…

この記事では、畳み込みニューラルネットワークを構築している画像認識の第二部に取り組私はあなたがこの記事のためにここに来たものを見つけて、この画像認識旅行の次のエピソードのために私と一緒に滞在することを願っています!

PS:私は現在、バークレーの工学の学生のマスターです、あなたがトピックを議論したい場合は、私に連絡して自由に感じます。 ここに私の電子メールがあります。

コメントを残す

メールアドレスが公開されることはありません。