تحميل الصور والمعالجة المسبقة

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

يوضح هذا البرنامج التعليمي كيفية تحميل مجموعة بيانات الصورة ومعالجتها مسبقًا بثلاث طرق:

يثبت

import numpy as np
import os
import PIL
import PIL.Image
import tensorflow as tf
import tensorflow_datasets as tfds
print(tf.__version__)
2.8.0-rc1

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

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

flowers_photos/
  daisy/
  dandelion/
  roses/
  sunflowers/
  tulips/
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file(origin=dataset_url,
                                   fname='flower_photos',
                                   untar=True)
data_dir = pathlib.Path(data_dir)

بعد تنزيل (218 ميجابايت) ، يجب أن يكون لديك الآن نسخة من صور الزهور المتاحة. هناك 3670 صورة إجمالية:

image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)
3670

يحتوي كل دليل على صور من هذا النوع من الزهور. إليك بعض الورود:

roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))

بي إن جي

roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[1]))

بي إن جي

تحميل البيانات باستخدام أداة Keras

لنقم بتحميل هذه الصور من القرص باستخدام الأداة المساعدة tf.keras.utils.image_dataset_from_directory .

أنشئ مجموعة بيانات

حدد بعض المعلمات للمحمل:

batch_size = 32
img_height = 180
img_width = 180

من الممارسات الجيدة استخدام تقسيم التحقق عند تطوير نموذجك. ستستخدم 80٪ من الصور للتدريب و 20٪ للتحقق.

train_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
val_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  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 734 files for validation.

يمكنك العثور على أسماء الفئات في سمة class_names في مجموعات البيانات هذه.

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

تصور البيانات

فيما يلي الصور التسع الأولى من مجموعة بيانات التدريب.

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")

بي إن جي

يمكنك تدريب نموذج باستخدام مجموعات البيانات هذه عن طريق تمريرها إلى model.fit (كما هو موضح لاحقًا في هذا البرنامج التعليمي). إذا كنت ترغب في ذلك ، يمكنك أيضًا التكرار يدويًا عبر مجموعة البيانات واسترداد مجموعات الصور:

for image_batch, labels_batch in train_ds:
  print(image_batch.shape)
  print(labels_batch.shape)
  break
(32, 180, 180, 3)
(32,)

image_batch هو موتر للشكل (32, 180, 180, 3) . هذه دفعة من 32 صورة للشكل 180x180x3 (يشير البعد الأخير إلى قنوات الألوان RGB). label_batch هي موتر للشكل (32,) ، هذه تسميات مطابقة للصور الـ 32.

يمكنك استدعاء .numpy() على أي من هذه الموترات لتحويلها إلى numpy.ndarray .

توحيد البيانات

قيم قناة RGB تقع في النطاق [0, 255] . هذا ليس مثاليًا للشبكة العصبية ؛ بشكل عام يجب أن تسعى إلى جعل قيم المدخلات الخاصة بك صغيرة.

هنا ، ستقوم بتوحيد القيم لتكون في النطاق [0, 1] باستخدام tf.keras.layers.Rescaling :

normalization_layer = tf.keras.layers.Rescaling(1./255)

هناك طريقتان لاستخدام هذه الطبقة. يمكنك تطبيقه على مجموعة البيانات عن طريق استدعاء Dataset.map :

normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
image_batch, labels_batch = next(iter(normalized_ds))
first_image = image_batch[0]
# Notice the pixel values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image))
0.0 0.96902645

أو يمكنك تضمين الطبقة داخل تعريف النموذج لتبسيط عملية النشر. ستستخدم الطريقة الثانية هنا.

تكوين مجموعة البيانات للأداء

دعنا نتأكد من استخدام الجلب المسبق المخزن حتى تتمكن من إنتاج البيانات من القرص دون أن يصبح الإدخال / الإخراج محظورًا. هاتان طريقتان مهمتان يجب عليك استخدامهما عند تحميل البيانات:

  • يحتفظ Dataset.cache بالصور في الذاكرة بعد تحميلها خارج القرص خلال المرحلة الأولى. سيضمن ذلك عدم تحول مجموعة البيانات إلى عنق زجاجة أثناء تدريب نموذجك. إذا كانت مجموعة البيانات الخاصة بك كبيرة جدًا بحيث لا يمكن وضعها في الذاكرة ، فيمكنك أيضًا استخدام هذه الطريقة لإنشاء ذاكرة تخزين مؤقت على القرص.
  • Dataset.prefetch يتداخل مع المعالجة المسبقة للبيانات وتنفيذ النموذج أثناء التدريب.

يمكن للقراء المهتمين معرفة المزيد حول كلتا الطريقتين ، بالإضافة إلى كيفية تخزين البيانات مؤقتًا على القرص في قسم الجلب المسبق للأداء الأفضل باستخدام دليل 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)

تدريب نموذج

للتأكد من اكتمالها ، سوف توضح كيفية تدريب نموذج بسيط باستخدام مجموعات البيانات التي أعددتها للتو.

يتكون النموذج التسلسلي من ثلاث كتل التفاف ( tf.keras.layers.Conv2D ) مع أقصى طبقة تجميع ( tf.keras.layers.MaxPooling2D ) في كل منها. هناك طبقة متصلة بالكامل ( tf.keras.layers.Dense ) مع 128 وحدة فوقها يتم تنشيطها بواسطة وظيفة تنشيط ReLU ( 'relu' ). لم يتم ضبط هذا النموذج بأي شكل من الأشكال - الهدف هو إظهار الآليات التي تستخدم مجموعات البيانات التي أنشأتها للتو. لمعرفة المزيد حول تصنيف الصور ، قم بزيارة البرنامج التعليمي لتصنيف الصور .

num_classes = 5

model = tf.keras.Sequential([
  tf.keras.layers.Rescaling(1./255),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(num_classes)
])

اختر وظيفة محسن tf.keras.optimizers.Adam و tf.keras.losses.SparseCategoricalCrossentropy . لعرض دقة التدريب والتحقق من الصحة لكل فترة تدريب ، قم بتمرير وسيطة metrics إلى Model.compile .

model.compile(
  optimizer='adam',
  loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
  metrics=['accuracy'])
model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 4s 21ms/step - loss: 1.3091 - accuracy: 0.4281 - val_loss: 1.0982 - val_accuracy: 0.5599
Epoch 2/3
92/92 [==============================] - 1s 12ms/step - loss: 1.0196 - accuracy: 0.5879 - val_loss: 0.9572 - val_accuracy: 0.6213
Epoch 3/3
92/92 [==============================] - 1s 12ms/step - loss: 0.8455 - accuracy: 0.6775 - val_loss: 0.8839 - val_accuracy: 0.6512
<keras.callbacks.History at 0x7ff10c168850>

قد تلاحظ أن دقة التحقق منخفضة مقارنةً بدقة التدريب ، مما يشير إلى أن نموذجك يتناسب بشكل زائد. يمكنك معرفة المزيد حول التجهيز الزائد وكيفية تقليله في هذا البرنامج التعليمي .

استخدام tf.data للتحكم الدقيق

تعتبر أداة Keras السابقة للمعالجة المسبقة - tf.keras.utils.image_dataset_from_directory - طريقة ملائمة لإنشاء tf.data.Dataset من دليل للصور.

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

list_ds = tf.data.Dataset.list_files(str(data_dir/'*/*'), shuffle=False)
list_ds = list_ds.shuffle(image_count, reshuffle_each_iteration=False)
for f in list_ds.take(5):
  print(f.numpy())
b'/home/kbuilder/.keras/datasets/flower_photos/roses/14267691818_301aceda07.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/2641151167_3bf1349606_m.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/sunflowers/6495554833_86eb8faa8e_n.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/4578030672_e6aefd45af.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/144686365_d7e96941ee_n.jpg'

يمكن استخدام هيكل الشجرة للملفات لتجميع قائمة class_names .

class_names = np.array(sorted([item.name for item in data_dir.glob('*') if item.name != "LICENSE.txt"]))
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']

قسّم مجموعة البيانات إلى مجموعات تدريب وتحقق:

val_size = int(image_count * 0.2)
train_ds = list_ds.skip(val_size)
val_ds = list_ds.take(val_size)

يمكنك طباعة طول كل مجموعة بيانات على النحو التالي:

print(tf.data.experimental.cardinality(train_ds).numpy())
print(tf.data.experimental.cardinality(val_ds).numpy())
2936
734

اكتب دالة قصيرة تحول مسار ملف إلى زوج (img, label) :

def get_label(file_path):
  # Convert the path to a list of path components
  parts = tf.strings.split(file_path, os.path.sep)
  # The second to last is the class-directory
  one_hot = parts[-2] == class_names
  # Integer encode the label
  return tf.argmax(one_hot)
def decode_img(img):
  # Convert the compressed string to a 3D uint8 tensor
  img = tf.io.decode_jpeg(img, channels=3)
  # Resize the image to the desired size
  return tf.image.resize(img, [img_height, img_width])
def process_path(file_path):
  label = get_label(file_path)
  # Load the raw data from the file as a string
  img = tf.io.read_file(file_path)
  img = decode_img(img)
  return img, label

استخدم Dataset.map لإنشاء مجموعة بيانات image, label :

# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.
train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)
val_ds = val_ds.map(process_path, num_parallel_calls=AUTOTUNE)
for image, label in train_ds.take(1):
  print("Image shape: ", image.numpy().shape)
  print("Label: ", label.numpy())
Image shape:  (180, 180, 3)
Label:  1

تكوين مجموعة البيانات للأداء

لتدريب نموذج باستخدام مجموعة البيانات هذه ، ستحتاج إلى البيانات:

  • ليتم خلطها بشكل جيد.
  • على دفعات.
  • ستكون الدُفعات متاحة في أقرب وقت ممكن.

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

def configure_for_performance(ds):
  ds = ds.cache()
  ds = ds.shuffle(buffer_size=1000)
  ds = ds.batch(batch_size)
  ds = ds.prefetch(buffer_size=AUTOTUNE)
  return ds

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)

تصور البيانات

يمكنك تصور مجموعة البيانات هذه بشكل مشابه لتلك التي قمت بإنشائها مسبقًا:

image_batch, label_batch = next(iter(train_ds))

plt.figure(figsize=(10, 10))
for i in range(9):
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(image_batch[i].numpy().astype("uint8"))
  label = label_batch[i]
  plt.title(class_names[label])
  plt.axis("off")
2022-01-26 06:29:45.209901: 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.

بي إن جي

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

لقد قمت الآن بإنشاء tf.data.Dataset مشابه يدويًا لتلك التي تم إنشاؤها بواسطة tf.keras.utils.image_dataset_from_directory أعلاه. يمكنك متابعة تدريب النموذج به. كما كان من قبل ، سوف تتدرب على فترات قليلة فقط لجعل وقت الجري قصيرًا.

model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 3s 21ms/step - loss: 0.7305 - accuracy: 0.7245 - val_loss: 0.7311 - val_accuracy: 0.7139
Epoch 2/3
92/92 [==============================] - 1s 13ms/step - loss: 0.5279 - accuracy: 0.8069 - val_loss: 0.7021 - val_accuracy: 0.7316
Epoch 3/3
92/92 [==============================] - 1s 13ms/step - loss: 0.3739 - accuracy: 0.8644 - val_loss: 0.8266 - val_accuracy: 0.6948
<keras.callbacks.History at 0x7ff0ee071f10>

استخدام مجموعات بيانات TensorFlow

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

نظرًا لأنك قمت مسبقًا بتحميل مجموعة بيانات الزهور من القرص ، فلنقم الآن باستيرادها باستخدام مجموعات بيانات TensorFlow.

قم بتنزيل مجموعة بيانات الزهور باستخدام مجموعات بيانات TensorFlow:

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

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

num_classes = metadata.features['label'].num_classes
print(num_classes)
5

استرجع صورة من مجموعة البيانات:

get_label_name = metadata.features['label'].int2str

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2022-01-26 06:29:54.281352: 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.

بي إن جي

كما كان من قبل ، تذكر تجميع مجموعات التدريب والتحقق والاختبار للأداء وتعديلها عشوائيًا وتكوينها:

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)
test_ds = configure_for_performance(test_ds)

يمكنك العثور على مثال كامل للعمل مع مجموعة بيانات Flowers و TensorFlow Datasets من خلال زيارة البرنامج التعليمي لزيادة البيانات .

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

أظهر هذا البرنامج التعليمي طريقتين لتحميل الصور من القرص. أولاً ، تعلمت كيفية تحميل مجموعة بيانات الصورة ومعالجتها مسبقًا باستخدام طبقات وأدوات معالجة Keras المسبقة. بعد ذلك ، تعلمت كيفية كتابة مسار إدخال من البداية باستخدام tf.data . أخيرًا ، تعلمت كيفية تنزيل مجموعة بيانات من مجموعات بيانات TensorFlow.

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