Bitki hastalık tespiti için ince ayar modelleri

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın GitHub'da görüntüle Not defterini indir TF Hub modellerine bakın

Bu not defteri, TensorFlow Hub'dan CropNet modellerini TFDS'den bir veri kümesinde veya kendi mahsul hastalığı saptama veri kümenizde nasıl ince ayar yapacağınızı gösterir.

Olacaksın:

  • TFDS manyok veri setini veya kendi verilerinizi yükleyin
  • Daha sağlam bir model elde etmek için verileri bilinmeyen (negatif) örneklerle zenginleştirin
  • Verilere görüntü büyütmeleri uygulayın
  • TF Hub'dan bir CropNet modeli yükleyin ve ince ayar yapın
  • Doğrudan Görev Kitaplığı , MLKit veya TFLite ile uygulamanıza dağıtılmaya hazır bir TFLite modelini dışa aktarın

İçe Aktarma ve Bağımlılıklar

Başlamadan önce Model Maker ve TensorFlow Datasets'in en son sürümü gibi ihtiyaç duyulacak bazı bağımlılıkları yüklemeniz gerekir.

pip install --use-deprecated=legacy-resolver tflite-model-maker
pip install -U tensorflow-datasets
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
-yer tutucu2 l10n-yer
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_addons/utils/ensure_tf_install.py:67: UserWarning: Tensorflow Addons supports using Python ops for all Tensorflow versions above or equal to 2.5.0 and strictly below 2.8.0 (nightly versions are not supported). 
 The versions of TensorFlow you are currently using is 2.8.0-rc1 and is not supported. 
Some things might work, some things might not.
If you were to encounter a bug, do not file an issue.
If you want to make sure you're using a tested and supported configuration, either change the TensorFlow version or the TensorFlow Addons's version. 
You can find the compatibility matrix in TensorFlow Addon's readme:
https://github.com/tensorflow/addons
  UserWarning,
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/numba/core/errors.py:154: UserWarning: Insufficiently recent colorama version found. Numba requires colorama >= 0.3.9
  warnings.warn(msg)

İnce ayar yapmak için bir TFDS veri kümesi yükleyin

TFDS'den halka açık Cassava Yaprak Hastalığı veri setini kullanalım.

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

Veya alternatif olarak ince ayar yapmak için kendi verilerinizi yükleyin

Bir TFDS veri seti kullanmak yerine, kendi verileriniz üzerinde de eğitim verebilirsiniz. Bu kod parçacığı, kendi özel veri kümenizi nasıl yükleyeceğinizi gösterir. Verilerin desteklenen yapısı için bu bağlantıya bakın. Burada, halka açık Manyok Yaprak Hastalığı veri seti kullanılarak bir örnek verilmiştir.

# 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)

Tren bölümünden örnekleri görselleştirin

Görüntü örnekleri ve etiketleri için sınıf kimliği ve sınıf adı da dahil olmak üzere veri kümesinden bazı örneklere bakalım.

_ = tfds.show_examples(ds_train, ds_info)

png

TFDS veri kümelerinden Bilinmeyen örnekler olarak kullanılacak resimler ekleyin

Eğitim veri kümesine ek bilinmeyen (negatif) örnekler ekleyin ve bunlara yeni bir bilinmeyen sınıf etiket numarası atayın. Amaç, pratikte (örneğin sahada) kullanıldığında, beklenmedik bir şey gördüğünde "Bilinmeyen"i tahmin etme seçeneğine sahip bir modele sahip olmaktır.

Aşağıda, ek bilinmeyen görüntüleri örneklemek için kullanılacak veri kümelerinin bir listesini görebilirsiniz. Çeşitliliği artırmak için tamamen farklı 3 veri seti içerir. Bunlardan biri fasulye yaprağı hastalığı veri setidir, böylece model manyok dışındaki hastalıklı bitkilere maruz kalır.

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 veri kümeleri de TFDS'den yüklenir.

# 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.'))
tutucu8 l10n-yer
Added 16968 negative examples.Training dataset has now 22624 examples in total.

Büyütme uygula

Tüm resimler için, onları daha çeşitli hale getirmek için, aşağıdaki değişiklikler gibi bazı büyütmeler uygulayacaksınız:

  • Parlaklık
  • Zıtlık
  • Doyma
  • renk tonu
  • Mahsul

Bu tür büyütmeler, modeli görüntü girdilerindeki değişikliklere karşı daha sağlam hale getirmeye yardımcı olur.

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)

Büyütmeyi uygulamak için Dataset sınıfından map yöntemini kullanır.

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)
tutucu11 l10n-yer
INFO:tensorflow:Use default resize_bicubic.
INFO:tensorflow:Use default resize_bicubic.
INFO:tensorflow:Use customized resize method bilinear
INFO:tensorflow:Use customized resize method bilinear

Verileri Model Oluşturucu dostu formata sarın

Bu veri kümesini Model Maker ile kullanmak için ImageClassifierDataLoader sınıfında olmaları gerekir.

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)

Eğitimi çalıştırın

TensorFlow Hub , Transfer Learning için birden fazla modele sahiptir.

Burada birini seçebilir ve daha iyi sonuçlar elde etmek için diğerlerini denemeye devam edebilirsiniz.

Daha fazla model denemek isterseniz bu koleksiyondan ekleyebilirsiniz.

Bir temel model seçin

Modele ince ayar yapmak için Model Maker'ı kullanacaksınız. Bu, genel çözümü kolaylaştırır, çünkü modelin eğitiminden sonra da TFLite'a dönüştürülür.

Model Maker, bu dönüşümü mümkün olan en iyi dönüşüm haline getirir ve modeli daha sonra cihaza kolayca yerleştirmek için gerekli tüm bilgilerle birlikte.

Model spesifikasyonu, Model Maker'a hangi temel modeli kullanmak istediğinizi nasıl söylediğinizdir.

image_model_spec = ModelSpec(uri=model_handle)

Buradaki önemli bir ayrıntı, temel modelin eğitim sırasında ince ayarını yapacak olan train_whole_model ayarıdır. Bu, süreci yavaşlatır ancak nihai modelin doğruluğu daha yüksektir. shuffle ayarı, modelin verileri, model öğrenimi için en iyi uygulama olan rastgele karıştırılmış bir sırada görmesini sağlar.

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)
tutucu16 l10n-yer
INFO:tensorflow:Retraining the models...
INFO:tensorflow:Retraining the models...
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 hub_keras_layer_v1v2 (HubKe  (None, 1280)             4226432   
 rasLayerV1V2)                                                   
                                                                 
 dropout (Dropout)           (None, 1280)              0         
                                                                 
 dense (Dense)               (None, 6)                 7686      
                                                                 
=================================================================
Total params: 4,234,118
Trainable params: 4,209,718
Non-trainable params: 24,400
_________________________________________________________________
None
Epoch 1/5
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/optimizer_v2/gradient_descent.py:102: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.
  super(SGD, self).__init__(name, **kwargs)
176/176 [==============================] - 120s 488ms/step - loss: 0.8874 - accuracy: 0.9148 - val_loss: 1.1721 - val_accuracy: 0.7935
Epoch 2/5
176/176 [==============================] - 84s 444ms/step - loss: 0.7907 - accuracy: 0.9532 - val_loss: 1.0761 - val_accuracy: 0.8100
Epoch 3/5
176/176 [==============================] - 85s 441ms/step - loss: 0.7743 - accuracy: 0.9582 - val_loss: 1.0305 - val_accuracy: 0.8444
Epoch 4/5
176/176 [==============================] - 79s 409ms/step - loss: 0.7653 - accuracy: 0.9611 - val_loss: 1.0166 - val_accuracy: 0.8422
Epoch 5/5
176/176 [==============================] - 75s 402ms/step - loss: 0.7534 - accuracy: 0.9665 - val_loss: 0.9988 - val_accuracy: 0.8555

Modeli test bölümünde değerlendirin

model.evaluate(test_data)
tutucu18 l10n-yer
59/59 [==============================] - 10s 81ms/step - loss: 0.9956 - accuracy: 0.8594
[0.9956456422805786, 0.8594164252281189]

İnce ayarlı modeli daha da iyi anlamak için, karışıklık matrisini analiz etmek iyidir. Bu, bir sınıfın başka bir sınıf olarak ne sıklıkla tahmin edildiğini gösterecektir.

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()
tutucu20 l10n-yer
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)

png

Modeli bilinmeyen test verilerine göre değerlendirin

Bu değerlendirmede modelin neredeyse 1 doğrulukta olmasını bekliyoruz. Modelin test edildiği tüm görüntüler normal veri seti ile ilgili değil ve bu nedenle modelin "Bilinmeyen" sınıf etiketini tahmin etmesini bekliyoruz.

model.evaluate(unknown_test_data)
tutucu22 l10n-yer
259/259 [==============================] - 36s 127ms/step - loss: 0.6777 - accuracy: 0.9996
[0.677702784538269, 0.9996375441551208]

Karışıklık matrisini yazdırın.

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)

png

Modeli TFLite ve SavedModel olarak dışa aktarın

Artık eğitilmiş modelleri, cihazda dağıtmak ve TensorFlow'da çıkarım için kullanmak için TFLite ve SavedModel formatlarında dışa aktarabiliriz.

tflite_filename = f'{TFLITE_NAME_PREFIX}_model_{model_name}.tflite'
model.export(export_dir='.', tflite_filename=tflite_filename)
2022-01-26 12:25:57.742415: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmppliqmyki/assets
INFO:tensorflow:Assets written to: /tmp/tmppliqmyki/assets
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/lite/python/convert.py:746: UserWarning: Statistics for quantized inputs were expected, but not specified; continuing anyway.
  warnings.warn("Statistics for quantized inputs were expected, but not "
2022-01-26 12:26:07.247752: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:357] Ignored output_format.
2022-01-26 12:26:07.247806: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:360] Ignored drop_control_dependency.
INFO:tensorflow:Label file is inside the TFLite model with metadata.
fully_quantize: 0, inference_type: 6, input_inference_type: 3, output_inference_type: 3
INFO:tensorflow:Label file is inside the TFLite model with metadata.
INFO:tensorflow:Saving labels in /tmp/tmp_k_gr9mu/labels.txt
INFO:tensorflow:Saving labels in /tmp/tmp_k_gr9mu/labels.txt
INFO:tensorflow:TensorFlow Lite model exported successfully: ./cassava_model_mobilenet_v3_large_100_224.tflite
INFO:tensorflow:TensorFlow Lite model exported successfully: ./cassava_model_mobilenet_v3_large_100_224.tflite
yer tutucu26 l10n-yer
# Export saved model version.
model.export(export_dir='.', export_format=ExportFormat.SAVED_MODEL)
INFO:tensorflow:Assets written to: ./saved_model/assets
INFO:tensorflow:Assets written to: ./saved_model/assets

Sonraki adımlar

Az önce eğittiğiniz model mobil cihazlarda kullanılabilir ve hatta sahada konuşlandırılabilir!

Modeli indirmek için, işbirliğinin sol tarafındaki Dosyalar menüsü için klasör simgesine tıklayın ve indirme seçeneğini seçin.

Burada kullanılan aynı teknik, kullanım durumunuza veya başka herhangi bir görüntü sınıflandırma görevine daha uygun olabilecek diğer bitki hastalıkları görevlerine uygulanabilir. Bir Android uygulamasını takip etmek ve dağıtmak istiyorsanız, bu Android hızlı başlangıç ​​kılavuzuna devam edebilirsiniz.