انقل التعلم باستخدام TensorFlow Hub

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

TensorFlow Hub هو مستودع لنماذج TensorFlow المدربة مسبقًا.

يوضح هذا البرنامج التعليمي كيفية:

  1. استخدم نماذج من TensorFlow Hub مع tf.keras .
  2. استخدم نموذج تصنيف الصورة من TensorFlow Hub.
  3. قم بتعلم النقل البسيط لضبط نموذج لفئات الصور الخاصة بك.

يثبت

import numpy as np
import time

import PIL.Image as Image
import matplotlib.pylab as plt

import tensorflow as tf
import tensorflow_hub as hub

import datetime

%load_ext tensorboard

مصنف ImageNet

ستبدأ باستخدام نموذج مصنف تم تدريبه مسبقًا على مجموعة البيانات المعيارية ImageNet - لا يتطلب الأمر تدريبًا أوليًا!

قم بتنزيل المصنف

حدد نموذج MobileNetV2 مدرب مسبقًا من TensorFlow Hub وقم بلفه كطبقة Keras مع hub.KerasLayer . سيعمل أي نموذج مصنف صور متوافق من TensorFlow Hub هنا ، بما في ذلك الأمثلة الواردة في القائمة المنسدلة أدناه.

mobilenet_v2 ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4"
inception_v3 = "https://tfhub.dev/google/imagenet/inception_v3/classification/5"

classifier_model = mobilenet_v2
IMAGE_SHAPE = (224, 224)

classifier = tf.keras.Sequential([
    hub.KerasLayer(classifier_model, input_shape=IMAGE_SHAPE+(3,))
])

قم بتشغيله على صورة واحدة

قم بتنزيل صورة واحدة لتجربة النموذج على:

grace_hopper = tf.keras.utils.get_file('image.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg')
grace_hopper = Image.open(grace_hopper).resize(IMAGE_SHAPE)
grace_hopper
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg
65536/61306 [================================] - 0s 0us/step
73728/61306 [====================================] - 0s 0us/step

بي إن جي

grace_hopper = np.array(grace_hopper)/255.0
grace_hopper.shape
(224, 224, 3)

أضف بعدًا دفعة (باستخدام np.newaxis ) وقم بتمرير الصورة إلى النموذج:

result = classifier.predict(grace_hopper[np.newaxis, ...])
result.shape
(1, 1001)

والنتيجة هي متجه من اللوغاريتمات مكون من 1001 عنصر ، ويصنف احتمالية كل فئة للصورة.

يمكن العثور على معرّف الفئة الأعلى باستخدام tf.math.argmax :

predicted_class = tf.math.argmax(result[0], axis=-1)
predicted_class
<tf.Tensor: shape=(), dtype=int64, numpy=653>

فك التنبؤات

خذ معرف الفئة predicted_class (مثل 653 ) واجلب تسميات مجموعة بيانات ImageNet لفك تشفير التنبؤات:

labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt
16384/10484 [==============================================] - 0s 0us/step
24576/10484 [======================================================================] - 0s 0us/step
plt.imshow(grace_hopper)
plt.axis('off')
predicted_class_name = imagenet_labels[predicted_class]
_ = plt.title("Prediction: " + predicted_class_name.title())

بي إن جي

نقل التعلم البسيط

ولكن ماذا لو كنت تريد إنشاء مصنف مخصص باستخدام مجموعة البيانات الخاصة بك التي تحتوي على فئات غير مضمنة في مجموعة بيانات ImageNet الأصلية (التي تم تدريب النموذج المدرب مسبقًا عليها)؟

للقيام بذلك ، يمكنك:

  1. حدد نموذجًا تم تدريبه مسبقًا من TensorFlow Hub ؛ و
  2. أعد تدريب الطبقة العلوية (الأخيرة) للتعرف على الفئات من مجموعة البيانات المخصصة.

مجموعة البيانات

في هذا المثال ، ستستخدم مجموعة بيانات زهور TensorFlow:

data_root = tf.keras.utils.get_file(
  'flower_photos',
  'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
   untar=True)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
228818944/228813984 [==============================] - 7s 0us/step
228827136/228813984 [==============================] - 7s 0us/step

أولاً ، قم بتحميل هذه البيانات في النموذج باستخدام بيانات الصورة خارج القرص مع tf.keras.utils.image_dataset_from_directory ، والذي سينشئ tf.data.Dataset :

batch_size = 32
img_height = 224
img_width = 224

train_ds = tf.keras.utils.image_dataset_from_directory(
  str(data_root),
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size
)

val_ds = tf.keras.utils.image_dataset_from_directory(
  str(data_root),
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size
)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
Found 3670 files belonging to 5 classes.
Using 734 files for validation.

تتكون مجموعة بيانات الزهور من خمس فئات:

class_names = np.array(train_ds.class_names)
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']

ثانيًا ، نظرًا لأن اصطلاح TensorFlow Hub لنماذج الصور هو توقع مدخلات تعويم في النطاق [0, 1] ، استخدم tf.keras.layers.Rescaling طبقة المعالجة المسبقة لتحقيق ذلك.

normalization_layer = tf.keras.layers.Rescaling(1./255)
train_ds = train_ds.map(lambda x, y: (normalization_layer(x), y)) # Where x—images, y—labels.
val_ds = val_ds.map(lambda x, y: (normalization_layer(x), y)) # Where x—images, y—labels.

ثالثًا ، قم بإنهاء مسار الإدخال باستخدام الجلب المسبق المخزن مع Dataset.prefetch ، بحيث يمكنك الحصول على البيانات من القرص دون حدوث مشكلات في حظر الإدخال / الإخراج.

هذه بعض من أهم طرق tf.data التي يجب عليك استخدامها عند تحميل البيانات. يمكن للقراء المهتمين معرفة المزيد عنها ، بالإضافة إلى كيفية تخزين البيانات مؤقتًا على القرص وتقنيات أخرى ، في الأداء الأفضل باستخدام دليل tf.data API .

AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
for image_batch, labels_batch in train_ds:
  print(image_batch.shape)
  print(labels_batch.shape)
  break
(32, 224, 224, 3)
(32,)
2022-01-26 05:06:19.465331: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

قم بتشغيل المصنف على مجموعة من الصور

الآن ، قم بتشغيل المصنف على مجموعة صور:

result_batch = classifier.predict(train_ds)
predicted_class_names = imagenet_labels[tf.math.argmax(result_batch, axis=-1)]
predicted_class_names
array(['daisy', 'coral fungus', 'rapeseed', ..., 'daisy', 'daisy',
       'birdhouse'], dtype='<U30')

تحقق من كيفية توافق هذه التوقعات مع الصور:

plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)
for n in range(30):
  plt.subplot(6,5,n+1)
  plt.imshow(image_batch[n])
  plt.title(predicted_class_names[n])
  plt.axis('off')
_ = plt.suptitle("ImageNet predictions")

بي إن جي

النتائج أبعد ما تكون عن الكمال ، لكنها معقولة بالنظر إلى أن هذه ليست الفئات التي تم تدريب النموذج عليها (باستثناء "ديزي").

تنزيل نموذج مقطوعة الرأس

يوزع TensorFlow Hub أيضًا النماذج بدون طبقة التصنيف العليا. يمكن استخدامها لأداء نقل التعلم بسهولة.

حدد نموذج MobileNetV2 مدرب مسبقًا من TensorFlow Hub . سيعمل هنا أي نموذج متجه لميزة صورة متوافقة من TensorFlow Hub ، بما في ذلك الأمثلة من القائمة المنسدلة.

mobilenet_v2 = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4"
inception_v3 = "https://tfhub.dev/google/tf2-preview/inception_v3/feature_vector/4"

feature_extractor_model = mobilenet_v2

قم بإنشاء مستخرج الميزة عن طريق لف النموذج المدرب مسبقًا كطبقة Keras مع المحور. hub.KerasLayer . استخدم الوسيطة trainable=False لتجميد المتغيرات ، بحيث يقوم التدريب بتعديل طبقة المصنف الجديدة فقط:

feature_extractor_layer = hub.KerasLayer(
    feature_extractor_model,
    input_shape=(224, 224, 3),
    trainable=False)

يُرجع مستخرج الميزة متجهًا بطول 1280 لكل صورة (يظل حجم دفعة الصورة عند 32 في هذا المثال):

feature_batch = feature_extractor_layer(image_batch)
print(feature_batch.shape)
(32, 1280)

إرفاق رئيس التصنيف

لإكمال النموذج ، قم بلف طبقة مستخرج المعالم في نموذج tf.keras.Sequential وأضف طبقة متصلة بالكامل من أجل التصنيف:

num_classes = len(class_names)

model = tf.keras.Sequential([
  feature_extractor_layer,
  tf.keras.layers.Dense(num_classes)
])

model.summary()
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 keras_layer_1 (KerasLayer)  (None, 1280)              2257984   
                                                                 
 dense (Dense)               (None, 5)                 6405      
                                                                 
=================================================================
Total params: 2,264,389
Trainable params: 6,405
Non-trainable params: 2,257,984
_________________________________________________________________
predictions = model(image_batch)
predictions.shape
TensorShape([32, 5])

تدريب النموذج

استخدم Model.compile لتكوين عملية التدريب وإضافة رد tf.keras.callbacks.TensorBoard لإنشاء السجلات وتخزينها:

model.compile(
  optimizer=tf.keras.optimizers.Adam(),
  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
  metrics=['acc'])

log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(
    log_dir=log_dir,
    histogram_freq=1) # Enable histogram computation for every epoch.

الآن استخدم طريقة Model.fit لتدريب النموذج.

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

NUM_EPOCHS = 10

history = model.fit(train_ds,
                    validation_data=val_ds,
                    epochs=NUM_EPOCHS,
                    callbacks=tensorboard_callback)
Epoch 1/10
92/92 [==============================] - 7s 42ms/step - loss: 0.7904 - acc: 0.7210 - val_loss: 0.4592 - val_acc: 0.8515
Epoch 2/10
92/92 [==============================] - 3s 33ms/step - loss: 0.3850 - acc: 0.8713 - val_loss: 0.3694 - val_acc: 0.8787
Epoch 3/10
92/92 [==============================] - 3s 33ms/step - loss: 0.3027 - acc: 0.9057 - val_loss: 0.3367 - val_acc: 0.8856
Epoch 4/10
92/92 [==============================] - 3s 33ms/step - loss: 0.2524 - acc: 0.9237 - val_loss: 0.3210 - val_acc: 0.8869
Epoch 5/10
92/92 [==============================] - 3s 33ms/step - loss: 0.2164 - acc: 0.9373 - val_loss: 0.3124 - val_acc: 0.8896
Epoch 6/10
92/92 [==============================] - 3s 33ms/step - loss: 0.1888 - acc: 0.9469 - val_loss: 0.3070 - val_acc: 0.8937
Epoch 7/10
92/92 [==============================] - 3s 33ms/step - loss: 0.1668 - acc: 0.9550 - val_loss: 0.3032 - val_acc: 0.9005
Epoch 8/10
92/92 [==============================] - 3s 33ms/step - loss: 0.1487 - acc: 0.9619 - val_loss: 0.3004 - val_acc: 0.9005
Epoch 9/10
92/92 [==============================] - 3s 33ms/step - loss: 0.1335 - acc: 0.9687 - val_loss: 0.2981 - val_acc: 0.9019
Epoch 10/10
92/92 [==============================] - 3s 33ms/step - loss: 0.1206 - acc: 0.9748 - val_loss: 0.2964 - val_acc: 0.9046

ابدأ لوحة TensorBoard لعرض كيفية تغير المقاييس مع كل فترة ولتعقب القيم العددية الأخرى:

%tensorboard --logdir logs/fit

تحقق من التوقعات

احصل على القائمة المرتبة لأسماء الفئات من تنبؤات النموذج:

predicted_batch = model.predict(image_batch)
predicted_id = tf.math.argmax(predicted_batch, axis=-1)
predicted_label_batch = class_names[predicted_id]
print(predicted_label_batch)
['roses' 'dandelion' 'tulips' 'sunflowers' 'dandelion' 'roses' 'dandelion'
 'roses' 'tulips' 'dandelion' 'tulips' 'tulips' 'sunflowers' 'tulips'
 'dandelion' 'roses' 'daisy' 'tulips' 'dandelion' 'dandelion' 'dandelion'
 'tulips' 'sunflowers' 'roses' 'sunflowers' 'dandelion' 'tulips' 'roses'
 'roses' 'sunflowers' 'tulips' 'sunflowers']

ارسم تنبؤات النموذج:

plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)

for n in range(30):
  plt.subplot(6,5,n+1)
  plt.imshow(image_batch[n])
  plt.title(predicted_label_batch[n].title())
  plt.axis('off')
_ = plt.suptitle("Model predictions")

بي إن جي

تصدير وإعادة تحميل النموذج الخاص بك

الآن بعد أن قمت بتدريب النموذج ، قم بتصديره كنموذج SavedModel لإعادة استخدامه لاحقًا.

t = time.time()

export_path = "/tmp/saved_models/{}".format(int(t))
model.save(export_path)

export_path
2022-01-26 05:07:03.429901: 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/saved_models/1643173621/assets
INFO:tensorflow:Assets written to: /tmp/saved_models/1643173621/assets
'/tmp/saved_models/1643173621'

تأكد من أنه يمكنك إعادة تحميل SavedModel وأن النموذج قادر على إخراج نفس النتائج:

reloaded = tf.keras.models.load_model(export_path)
result_batch = model.predict(image_batch)
reloaded_result_batch = reloaded.predict(image_batch)
abs(reloaded_result_batch - result_batch).max()
0.0
reloaded_predicted_id = tf.math.argmax(reloaded_result_batch, axis=-1)
reloaded_predicted_label_batch = class_names[reloaded_predicted_id]
print(reloaded_predicted_label_batch)
['roses' 'dandelion' 'tulips' 'sunflowers' 'dandelion' 'roses' 'dandelion'
 'roses' 'tulips' 'dandelion' 'tulips' 'tulips' 'sunflowers' 'tulips'
 'dandelion' 'roses' 'daisy' 'tulips' 'dandelion' 'dandelion' 'dandelion'
 'tulips' 'sunflowers' 'roses' 'sunflowers' 'dandelion' 'tulips' 'roses'
 'roses' 'sunflowers' 'tulips' 'sunflowers']
plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)
for n in range(30):
  plt.subplot(6,5,n+1)
  plt.imshow(image_batch[n])
  plt.title(reloaded_predicted_label_batch[n].title())
  plt.axis('off')
_ = plt.suptitle("Model predictions")

بي إن جي

الخطوات التالية

يمكنك استخدام SavedModel للتحميل للاستدلال أو تحويله إلى نموذج TensorFlow Lite (للتعلم الآلي على الجهاز) أو نموذج TensorFlow.js (للتعلم الآلي في JavaScript).

اكتشف المزيد من البرامج التعليمية لمعرفة كيفية استخدام النماذج المدربة مسبقًا من TensorFlow Hub في مهام الصور والنص والصوت والفيديو.