Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/ja/hub/tutorials/cropnet_on_device.ipynb
25118 views
Kernel: Python 3

Licensed under the Apache License, Version 2.0 (the "License");

#@title Copyright 2021 The TensorFlow Hub Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ==============================================================================

植物病害検出のための微調整モデル

このノートブックは、TFDS のデータセットまたは独自の作物病害検出データセットで TensorFlow Hub の CropNet モデルを微調整する方法を説明しています。

ここでは次を行います。

  • TFDS キャッサバデータセットまたは独自データをロードする

  • 未知の(負の)例でデータを強化して、より堅牢なモデルを取得する

  • データに画像拡張を適用する

  • TF Hub から CropNet モデルを読み込んで微調整する

  • TFLite モデルをエクスポートし、タスクライブラリMLKit、または TFLite を使用してアプリに直接デプロイできるようにする

インポートと依存関係

開始する前に、Model Maker や最新バージョンの TensorFlow データセットなどの必要な依存関係のいくつかをインストールする必要があります。

!sudo apt install -q libportaudio2 ## image_classifier library requires numpy <= 1.23.5 !pip install "numpy<=1.23.5" !pip install --use-deprecated=legacy-resolver tflite-model-maker-nightly !pip install -U tensorflow-datasets ## scann library requires tensorflow < 2.9.0 !pip install "tensorflow<2.9.0" !pip install "tensorflow-datasets~=4.8.0" # protobuf>=3.12.2 !pip install tensorflow-metadata~=1.10.0 # protobuf>=3.13 ## tensorflowjs requires packaging < 20.10 !pip install "packaging<20.10"
import matplotlib.pyplot as plt import os import seaborn as sns import tensorflow as tf import tensorflow_datasets as tfds from tensorflow_examples.lite.model_maker.core.export_format import ExportFormat from tensorflow_examples.lite.model_maker.core.task import image_preprocessing from tflite_model_maker import image_classifier from tflite_model_maker import ImageClassifierDataLoader from tflite_model_maker.image_classifier import ModelSpec

TFDS データセットをロードして微調整する

TFDS から公開されているキャッサバの葉の病害のデータセットを使用してみましょう。

tfds_name = 'cassava' (ds_train, ds_validation, ds_test), ds_info = tfds.load( name=tfds_name, split=['train', 'validation', 'test'], with_info=True, as_supervised=True) TFLITE_NAME_PREFIX = tfds_name

または、独自データを読み込んで微調整する

TFDS データセットを使用する代わりに、独自のデータでトレーニングすることもできます。このコードスニペットは、独自のカスタムデータセットをロードする方法を示しています。サポートされているデータの構造については、このリンクをご覧ください。ここでは、公開されているキャッサバの葉の病害のデータセットを使用した例を示します。

# data_root_dir = tf.keras.utils.get_file( # 'cassavaleafdata.zip', # 'https://storage.googleapis.com/emcassavadata/cassavaleafdata.zip', # extract=True) # data_root_dir = os.path.splitext(data_root_dir)[0] # Remove the .zip extension # builder = tfds.ImageFolder(data_root_dir) # ds_info = builder.info # ds_train = builder.as_dataset(split='train', as_supervised=True) # ds_validation = builder.as_dataset(split='validation', as_supervised=True) # ds_test = builder.as_dataset(split='test', as_supervised=True)

train split からのサンプルを視覚化する

画像サンプルとそのラベルのクラス ID とクラス名を含むデータセットのいくつかの例を見てみましょう。

_ = tfds.show_examples(ds_train, ds_info)

TFDS データセットから未知の例として使用する画像を追加する

未知の(負の)例をトレーニングデータセットに追加し、それらに新しい未知のクラスラベル番号を割り当てます。目標は、実際に(たとえばフィールドで)使用される際に、予期しないものが見つかった場合に「未知」を予測するオプションを持つモデルを作成することです。

以下に、追加の未知の画像をサンプリングするために使用されるデータセットのリストを示します。多様性を高めるために、3 つの完全に異なるデータセットが含まれています。それらの 1 つは豆の葉の病害のデータセットであるため、モデルはキャッサバ以外の罹病植物にさらされています。

UNKNOWN_TFDS_DATASETS = [{ 'tfds_name': 'imagenet_v2/matched-frequency', 'train_split': 'test[:80%]', 'test_split': 'test[80%:]', 'num_examples_ratio_to_normal': 1.0, }, { 'tfds_name': 'oxford_flowers102', 'train_split': 'train', 'test_split': 'test', 'num_examples_ratio_to_normal': 1.0, }, { 'tfds_name': 'beans', 'train_split': 'train', 'test_split': 'test', 'num_examples_ratio_to_normal': 1.0, }]

UNKNOWN データセットも TFDS からロードされます。

# Load unknown datasets. weights = [ spec['num_examples_ratio_to_normal'] for spec in UNKNOWN_TFDS_DATASETS ] num_unknown_train_examples = sum( int(w * ds_train.cardinality().numpy()) for w in weights) ds_unknown_train = tf.data.Dataset.sample_from_datasets([ tfds.load( name=spec['tfds_name'], split=spec['train_split'], as_supervised=True).repeat(-1) for spec in UNKNOWN_TFDS_DATASETS ], weights).take(num_unknown_train_examples) ds_unknown_train = ds_unknown_train.apply( tf.data.experimental.assert_cardinality(num_unknown_train_examples)) ds_unknown_tests = [ tfds.load( name=spec['tfds_name'], split=spec['test_split'], as_supervised=True) for spec in UNKNOWN_TFDS_DATASETS ] ds_unknown_test = ds_unknown_tests[0] for ds in ds_unknown_tests[1:]: ds_unknown_test = ds_unknown_test.concatenate(ds) # All examples from the unknown datasets will get a new class label number. num_normal_classes = len(ds_info.features['label'].names) unknown_label_value = tf.convert_to_tensor(num_normal_classes, tf.int64) ds_unknown_train = ds_unknown_train.map(lambda image, _: (image, unknown_label_value)) ds_unknown_test = ds_unknown_test.map(lambda image, _: (image, unknown_label_value)) # Merge the normal train dataset with the unknown train dataset. weights = [ ds_train.cardinality().numpy(), ds_unknown_train.cardinality().numpy() ] ds_train_with_unknown = tf.data.Dataset.sample_from_datasets( [ds_train, ds_unknown_train], [float(w) for w in weights]) ds_train_with_unknown = ds_train_with_unknown.apply( tf.data.experimental.assert_cardinality(sum(weights))) print((f"Added {ds_unknown_train.cardinality().numpy()} negative examples." f"Training dataset has now {ds_train_with_unknown.cardinality().numpy()}" ' examples in total.'))

拡張を適用する

すべての画像に対して、それらをより多様化するために、次の点での変更など、いくつかの拡張を適用します。

  • 明るさ

  • コントラスト

  • 彩度

  • 色合い

  • クロップ

これらのタイプの拡張は、モデルを画像入力の変動に対してより堅牢にするのに役立ちます。

def random_crop_and_random_augmentations_fn(image): # preprocess_for_train does random crop and resize internally. image = image_preprocessing.preprocess_for_train(image) image = tf.image.random_brightness(image, 0.2) image = tf.image.random_contrast(image, 0.5, 2.0) image = tf.image.random_saturation(image, 0.75, 1.25) image = tf.image.random_hue(image, 0.1) return image def random_crop_fn(image): # preprocess_for_train does random crop and resize internally. image = image_preprocessing.preprocess_for_train(image) return image def resize_and_center_crop_fn(image): image = tf.image.resize(image, (256, 256)) image = image[16:240, 16:240] return image no_augment_fn = lambda image: image train_augment_fn = lambda image, label: ( random_crop_and_random_augmentations_fn(image), label) eval_augment_fn = lambda image, label: (resize_and_center_crop_fn(image), label)

拡張を適用するには、Dataset クラスの map メソッドを使用します。

ds_train_with_unknown = ds_train_with_unknown.map(train_augment_fn) ds_validation = ds_validation.map(eval_augment_fn) ds_test = ds_test.map(eval_augment_fn) ds_unknown_test = ds_unknown_test.map(eval_augment_fn)

データを Model Maker に適した形式にラップする

これらのデータセットを Model Maker で使用するには、ImageClassifierDataLoader クラスに含まれている必要があります。

label_names = ds_info.features['label'].names + ['UNKNOWN'] train_data = ImageClassifierDataLoader(ds_train_with_unknown, ds_train_with_unknown.cardinality(), label_names) validation_data = ImageClassifierDataLoader(ds_validation, ds_validation.cardinality(), label_names) test_data = ImageClassifierDataLoader(ds_test, ds_test.cardinality(), label_names) unknown_test_data = ImageClassifierDataLoader(ds_unknown_test, ds_unknown_test.cardinality(), label_names)

トレーニングを実行する

TensorFlow Hub には、転移学習に利用できる複数のモデルがあります。

ここでは 1 つを選択でき、引き続き他のものを試して、より良い結果を得るようにすることもできます。

さらに多くのモデルを試してみたい場合は、このコレクションからモデルを追加できます。

#@title Choose a base model model_name = 'mobilenet_v3_large_100_224' #@param ['cropnet_cassava', 'cropnet_concat', 'cropnet_imagenet', 'mobilenet_v3_large_100_224'] map_model_name = { 'cropnet_cassava': 'https://tfhub.dev/google/cropnet/feature_vector/cassava_disease_V1/1', 'cropnet_concat': 'https://tfhub.dev/google/cropnet/feature_vector/concat/1', 'cropnet_imagenet': 'https://tfhub.dev/google/cropnet/feature_vector/imagenet/1', 'mobilenet_v3_large_100_224': 'https://tfhub.dev/google/imagenet/mobilenet_v3_large_100_224/feature_vector/5', } model_handle = map_model_name[model_name]

モデルを微調整するには、Model Maker を使用します。これにより、モデルのトレーニング後にモデルが TFLite に変換されるため、ソリューション全体が簡単になります。

Model Maker は、この変換を可能な限り最良のものにし、後でモデルをデバイスに簡単に展開するために必要なすべての情報を提供します。

モデル仕様は、使用する基本モデルを Model Maker に指示する方法です。

image_model_spec = ModelSpec(uri=model_handle)

ここでの重要な詳細の 1 つは、 train_whole_model を設定することで、トレーニング中にベースモデルが微調整されます。これによりプロセスは遅くなりますが、最終的なモデルの精度は高くなります。 shuffle を設定すると、モデルがランダムにシャッフルされた順序でデータを確認できるようになります。これは、モデル学習のベストプラクティスです。

model = image_classifier.create( train_data, model_spec=image_model_spec, batch_size=128, learning_rate=0.03, epochs=5, shuffle=True, train_whole_model=True, validation_data=validation_data)

test split でモデルを評価する

model.evaluate(test_data)

微調整されたモデルをさらによく理解するには、混同行列を分析することをお勧めします。これは、あるクラスが別のクラスとして予測される頻度を示します。

def predict_class_label_number(dataset): """Runs inference and returns predictions as class label numbers.""" rev_label_names = {l: i for i, l in enumerate(label_names)} return [ rev_label_names[o[0][0]] for o in model.predict_top_k(dataset, batch_size=128) ] def show_confusion_matrix(cm, labels): plt.figure(figsize=(10, 8)) sns.heatmap(cm, xticklabels=labels, yticklabels=labels, annot=True, fmt='g') plt.xlabel('Prediction') plt.ylabel('Label') plt.show()
confusion_mtx = tf.math.confusion_matrix( list(ds_test.map(lambda x, y: y)), predict_class_label_number(test_data), num_classes=len(label_names)) show_confusion_matrix(confusion_mtx, label_names)

未知のテストデータでモデルを評価する

この評価では、モデルの精度はほぼ 1 であると予想されます。モデルがテストされるすべての画像は通常のデータセットに関連していないため、モデルは「未知の」クラスラベルを予測すると予想されます。

model.evaluate(unknown_test_data)

混同行列を印刷します。

unknown_confusion_mtx = tf.math.confusion_matrix( list(ds_unknown_test.map(lambda x, y: y)), predict_class_label_number(unknown_test_data), num_classes=len(label_names)) show_confusion_matrix(unknown_confusion_mtx, label_names)

モデルを TFLite および SavedModel としてエクスポートする

これで、トレーニング済みモデルを TFLite および SavedModel 形式でエクスポートして、デバイスにデプロイし、TensorFlow で推論に使用できるようになりました。

tflite_filename = f'{TFLITE_NAME_PREFIX}_model_{model_name}.tflite' model.export(export_dir='.', tflite_filename=tflite_filename)
# Export saved model version. model.export(export_dir='.', export_format=ExportFormat.SAVED_MODEL)

次のステップ

トレーニングしたばかりのモデルは、モバイルデバイスで使用でき、フィールドに展開することもできます。

モデルをダウンロードするには、colab の左側にある [ファイル] メニューのフォルダーアイコンをクリックして、ダウンロードオプションを選択します。

ここで使用されているものと同じ手法は、ユースケースや他のタイプの画像分類タスクにより適している可能性がある他の植物病害タスクに適用できます。フォローアップして Android アプリにデプロイする場合は、この Android クイックスタートガイド を続行できます。