画像データ拡張とは何か、および深層学習プロジェクトで Keras を使用してそれを使用する方法を理解する
深層学習を使用して画像認識を実行したことがある場合は、トレーニングのための優れたデータセットの重要性をご存知でしょう。 ただし、トレーニングに十分な画像を見つけることは必ずしも容易ではなく、モデルの精度はトレーニング データの品質に直接依存します。
幸いなことに、トレーニングに使用する画像データセットを補足するために使用できる手法があります。 テクニックのXNUMXつと呼ばれる 画像データ増強. この記事では、画像データ拡張とは何か、その仕組み、深層学習で役立つ理由、最後に Keras ライブラリを使用して画像データ拡張を実行する方法について説明します。
画像データの拡張 というテクニックです 既存のイメージから新しいイメージを作成する. そのためには、画像の明るさを調整したり、画像を回転させたり、画像内の被写体を水平または垂直に移動したりするなど、いくつかの小さな変更を加えます。
画像拡張技術を使用すると、トレーニング セットのサイズを人為的に増やすことができるため、トレーニング用のモデルにより多くのデータを提供できます。 これにより、モデルがトレーニング データの新しいバリアントを認識する機能が強化され、モデルの精度が向上します。
画像データ拡張の種類
画像拡張にはさまざまな形式がありますが、一般的なもののいくつかを次に示します — 垂直シフト、水平シフト、垂直フリップ、水平フリップ、回転、明るさ調整、ズームイン/アウト.
最初に、Python と Keras を使用したさまざまな画像拡張手法を示します。 試してみたい場合は、次のソフトウェアとパッケージがインストールされていることを確認してください。
Anaconda と TensorFlow がインストールされたら、新しい Jupyter Notebook を作成します。
垂直シフト
最初に紹介したい画像拡張技術は、 垂直シフトを選択します。 垂直シフト 画像を上下にランダムにシフトします。 この例では、という名前の画像を使用します 747.jpg、Jupyter Notebook と同じフォルダーにあります。
次のコード スニペットでは、 ImageDataGenerator
画像を垂直方向にシフトする Keras のクラス。
ImageDataGenerator
Keras のクラスは、リアルタイムのデータ拡張を使用して画像データのバッチを生成します。
#---モジュールをインポートする---
npとしてnumpyをインポートする
matplotlib.pyplotをpltとしてインポートするtensorflow.keras.preprocessing.image import load_img から
tensorflow.keras.preprocessing.image import img_to_array から
tensorflow.keras.preprocessing.image import ImageDataGenerator から#---画像を読み込む---
image_filename = '747.jpg'
img = load_img(画像ファイル名)#---画像を3D配列に変換---
image_data = img_to_array(img)#--- を表す 4D 配列の 1 つの要素の 3-D 配列に変換する
# 画像 - -
画像データ = np.expand_dims(画像データ, axis=0)#---画像データ拡張ジェネレーターを作成する---
datagen = ImageDataGenerator(width_shift_range=0.2)#--- イテレータを準備します。 flow() は 4D 配列を受け取って返します
# 画像のバッチを含むイテレータ ---
train_generator = datagen.flow(画像データ、バッチサイズ=1)行= 5
列 = 4#---5 行 4 列をプロット ---
図、軸 = plt.subplots(rows,columns)範囲内の r (行):
範囲内の c の場合 (列):
#--- バッチ内の次の画像を取得 (バッチ以降の XNUMX つの画像)
# サイズは 1)---
image_batch = train_generator.next()#---表示用に符号なし整数に変換---
#---画像を表示---
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)#---図形の大きさを設定する---
fig.set_size_inches(15,10)
上記のコード スニペットは、次の出力を生成します。
上記の出力からわかるように、呼び出すたびに next()
からのメソッド train_generator
わずかに変更された画像が得られます。 上記のコード スニペットでは、元の画像の高さに基づいて 20% シフトされた新しい画像が返されます。 next()
方法:
datagen = ImageDataGenerator(width_shift_range=0.2)
興味深いことに、このバージョンの
ImageDataGenerator
(tensorflow.keras.preprocessing.image
) クラス、指定width_shift_range
パラメータは、イメージを水平方向ではなく垂直方向にシフトします (これは、古いバージョンの動作です)。ImageDataGenerator
keras.preprocessing.image
モジュール)。 同様に、画像を水平方向にシフトしたい場合は、height_shift_range
パラメータ (次のセクションを参照)。
なお、 next()
メソッドは、拡張された画像を必要な回数だけ返します。 上記のコード スニペットでは、20 回呼び出しました (5 行 x 4 列)。
水平シフト
を使用して画像を水平方向にシフトすることができます。 height_shift_range
パラメータ を使用します。
datagen = ImageDataGenerator(高さのシフト範囲=0.2)
train_generator = datagen.flow(画像データ、バッチサイズ=1)行= 5
列 = 4図、軸 = plt.subplots(rows,columns)
範囲内の r (行):
範囲内の c の場合 (列):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)fig.set_size_inches(15,10)
上記のコード スニペットは、次の出力を生成します。
水平反転
場合によっては、画像を水平方向に反転することが理にかなっていることがあります。 飛行機の場合、飛行機の正面は左または右を向いている場合があります。
datagen = ImageDataGenerator(horizontal_flip=True)
train_generator = datagen.flow(画像データ、バッチサイズ=1)行= 2
列 = 2図、軸 = plt.subplots(rows,columns)
範囲内の r (行):
範囲内の c の場合 (列):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)fig.set_size_inches(15,10)
上記のコード スニペットでは、飛行機の前面が左または右を向いている可能性があるため、XNUMX つの画像を生成するだけで十分です。
反転はランダムであることに注意してください (元の XNUMX つの画像すべてが取得される場合もあれば、水平方向に反転された画像が取得される場合もあります)。 上記の XNUMX つの画像はすべて同じである可能性があります。 その場合は、そのコード ブロックをもう一度実行してください。
垂直フリップ
水平方向の反転と同様に、垂直方向の反転も実行できます。
datagen = ImageDataGenerator(垂直_フリップ=真)
train_generator = datagen.flow(画像データ、バッチサイズ=1)行= 2
列 = 2図、軸 = plt.subplots(rows,columns)
範囲内の r (行):
範囲内の c の場合 (列):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)fig.set_size_inches(15,10)
飛行機の場合、飛行機をひっくり返すのはあまり意味がないかもしれません! 画像認識を実行しようとしている場合、平面の画像は直立している可能性が高いため、逆さまの平面を認識するようにモデルをトレーニングすることはあまり一般的ではない可能性があります。 他の場合では、垂直方向の反転は非常に理にかなっています。
回転
回転は、名前が示すように、画像を回転させます。 これは、飛行機の画像に非常に役立ちます。 次のコード スニペットは、画像を 50 度までランダムに回転させます。
datagen = ImageDataGenerator(回転範囲=50)
train_generator = datagen.flow(images_data)行= 5
列 = 4図、軸 = plt.subplots(rows,columns)
範囲内の r (行):
範囲内の c の場合 (列):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)fig.set_size_inches(15,10)
回転すると、出力は飛行機がさまざまな位置にあることを示します — 離陸位置と着陸位置をシミュレートします。
輝度
もう XNUMX つの拡張技術は、画像の明るさを調整することです。 次のコード スニペットは、輝度シフト値の範囲を設定します。
datagen = ImageDataGenerator(明るさの範囲=[0.15,2.0])
train_generator = datagen.flow(画像データ、バッチサイズ=1)行= 5
列 = 4図、軸 = plt.subplots(rows,columns)
範囲内の r (行):
範囲内の c の場合 (列):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)fig.set_size_inches(15,10)
出力には、さまざまな明るさの一連の画像が含まれます。
ズーム
画像をズームインまたはズームアウトすることもできます。
datagen = ImageDataGenerator(ズーム範囲=[5,0.5])
train_generator = datagen.flow(画像データ、バッチサイズ=1)行= 5
列 = 4図、軸 = plt.subplots(rows,columns)
範囲内の r (行):
範囲内の c の場合 (列):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)fig.set_size_inches(15,10)
出力は、さまざまなズーム比で画像を示しています。
画像をズームすると、画像の縦横比が変わることに注意してください。
すべての拡張機能を組み合わせる
もちろん、これまで説明してきたさまざまな拡張技術はすべて組み合わせることができます。
datagen = ImageDataGenerator(width_shift_range=0.2、
高さシフト範囲=0.2、
horizontal_flip=真、
回転範囲=50、
明るさの範囲=[0.15,2.0],
ズーム範囲=[5,0.5])train_generator = datagen.flow(画像データ、バッチサイズ=1)行= 8
列 = 8図、軸 = plt.subplots(rows,columns)
範囲内の r (行):
範囲内の c の場合 (列):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
軸[r、c].imshow(画像)fig.set_size_inches(15,10)
この例では意味をなさないため、垂直方向の反転を省略していることに注意してください。
出力には、さまざまな拡張が適用された画像が表示されます。
前のセクションでは、画像データ拡張の基本と、それを単一の画像に適用する方法を示しました。 深層学習では、一連の画像を扱うことがよくあります。 それでは、一連の画像に画像拡張を適用する方法を見てみましょう。 説明のために、Jupyter Notebook を含むフォルダーに、 果物 フォルダと次のサブフォルダ:
果物
|__バナナ
|__バナナ1.jpg
|__バナナ2.jpg
|__バナナ3.jpg
|__ ...
|__ドリアン
|__ドリアン1.jpg
|__ドリアン2.jpg
|__ドリアン3.jpg
|__ ...
|__オレンジ
|__オレンジ1.jpg
|__オレンジ2.jpg
|__オレンジ3.jpg
|__ ...
|__いちご
|__strawberry1.jpg
|__strawberry2.jpg
|__strawberry3.jpg
|__ ...
各サブフォルダーには、一連の画像が含まれています。 たとえば、 banana フォルダーには、名前の付いた多数の画像が含まれています バナナ1.jpg, バナナ2.jpg、 等々。 サブフォルダーの名前は、さまざまな画像のラベルとして機能します。 これは、 banana フォルダーには、バナナの画像などが含まれています。
ディスクから一連の画像をロードするには、 flow_from_directory()
の方法 ImageDataGenerator
インスタンスの代わりに flow()
メソッド(メモリから画像をロードするため):
train_datagen = ImageDataGenerator(
horizontal_flip=真、
vertical_flip=真、
回転範囲=50、
)バッチサイズ = 8train_generator = train_datagen.flow_from_directory(
'./フルーツ',
target_size =(224,224)、
color_mode='rgb',
batch_size = batch_size、
class_mode='カテゴリー',
シャッフル=真)
私が今設定していることを観察してください
batch_size
バッチ サイズの使用方法については、すぐに説明します。
返された反復子を使用して、さまざまな果物 (バナナ、ドリアン、オレンジ、イチゴ) のラベルを見つけることができます。
class_dictionary = train_generator.class_indices#---ラベルの辞書を作成---
class_dictionary = { 値:キーのキー、値の
class_dictionary.items()}#---辞書をリストに変換---
class_list = [_ の値、class_dictionary.items() の値]
印刷 (class_list)
次の出力が表示されます。
54 つのクラスに属する 4 枚の画像が見つかりました。
['バナナ'、'ドリアン'、'オレンジ'、'いちご']
全部で、54 つのフォルダーに合計 4 枚の画像があります。 また、 class_list
変数には果物のリストが含まれています。
によって作成された拡張画像のセットを印刷します。 ImageDataGenerator
クラス。 行を任意に 10 に設定し、各行について、返された画像のバッチを印刷したいと考えています (この例では 8 です)。
行= 10図、軸 = plt.subplots(rows,batch_size)範囲内の r (行):
#---拡張画像のバッチを取得---
image_batch = train_generator.next() #---返された画像の数を取得---
画像数 = 画像バッチ[0].形状[0]範囲内の c の場合 (images_count):
#---表示用に符号なし整数に変換---
image = image_batch[0][c].astype('uint8')#---画像を表示する---
#---画像のラベルを表示---
軸[r、c].imshow(画像)
軸[r、c].title.set_text(
class_list[np.argmax(image_batch[1][c])]) #---x と y の目盛りを隠す---
軸[r、c].set_xticks([])
軸[r、c].set_yticks([])fig.set_size_inches(15,18)
から batch_size
は現在 8 に設定されています (1 ではなくなりました)。 train_generator.next()
メソッドはあなたに バッチ 呼び出すたびに XNUMX つの拡張画像が表示されます。 返される画像の数は、 batch_size
以前に設定した flow_from_directory()
方法:
train_generator = train_datagen.flow_from_directory(
'./フルーツ',
target_size =(224,224)、
color_mode='rgb',
batch_size = batch_size、 # バッチサイズ = 8
class_mode='カテゴリー',
シャッフル=真)
の値 image_batch
変数 (によって返されます next()
method) は XNUMX つの要素のタプルです。
- 最初の要素 (
image_batch[0]
) の配列です。 バッチサイズ 画像 (4D 配列) - XNUMX 番目の要素 (
image_batch[1]
) 画像のラベルが含まれています
上記のコード スニペットは、次の出力を生成します。
54 行目には、画像のない空のグラフが 8 つあることに注意してください。 画像セットには合計 54 個の画像があることを思い出してください。各バッチは (8 行あたり) 6 個の画像を返すため、最初の 6 行には合計 XNUMX 個の画像 (XNUMX×XNUMX + XNUMX) が表示されます。 次の図はそれを明確にしています。
設定できることに注意してください
rows
任意の数にImageDataGenerator
クラスは、新しい拡張画像を生成し続けます。
転移学習を使用したモデルの構築
これで、 ImageDataGenerator
拡張のためにディスクから画像のセットをロードします。 しかし、それをどのようにトレーニングに使用しますか? 次のコード スニペットは、以下を使用してディープ ラーニング モデルを構築する方法を示しています。 転移学習.
転移学習は、タスク用に開発されたモデルを XNUMX 番目のタスクのモデルの開始点として再利用する機械学習手法です。 転移学習により、トレーニングに費やす必要のある時間が短縮されます。
tensorflow.keras.modelsインポートモデルから
tensorflow.keras.applications インポート VGG16 から
tensorflow.keras.layers から Dense、GlobalAveragePooling2D をインポート#---実数---
NO_CLASSES = max(train_generator.class_indices.values()) + 1#---VGG16 モデルをトレーニングのベース モデルとしてロードします---
Base_model = VGG16(include_top=False、input_shape=(224, 224, 3))#---独自のレイヤーを追加---
x = ベースモデル.出力
x = GlobalAveragePooling2D()(x)
x = Dense(1024,activation='relu')(x) # 密層を追加するので
# モデルができること
# もっと複雑に学ぶ
# 関数と
# より良い分類
# 結果。
x = Dense(1024,activation='relu')(x) # 密層 2
x = Dense(512,activation='relu')(x) # 密層 3preds = 高密度(NO_CLASSES,
activation='softmax')(x) # 最終レイヤー
# ソフトマックス活性化#--- ベース モデルのオリジナルで新しいモデルを作成する
# 入力と新しいモデルの出力---
モデル = モデル (入力 = base_model.input、出力 = preds)#---最初の 19 層をトレーニングしない - 0..18---
model.layers[:19] のレイヤーの場合:
Layer.trainable=False#---残りの層を訓練する - 19以降---
model.layers[19:] のレイヤーの場合:
layer.trainable=True#---モデルをコンパイルします---
model.compile(optimizer='Adam',
loss='categorical_crossentropy',
metrics = ['精度'])
転移学習がどのように機能するかを説明することは、この記事の範囲を超えています。 別記事に譲ります。
生成された画像をトレーニングに使用する
拡張された画像をトレーニングに使用するには、 train_generator
に fit()
モデルの方法:
#---モデルのトレーニング---
step_size_train = train_generator.n // train_generator.batch_sizeモデル.フィット(トレインジェネレータ,
epoch ごとのステップ数=step_size_train、
エポック=15)
steps_per_epoch
パラメーターは基本的に、エポックにいくつのステップがあるかを意味します。これは、持っている画像の数と、以前に定義されたバッチサイズに依存します。 これを高い数値に設定すると、反復トレーニングが行われます。 次の式に基づいて設定する必要があります。
画像数 / バッチサイズ
この例では、合計 54 枚の画像があります。 そして、各時代において、 ImageDataGenerator
クラスは、トレーニング用に 54 個の画像すべてを変換します。 各エポックで、モデルはさまざまなバリエーションの画像を取得します。 エポックが 15 の場合、合計で 15×54 の画像のバリエーションが生成され、トレーニング モデルに入力されます。
ImageDataGenerator
クラスを使用すると、モデルは各エポックで画像の新しいバリエーションを受け取ることができます。 ただし、変換された画像を返すだけで、持っている画像のセットには追加しないことに注意してください。
この記事で、画像データ拡張とは何か、またディープ ラーニング モデルのトレーニングで画像データ拡張が必要な理由を理解していただければ幸いです。 特に、TensorFlow ライブラリの Keras モジュールを使用してデモを行いました。
ソースから再公開された深層学習のための画像データ増強
<!–
–>