تصنيف الزهور مع نقل التعلم

عرض على TensorFlow.org تشغيل في Google Colab عرض على جيثب تحميل دفتر انظر نموذج TF Hub

هل سبق لك أن رأيت زهرة جميلة وتساءلت عن نوع هذه الزهرة؟ حسنًا ، أنت لست الأول ، لذلك دعونا نبني طريقة لتحديد نوع الزهرة من الصورة!

لتصنيف الصور، وقد أثبتت نوع معين من الشبكة العصبية العميقة، ودعا الى الشبكة العصبية التلافيف أن تكون قوية بشكل خاص. ومع ذلك ، فإن الشبكات العصبية التلافيفية الحديثة لديها ملايين من المعلمات. يتطلب تدريبهم من البداية الكثير من بيانات التدريب المصنفة والكثير من قوة الحوسبة (مئات ساعات GPU أو أكثر). لدينا فقط حوالي ثلاثة آلاف صورة مصنفة ونريد قضاء وقت أقل بكثير ، لذلك نحن بحاجة إلى أن نكون أكثر ذكاءً.

سوف نستخدم تقنية تسمى التعلم نقل حيث نأخذ شبكة المدربين قبل (تدريبهم على حوالي مليون الصور العامة)، واستخدامها لاستخراج الميزات، وتدريب طبقة جديدة على رأس لمهمة الخاصة بنا لتصنيف الصور من الزهور.

يثبت

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

مجموعة بيانات الزهور

تتكون مجموعة بيانات الزهور من صور زهور مع 5 تسميات فئات محتملة.

عند تدريب نموذج التعلم الآلي ، نقوم بتقسيم بياناتنا إلى مجموعات بيانات تدريب واختبار. سنقوم بتدريب النموذج على بيانات التدريب الخاصة بنا ثم تقييم مدى جودة أداء النموذج على البيانات التي لم يسبق لها مثيل - مجموعة الاختبار.

لنقم بتنزيل أمثلة التدريب والاختبار الخاصة بنا (قد يستغرق الأمر بعض الوقت) ونقسمها إلى مجموعات تدريب واختبار.

قم بتشغيل الخليتين التاليتين:

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

استكشف البيانات

تتكون مجموعة بيانات الزهور من أمثلة مصنفة على أنها صور للزهور. يحتوي كل مثال على صورة زهرة JPEG وتسمية الفئة: ما نوع هذه الزهرة. دعونا نعرض بعض الصور مع تسمياتها.

اعرض بعض الصور المصنفة

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

بي إن جي

بناء النموذج

وسوف تحميل TF-محور وحدة مكافحة ناقلات ميزة صورة، كومة المصنف الخطية على ذلك، وإضافة التقاط التدريب والتقييم. تقوم الخلية التالية ببناء رسم بياني TF يصف النموذج وتدريبه ، لكنها لا تدير التدريب (ستكون هذه هي الخطوة التالية).

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)

تدريب الشبكة

الآن بعد أن تم بناء نموذجنا ، دعنا ندربه ونرى كيف يعمل في مجموعة الاختبار الخاصة بنا.

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

بي إن جي

تنبؤات غير صحيحة

دعنا نلقي نظرة فاحصة على أمثلة الاختبار التي أخطأ نموذجنا فيها.

  • هل هناك أي أمثلة مضللة في مجموعة الاختبار الخاصة بنا؟
  • هل هناك أي بيانات سيئة في مجموعة الاختبار - الصور التي ليست في الواقع صورًا للزهور؟
  • هل توجد صور يمكنك من خلالها فهم سبب ارتكاب النموذج لخطأ؟
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]])

بي إن جي

تمارين: تحسين النموذج!

لقد قمنا بتدريب نموذج أساسي ، والآن دعونا نحاول تحسينه لتحقيق دقة أفضل. (تذكر أنك ستحتاج إلى إعادة تشغيل الخلايا عند إجراء تغيير.)

التمرين 1: جرب نموذج صورة مختلف.

باستخدام TF-Hub ، تكون تجربة بعض نماذج الصور المختلفة أمرًا بسيطًا. عادل يحل محل "https://tfhub.dev/google/imagenet/mobilenet_v2_050_128/feature_vector/2" مقبض في hub.Module() دعوة مع مقبض من حدة نمطية مختلفة ثم أعد تشغيل كافة التعليمات البرمجية. يمكنك ان ترى كل وحدات صورة المتاحة في tfhub.dev .

قد يكون خيارا جيدا احدة من الأخرى وحدات MobileNet V2 . العديد من وحدات - بما في ذلك وحدات MobileNet - تم تدريبهم على ImageNet مجموعة البيانات التي تحتوي على أكثر من 1 مليون صورة و 1000 فصول. يوفر اختيار بنية الشبكة مفاضلة بين السرعة ودقة التصنيف: نماذج مثل MobileNet أو NASNet Mobile سريعة وصغيرة ، وقد تم تصميم البنى التقليدية مثل Inception و ResNet من أجل الدقة.

لبنية أكبر التأسيس V3، يمكنك أيضا استكشاف فوائد ما قبل التدريب على نطاق أقرب إلى المهمة الخاصة بك: وهي متوفرة أيضا على وحدة تدريبهم على مجموعة البيانات iNaturalist من النباتات والحيوانات.

التمرين 2: قم بإضافة طبقة مخفية.

كومة طبقة خفية بين ملامح الصورة المستخرجة والمصنف الخطي (في وظيفة create_model() أعلاه). لخلق طبقة غير الخطية الخفية مع مثلا 100 العقد، واستخدام tf.layers.dense مع وحدات المقرر ان 100 ومجموعة التنشيط tf.nn.relu . هل تغيير حجم الطبقة المخفية يؤثر على دقة الاختبار؟ هل إضافة الطبقة المخفية الثانية يحسن الدقة؟

التمرين 3: تغيير المعامِلات الفوقية.

هل عدد متزايد من خطوات التدريب يحسن دقة النهائية؟ يمكنك تغيير معدل التعلم لجعل تلتقي النموذج الخاص بك بسرعة أكبر؟ هل يؤثر حجم التدريب دفعة أداء النموذج الخاص بك؟

التمرين 4: جرب مُحسِّنًا مختلفًا.

استبدال GradientDescentOptimizer الأساسية مع أكثر محسن المحنك، على سبيل المثال AdagradOptimizer . هل يحدث فرقًا في تدريب النموذج الخاص بك؟ إذا كنت ترغب في معرفة المزيد عن فوائد خوارزميات التحسين المختلفة، وتحقق من هذا المنصب .

تريد معرفة المزيد؟

إذا كنت مهتما في نسخة أكثر تطورا من هذا البرنامج التعليمي، وتحقق من صورة TensorFlow إعادة تدريب البرنامج التعليمي الذي يرشدك من خلال تصور التدريب باستخدام TensorBoard، وتقنيات متقدمة مثل بيانات زيادة من خلال تشويه الصور، واستبدال الزهور بيانات لمعرفة من المصنف الصورة على مجموعة البيانات الخاصة بك.

يمكنك معرفة المزيد عن TensorFlow في tensorflow.org وراجع وثائق API TF-محور متاح في tensorflow.org/hub . البحث عن وحدات TensorFlow محور المتاحة في tfhub.dev بما في ذلك وحدات ناقلات أكثر صورة ميزة وحدات تضمين النص.

كما تحقق من آلة التعلم دورة مكثفة وهو سريع الخطى، وإدخال جوجل عملي لتعلم الآلة.