כיצד להשתמש במודל מאומן של TensorFlow Hub לסיווג תמונות?

מחבר:
בתאריך:

היכולת של מחשבים לזהות אובייקטים בתמונות נעשית באמצעות מודלים מבוססי קונבולוציה (convolution). הבעיה היא שפיתוח המודלים הוא קשה ומסובך כמו גם הצורך להזין למערכת מספר גדול מאוד של תמונות כדי שתלמד להבחין ביניהם. TensorFlow Hub מאפשר לפתור את הבעיה באמצעות מודלים מאומנים שפיתחו המומחים המובילים בעולם שאנחנו יכולים להשתמש בהם למטרות שלנו.

במדריך זה אני משתמש במודל MobileNet לזיהוי תמונה. המודל קטן יחסית ועל כן משך הזמן שנדרש לאימון ולסיווג פוחת.

ניתן להשתמש בעקרונות שילמדו במדריך במודלים אחרים במאגר TensorFlow Hub.

להורדת הקוד שנפתח במדריך.

 

ייבוא הספריות במדריך

נייבא את הספריות שישמשו אותנו במדריך:

import numpy as np
import matplotlib.pyplot as plt

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Sequential

# download the pretrained model from tensorflow hub
# choose a model from https://tfhub.dev/
import tensorflow_hub as hub
  • numpy בשביל פעולות על מערכים.
  • pyplot בשביל להציג תמונות.
  • המודל מבוסס TensorFlow.
  • את המודל המאומן נביא מ-TensorFlow Hub.

 

יבוא מודל מאומן מ-TensorFlow Hub

במדריך אני משתמש במודל MobileNetV2 שאומן להבחין בין 1,001 קטגוריות של תמונות.

את המודל הורדתי מ-TensorFlow Hub:

ori_model ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4"

# the input shape that the model expects
# - (height, width, channels)
INPUT_SHAPE = (224, 224, 3)

model = Sequential()
model.add(hub.KerasLayer(ori_model, input_shape=INPUT_SHAPE))
  • כל המודלים מרוכזים לפי נושאים בכתובת https://tfhub.dev. משם נכנסתי לכתובת של המודל המבוקש, והעתקתי את כתובת ה-URL שלו.
  • את המודל המאומן הוספתי כשכבה למודל TensorFlow.
  • המשתנה INPUT_SHAPE מגדיר את ממדי התמונה בהתאם לדרישות המודל המאומן: רוחב ואורך 224 פיקסלים ו-3 ערוצי צבע.

מה מבנה המודל?

model.summary()
Model: "sequential"
________________________________________________
Layer (type)             Output Shape    Param #   
=================================================
keras_layer (KerasLayer) (None, 1001)    3540265   
=================================================
Total params: 3,540,265
Trainable params: 0
Non-trainable params: 3,540,265
  • לא ניתן לאמן מחדש את המודל כברירת מחדל. זה חוסך הרבה אבל מגביל אותנו ל-1,001 הקטגוריות עליהם אומן המודל.
  • אנחנו לא יכולים לראות את השכבות של המודל וגם אין לנו אפשרות לאמץ רק חלק מהשכבות כמו שאפשר לעשות במודלים של Keras.

 

עיבוד התמונה ללמידת מכונה

התמונה עליה נבחן את המודל היא:

האם המודל ידע לזהות תמונה של מכונית?

האם המודל יצליח לסווג אותה נכונה?

נכין את התמונה לסיווג באמצעות מודל למידת מכונה. ראשית על ידי התאמת גודל התמונה לדרישות המודל.

הפונקציה הבאה תאפשר להתאים את ממדי התמונה באמצעות אלגוריתמים שונים:

# resize the image to a specific size with various methods
def resize_image(image, height, width, method='nearest_neighbor'):
  if method == 'bilinear':
    resized_image = tf.image.resize(image, size=[height,width], method=tf.image.ResizeMethod.BILINEAR)
  elif method == 'bicubic':
    resized_image = tf.image.resize(image, size=[height,width], method=tf.image.ResizeMethod.BICUBIC)
  elif method == 'area':
    resized_image = tf.image.resize(image, size=[height,width], method=tf.image.ResizeMethod.AREA)
  elif method == 'crop':
    resized_image = tf.image.resize_with_crop_or_pad(image, target_height=height, target_width=width)
  else:
    resized_image = tf.image.resize(image, size=[height,width], method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
  return resized_image
  • חובה להזין את הפונקציה בנתיב לקובץ התמונה ובממדים שלה. האלגוריתם ברירת המחדל הוא nearest_neighbor.

נהפוך את התמונה למערך שאיתו המודל יכול לעבוד:

fileName = 'car.jpg'

# make an array out of an imported image
fileContent = tf.io.read_file(fileName)

# output an RGB image with 3 channels - jpeg
image = tf.image.decode_jpeg(fileContent, channels=3) 

# png
#image = tf.io.decode_png(fileContent, channels=3) 

resized_image = resize_image(image, 224, 224)
  • בהתאם לדרישות המודל נזין אותו במערך שממדיו (224, 224, 3).

נציג את התמונה המעובדת:

# show the resized image
plt.imshow(resized_image)

תמונה שהותאם גודלה לצורך למידת מכונה

ננרמל את התמונה על ידי חלוקה ב-255 - כמספר האפשרויות בכל אחד משלושת ערוצי הצבע:

# divide by 255 
# (number of possibilities inside each color channel)
resized_image = np.array(resized_image)/255.0

מה ממדי התמונה?

resized_image.shape
(224, 224, 3)

ממדי המערך תואמים לנדרש עבור דוגמה בודדת אבל את המודל צריך להזין במערך של דוגמאות. נוסיף ממד כדי לחקות הזנה של אצוות דוגמאות:

# since we use a single sample while
# the model expects arrays we need to add
# a dimension prior to feeding the model
resized_image[np.newaxis, ...].shape
(1, 224, 224, 3)

 

תחזית המודל

מה הסיווג אותו מפיק המודל?

# predict
logits = model.predict(resized_image[np.newaxis, ...])

התוצאה היא מערך של 1,001 לוגריתמים. כל אחד מהם מכיל את הסיכוי שהתמונה שייכת לאחד הקבוצות שהמודל יודע לסווג להם.

# the model produces logits represeting the probabilities of the
# sample being part of each of the 1001 classes that
# the model is able to predict
logits
array([[ 0.5090804 ,  1.6978539 ,  0.62588006, ..., -1.1041079 ,
         1.2932084 , -0.8815598 ]], dtype=float32)
logits.shape
(1, 1001)

מה התוצאה הגבוהה ביותר?

np.amax(logits[0])
6.382544
  • מזה אנחנו יכולים ללמוד שהתוצאה אינה הסתברות שערכה נע בין 0 ל-1.

נפיק מהלוגריתמים את ההסתברויות לשיוך התמונה לאחת הקבוצות:

# map logits to probability
probabilities = tf.nn.softmax(logits)

מה ההסתברויות?

probabilities
tf.Tensor: shape=(1, 1001), dtype=float32, numpy=
array([[4.6058584e-04, 1.5121275e-03, 5.1764987e-04, ..., 9.1772345e-05,
        1.0089116e-03, 1.1464713e-04]], dtype=float32)

נשלוף מתוך 1,001 ההסתברויות את האינדקסים של חמש הגבוהות ביותר:

# get the five highest proabale classes indices
# predicted_class = np.argmax(predictions)
# predicted_class
predicted_indices = np.asarray(probabilities[0]).argsort()[-5:][::-1]
array([622, 596, 585, 804, 867])

נתרגם את האינדקסים לקטגוריות בשלב הבא.

 

פירוש סיווג המודל

כדי שנוכל לתרגם את האינדקסים המספריים לקטגוריות שמיות אנחנו צריכים קודם כל להוריד את רשימת הקטגוריות:

import urllib.request

labels_url = 'https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt'

labels = []
labels_data = urllib.request.urlopen(labels_url) # it's a file like object and works just like a file
for label in labels_data: # files are iterable
    labels.append(label.decode('utf-8').strip('\n'))
  • התוצאה היא רשימה של קטגוריות אותם קיבצנו לתוך המערך labels.

איזו קטגוריה היא הסבירה ביותר?

# what's the highest probable class
plt.imshow(resized_image)
plt.axis('off')
_ = plt.title("Predicted class: " + labels[predicted_indices[0]])

המודל זיהה מכסחת דשא

הקטגוריה הסבירה ביותר על פי המודל היא מכסחת דשא.

מהם חמש הקטגוריות הסבירות ביותר?

# what's the 5 highest probable classes
for predicted_index in predicted_indices:
  proba = np.asarray(probabilities[0])[predicted_index] * 100
  print(labels[predicted_index], "{:.2f}".format(proba) , '%')
lawn mower 16.37 %
harvester 10.91 %
hair slide 3.15 %
snowplow 3.10 %
tractor 2.37 %

חמש הקטגוריות הסבירות ביותר הם: מכסחת דשא, קומביין, סיכת ראש, מפלסת שלג, טרקטור. עם מכסחת דשא כקטגוריה הסבירה ביותר הזוכה למידת בטחון של 16%. סבירות נמוכה המעידה על כך שהמודל מתקשה בזיהוי התמונה.

המודל שבו השתמשנו במדריך MobileNet הוא מהיר אך פחות מדויק. כדי לשפר את מידת הדיוק אפשר לאמן את המודל על הקטגוריות הספציפיות בהם אנו מעוניינים או להשתמש במודלים גדולים ומסורבלים יותר, דוגמת: VGG16 בו נשתמש לסיווג תמונות במדריך סיווג תמונות באמצעות מודל מאומן VGG16 על מסד נתונים שהורדנו מ-kaggle.

 

לכל המדריכים בנושא של למידת מכונה

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

הוסף תגובה חדשה

 

= 6 + 3