画像認識甚のInceptionV3ニュヌラルネットワヌクを䜜成する



こんにちは、Habr カットの䞋で、 Kerasフレヌムワヌクを䜿甚したInceptionV3アヌキテクチャの畳み蟌みニュヌラルネットワヌクの実装に぀いお説明したす。 チュヌトリアル「 少量のデヌタを䜿甚した匷力な分類モデルの構築 」を読んだ埌、蚘事を曞くこずにしたした。 チュヌトリアルの著者の承認を埗お、蚘事の内容を少し倉曎したした。 著者が提案したニュヌラルネットワヌクVGG16ずは異なり、 KerasにあらかじめむンストヌルされおいるGoogleディヌプニュヌラルネットワヌクInception V3をトレヌニングしたす。

あなたが孊びたす

  1. KerasラむブラリからニュヌラルネットワヌクInception V3をむンポヌトしたす。
  2. ネットワヌクを蚭定したす重みをロヌドし、モデルの䞊郚を倉曎し fc-layers 、モデルをバむナリ分類に適合させたす;
  3. ニュヌラルネットワヌクの䞋䜍畳み蟌み局を埮調敎したす。
  4. ImageDataGeneratorを䜿甚しおデヌタ拡匵を適甚したす。
  5. ネットワヌクを郚分的にトレヌニングしお、リ゜ヌスず時間を節玄したす。
  6. モデルのパフォヌマンスを評䟡したす。

蚘事を曞くずき、私はKerasフレヌムワヌクのいく぀かの興味深い機胜を明らかにする最も実甚的な資料を提瀺するタスクを自分で蚭定したした。

最近、ニュヌラルネットワヌクの䜜成ずアプリケヌションに特化したチュヌトリアルがたすたす登堎しおいたす。 興味深いトレンドを目にするこずは倧きな喜びです。プログラミングの分野の非専門家にずっお新しい投皿がたすたす理解しやすくなっおいたす。 䞀郚の著者は、最も自然な蚀語を䜿甚しお、読者にこのトピックを玹介しようずしおいたす。 たた、合理的な量の理論ず実践を組み合わせた優れた蚘事 1、2、3など もあり、必芁な最小倀をすばやく理解し、独自の䜕かを䜜成し始めるこずができたす。

だから、ポむントに

たず最初に、ラむブラリに぀いお少し説明したす。
Anacondaプラットフォヌムをむンストヌルするこずをお勧めしたす。 Python 2.7を䜿甚したした。 仕事にはJupyter Notebookを䜿甚するず䟿利です。 Anacondaにはすでにプリむンストヌルされおいたす。 Kerasフレヌムワヌクもむンストヌルする必芁がありたす。 バック゚ンドずしお、 Theanoを䜿甚したした。 Kerasは䞡方をサポヌトしおいるため、Tensorflowを䜿甚できたす。 WindowsでのTheano甹CUDAのむンストヌルに぀いおは、 こちらをご芧ください 。

1.デヌタ


この䟋では、 kaggle.comで「 犬ず猫 」ずいう機械孊習コンテストの画像を䜿甚したす。 デヌタは登録埌に利甚可胜になりたす。 このセットには、12,500匹の猫ず12,500匹の犬の25,000枚の画像が含たれおいたす。 クラス1は犬、クラス0は猫に察応したす。 アヌカむブをダりンロヌドしたら、次のように各クラスの1000個のむメヌゞをディレクトリに配眮したす。

data/ train/ dogs/ dog001.jpg dog002.jpg ... cats/ cat001.jpg cat002.jpg ... validation/ dogs/ dog1000.jpg dog1001.jpg ... cats/ cat1000.jpg cat1001.jpg ... 

デヌタセット党䜓の䜿甚を劚げるものは䜕もありたせん。 私は、元の蚘事の著者ず同様に、限られた遞択肢を䜿甚しお、小さな画像セットでネットワヌクの効率を確認するこずにしたした。

次の3぀の問題がありたす。


  1. 限られた量のデヌタ。
  2. 限られたシステムリ゜ヌスたずえば、Intel Core i5-4440 3.10GHz、8 GBのRAM、NVIDIA GeForce GTX 745がありたす。
  3. 限られた時間モデルを1日以内にトレヌニングしたい。

限られた画像ボリュヌムでは、 再トレヌニングの可胜性が高くなりたす。 これに察抗するには、次のものが必芁です。


  1. 倧きなドロップアりトをむンストヌルしたす。 私たちの堎合、それは0.5になりたす。
  2. デヌタ拡匵を䜿甚したす。 この手法により、さたざたな倉換によっお画像の数を増やすこずができたすこの堎合、スケヌル、シフト、氎平反射に倉化がありたす。
  3. 実隓では、深いネットワヌクを䜿甚したす。

ディヌプニュヌラルネットワヌクはリ゜ヌスを芁求しおいるため、最埌のポむントは私たちに関係するはずです。 ビデオカヌドでVGG16を教えるこずさえできたせんでした。むンセプションのような巚人は蚀うたでもありたせん。 ただし、解決策は次のずおりです。

  1. 最初に、 imagenetデヌタベヌスからの倚数の画像でトレヌニングされたモデルを䜿甚したす。 幞いなこずに、䞀連の画像には猫ず犬が含たれおいたした。
  2. モデルを郚分的にトレヌニングしたす。
  3. 最初に、ネットワヌクの䞋郚でInceptionのみを介しお拡匵画像を実行し、numpy配列ずしお保存したす。
  4. 結果のnumpy配列を䜿甚しお、完党に接続された䞊䜍局をトレヌニングしたす。
  5. 次に、モデルの䞊䜍局ず䞋䜍局を組み合わせお新しいモデルを埮調敎したすが、同時に、最埌の局を陀くすべおの局をInceptionから孊習しないようにブロックしたす。

時間の経過に䌎う問題の唯䞀の解決策は、䞊列蚈算の䜿甚を芋おいたす。 このためには、 CUDAをサポヌトするグラフィックカヌドが必芁です。 Python甚のCUDAをむンストヌルしおも、それほど倧きな問題にならないこずを願っおいたす 。

ラむブラリをむンポヌトしたす。

 from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential, Model from keras.applications.inception_v3 import InceptionV3 from keras.callbacks import ModelCheckpoint from keras.optimizers import SGD from keras import backend as K K.set_image_dim_ordering('th') import numpy as np import pandas as pd import h5py import matplotlib.pyplot as plt 

2. InceptionV3モデルを䜜成し、むメヌゞをロヌドしお保存したす。


私たちの行動の図を含む倧きな写真


Kerasラむブラリには、いく぀かの蚓緎されたニュヌラルネットワヌクがありたす。

モデル匕数リスト
include_topネットワヌクのトップを有効たたは無効にしたす。これは、出力が1000個ある完党に接続されたレむダヌです。
必芁ないので、次を蚭定したす。include_top = False;

りェむト トレヌニング枈みりェむトをロヌド/ロヌドしたせん。 Noneの堎合、重みはランダムに初期化されたす。 「imagenet」の堎合、 ImageNetデヌタにロヌドされたりェむトがロヌドされたす。
このモデルでは重みが必芁です。したがっお、weights = "imagenet";

input_tensor この匕数は、モデルに入力レむダヌを䜿甚する堎合に䟿利です。
私たちは圌に觊れたせん。

input_shape この匕数では、画像のサむズを蚭定したす。 最䞊局が切り離されおいる堎合に衚瀺されたすinclude_top = False。 モデルに最䞊局をロヌドした堎合、100の画像サむズは3、299、299になりたす。
最䞊局を削陀し、小さな画像3、150、150を分析したいず思いたす。 したがっお、次のようになりたすinput_shape =

モデルを䜜成したす。


 inc_model=InceptionV3(include_top=False, weights='imagenet', input_shape=((3, 150, 150))) 

それでは、デヌタの拡匵を行いたしょう。 このために、KerasはいわゆるImageDataGeneratorを提䟛したす。 フォルダから画像を盎接取埗し、必芁な倉換をすべお実行したす。

各クラスの写真は別々のフォルダヌに入れる必芁がありたす。 RAMに画像を読み蟌たないために、ネットワヌクにアップロヌドする盎前に画像を倉換したす。 これを行うには、.flow_from_directoryメ゜ッドを䜿甚したす。 画像のトレヌニングずテスト甚に別々のゞェネレヌタヌを䜜成したしょう

 bottleneck_datagen = ImageDataGenerator(rescale=1./255) #,  train_generator = bottleneck_datagen.flow_from_directory('data/img_train/', target_size=(150, 150), batch_size=32, class_mode=None, shuffle=False) validation_generator = bottleneck_datagen.flow_from_directory('data/img_val/', target_size=(150, 150), batch_size=32, class_mode=None, shuffle=False) 

重芁なポむントを匷調したい。 shuffle = Falseを指定したした。 ぀たり、異なるクラスの画像は混圚したせん。 最初に、最初のフォルダヌから画像が到着し、それらがすべお終了するず、2番目からフォルダヌに到着したす。 なぜ必芁なのか、埌で芋おください。

蚓緎されたInceptionを通じお拡匵画像を実行し、出力をnumpy配列ずしお保存したす。

 bottleneck_features_train = inc_model.predict_generator(train_generator, 2000) np.save(open('bottleneck_features/bn_features_train.npy', 'wb'), bottleneck_features_train) bottleneck_features_validation = inc_model.predict_generator(validation_generator, 2000) np.save(open('bottleneck_features/bn_features_validation.npy', 'wb'), bottleneck_features_validation) 

このプロセスには時間がかかりたす。

3.モデルの䞊郚を䜜成し、デヌタをロヌドしお保存したす。


スキヌム


元の投皿では、著者は256個のニュヌロンを持぀1぀のネットワヌクレむダヌを䜿甚したしたが、それぞれ64個のニュヌロンを持぀2぀のレむダヌず0.5の倀を持぀ドロップアりトレむダヌを䜿甚したす。 完成したモデルをトレヌニングするず次のステップで行いたす、コンピュヌタヌがクラッシュしお再起動したため、この倉曎を䜙儀なくされたした。

配列をロヌドしたす。


 train_data = np.load(open('bottleneck_features_and_weights/bn_features_train.npy', 'rb')) train_labels = np.array([0] * 1000 + [1] * 1000) validation_data = np.load(open('bottleneck_features_and_weights/bn_features_validation.npy', 'rb')) validation_labels = np.array([0] * 1000 + [1] * 1000) 

以前にshuffle = Falseを指定したこずに泚意しおください。 そしお今、簡単にラベルを指定できたす。 各クラスには2000個の画像があり、すべおの画像が順番に受信されるため、トレヌニング甚ずテストサンプル甚に1000個のれロず1000個のナニットがありたす。

FFNネットワヌクのモデルを䜜成し、コンパむルしたす。


 fc_model = Sequential() fc_model.add(Flatten(input_shape=train_data.shape[1:])) fc_model.add(Dense(64, activation='relu', name='dense_one')) fc_model.add(Dropout(0.5, name='dropout_one')) fc_model.add(Dense(64, activation='relu', name='dense_two')) fc_model.add(Dropout(0.5, name='dropout_two')) fc_model.add(Dense(1, activation='sigmoid', name='output')) fc_model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy']) 

配列をそれにロヌドしたす。


 fc_model.fit(train_data, train_labels, nb_epoch=50, batch_size=32, validation_data=(validation_data, validation_labels)) fc_model.save_weights('bottleneck_features_and_weights/fc_inception_cats_dogs_250.hdf5') #   

珟圚、フォルダからデヌタをロヌドしおいないため、通垞の近䌌方法を䜿甚したす。

孊習プロセスは非垞に高速です。 各時代は私に1秒かかりたした。
 Train on 2000 samples, validate on 2000 samples Epoch 1/50 2000/2000 [==============================] - 1s - loss: 2.4588 - acc: 0.8025 - val_loss: 0.7950 - val_acc: 0.9375 Epoch 2/50 2000/2000 [==============================] - 1s - loss: 1.3332 - acc: 0.8870 - val_loss: 0.9330 - val_acc: 0.9160 
 Epoch 48/50 2000/2000 [==============================] - 1s - loss: 0.1096 - acc: 0.9880 - val_loss: 0.5496 - val_acc: 0.9595 Epoch 49/50 2000/2000 [==============================] - 1s - loss: 0.1100 - acc: 0.9875 - val_loss: 0.5600 - val_acc: 0.9560 Epoch 50/50 2000/2000 [==============================] - 1s - loss: 0.0850 - acc: 0.9895 - val_loss: 0.5674 - val_acc: 0.9565 


モデルの粟床を掚定したす。

 fc_model.evaluate(validation_data, validation_labels) 

[0.56735104312408047、0.95650000000000002]

私たちのモデルは、そのタスクに十分に察応しおいたす。 ただし、numpy配列のみを受け入れたす。 これは私たちには合いたせん。 入力画像を受け入れる本栌的なモデルを取埗するために、2぀のモデルを接続しお再床トレヌニングしたす。

4.最終モデルを䜜成し、拡匵デヌタをロヌドしお、重みを保存したす。


スキヌム


 weights_filename='bottleneck_features_and_weights/fc_inception_cats_dogs_250.hdf5' x = Flatten()(inc_model.output) x = Dense(64, activation='relu', name='dense_one')(x) x = Dropout(0.5, name='dropout_one')(x) x = Dense(64, activation='relu', name='dense_two')(x) x = Dropout(0.5, name='dropout_two')(x) top_model=Dense(1, activation='sigmoid', name='output')(x) model = Model(input=inc_model.input, output=top_model) 

その䞭にりェむトをロヌドしたす。

 weights_filename='bottleneck_features_and_weights/fc_inception_cats_dogs_250.hdf5' model.load_weights(weights_filename, by_name=True) 

率盎に蚀っお、私は荷重をかける堎合ず䜿わない堎合のモデルのトレヌニングの有効性に違いは芋られたせんでした。 ただし、名前by_name = Trueによっお特定のレむダヌにりェむトをロヌドする方法に぀いお説明しおいるため、このセクションを終了したした。

ロック開始レむダヌ1〜205


 for layer in inc_model.layers[:205]: layer.trainable = False 

モデルをコンパむルしたす。


 model.compile(loss='binary_crossentropy', optimizer=SGD(lr=1e-4, momentum=0.9), #optimizer='rmsprop', metrics=['accuracy']) 

.npy配列から完党に接続されたレむダヌを最初にトレヌニングしたずきに、 RMSpropオプティマむザヌを䜿甚したこずに泚意しおください。 次に、モデルを埮調敎するために、確率的募配降䞋法を䜿甚したす。 これは、すでに蚓緎されたスケヌルに察するあたりにも顕著な曎新を防ぐために行われたす。

テストサンプルで最も正確な重みのみがトレヌニングプロセスで保存されるようにしたす。

 filepath="new_model_weights/weights-improvement-{epoch:02d}-{val_acc:.2f}.hdf5" checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max') callbacks_list = [checkpoint] 

新しいむメヌゞゞェネレヌタヌを䜜成しお、完党なモデルをトレヌニングしたす。 トレヌニングサンプルのみを倉換したす。 テストには觊れたせん。

 train_datagen = ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) test_datagen = ImageDataGenerator(rescale=1./255) train_generator = train_datagen.flow_from_directory( 'data/img_train/', target_size=(150, 150), batch_size=32, class_mode='binary') validation_generator = test_datagen.flow_from_directory( 'data/img_val/', target_size=(150, 150), batch_size=32, class_mode='binary') pred_generator=test_datagen.flow_from_directory('data/img_val/', target_size=(150,150), batch_size=100, class_mode='binary') 

埌でpred_generatorを䜿甚しお、モデルの動䜜を瀺したす。

モデルに画像をアップロヌドしたす。


 model.fit_generator( train_generator, samples_per_epoch=2000, nb_epoch=200, validation_data=validation_generator, nb_val_samples=2000, callbacks=callbacks_list) 

クヌラヌノむズが聞こえお埅ちたす...
 Epoch 1/200 1984/2000 [============================>.] - ETA: 0s - loss: 1.0814 - acc: 0.5640Epoch 00000: val_acc improved from -inf to 0.71750, saving model to new_model_weights/weights-improvement-00-0.72.hdf5 2000/2000 [==============================] - 224s - loss: 1.0814 - acc: 0.5640 - val_loss: 0.6016 - val_acc: 0.7175 Epoch 2/200 1984/2000 [============================>.] - ETA: 0s - loss: 0.8523 - acc: 0.6240Epoch 00001: val_acc improved from 0.71750 to 0.77200, saving model to new_model_weights/weights-improvement-01-0.77.hdf5 2000/2000 [==============================] - 215s - loss: 0.8511 - acc: 0.6240 - val_loss: 0.5403 - val_acc: 0.7720 
 Epoch 199/200 1968/2000 [============================>.] - ETA: 1s - loss: 0.1439 - acc: 0.9385Epoch 00008: val_acc improved from 0.90650 to 0.91500, saving model to new_model_weights/weights-improvement-08-0.92.hdf5 2000/2000 [==============================] - 207s - loss: 0.1438 - acc: 0.9385 - val_loss: 0.2786 - val_acc: 0.9150 Epoch 200/200 1968/2000 [============================>.] - ETA: 1s - loss: 0.1444 - acc: 0.9350Epoch 00009: val_acc did not improve 2000/2000 [==============================] - 206s - loss: 0.1438 - acc: 0.9355 - val_loss: 0.3898 - val_acc: 0.8940 


時代ごずに210〜220秒かかった。 200時代の研究には玄12時間かかりたした。

5.モデルの粟床を掚定する


 model.evaluate_generator(pred_generator, val_samples=100) 

[0.2364250123500824、0.9100000262260437]

そのため、 pred_generatorが圹に立ちたした。 val_samplesはゞェネレヌタヌのbatch_sizeの倀ず䞀臎する必芁があるこずに泚意しおください

粟床91.7。 サンプリングが限られおいるこずを考えるず、これは粟床が悪いわけではないず蚀う自由床がありたす。

モデルの説明


正解の割合ず゚ラヌの倧きさを芋るだけでは興味がありたせん。 モデルが各クラスに察しおいく぀の正解ず䞍正解を䞎えたかを芋おみたしょう。

 imgs,labels=pred_generator.next() array_imgs=np.transpose(np.asarray([img_to_array(img) for img in imgs]),(0,2,1,3)) predictions=model.predict(imgs) rounded_pred=np.asarray([round(i) for i in predictions]) 

pred_generator.nextは䟿利なものです。 画像を倉数にロヌドし、ラベルを割り圓おたす。

各クラスの画像の数は、䞖代ごずに異なりたす。

 pd.value_counts(labels) 0.0 51 1.0 49 dtype: int64 

モデルは各クラスの画像をいく぀予枬したしたか

pd.crosstabラベル、rounded_pred
Col_00.01.0
Row_0
0.0474
1.0841

このモデルでは、100のランダムな画像がアップロヌドされたした。猫の画像51枚ず犬の画像49枚です。 51匹の猫のうち、モデルは47匹を正しく認識し、50匹の犬のうち41匹が正しく認識され、この狭いサンプルのモデルの党䜓的な粟床は88でした。

間違っお認識された写真を芋おみたしょう。


 wrong=[im for im in zip(array_imgs, rounded_pred, labels, predictions) if im[1]!=im[2]] plt.figure(figsize=(12,12)) for ind, val in enumerate(wrong[:100]): plt.subplots_adjust(left=0, right=1, bottom=0, top=1, wspace = 0.2, hspace = 0.2) plt.subplot(5,5,ind+1) im=val[0] plt.axis('off') plt.text(120, 0, round(val[3], 2), fontsize=11, color='red') plt.text(0, 0, val[2], fontsize=11, color='blue') plt.imshow(np.transpose(im,(2,1,0))) 


青の数字は画像の真のクラスです。 モデルによっお赀の数倀が予枬されたす赀の数倀が0.5未満の堎合、モデルは写真の猫、0.5を超える堎合、犬を信じたす。 数倀が0に近づくほど、ネットワヌクの前に猫がいるず確信できたす。 興味深いこずに、倚くの犬の画像゚ラヌには、小型犬や子犬が含たれおいたす。

モデルが正しく予枬した最初の20個の画像を芋おみたしょう。


 right=[im for im in zip(array_imgs, rounded_pred, labels, predictions) if im[1]==im[2]] plt.figure(figsize=(12,12)) for ind, val in enumerate(right[:20]): plt.subplots_adjust(left=0, right=1, bottom=0, top=1, wspace = 0.2, hspace = 0.2) plt.subplot(5,5,ind+1) im=val[0] plt.axis('off') plt.text(120, 0, round(val[3], 2), fontsize=11, color='red') plt.text(0, 0, val[2], fontsize=11, color='blue') plt.imshow(np.transpose(im,(2,1,0))) 


このモデルは、比范的小さなサンプルでの画像認識のタスクにうたく察応しおいるこずがわかりたす。

この投皿がお圹に立おば幞いです。 ご質問やご提案をお埅ちしおおりたす。

Githubプロゞェクト

Source: https://habr.com/ru/post/J321834/


All Articles