Klasifikasi Bunga dengan Pembelajaran Transfer

Lihat di TensorFlow.org Jalankan di Google Colab Lihat di GitHub Unduh buku catatan Lihat model TF Hub

Pernahkah Anda melihat bunga yang indah dan bertanya-tanya bunga apa itu? Nah, Anda bukan yang pertama, jadi mari kita buat cara untuk mengidentifikasi jenis bunga dari sebuah foto!

Untuk mengklasifikasikan gambar, jenis tertentu dari jaringan saraf yang mendalam, disebut jaringan saraf convolutional telah terbukti sangat kuat. Namun, jaringan saraf convolutional modern memiliki jutaan parameter. Melatih mereka dari awal membutuhkan banyak data pelatihan berlabel dan banyak daya komputasi (ratusan GPU-jam atau lebih). Kami hanya memiliki sekitar tiga ribu foto berlabel dan ingin menghabiskan lebih sedikit waktu, jadi kami harus lebih pintar.

Kami akan menggunakan teknik yang disebut mentransfer pembelajaran di mana kita mengambil jaringan pra-dilatih (dilatih pada sekitar satu juta gambar umum), menggunakannya untuk mengekstrak fitur, dan melatih layer baru di atas untuk tugas kita sendiri mengklasifikasi gambar bunga.

Mempersiapkan

import collections
import io
import math
import os
import random
from six.moves import urllib

from IPython.display import clear_output, Image, display, HTML

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

import tensorflow_hub as hub

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn.metrics as sk_metrics
import time
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/compat/v2_compat.py:111: disable_resource_variables (from tensorflow.python.ops.variable_scope) is deprecated and will be removed in a future version.
Instructions for updating:
non-resource variables are not supported in the long term

kumpulan data bunga

Dataset bunga terdiri dari gambar bunga dengan 5 kemungkinan label kelas.

Saat melatih model pembelajaran mesin, kami membagi data menjadi set data pelatihan dan pengujian. Kami akan melatih model pada data pelatihan kami dan kemudian mengevaluasi seberapa baik kinerja model pada data yang belum pernah dilihat - set pengujian.

Mari unduh contoh pelatihan dan pengujian kami (mungkin perlu beberapa saat) dan pisahkan menjadi rangkaian latihan dan pengujian.

Jalankan dua sel berikut:

FLOWERS_DIR = './flower_photos'
TRAIN_FRACTION = 0.8
RANDOM_SEED = 2018


def download_images():
  """If the images aren't already downloaded, save them to FLOWERS_DIR."""
  if not os.path.exists(FLOWERS_DIR):
    DOWNLOAD_URL = 'http://download.tensorflow.org/example_images/flower_photos.tgz'
    print('Downloading flower images from %s...' % DOWNLOAD_URL)
    urllib.request.urlretrieve(DOWNLOAD_URL, 'flower_photos.tgz')
    !tar xfz flower_photos.tgz
  print('Flower photos are located in %s' % FLOWERS_DIR)


def make_train_and_test_sets():
  """Split the data into train and test sets and get the label classes."""
  train_examples, test_examples = [], []
  shuffler = random.Random(RANDOM_SEED)
  is_root = True
  for (dirname, subdirs, filenames) in tf.gfile.Walk(FLOWERS_DIR):
    # The root directory gives us the classes
    if is_root:
      subdirs = sorted(subdirs)
      classes = collections.OrderedDict(enumerate(subdirs))
      label_to_class = dict([(x, i) for i, x in enumerate(subdirs)])
      is_root = False
    # The sub directories give us the image files for training.
    else:
      filenames.sort()
      shuffler.shuffle(filenames)
      full_filenames = [os.path.join(dirname, f) for f in filenames]
      label = dirname.split('/')[-1]
      label_class = label_to_class[label]
      # An example is the image file and it's label class.
      examples = list(zip(full_filenames, [label_class] * len(filenames)))
      num_train = int(len(filenames) * TRAIN_FRACTION)
      train_examples.extend(examples[:num_train])
      test_examples.extend(examples[num_train:])

  shuffler.shuffle(train_examples)
  shuffler.shuffle(test_examples)
  return train_examples, test_examples, classes
# Download the images and split the images into train and test sets.
download_images()
TRAIN_EXAMPLES, TEST_EXAMPLES, CLASSES = make_train_and_test_sets()
NUM_CLASSES = len(CLASSES)

print('\nThe dataset has %d label classes: %s' % (NUM_CLASSES, CLASSES.values()))
print('There are %d training images' % len(TRAIN_EXAMPLES))
print('there are %d test images' % len(TEST_EXAMPLES))
Downloading flower images from http://download.tensorflow.org/example_images/flower_photos.tgz...
Flower photos are located in ./flower_photos

The dataset has 5 label classes: odict_values(['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'])
There are 2934 training images
there are 736 test images

Jelajahi datanya

Kumpulan data bunga terdiri dari contoh yang diberi label gambar bunga. Setiap contoh berisi gambar bunga JPEG dan label kelas: jenis bunga apa itu. Mari kita tampilkan beberapa gambar bersama dengan labelnya.

Tampilkan beberapa gambar berlabel

def get_label(example):
  """Get the label (number) for given example."""
  return example[1]

def get_class(example):
  """Get the class (string) of given example."""
  return CLASSES[get_label(example)]

def get_encoded_image(example):
  """Get the image data (encoded jpg) of given example."""
  image_path = example[0]
  return tf.gfile.GFile(image_path, 'rb').read()

def get_image(example):
  """Get image as np.array of pixels for given example."""
  return plt.imread(io.BytesIO(get_encoded_image(example)), format='jpg')

def display_images(images_and_classes, cols=5):
  """Display given images and their labels in a grid."""
  rows = int(math.ceil(len(images_and_classes) / cols))
  fig = plt.figure()
  fig.set_size_inches(cols * 3, rows * 3)
  for i, (image, flower_class) in enumerate(images_and_classes):
    plt.subplot(rows, cols, i + 1)
    plt.axis('off')
    plt.imshow(image)
    plt.title(flower_class)

NUM_IMAGES = 15
display_images([(get_image(example), get_class(example))
               for example in TRAIN_EXAMPLES[:NUM_IMAGES]])

png

Bangun modelnya

Kami akan memuat TF-Hub modul vektor fitur citra, tumpukan classifier linear di atasnya, dan menambahkan pelatihan dan evaluasi ops. Sel berikut membuat grafik TF yang menjelaskan model dan pelatihannya, tetapi tidak menjalankan pelatihan (itu akan menjadi langkah berikutnya).

LEARNING_RATE = 0.01

tf.reset_default_graph()

# Load a pre-trained TF-Hub module for extracting features from images. We've
# chosen this particular module for speed, but many other choices are available.
image_module = hub.Module('https://tfhub.dev/google/imagenet/mobilenet_v2_035_128/feature_vector/2')

# Preprocessing images into tensors with size expected by the image module.
encoded_images = tf.placeholder(tf.string, shape=[None])
image_size = hub.get_expected_image_size(image_module)


def decode_and_resize_image(encoded):
  decoded = tf.image.decode_jpeg(encoded, channels=3)
  decoded = tf.image.convert_image_dtype(decoded, tf.float32)
  return tf.image.resize_images(decoded, image_size)


batch_images = tf.map_fn(decode_and_resize_image, encoded_images, dtype=tf.float32)

# The image module can be applied as a function to extract feature vectors for a
# batch of images.
features = image_module(batch_images)


def create_model(features):
  """Build a model for classification from extracted features."""
  # Currently, the model is just a single linear layer. You can try to add
  # another layer, but be careful... two linear layers (when activation=None)
  # are equivalent to a single linear layer. You can create a nonlinear layer
  # like this:
  # layer = tf.layers.dense(inputs=..., units=..., activation=tf.nn.relu)
  layer = tf.layers.dense(inputs=features, units=NUM_CLASSES, activation=None)
  return layer


# For each class (kind of flower), the model outputs some real number as a score
# how much the input resembles this class. This vector of numbers is often
# called the "logits".
logits = create_model(features)
labels = tf.placeholder(tf.float32, [None, NUM_CLASSES])

# Mathematically, a good way to measure how much the predicted probabilities
# diverge from the truth is the "cross-entropy" between the two probability
# distributions. For numerical stability, this is best done directly from the
# logits, not the probabilities extracted from them.
cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=labels)
cross_entropy_mean = tf.reduce_mean(cross_entropy)

# Let's add an optimizer so we can train the network.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=LEARNING_RATE)
train_op = optimizer.minimize(loss=cross_entropy_mean)

# The "softmax" function transforms the logits vector into a vector of
# probabilities: non-negative numbers that sum up to one, and the i-th number
# says how likely the input comes from class i.
probabilities = tf.nn.softmax(logits)

# We choose the highest one as the predicted class.
prediction = tf.argmax(probabilities, 1)
correct_prediction = tf.equal(prediction, tf.argmax(labels, 1))

# The accuracy will allow us to eval on our test set. 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
WARNING:tensorflow:From /tmp/ipykernel_3995/2879154528.py:20: calling map_fn (from tensorflow.python.ops.map_fn) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Use fn_output_signature instead
WARNING:tensorflow:From /tmp/ipykernel_3995/2879154528.py:20: calling map_fn (from tensorflow.python.ops.map_fn) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Use fn_output_signature instead
INFO:tensorflow:Saver not created because there are no variables in the graph to restore
INFO:tensorflow:Saver not created because there are no variables in the graph to restore
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:34: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:255: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)

Latih jaringan

Sekarang setelah model kita dibuat, mari kita latih dan lihat bagaimana kinerjanya di set pengujian kita.

# How long will we train the network (number of batches).
NUM_TRAIN_STEPS = 100
# How many training examples we use in each step.
TRAIN_BATCH_SIZE = 10
# How often to evaluate the model performance.
EVAL_EVERY = 10

def get_batch(batch_size=None, test=False):
  """Get a random batch of examples."""
  examples = TEST_EXAMPLES if test else TRAIN_EXAMPLES
  batch_examples = random.sample(examples, batch_size) if batch_size else examples
  return batch_examples

def get_images_and_labels(batch_examples):
  images = [get_encoded_image(e) for e in batch_examples]
  one_hot_labels = [get_label_one_hot(e) for e in batch_examples]
  return images, one_hot_labels

def get_label_one_hot(example):
  """Get the one hot encoding vector for the example."""
  one_hot_vector = np.zeros(NUM_CLASSES)
  np.put(one_hot_vector, get_label(example), 1)
  return one_hot_vector

with tf.Session() as sess:
  sess.run(tf.global_variables_initializer())
  for i in range(NUM_TRAIN_STEPS):
    # Get a random batch of training examples.
    train_batch = get_batch(batch_size=TRAIN_BATCH_SIZE)
    batch_images, batch_labels = get_images_and_labels(train_batch)
    # Run the train_op to train the model.
    train_loss, _, train_accuracy = sess.run(
        [cross_entropy_mean, train_op, accuracy],
        feed_dict={encoded_images: batch_images, labels: batch_labels})
    is_final_step = (i == (NUM_TRAIN_STEPS - 1))
    if i % EVAL_EVERY == 0 or is_final_step:
      # Get a batch of test examples.
      test_batch = get_batch(batch_size=None, test=True)
      batch_images, batch_labels = get_images_and_labels(test_batch)
      # Evaluate how well our model performs on the test set.
      test_loss, test_accuracy, test_prediction, correct_predicate = sess.run(
        [cross_entropy_mean, accuracy, prediction, correct_prediction],
        feed_dict={encoded_images: batch_images, labels: batch_labels})
      print('Test accuracy at step %s: %.2f%%' % (i, (test_accuracy * 100)))
Test accuracy at step 0: 22.01%
Test accuracy at step 10: 52.04%
Test accuracy at step 20: 63.99%
Test accuracy at step 30: 69.97%
Test accuracy at step 40: 74.59%
Test accuracy at step 50: 75.00%
Test accuracy at step 60: 75.00%
Test accuracy at step 70: 78.26%
Test accuracy at step 80: 80.98%
Test accuracy at step 90: 79.21%
Test accuracy at step 99: 80.30%
def show_confusion_matrix(test_labels, predictions):
  """Compute confusion matrix and normalize."""
  confusion = sk_metrics.confusion_matrix(
    np.argmax(test_labels, axis=1), predictions)
  confusion_normalized = confusion.astype("float") / confusion.sum(axis=1)
  axis_labels = list(CLASSES.values())
  ax = sns.heatmap(
      confusion_normalized, xticklabels=axis_labels, yticklabels=axis_labels,
      cmap='Blues', annot=True, fmt='.2f', square=True)
  plt.title("Confusion matrix")
  plt.ylabel("True label")
  plt.xlabel("Predicted label")

show_confusion_matrix(batch_labels, test_prediction)

png

Prediksi yang salah

Mari kita lihat lebih dekat pada contoh pengujian bahwa model kita salah.

  • Apakah ada contoh yang salah label di set pengujian kami?
  • Apakah ada data buruk dalam set pengujian - gambar yang sebenarnya bukan gambar bunga?
  • Apakah ada gambar di mana Anda dapat memahami mengapa model melakukan kesalahan?
incorrect = [
    (example, CLASSES[prediction])
    for example, prediction, is_correct in zip(test_batch, test_prediction, correct_predicate)
    if not is_correct
]
display_images(
  [(get_image(example), "prediction: {0}\nlabel:{1}".format(incorrect_prediction, get_class(example)))
   for (example, incorrect_prediction) in incorrect[:20]])

png

Latihan: Perbaiki modelnya!

Kami telah melatih model dasar, sekarang mari kita coba memperbaikinya untuk mencapai akurasi yang lebih baik. (Ingat bahwa Anda harus menjalankan kembali sel saat membuat perubahan.)

Latihan 1: Cobalah model gambar yang berbeda.

Dengan TF-Hub, mencoba beberapa model gambar yang berbeda itu sederhana. Hanya mengganti "https://tfhub.dev/google/imagenet/mobilenet_v2_050_128/feature_vector/2" pegangan di hub.Module() panggilan dengan pegangan modul yang berbeda dan jalankan kembali semua kode. Anda dapat melihat semua modul gambar yang tersedia di tfhub.dev .

Sebuah pilihan yang baik mungkin menjadi salah satu yang lain modul MobileNet V2 . Banyak dari modul - termasuk MobileNet modul - dilatih pada ImageNet dataset yang berisi lebih dari 1 juta gambar dan 1000 kelas. Memilih arsitektur jaringan memberikan keseimbangan antara kecepatan dan akurasi klasifikasi: model seperti MobileNet atau NASNet Mobile cepat dan kecil, arsitektur yang lebih tradisional seperti Inception dan ResNet dirancang untuk akurasi.

Untuk yang lebih besar arsitektur Inception V3, Anda juga bisa mengeksplorasi manfaat dari pra-pelatihan tentang domain lebih dekat dengan tugas Anda sendiri: itu juga tersedia sebagai modul dilatih pada dataset iNaturalist tanaman dan hewan.

Latihan 2: Tambahkan lapisan tersembunyi.

Stack lapisan tersembunyi di antara fitur citra diekstrak dan classifier linier (dalam fungsi create_model() di atas). Untuk membuat lapisan non-linear tersembunyi dengan misalnya 100 node, digunakan tf.layers.dense dengan unit set ke 100 dan aktivasi set untuk tf.nn.relu . Apakah mengubah ukuran lapisan tersembunyi mempengaruhi akurasi pengujian? Apakah menambahkan lapisan tersembunyi kedua meningkatkan akurasi?

Latihan 3: Ubah hyperparameter.

Apakah peningkatan jumlah langkah pelatihan meningkatkan akurasi akhir? Anda dapat mengubah tingkat belajar untuk membuat konvergen model Anda lebih cepat? Apakah ukuran bets pelatihan mempengaruhi kinerja model Anda?

Latihan 4: Coba pengoptimal yang berbeda.

Mengganti dasar GradientDescentOptimizer dengan canggih optimizer lebih, misalnya AdagradOptimizer . Apakah itu membuat perbedaan untuk pelatihan model Anda? Jika Anda ingin mempelajari lebih lanjut tentang manfaat algoritma optimasi yang berbeda, periksa posting ini .

Ingin belajar lebih banyak?

Jika Anda tertarik dalam versi yang lebih canggih dari tutorial ini, memeriksa TensorFlow gambar pelatihan ulang tutorial yang menuntun Anda melalui visualisasi pelatihan menggunakan TensorBoard, teknik canggih seperti pembesaran dataset dengan mendistorsi gambar, dan mengganti bunga dataset untuk belajar classifier gambar di kumpulan data Anda sendiri.

Anda dapat mempelajari lebih lanjut tentang TensorFlow di tensorflow.org dan melihat TF-Hub dokumentasi API tersedia di tensorflow.org/hub . Cari modul TensorFlow Hub tersedia di tfhub.dev termasuk modul vektor fitur citra yang lebih dan modul embedding teks.

Juga memeriksa Belajar Crash Course Mesin yang cepat, pengenalan praktis Google untuk mesin belajar.