{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "h2q27gKz1H20" }, "source": [ "##### Copyright 2019 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "id": "TUfAcER1oUS6" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "Gb7qyhNL1yWt" }, "source": [ "# TensorFlow Lite Model Maker による画像分類" ] }, { "cell_type": "markdown", "metadata": { "id": "nDABAblytltI" }, "source": [ "
![]() | \n",
" ![]() | \n",
" ![]() | \n",
" ![]() | \n",
" ![]() | \n",
"
<b>flower_photos</b>\n", "|__ <b>daisy</b>\n", " |______ 100080576_f52e8ee070_n.jpg\n", " |______ 14167534527_781ceb1b7a_n.jpg\n", " |______ ...\n", "|__ <b>dandelion</b>\n", " |______ 10043234166_e6dd915111_n.jpg\n", " |______ 1426682852_e62169221f_m.jpg\n", " |______ ...\n", "|__ <b>roses</b>\n", " |______ 102501987_3cdb8e5394_n.jpg\n", " |______ 14982802401_a3dfb22afb.jpg\n", " |______ ...\n", "|__ <b>sunflowers</b>\n", " |______ 12471791574_bb1be83df4.jpg\n", " |______ 15122112402_cafa41934f.jpg\n", " |______ ...\n", "|__ <b>tulips</b>\n", " |______ 13976522214_ccec508fe7.jpg\n", " |______ 14487943607_651e8062a1_m.jpg\n", " |______ ...\n", "" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "7tOfUr2KlgpU" }, "outputs": [], "source": [ "image_path = tf.keras.utils.get_file(\n", " 'flower_photos.tgz',\n", " 'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',\n", " extract=True)\n", "image_path = os.path.join(os.path.dirname(image_path), 'flower_photos')" ] }, { "cell_type": "markdown", "metadata": { "id": "E051HBUM5owi" }, "source": [ "`DataLoader` クラスを使用して、データを読み込みます。\n", "\n", "`from_folder()` メソッドについては、フォルダからデータを読み込むことができます。同じクラスの画像データは同じサブディレクトリに存在し、サブフォルダ名はクラス名であることを前提とします。現在のところ、JPEG エンコード画像と PNG エンコード画像がサポートされています。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "I_fOlZsklmlL" }, "outputs": [], "source": [ "data = DataLoader.from_folder(image_path)" ] }, { "cell_type": "markdown", "metadata": { "id": "u501eT4koURB" }, "source": [ "これをトレーニングデータ(80%)、検証データ(10% - オプション)、およびテストデータ(10%)に分割します。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "cY4UU5SUobtJ" }, "outputs": [], "source": [ "train_data, rest_data = data.split(0.8)\n", "validation_data, test_data = rest_data.split(0.5)" ] }, { "cell_type": "markdown", "metadata": { "id": "Z9_MYPie3EMO" }, "source": [ "ラベル付きの 25 個の画像サンプルを表示します。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Ih4Wx44I482b" }, "outputs": [], "source": [ "plt.figure(figsize=(10,10))\n", "for i, (image, label) in enumerate(data.gen_dataset().unbatch().take(25)):\n", " plt.subplot(5,5,i+1)\n", " plt.xticks([])\n", " plt.yticks([])\n", " plt.grid(False)\n", " plt.imshow(image.numpy(), cmap=plt.cm.gray)\n", " plt.xlabel(data.index_to_label[label.numpy()])\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "AWuoensX4vDA" }, "source": [ "### ステップ 2: TensorFlow モデルをカスタマイズする\n", "\n", "読み込んだデータをもとに、カスタム画像分類器モデルを作成します。デフォルトのモデルは EfficientNet-Lite0 です。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "TvYSUuJY3QxR" }, "outputs": [], "source": [ "model = image_classifier.create(train_data, validation_data=validation_data)" ] }, { "cell_type": "markdown", "metadata": { "id": "4JFOKWnH9x8_" }, "source": [ "モデル構造を詳しく確認します。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "QNXAfjl192dC" }, "outputs": [], "source": [ "model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "LP5FPk_tOxoZ" }, "source": [ "### ステップ 3: カスタマイズ済みのモデルを評価する\n", "\n", "モデルの結果を評価し、モデルの損失と精度を取得します。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "A8c2ZQ0J3Riy" }, "outputs": [], "source": [ "loss, accuracy = model.evaluate(test_data)" ] }, { "cell_type": "markdown", "metadata": { "id": "6ZCrYOWoCt05" }, "source": [ "100 個のテスト画像で予測結果を描画できます。赤色の予測ラベルは誤った予測結果を表し、ほかは正しい結果を表します。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "n9O9Kx7nDQWD" }, "outputs": [], "source": [ "# A helper function that returns 'red'/'black' depending on if its two input\n", "# parameter matches or not.\n", "def get_label_color(val1, val2):\n", " if val1 == val2:\n", " return 'black'\n", " else:\n", " return 'red'\n", "\n", "# Then plot 100 test images and their predicted labels.\n", "# If a prediction result is different from the label provided label in \"test\"\n", "# dataset, we will highlight it in red color.\n", "plt.figure(figsize=(20, 20))\n", "predicts = model.predict_top_k(test_data)\n", "for i, (image, label) in enumerate(test_data.gen_dataset().unbatch().take(100)):\n", " ax = plt.subplot(10, 10, i+1)\n", " plt.xticks([])\n", " plt.yticks([])\n", " plt.grid(False)\n", " plt.imshow(image.numpy(), cmap=plt.cm.gray)\n", "\n", " predict_label = predicts[i][0][0]\n", " color = get_label_color(predict_label,\n", " test_data.index_to_label[label.numpy()])\n", " ax.xaxis.label.set_color(color)\n", " plt.xlabel('Predicted: %s' % predict_label)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "S3H0rkbLUZAG" }, "source": [ "精度がアプリの要件を満たさない場合は、[高度な使用](#scrollTo=zNDBP2qA54aK)を参照し、より大規模なモデルに変更したり、再トレーニングパラメータを調整したりといった別の手段を調べてください。" ] }, { "cell_type": "markdown", "metadata": { "id": "aeHoGAceO2xV" }, "source": [ "### ステップ 4: TensorFlow Lite モデルにエクスポートする\n", "\n", "トレーニングされたモデルを[メタデータ](https://www.tensorflow.org/lite/convert/metadata)で TensorFlow Lite モデル形式に変換し、後でオンデバイス ML アプリケーションで使用できるようにします。ラベルファイルと語彙ファイルはメタデータに埋め込まれています。デフォルトの TFLite ファイル名は `model.tflite` です。\n", "\n", "多くのオンデバイス ML アプリケーションでは、モデルサイズが重要な要因です。そのため、モデルの量子化を適用して小さくし、実行速度を高められるようにすることをお勧めします。デフォルトのポストトレーニング量子化手法は、画像分類タスクの完全整数量子化です。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Im6wA9lK3TQB" }, "outputs": [], "source": [ "model.export(export_dir='.')" ] }, { "cell_type": "markdown", "metadata": { "id": "ROS2Ay2jMPCl" }, "source": [ "TensorFlow Lite モデルをモバイルアプリに統合する方法については、[画像分類のサンプルアプリケーションとガイド](https://www.tensorflow.org/lite/models/image_classification/overview#example_applications_and_guides)をご覧ください。\n", "\n", "このモデルは、[ImageClassifier API](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_classifier)([TensorFlow Lite Task ライブラリ](https://www.tensorflow.org/lite/inference_with_metadata/task_library/overview))を使って Android または iOS アプリに統合することができます。" ] }, { "cell_type": "markdown", "metadata": { "id": "habFnvRxxQ4A" }, "source": [ "次のいずれかのエクスポートフォーマットを使用できます。\n", "\n", "- `ExportFormat.TFLITE`\n", "- `ExportFormat.LABEL`\n", "- `ExportFormat.SAVED_MODEL`\n", "\n", "デフォルトでは、メタデータとともに TensorFlow Lite モデルをエクスポートするだけです。さまざまなファイルを選択的にエクスポートすることも可能です。たとえば、ラベルファイルのみをエクスポートする場合は、次のように行います。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "BvxWsOTmKG4P" }, "outputs": [], "source": [ "model.export(export_dir='.', export_format=ExportFormat.LABEL)" ] }, { "cell_type": "markdown", "metadata": { "id": "-4jQaxyT5_KV" }, "source": [ "また、`evaluate_tflite` メソッドを使って tflite を評価することもできます。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "S1YoPX5wOK-u" }, "outputs": [], "source": [ "model.evaluate_tflite('model.tflite', test_data)" ] }, { "cell_type": "markdown", "metadata": { "id": "zNDBP2qA54aK" }, "source": [ "## 高度な使用\n", "\n", "このライブラリでは、`create` 関数が非常に重要な役割を果たします。この関数は、[チュートリアル](https://www.tensorflow.org/tutorials/images/transfer_learning)と同様に、トレーニング済みのモデルで転移学習を使います。\n", "\n", "`create` 関数には、次のステップが含まれます。\n", "\n", "1. パラメータ `validation_ratio` と `test_ratio` に基づき、データをトレーニング、検証、テストのデータに分割します。`validation_ratio` と `test_ratio` のデフォルト値は、`0.1` と `0.1` です。\n", "2. ベースモデルとして、TensorFlow Hub から [Image Feature Vector](https://www.tensorflow.org/hub/common_signatures/images#image_feature_vector) をダウンロードします。デフォルトのトレーニング済みモデルは EfficientNet-Lite0 です。\n", "3. ヘッドレイヤーとトレーニング済みモデルの間に、`dropout_rate` を使用して、ドロップアウトレイヤー付きの分類器ヘッドを追加します。デフォルトの`dropout_rate` は TensorFlow Hub の [make_image_classifier_lib](https://github.com/tensorflow/hub/blob/master/tensorflow_hub/tools/make_image_classifier/make_image_classifier_lib.py#L55) のデフォルトの `dropout_rate` 値です。\n", "4. 生の入力データを前処理します。現在のところ、前処理ステップには、各画像ピクセルの値をモデルの入力スケールに正規化し、モデルの入力サイズにサイズ変更することが含まれます。EfficientNet-Lite0 の入力スケールは `[0, 1]`、入力画像サイズは `[224, 224, 3]` です。\n", "5. データを分類器モデルにフィードします。デフォルトでは、トレーニングエポック、バッチサイズ、学習率、運動量などのトレーニングパラメータは、TensorFlow Hub の[make_image_classifier_lib](https://github.com/tensorflow/hub/blob/master/tensorflow_hub/tools/make_image_classifier/make_image_classifier_lib.py#L55) のデフォルト値です。分類器ヘッドのみがトレーニングされています。\n", "\n", "このセクションでは、異なる画像分類モデルへの切り替えやトレーニングハイパーパラメータの変更など、いくつかの高度なトピックを説明します。\n" ] }, { "cell_type": "markdown", "metadata": { "id": "Gc4Jk8TvBQfm" }, "source": [ "## TensorFlow Lite モデルでポストトレーニング量子化をカスタマイズする\n" ] }, { "cell_type": "markdown", "metadata": { "id": "tD8BOYrHBiDt" }, "source": [ "[ポストトレーニング量子化](https://www.tensorflow.org/lite/performance/post_training_quantization)は、モデルサイズと推論レイテンシを縮小できる変換テクニックです。このテクニックでは、モデル精度にほとんど影響することなく、CPU とハードウェアアクセラレータの推論速度も改善することができます。したがって、モデルを改善するために広く使われています。\n" ] }, { "cell_type": "markdown", "metadata": { "id": "iyIo0d5TCzE2" }, "source": [ "Model Maker ライブラリは、モデルをエクスポートする際に、デフォルトのポストトレーニング量子化手法を適用します。ポストトレーニング量子化をカスタマイズするのであれば、Model Maker は、[QuantizationConfig](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/config/QuantizationConfig) を使った複数のポストトレーニング量子化オプションもサポートしています。例として、float16 量子化を見てみましょう。まず、量子化構成を定義します。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "k8hL2mstCxQl" }, "outputs": [], "source": [ "config = QuantizationConfig.for_float16()" ] }, { "cell_type": "markdown", "metadata": { "id": "K1gzx_rmFMOA" }, "source": [ "次に、その構成で TensorFlow Lite モデルをエクスポートします。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "WTJzFQnJFMjr" }, "outputs": [], "source": [ "model.export(export_dir='.', tflite_filename='model_fp16.tflite', quantization_config=config)" ] }, { "cell_type": "markdown", "metadata": { "id": "Safo0e40wKZW" }, "source": [ "Colab では、前述のアップロード手順と同様に、左サイドバーから `model_fp16.tflite` というモデルをダウンロードできます。" ] }, { "cell_type": "markdown", "metadata": { "id": "A4kiTJtZ_sDm" }, "source": [ "## モデルを変更する\n" ] }, { "cell_type": "markdown", "metadata": { "id": "794vgj6ud7Ep" }, "source": [ "### このライブラリでサポートされているモデルに変更する\n", "\n", "このライブラリは、EfficientNet-Lite モデル、MobileNetV2、ResNet50 をサポートします。[EfficientNet-Lite](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet/lite) は、最新の精度を達成し、エッジデバイスに適切した一群の画像分類モデルです。デフォルトのモデルは EfficientNet-Lite0 です。\n", "\n", "このモデルを、`create` メソッドのパラメータ `model_spec` を MobileNet_v2_spec に設定することで、MobileNetV2 に切り替えることができます。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "7JKsJ6-P6ae1" }, "outputs": [], "source": [ "model = image_classifier.create(train_data, model_spec=model_spec.get('mobilenet_v2'), validation_data=validation_data)" ] }, { "cell_type": "markdown", "metadata": { "id": "gm_B1Wv08AxR" }, "source": [ "新たにトレーニングした MobileNetV2 モデルを評価し、テストデータで精度と損失を確認します。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "lB2Go3HW8X7_" }, "outputs": [], "source": [ "loss, accuracy = model.evaluate(test_data)" ] }, { "cell_type": "markdown", "metadata": { "id": "vAciGzVWtmWp" }, "source": [ "### TensorFlow Hub にモデルに変更する\n", "\n", "さらに、画像を入力し、TensorFlow Hub 形式の特徴ベクトルを出力する他の新しいモデルに切り替えることもできます。\n", "\n", "[Inception V3](https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1) モデルを例とすると、`inception_v3_spec` を定義することができます。これには、[image_classifier.ModelSpec](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker/image_classifier/ModelSpec) のオブジェクトであり、Inception V3 モデルの仕様が含まれます。\n", "\n", "モデル名 `name`、TensorFlow Hub モデルの URL `uri` を指定する必要があります。その間、`input_image_shape` のデフォルト値は `[224, 224]` です。これを Inception V3 モデルの `[299, 299]` に変更する必要があります。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "xdiMF2WMfAR4" }, "outputs": [], "source": [ "inception_v3_spec = image_classifier.ModelSpec(\n", " uri='https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1')\n", "inception_v3_spec.input_image_shape = [299, 299]" ] }, { "cell_type": "markdown", "metadata": { "id": "T_GGIoXZCs5F" }, "source": [ "次に、`create` メソッドでパラメータ `model_spec` を `inception_v3_spec` に設定することで、Inception V3 モデルを再トレーニングすることができます。\n", "\n", "残りのステップはまったく同じで、最終的にカスタマイズされた InceptionV3 TensorFlow Lite モデルを得ることができます。" ] }, { "cell_type": "markdown", "metadata": { "id": "UhZ5IRKdeex3" }, "source": [ "### 独自のカスタムモデルを変更する" ] }, { "cell_type": "markdown", "metadata": { "id": "svTjlZhrCrcV" }, "source": [ "TensorFlow Hub にないカスタムモデルを使用する場合は、[ModelSpec](https://www.tensorflow.org/hub/api_docs/python/hub/ModuleSpec) を作成して TensorFlow Hub にエクスポートする必要があります。\n", "\n", "次に、上記のプロセスのように `ImageModelSpec` オブジェクトを定義し始めます。" ] }, { "cell_type": "markdown", "metadata": { "id": "4M9bn703AHt2" }, "source": [ "## トレーニングハイパーパラメータを変更する\n", "\n", "また、モデルの精度に影響する `epochs`、`dropout_rate`、および `batch_size` などのトレーニングハイパーパラメータも変更できます。以下は、調整できるモデルパラメータです。\n", "\n", "- `epochs`: エポックを増やすと、収束するまでより優れた精度を達成できますが、エポック数が多すぎると、トレーニングは過適合となる可能性があります。\n", "- `dropout_rate`: ドロップアウト率。過適合を回避します。\n", "- `batch_size`: 1 つのトレーニングステップに使用するサンプル数。デフォルトは None。\n", "- `validation_data`: 検証データ。None の場合は、検証をスキップします。デフォルトは None。\n", "- `train_whole_model`: true の場合、Hub モジュールは上の分類レイヤーとともにトレーニングされます。そうでない場合は、上の分類レイヤーのみがトレーニングされます。デフォルトは None です。\n", "- `learning_rate`: 基本学習率。デフォルトは None です。\n", "- `momentum`: オプティマイザに転送される Python float。`use_hub_library` が True の場合にのみ使用されます。デフォルトは None です。\n", "- `shuffle`: データをシャッフルするかどうかを決めるブール型。デフォルトは False です。\n", "- `use_augmentation`: 前処理にデータ拡張を行うかを決めるブール型。デフォルトは False です。\n", "- `use_hub_library`: モデルの再トレーニングに TensorFlow Hub の `make_image_classifier_lib` を使用するかを決めるブール型。このトレーニングパイプラインは、多数のカテゴリを持つ複雑なデータセットのパフォーマンスを改善する可能性があります。デフォルトは True です。\n", "- `warmup_steps`: 学習率に関するウォームアップスケジュールのウォームアップステップ数。None の場合、2 エポックの傍系トレーニングステップ数であるデフォルトの warmup_steps が使用されます。`use_hub_library` が False の場合にのみ使用されます。デフォルトは None です。\n", "- `model_dir`: オプション。モデルチェックポイントファイルの場所です。`use_hub_library` がFalse の場合にのみ使用されます。デフォルトは None です。\n", "\n", "
epochs
など、デフォルトが None であるパラメータは、TensorFlow Hub library の make_image_classifier_lib または train_image_classifier_lib にある具体的なデフォルトパラメータを取得します。\n",
"\n",
"たとえば、エポック数を増やしてトレーニングすることができます。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "A3k7mhH54QcK"
},
"outputs": [],
"source": [
"model = image_classifier.create(train_data, validation_data=validation_data, epochs=10)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VaYBQymQDsXU"
},
"source": [
"新たに再トレーニングされたモデルを 10 個のトレーニングエポックで評価します。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "VafIYpKWD4Sw"
},
"outputs": [],
"source": [
"loss, accuracy = model.evaluate(test_data)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "dhBU5NCy5Ji2"
},
"source": [
"# その他の資料\n",
"\n",
"技術的な詳細については、[画像分類](https://www.tensorflow.org/lite/examples/image_classification/overview)の例をご覧ください。詳細については、以下をご覧ください。\n",
"\n",
"- TensorFlow Lite Model Maker の[ガイド](https://www.tensorflow.org/lite/guide/model_maker)と [API リファレンス](https://www.tensorflow.org/lite/api_docs/python/tflite_model_maker)\n",
"- タスクライブラリ: デプロイ用の [ImageClassifier](https://www.tensorflow.org/lite/inference_with_metadata/task_library/image_classifier)\n",
"- エンドツーエンドリファレンスアプリ: [Android](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/android)、[iOS](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/ios)、および [Raspberry PI](https://github.com/tensorflow/examples/tree/master/lite/examples/image_classification/raspberry_pi)\n"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"collapsed_sections": [],
"name": "model_maker_image_classification.ipynb",
"toc_visible": true
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}