👙

けしからん画像分類器を作ってみる (9) 推論

2021/04/15に公開

目次

ついにkeshikaran.pyを手に入れた

前回、「EfficientNet B0」を使った画像分類モデルを約2万枚の画像で学習し、精度85%を得ることができました。
「テストデータで精度85%!」と言われても、現実の「けしからん画像」を分類できないと意味が無いですよね。

今回は、得られた画像分類モデルを使って推論(Inference、Predict)するスクリプトを書いてみます。
そう、ついに最初の記事で妄想したkeshikaran.pyを手に入れる時が来たのです!

モデルの読み込みで少しハマった

学習スクリプトtrain.pyは、学習済みのモデルをmodel.save("model.h5")みたいな感じでファイルとして書き込んでいます。
このモデルファイルmodel.h5を読み込んで推論してみましょう。

・・・いきなりモデルの読み込みで少しハマりました。

import tensorflow as tf
model = tf.keras.models.load_model("model.h5")

みたいなコードでモデルを読み込むと、ValueError: Unknown layer: KerasLayerが発生しました。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/saving/save.py", line 206, in load_model
    return hdf5_format.load_model_from_hdf5(filepath, custom_objects,
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/saving/hdf5_format.py", line 183, in load_model_from_hdf5
    model = model_config_lib.model_from_config(model_config,
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/saving/model_config.py", line 64, in model_from_config
    return deserialize(config, custom_objects=custom_objects)
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/layers/serialization.py", line 173, in deserialize
    return generic_utils.deserialize_keras_object(
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/utils/generic_utils.py", line 354, in deserialize_keras_object
    return cls.from_config(
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/engine/sequential.py", line 492, in from_config
    layer = layer_module.deserialize(layer_config,
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/layers/serialization.py", line 173, in deserialize
    return generic_utils.deserialize_keras_object(
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/utils/generic_utils.py", line 346, in deserialize_keras_object
    (cls, cls_config) = class_and_config_for_serialized_keras_object(
  File "/usr/local/lib/python3.8/dist-packages/tensorflow/python/keras/utils/generic_utils.py", line 296, in class_and_config_for_serialized_keras_object
    raise ValueError('Unknown ' + printable_module_name + ': ' + class_name)
ValueError: Unknown layer: KerasLayer

少し調べてみると、hub.KerasLayerを使っている場合は、読み込み時にカスタムレイヤーについての情報が必要とのこと。
以下の様にcustom_objectsを指定することで、モデルを読み込むことができました。

import tensorflow as tf
import tensorflow_hub as hub
model = tf.keras.models.load_model("model.h5", custom_objects={"KerasLayer": hub.KerasLayer})

参考:

keshikaran.pyを実装する

モデルの読み込みが成功したので、早速keshikaran.pyを実装してみましょう。仕様は以下の通りとします。

  • 画像のファイル名をコマンドライン引数として渡す。
  • 標準出力に「けしからん度合い」(要するにエロい度合い)を0〜1の実数で出力する。

実際のスクリプトは以下の通りです。短いですね。

keshikaran.py
#!/usr/bin/env python3

import numpy as np
import PIL.Image
import sys
import tensorflow as tf
import tensorflow_hub as hub

image_path = sys.argv[1]

image = PIL.Image.open(image_path).convert("RGB").resize((224, 224))
image = np.array(image) / 255
image = np.expand_dims(image, 0)

model = tf.keras.models.load_model("model.h5", custom_objects={"KerasLayer": hub.KerasLayer})

predictions = model.predict(image)
print(predictions[0][0])

推論してみる

では実際の画像を入力して推論してみましょう。以下の画像はぱくたそからお借りしました。

まずはこちらの犬の画像から推論してみます。ちょっと羊っぽくて可愛いですね。

$ python3 keshikaran.py dog.jpg
0.29267535

思ったよりも数値が高いですが、中間(0.5)は下回っているので「けしからんくない画像」と見なして良さそうです。

続いて、こちらのちょっとセクシーな女性の画像を推論してみます。

$ python3 keshikaran.py woman.jpg
0.824198

犬の写真よりもだいぶ数値が上がりました。こちらは「けしからん画像」のようです。

さらに、より実践的(?)な画像を入力してみます。
aHR0cHM6Ly9ibG9nLWltZ3MtMTQ1LmZjMi5jb20vcy91L20vc3Vtb21vY2hhbm5lbC92cl9ha2lyYWVsbHlfMTAyNTgtMDAyLmpwZw==から入手した画像(リンクするのは憚られるので、URLをBase64エンコードしています)を入力してみます。

$ python3 keshikaran.py sexy.jpg
0.9372734

キター!いやー、これはけしからん。

最後にもう1枚、肌色が多めのこちらの画像を入力してみます。

$ python3 keshikaran.py man_and_dog.jpg
0.34251067

こちらは「けしからんくない画像」の様です。激しく同意。

今回はここまで

ついに妄想していたkeshikaran.pyを実装することができました。ここでは数枚の画像しか試していませんが、基本的には上手く動作しているようです。
正直、何に使えるかは分からないので、面白いアイデアを思いついたら教えて欲しいです。前回も書きましたが、要望があれば学習済みモデルは公開します。

途中、ラベル付けなどのネタを飛ばしてしまったので、追々、そちらも書いていければと思っています。今日はここまで!

追記: 番外編「EfficientNet B0〜B7で画像分類器を転移学習してみる」を書きました。

Discussion