Help us understand the problem. What is going on with this article?

MacでTensorFlow Liteを実装する【2019年版】

MacでTensorFlow Liteを動かすまでの流れを解説していきます。

環境

動作確認済の環境は以下の通りです。
・macOS Catalina バージョン10.15
・Python 3.7.4
・conda 4.7.12
・TensorFlow 1.15.0
・keras 2.2.4

環境構築

以下のURLよりAnacondaをインストール
https://www.anaconda.com/distribution/
スクリーンショット 2019-11-29 10.42.24.png
ダウンロードしたインストーラパッケージをダブルクリックして起動します。 利用規約に同意し、保存先を決めてインストールします。
HomeからJupyter Notebookを起動します。
スクリーンショット 2019-11-29 10.49.31.png
作業場所を決めて、NEW→Python3でipynbファイルを作成します。
スクリーンショット 2019-11-29 10.52.39.png
ファイルを開くとこのようにプログラムを書ける画面に移ります。ここにプログラムを書いていきます。
スクリーンショット 2019-11-29 11.00.34.png
次にTensorFlowを動作させるためのパッケージをインストールします。
スクリーンショット 2019-11-29 11.08.12.png
「Enviroments」→「Create」で新しい環境を作ります。base(root)を使用する場合は不要です。
検索条件を「Not installed」に変更し、「tensorflow」と検索します。
そして出てきたパッケージの「keras」、「tensorflow」を選択し、Applyをクリックします。
スクリーンショット 2019-11-29 11.25.28.png
先程のようにJupyterを起動して次のようにプログラムを書いて実行します。
実行は「control + Enter」もしくは「Shift + Enter」です。
エラーが出ていないことがわかります。使い方はざっとこんな感じです。

追記
nomkl、matplotlib、pillowもインストールしておいてください。
nomklはtensorflowを実行する際にカーネルが死ぬのを防げるみたいです。
matplotlibは画像を表示するために使用します。
pillowは画像をロードするために使用します。

モデルを構築する

TensorFlow Liteのモデルを生成するために、まずはTensorFlowのモデルを作る必要があります。
今回は、cifar10というデータセットを使用します。
https://www.cs.toronto.edu/~kriz/cifar.html
cifar10は、6万枚の画像にラベル付けされたデータセットです。飛行機、自動車、鳥、猫、鹿、犬、カエル、馬、船、トラックに分けられています。これを学習させ、画像分類できるモデルを作っていきます。

以下、画像を学習させるためのコードです。
epoch数を20に設定しているのでかなり時間がかかります。

"""
必要なライブラリのインポートと画像の前処理
"""
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.core import Dense,Activation,Dropout,Flatten
from keras.datasets import cifar10
from keras.utils import np_utils

 #cifar10をダウンロード
(x_train,y_train),(x_test,y_test)=cifar10.load_data()

#画像を0-1の範囲で正規化
x_train=x_train.astype('float32')/255.0
x_test=x_test.astype('float32')/255.0

#正解ラベルをOne-Hot表現に変換
y_train=np_utils.to_categorical(y_train,10)
y_test=np_utils.to_categorical(y_test,10)

"""
TensorFlowのモデルを構築
"""
model=Sequential()

model.add(Conv2D(32,(3,3),padding='same',input_shape=(32,32,3)))
model.add(Activation('relu'))
model.add(Conv2D(32,(3,3),padding='same'))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.25))

model.add(Conv2D(64,(3,3),padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(64,(3,3),padding='same'))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(10,activation='softmax'))

model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

history=model.fit(x_train,y_train,batch_size=128,nb_epoch=20,verbose=1,validation_split=0.1)

#モデルと重みを保存
json_string=model.to_json()
open('cifar10_cnn.json',"w").write(json_string)
model.save_weights('cifar10_cnn.h5')
model.save('cifar10_cnn_model.h5')

#モデルの表示
model.summary()

#評価
score=model.evaluate(x_test,y_test,verbose=0)
print('Test loss:',score[0])
print('Test accuracy:',score[1])

実行すると
「cifar10_cnn.h5」と「cifar10_cnn_model.h5」というファイルが生成されているかと思います。
「cifar10_cnn.h5」はモデルの重みのみが保存され、「cifar10_cnn_model.h5」はモデル構造と重みが保存されています。精度は78%でした。
以下のサイトを参考にするとより精度を上げられそうです。

CIFAR-10でaccuracy95%--CNNで精度を上げるテクニック--
10層の畳み込みニューラルネットワークでCIFAR-10のValidation Accuracy9割を達成する

実際に画像分類してみる

保存したモデルを使って画像分類していきます。
まず、予測する画像を用意します。
スクリーンショット 2019-11-29 13.01.30.png

コードに書かれている階層に合わせてフォルダを作成し、その中に画像を入れ、以下のコードを実行します。

"""
拾った画像を使って予測する
"""
from keras.models import model_from_json
import matplotlib.pyplot as plt
from keras.preprocessing.image import img_to_array, load_img
from tensorflow.python.keras.models import load_model

#画像読み込み
temp_img=load_img("./images/airplane1.jpeg",target_size=(32,32))

#画像を配列に変換し0-1で正規化
temp_img_array=img_to_array(temp_img)
temp_img_array=temp_img_array.astype('float32')/255.0
temp_img_array=temp_img_array.reshape((1,32,32,3))

#学習済みのモデルと重みを読み込む
json_string=open('cifar10_cnn.json').read()
model=model_from_json(json_string)
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])
model.load_weights('cifar10_cnn.h5')
# model = load_model('cifar10_cnn_model.h5')

#モデルを表示
model.summary()

#画像を予想
img_pred=model.predict_classes(temp_img_array)
print('\npredict_classes=',img_pred)
print('model=',model)

plt.imshow(temp_img)
plt.title('pred:{}'.format(img_pred))
plt.show()

"""
0 - airplane
1 - automobile
2 - bird
3 - cat
4 - deer
5 - dog
6 - frog
7 - horse
8 - ship
9 - truck
"""

上手くいくと、画像とインデックス番号が出力されます。
スクリーンショット 2019-11-29 13.04.43.png
↑こんな感じ
インデックス番号と画像が一致していることがわかります。画像分類成功です。

TensorFlow Lite用モデルに変換

そして、先程生成したモデルをTensorFlowLite用に変換します。

#既存のKeras用モデル(cifar10_cnn_model.h5)から、TensorFlow Lite用モデル(cifar10_cnn.tflite)を作成

import tensorflow as tf

if __name__ == '__main__':
    converter = tf.lite.TFLiteConverter.from_keras_model_file("cifar10_cnn_model.h5")
    tflite_model = converter.convert()
    open("cifar10_cnn.tflite", "wb").write(tflite_model)

こちらのコードを実行すると「cifar10_cnn.tflite」が生成されます。
これがTensorFlowLite用のモデルです。

このモデルを使用して、画像分類してみます。

#TensorFlow Lite用モデルを使って、入力画像からジャンル識別する

import tensorflow as tf
import numpy as np
from keras.models import model_from_json
import matplotlib.pyplot as plt
from keras.preprocessing.image import img_to_array, load_img
from tensorflow.python.keras.models import load_model

if __name__ == '__main__':
    # prepara input image
    #画像読み込み
    temp_img=load_img("./images/dog1.jpeg",target_size=(32,32))

    #画像を配列に変換し0-1で正規化
    temp_img_array=img_to_array(temp_img)
    img=temp_img_array.astype('float32')/255.0
    img=temp_img_array.reshape((1,32,32,3))

    # load model
    interpreter = tf.lite.Interpreter(model_path="cifar10_cnn.tflite")
    interpreter.allocate_tensors()
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()

    # set input tensor
    interpreter.set_tensor(input_details[0]['index'], img)

    # run
    interpreter.invoke()

    # get outpu tensor
    probs = interpreter.get_tensor(output_details[0]['index'])

    # print result
    result = np.argmax(probs[0])
    score = probs[0][result]
    print("予測した画像インデックス:{} [{:.2f}]".format(result, score)) 

    plt.imshow(temp_img)
    plt.title('pred:{}'.format(img_pred))
    plt.show()

"""
0 - airplane
1 - automobile
2 - bird
3 - cat
4 - deer
5 - dog
6 - frog
7 - horse
8 - ship
9 - truck
"""

こちらも上手くいくと画像とインデックス番号が出力されます。
スクリーンショット 2019-11-29 13.20.47.png

TensorflowとTensorflowLiteの比較

以下の比較は画像データによって左右されますので参考程度にしてください。
画像を予測するためにかかった時間をそれぞれ計測しました。

keras用のモデル
経過時間:0.8839559555053711
経過時間:0.6288352012634277
経過時間:0.5877768993377686
経過時間:0.5789699554443359
経過時間:0.5908827781677246
経過時間:0.7207329273223877
経過時間:0.7104830741882324
経過時間:0.6035618782043457
経過時間:0.5244758129119873
経過時間:0.5348677635192871
平均経過時間:0.636454225
TensorflowLite用のモデル
経過時間:0.27948904037475586
経過時間:0.05380606651306152
経過時間:0.022572994232177734
経過時間:0.06809115409851074
経過時間:0.07050800323486328
経過時間:0.06940007209777832
経過時間:0.12052798271179199
経過時間:0.17615199089050293
経過時間:0.12544798851013184
経過時間:0.027255773544311523
平均経過時間:0.101325107

TensorflowLiteの方が早いですね。
しかしその分精度に差があります。

keras用のモデルで予測できなかった画像はCatのみでした。
一方でTensorflowLiteのモデルでは、airplane、Bird、cat、Frogが予測することができませんでした。
TensorflowLite用に変換したモデルはかなり精度が下がっているようです。

99.4%の精度を持つMNISTのモデルで実行した場合はkeras用もTensorflowLite用も同じくらい予測することができました。TensorflowLiteを使用する場合は、かなり高い精度を持つモデルを用意する必要がありそうです。

参考

初心者に優しくないTensorflow Lite の公式サンプル
KerasでCNNを構築しCIFAR-10の画像分類をしてみよう

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away