"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

tf2.0betaでTensorflow-hubの画像分類の学習済モデルを使ってみる。

Tensorflow2.0betaで、tensorflow hubを使い、任意の画像分類をします。

なお、ここでのせているサンプルは「Tensorflow2.0安定版」では動きません。

f:id:arakan_no_boku:20190727132812p:plain

 

tensorflow hubの学習済画像分類器

 

TensorFlow Hub は再利用可能な機械学習モジュール用のライブラリです。

www.tensorflow.org

非常に簡単に最新のネットワークモデルの性能を体験してみることができます。

色々あるのですが、やっぱり、馴染みがあるのが画像分類器です。

現時点(2019/07/27時点)で提供されている学習済モデルのリストです。

tfhub.dev

この中に「tf2-preview」という名前のついたものが2つあります。

mobilenet_v2とinception_v3です。

mobilenet_v2は、2018年にGoogleが発表した「サイズ・処理速度・メモリ使用量・計算量が少なくモバイル端末でも耐えうるわりに、精度が高いという特徴」のモデル。

inception_v3は、1 つの入力画像に対して、複数の畳み込み層(1×1, 3×3, 5×5)を並列に適用した結果を最後に連結する構造であるinceptionモジュールを組み込んだGoogleNetのことだと思います。

今回は、この2つのモデルで自分で用意した適当な画像を分類してみます、

なお。

以下のサンプルの中で物体名を日本語にするのに、以下の記事の翻訳クラスを使っています。

arakan-pgm-ai.hatenablog.com 

 

 

 

まずは「mobilenet」から

 

tensorflowの2.0betaのチュートリアルにものっていますが、学習済モデルをkerasモデルに変換するのは、超簡単です。

# tensorflow hubの学習済モデル取得URL&モデル名
model_url = "https://tfhub.dev/google/tf2-preview/"
model_name = "mobilenet_v2/classification/2"
# サイズは224*224になる
IMAGE_SHAPE = (224, 224)
# kerasモデルに変換する。変数名の意味は分類器。
classifier = tf.keras.Sequential([
    hub.KerasLayer(model_url + model_name, input_shape=IMAGE_SHAPE + (3,))
])

URLを2つに分割している理由は、PEP8の警告(80文字以上)を消すためです。 

これを使って、自分で用意した適当な画像をソースと同じフォルダに「test.jpg」という名前でコピーして、どの程度分類できるものかを試してみた時のソースがこちらです。

tf_hub_sample02.py

import tensorflow as tf
import tensorflow_hub as hub
import numpy as np
import PIL.Image as Image
import to_japanese_ilsvrc2012 as toj

# @param {type:"string"}
# tensorflow hubの学習済モデル取得URL&モデル名
model_url = "https://tfhub.dev/google/tf2-preview/"
model_name = "mobilenet_v2/classification/2"
# サイズは224*224になる
IMAGE_SHAPE = (224, 224)
# kerasモデルに変換する。変数名の意味は分類器。
classifier = tf.keras.Sequential([
    hub.KerasLayer(model_url + model_name, input_shape=IMAGE_SHAPE + (3,))
])
# クラス名データ。結果は数字なので、これを使って英語名にする
data_url = "https://storage.googleapis.com/download.tensorflow.org/data/"
# 英語クラス名を取得するためのデータファイルを取得してリストに変換する
labels_path = tf.keras.utils.get_file(
    'ImageNetLabels.txt',
    data_url + 'ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())

# 画像データの読み込みとデータ化
target_image = Image.open('test.jpg').resize(IMAGE_SHAPE)
target_image_array = np.array(target_image) / 255.0
# 分類予測実行
result = classifier.predict(target_image_array[np.newaxis, ...])
# 分類予測結果をとりだし、英語名に変換
predicted_class = np.argmax(result[0], axis=-1)
predicted_class_name = imagenet_labels[predicted_class]
# 日本簿名に変換して結果を表示
translator = toj.Ilsvrc2012Japanese()
print(
    "この画像は",
    predicted_class_name,
    ":日本語名(",
    translator.convert(predicted_class_name),
    ")です")

迷うところがないくらいシンプルに書けて凄いです。

今回はスマホでとった自分のギターの写真でやってみます。

f:id:arakan_no_boku:20190727150607p:plain

処理結果は。

この画像は acoustic guitar :日本語名( アコースティックギター )です

まあ、当然かな・・って感じですが。

 

今度は「inception_v3」でやってみます

 

ちゃんと設計されているので、モデルの切り替えは簡単です。

mobilenetとinceptionでは入力サイズが違います。

モデルを構築する部分がこう変わります。

# tensorflow hubの学習済モデル取得URL&モデル名
model_url = "https://tfhub.dev/google/tf2-preview/"
model_name = "inception_v3/classification/4"
# Image-netのデータを学習しているので、サイズは224*224になる
IMAGE_SHAPE = (299, 299)
# kerasモデルに変換する。変数名の意味は分類器。
classifier = tf.keras.Sequential([
    hub.KerasLayer(model_url + model_name, output_shape=[1001])
])
classifier.build([None, 299, 299, 3])

この部分以外は、mobilenetの時のソースと全く同じす。 

ですが、一応、全体でソースをのせておきます。

tf_hub_sample03.py

import tensorflow as tf
import tensorflow_hub as hub
import numpy as np
import PIL.Image as Image
import to_japanese_ilsvrc2012 as toj

# @param {type:"string"}
# tensorflow hubの学習済モデル取得URL&モデル名
model_url = "https://tfhub.dev/google/tf2-preview/"
model_name = "inception_v3/classification/4"
# Image-netのデータを学習しているので、サイズは224*224になる
IMAGE_SHAPE = (299, 299)
# kerasモデルに変換する。変数名の意味は分類器。
classifier = tf.keras.Sequential([
    hub.KerasLayer(model_url + model_name, output_shape=[1001])
])
classifier.build([None, 299, 299, 3])
# クラス名データ。結果は数字なので、これを使って英語名にする
data_url = "https://storage.googleapis.com/download.tensorflow.org/data/"
# 英語クラス名を取得するためのデータファイルを取得してリストに変換する
labels_path = tf.keras.utils.get_file(
    'ImageNetLabels.txt',
    data_url + 'ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())

# 画像データの読み込みとデータ化
target_image = Image.open('test.jpg').resize(IMAGE_SHAPE)
target_image_array = np.array(target_image) / 255.0
# 分類予測実行
result = classifier.predict(target_image_array[np.newaxis, ...])
# 分類予測結果をとりだし、英語名に変換
predicted_class = np.argmax(result[0], axis=-1)
predicted_class_name = imagenet_labels[predicted_class]
# 日本簿名に変換して結果を表示
translator = toj.Ilsvrc2012Japanese()
print(
    "この画像は",
    predicted_class_name,
    ":日本語名(",
    translator.convert(predicted_class_name),
    ")です")

inceptionの方が精度は高いはずなので、処理結果は当然。

この画像は acoustic guitar :日本語名( アコースティックギター )です

まあ。

なるほど・・という感じです。

今回は、Tensorflow-hubを使ってみました。

ではでは。