Phân loại hoa với học chuyển giao

Xem trên TensorFlow.org Chạy trong Google Colab Xem trên GitHub Tải xuống sổ ghi chép Xem mô hình TF Hub

Bạn đã bao giờ nhìn thấy một loài hoa đẹp và tự hỏi đó là loài hoa gì chưa? Chà, bạn không phải là người đầu tiên, vì vậy hãy xây dựng một cách để xác định loại hoa từ một bức ảnh!

Để phân loại hình ảnh, một loại đặc biệt của mạng nơron sâu, được gọi là một mạng lưới thần kinh xoắn đã được chứng minh là đặc biệt mạnh mẽ. Tuy nhiên, mạng nơ-ron tích chập hiện đại có hàng triệu tham số. Đào tạo chúng từ đầu đòi hỏi rất nhiều dữ liệu đào tạo được gắn nhãn và rất nhiều sức mạnh tính toán (hàng trăm GPU-giờ trở lên). Chúng tôi chỉ có khoảng ba nghìn bức ảnh được gắn nhãn và muốn tốn ít thời gian hơn nhiều, vì vậy chúng tôi cần phải khéo léo hơn.

Chúng tôi sẽ sử dụng một kỹ thuật gọi là học tập chuyển nơi chúng tôi phải mất một mạng pre-đào tạo (đào tạo về khoảng một triệu hình ảnh nói chung), sử dụng nó để trích xuất các tính năng, và đào tạo một lớp mới trên đầu trang cho nhiệm vụ riêng của chúng ta về phân loại hình ảnh của hoa.

Thành lập

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

Bộ dữ liệu về những bông hoa

Tập dữ liệu về hoa bao gồm các hình ảnh của hoa với 5 nhãn lớp có thể có.

Khi đào tạo một mô hình học máy, chúng tôi chia dữ liệu của mình thành các tập dữ liệu đào tạo và kiểm tra. Chúng tôi sẽ đào tạo mô hình trên dữ liệu đào tạo của chúng tôi và sau đó đánh giá mức độ hoạt động của mô hình trên dữ liệu mà nó chưa từng thấy - bộ thử nghiệm.

Hãy tải xuống các ví dụ đào tạo và kiểm tra của chúng tôi (có thể mất một lúc) và chia chúng thành các bộ đào tạo và kiểm tra.

Chạy hai ô sau:

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

Khám phá dữ liệu

Tập dữ liệu về hoa bao gồm các ví dụ được gắn nhãn các hình ảnh về hoa. Mỗi ví dụ chứa một hình ảnh hoa JPEG và nhãn lớp: loại hoa đó là gì. Hãy hiển thị một vài hình ảnh cùng với nhãn của chúng.

Hiển thị một số hình ảnh được gắn nhãn

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

Xây dựng mô hình

Chúng tôi sẽ tải một TF-Hub mô-đun tính năng hình ảnh vector, ngăn xếp một bộ phân loại tuyến tính vào nó, và thêm đào tạo và đánh giá ops. Ô sau đây xây dựng một đồ thị TF mô tả mô hình và quá trình đào tạo của nó, nhưng nó không chạy quá trình đào tạo (đó sẽ là bước tiếp theo).

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)

Đào tạo mạng

Bây giờ mô hình của chúng tôi đã được xây dựng, hãy đào tạo nó và xem nó hoạt động như thế nào trên bộ thử nghiệm của chúng tôi.

# 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

Dự đoán không chính xác

Hãy xem xét kỹ hơn các ví dụ thử nghiệm mà mô hình của chúng tôi đã sai.

  • Có bất kỳ ví dụ nào bị gắn nhãn sai trong tập thử nghiệm của chúng tôi không?
  • Có bất kỳ dữ liệu xấu nào trong bộ thử nghiệm - những hình ảnh không thực sự là hình ảnh của những bông hoa?
  • Có những hình ảnh mà bạn có thể hiểu tại sao mô hình mắc lỗi không?
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

Bài tập: Cải thiện mô hình!

Chúng tôi đã đào tạo một mô hình cơ sở, bây giờ hãy cố gắng cải thiện nó để đạt được độ chính xác tốt hơn. (Hãy nhớ rằng bạn sẽ cần chạy lại các ô khi thực hiện thay đổi.)

Bài tập 1: Thử một mô hình hình ảnh khác.

Với TF-Hub, việc thử một vài mẫu hình ảnh khác nhau thật đơn giản. Chỉ cần thay thế "https://tfhub.dev/google/imagenet/mobilenet_v2_050_128/feature_vector/2" xử lý trong hub.Module() cuộc gọi với một tay cầm của mô-đun khác nhau và chạy lại tất cả các mã. Bạn có thể thấy tất cả các module hình ảnh có sẵn tại tfhub.dev .

Một sự lựa chọn tốt có thể là một trong những khác module MobileNet V2 . Nhiều người trong số các module - bao gồm cả MobileNet module - được tập huấn về các ImageNet bộ dữ liệu , trong đó có hơn 1 triệu hình ảnh và 1000 các lớp học. Việc chọn kiến ​​trúc mạng mang lại sự cân bằng giữa tốc độ và độ chính xác của phân loại: các mô hình như MobileNet hoặc NASNet Mobile nhanh và nhỏ, các kiến ​​trúc truyền thống hơn như Inception và ResNet được thiết kế để đảm bảo độ chính xác.

Đối với kiến trúc lớn hơn Inception V3, bạn cũng có thể khám phá những lợi ích của việc đào tạo trước trên một tên miền gần gũi hơn với công việc của riêng bạn: nó cũng có sẵn như là một mô-đun đào tạo về dataset iNaturalist của thực vật và động vật.

Bài tập 2: Thêm một lớp ẩn.

Ngăn xếp một lớp ẩn giữa các tính năng hình ảnh trích xuất và phân loại tuyến tính (trong chức năng create_model() ở trên). Để tạo một lớp phi tuyến tính ẩn với ví dụ như 100 nút, sử dụng tf.layers.dense với các đơn vị thiết lập đến 100 và kích hoạt các thiết lập để tf.nn.relu . Việc thay đổi kích thước của lớp ẩn có ảnh hưởng đến độ chính xác của bài kiểm tra không? Việc thêm lớp ẩn thứ hai có cải thiện độ chính xác không?

Bài tập 3: Thay đổi siêu tham số.

Liệu tăng số bước đào tạo cải thiện độ chính xác cuối cùng? Bạn có thể thay đổi tỷ lệ học để làm mô hình hội tụ của bạn nhanh hơn? Việc đào tạo có kích thước hàng loạt ảnh hưởng đến hiệu suất của mô hình của bạn?

Bài tập 4: Hãy thử một trình tối ưu hóa khác.

Thay GradientDescentOptimizer cơ bản với một ưu pha rượu hơn, ví dụ như AdagradOptimizer . Nó có tạo ra sự khác biệt cho việc đào tạo người mẫu của bạn không? Nếu bạn muốn tìm hiểu thêm về lợi ích của các thuật toán tối ưu hóa khác nhau, hãy kiểm tra bài này .

Muốn tìm hiểu thêm?

Nếu bạn đang quan tâm đến một phiên bản cao cấp hơn của hướng dẫn này, hãy kiểm tra các hình ảnh TensorFlow bồi dưỡng hướng dẫn mà bạn đi qua hình dung đào tạo sử dụng TensorBoard, kỹ thuật tiên tiến như bộ dữ liệu tăng thêm bởi bóp méo hình ảnh, và thay thế những bông hoa DataSet để tìm hiểu một phân loại hình ảnh trên tập dữ liệu của riêng bạn.

Bạn có thể tìm hiểu thêm về TensorFlow tại tensorflow.org và xem tài liệu TF-Hub API có sẵn tại tensorflow.org/hub . Tìm sẵn module TensorFlow Hub tại tfhub.dev bao gồm các module vector đặc trưng hình ảnh hơn và các module văn bản nhúng.

Ngoài ra kiểm tra Machine Learning Crash Course đó là nhịp độ nhanh, đưa vào thực tiễn của Google để học máy.