TensorFlow 2.0 : 上級 Tutorials : 画像 :- TensorFlow Hub で転移学習 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/05/2019
* 本ページは、TensorFlow org サイトの TF 2.0 – Advanced Tutorials – Images の以下のページを翻訳した上で
適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
画像 :- TensorFlow Hub で転移学習
TensorFlow Hub は事前訓練されたモデル・コンポーネントを共有するための方法です。事前訓練モデルの検索可能なリストのためには TensorFlow Module Hubを見てください。このチュートリアルは以下を実演します :
- tf.keras で TensorFlow Hub をどのように使用するか。
- TensorFlow Hub を使用してどのように画像分類を行なうか。
- どのように単純な転移学習を行なうか。
セットアップ
from __future__ import absolute_import, division, print_function, unicode_literals import matplotlib.pylab as plt import tensorflow as tf
!pip install -q -U tf-hub-nightly import tensorflow_hub as hub from tensorflow.keras import layers
ImageNet 分類器
分類器をダウンロードする
mobilenet をロードするために hub.module を、それを keras 層としてラップするために tf.keras.layers.Lambda を使用します。tfhub.dev からのどのような TensorFlow 2 互換画像分類器 URL もここで動作します。
classifier_url ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/2" #@param {type:"string"}
IMAGE_SHAPE = (224, 224) classifier = tf.keras.Sequential([ hub.KerasLayer(classifier_url, input_shape=IMAGE_SHAPE+(3,)) ])
単一画像上でそれを実行する
モデルを試すために単一のイメージをダウンロードします。
import numpy as np import PIL.Image as Image grace_hopper = tf.keras.utils.get_file('image.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg') grace_hopper = Image.open(grace_hopper).resize(IMAGE_SHAPE) grace_hopper
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg 65536/61306 [================================] - 0s 0us/step
grace_hopper = np.array(grace_hopper)/255.0 grace_hopper.shape
(224, 224, 3)
バッチ次元を追加して、画像をモデルに渡します。
result = classifier.predict(grace_hopper[np.newaxis, ...]) result.shape
(1, 1001)
結果はロジットの 1001 要素ベクトルで、画像のために各クラスの確率を見積もります。
そして top クラス ID は argmax で見つけられます :
predicted_class = np.argmax(result[0], axis=-1) predicted_class
653
予測をデコードする
予測されたクラス ID を持ち、ImageNet ラベルを取得して、そして予測をデコードします。
labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt') imagenet_labels = np.array(open(labels_path).read().splitlines())
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt 16384/10484 [==============================================] - 0s 0us/step
plt.imshow(grace_hopper) plt.axis('off') predicted_class_name = imagenet_labels[predicted_class] _ = plt.title("Prediction: " + predicted_class_name.title())
単純な転移学習
TF Hub を使用すると私達のデータセットでクラスを認識するためにモデルのトップ層を再訓練することは単純です。
データセット
このサンプルのために TensorFlow flower データセットを使用します :
data_root = tf.keras.utils.get_file( 'flower_photos','https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz', untar=True)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz 228818944/228813984 [==============================] - 4s 0us/step
このデータをモデルにロードする最も単純な方法は tf.keras.preprocessing.image.ImageDataGenerator を使用することです。
TensorFlow Hub の画像モジュールの総ては [0, 1] 範囲のfloat 入力を想定しています。これを達成するために ImageDataGenerator の rescale パラメータを使用します。
画像サイズは後で処理されます。
iimage_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1/255) image_data = image_generator.flow_from_directory(str(data_root), target_size=IMAGE_SHAPE)
Found 3670 images belonging to 5 classes.
結果としてのオブジェクトは image_batch, label_batch ペアを返す iterator です。
for image_batch, label_batch in image_data: print("Image batch shape: ", image_batch.shape) print("Label batch shape: ", label_batch.shape) break
Image batch shape: (32, 224, 224, 3) Label batch shape: (32, 5)
画像のバッチ上で分類器を実行する
今は画像バッチ上で分類器を実行します。
result_batch = classifier.predict(image_batch) result_batch.shape
(32, 1001)
predicted_class_names = imagenet_labels[np.argmax(result_batch, axis=-1)] predicted_class_names
array(['daisy', 'bee', 'viaduct', 'ringlet', 'shovel', 'trailer truck', 'pinwheel', 'daisy', 'daisy', 'bell pepper', 'coral fungus', 'spider web', 'conch', 'sea urchin', 'daisy', 'daisy', 'daisy', 'daisy', 'sulphur-crested cockatoo', 'buckeye', 'mushroom', 'picket fence', 'daisy', 'daisy', 'daisy', 'daisy', 'coral fungus', 'bonnet', 'picket fence', 'feather boa', 'daisy', 'daisy'], dtype='<U30')
今はこれらの予測が画像とともにどのように並ぶかを確認します :
plt.figure(figsize=(10,9)) plt.subplots_adjust(hspace=0.5) for n in range(30): plt.subplot(6,5,n+1) plt.imshow(image_batch[n]) plt.title(predicted_class_names[n]) plt.axis('off') _ = plt.suptitle("ImageNet predictions")
画像属性については LICENSE.txt 参照。
結果はパーフェクトからは程遠いですが、これらはモデルがそのために訓練されたクラスではないというのが合理的な考えです (“daisy” を除いて)。
ヘッドレス・モデルをダウンロードする
TensorFlow Hub はまた top 分類層なしのモデルも配布しています。これらは容易に転移学習を行なうために利用できます。
tfhub.dev からのどのようなどのような TensorFlow 2 互換画像特徴ベクトル URL もここで動作します。
feature_extractor_url = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/2" #@param {type:"string"}
特徴抽出器を作成します。
feature_extractor_layer = hub.KerasLayer(feature_extractor_url, input_shape=(224,224,3))
それは各画像のために 1280-長ベクトルを返します :
feature_batch = feature_extractor_layer(image_batch) print(feature_batch.shape)
(32, 1280)
特徴抽出器層の変数を凍結します、その結果訓練は新しい分類層だけを変更します。
feature_extractor_layer.trainable = False
分類ヘッドを装着する
今は hub 層を tf.keras.Sequential モデルでラップし、新しい分類層を追加します。
model = tf.keras.Sequential([ feature_extractor_layer, layers.Dense(image_data.num_classes, activation='softmax') ]) model.summary()
Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= keras_layer_1 (KerasLayer) (None, 1280) 2257984 _________________________________________________________________ dense (Dense) (None, 5) 6405 ================================================================= Total params: 2,264,389 Trainable params: 6,405 Non-trainable params: 2,257,984 _________________________________________________________________
predictions = model(image_batch)
predictions.shape
TensorShape([32, 5])
モデルを訓練する
訓練プロセスを configure するために compile を使用します :
model.compile( optimizer=tf.keras.optimizers.Adam(), loss='categorical_crossentropy', metrics=['acc'])
今はモデルを訓練するために .fit メソッドを使用します。
このサンプルを短く保持するために 2 エポックだけ訓練します。訓練進捗を可視化するために、エポック平均の代わりに各バッチの個々の損失と精度をログ記録するためにカスタム callback を使用します。
class CollectBatchStats(tf.keras.callbacks.Callback): def __init__(self): self.batch_losses = [] self.batch_acc = [] def on_train_batch_end(self, batch, logs=None): self.batch_losses.append(logs['loss']) self.batch_acc.append(logs['acc']) self.model.reset_metrics()
steps_per_epoch = np.ceil(image_data.samples/image_data.batch_size) batch_stats_callback = CollectBatchStats() history = model.fit_generator(image_data, epochs=2, steps_per_epoch=steps_per_epoch, callbacks = [batch_stats_callback])
Epoch 1/2 115/115 [==============================] - 22s 190ms/step - loss: 0.7020 - acc: 0.8750 Epoch 2/2 115/115 [==============================] - 17s 152ms/step - loss: 0.3386 - acc: 0.9375
さて 2, 3 の訓練反復後でさえ、モデルがタスクにおいて進捗していることを既に見ることができます。
plt.figure() plt.ylabel("Loss") plt.xlabel("Training Steps") plt.ylim([0,2]) plt.plot(batch_stats_callback.batch_losses)
[<matplotlib.lines.Line2D at 0x7f17b87cbe10>]
plt.figure() plt.ylabel("Accuracy") plt.xlabel("Training Steps") plt.ylim([0,1]) plt.plot(batch_stats_callback.batch_acc)
[<matplotlib.lines.Line2D at 0x7f179c5785f8>]
予測をチェックする
前からのプロットを再び行なうために、最初にクラス名の順序付けられたリストを取得します :
class_names = sorted(image_data.class_indices.items(), key=lambda pair:pair[1]) class_names = np.array([key.title() for key, value in class_names]) class_names
array(['Daisy', 'Dandelion', 'Roses', 'Sunflowers', 'Tulips'], dtype='<U10')
モデルを通して画像バッチを実行してインデックスをクラス名に変換します。
predicted_batch = model.predict(image_batch) predicted_id = np.argmax(predicted_batch, axis=-1) predicted_label_batch = class_names[predicted_id]
結果をプロットします。
label_id = np.argmax(label_batch, axis=-1)
plt.figure(figsize=(10,9)) plt.subplots_adjust(hspace=0.5) for n in range(30): plt.subplot(6,5,n+1) plt.imshow(image_batch[n]) color = "green" if predicted_id[n] == label_id[n] else "red" plt.title(predicted_label_batch[n].title(), color=color) plt.axis('off') _ = plt.suptitle("Model predictions (green: correct, red: incorrect)")
貴方のモデルをエクスポートする
モデルを訓練した今、それを saved model としてエクスポートします :
import time t = time.time() export_path = "/tmp/saved_models/{}".format(int(t)) model.save(export_path, save_format='tf') export_path
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_core/python/ops/resource_variable_ops.py:1785: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version. Instructions for updating: If using Keras pass *_constraint arguments to layers. WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_core/python/ops/resource_variable_ops.py:1785: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version. Instructions for updating: If using Keras pass *_constraint arguments to layers. INFO:tensorflow:Assets written to: /tmp/saved_models/1571882591/assets INFO:tensorflow:Assets written to: /tmp/saved_models/1571882591/assets '/tmp/saved_models/1571882591'
今はそれを再ロードできて、そしてそれが依然として同じ結果を与えることを確認しましょう :
reloaded = tf.keras.models.load_model(export_path)
result_batch = model.predict(image_batch) reloaded_result_batch = reloaded.predict(image_batch)
abs(reloaded_result_batch - result_batch).max()
0.0
savd model は後で推論のためにロードするか、TFLite や TFjs のために変換することができます。
以上