احفظ التاريخ! يعود مؤتمر Google I / O من 18 إلى 20 مايو. سجل الآن
ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

زيادة البيانات

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

ملخص

يوضح هذا البرنامج التعليمي زيادة البيانات: تقنية لزيادة تنوع مجموعة التدريب الخاصة بك عن طريق تطبيق تحويلات عشوائية (لكن واقعية) مثل تدوير الصورة. سوف تتعلم كيفية تطبيق زيادة البيانات بطريقتين. أولاً ، سوف تستخدم Keras Preprocessing Layers . بعد ذلك ، ستستخدم tf.image .

يثبت

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds

from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist

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

يستخدم هذا البرنامج التعليمي مجموعة بيانات tf_flowers . للراحة ، قم بتنزيل مجموعة البيانات باستخدام مجموعات بيانات 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,
)
Downloading and preparing dataset 218.21 MiB (download: 218.21 MiB, generated: 221.83 MiB, total: 440.05 MiB) to /home/kbuilder/tensorflow_datasets/tf_flowers/3.0.1...
Dataset tf_flowers downloaded and prepared to /home/kbuilder/tensorflow_datasets/tf_flowers/3.0.1. Subsequent calls will reuse this data.

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

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

بي إن جي

استخدم طبقات معالجة Keras

تغيير الحجم وإعادة القياس

يمكنك استخدام طبقات المعالجة المسبقة لتغيير حجم صورك إلى شكل متناسق ، ولإعادة قياس قيم البكسل.

IMG_SIZE = 180

resize_and_rescale = tf.keras.Sequential([
  layers.experimental.preprocessing.Resizing(IMG_SIZE, IMG_SIZE),
  layers.experimental.preprocessing.Rescaling(1./255)
])

يمكنك رؤية نتيجة تطبيق هذه الطبقات على صورة ما.

result = resize_and_rescale(image)
_ = plt.imshow(result)

بي إن جي

يمكنك التحقق من أن البيكسلات في [0-1] .

print("Min and max pixel values:", result.numpy().min(), result.numpy().max())
Min and max pixel values: 0.0 1.0

زيادة البيانات

يمكنك استخدام طبقات المعالجة المسبقة لزيادة البيانات أيضًا.

لنقم بإنشاء بعض طبقات المعالجة المسبقة ونطبقها بشكل متكرر على نفس الصورة.

data_augmentation = tf.keras.Sequential([
  layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
  layers.experimental.preprocessing.RandomRotation(0.2),
])
# Add the image to a batch
image = tf.expand_dims(image, 0)
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = data_augmentation(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0])
  plt.axis("off")

بي إن جي

هناك مجموعة متنوعة من طبقات المعالجة المسبقة التي يمكنك استخدامها لزيادة البيانات بما في ذلك layers.RandomContrast ، layers.RandomCrop ، layers.RandomZoom ، layers.RandomZoom ، layers.RandomZoom ، layers.RandomZoom ، وغيرها.

خياران لاستخدام طبقات المعالجة المسبقة

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

الخيار 1: اجعل طبقات المعالجة المسبقة جزءًا من نموذجك

model = tf.keras.Sequential([
  resize_and_rescale,
  data_augmentation,
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  # Rest of your model
])

هناك نقطتان مهمتان يجب الانتباه لهما في هذه الحالة:

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

  • عند تصدير النموذج الخاص بك باستخدام model.save ، سيتم حفظ طبقات المعالجة المسبقة مع باقي نموذجك. إذا قمت بنشر هذا النموذج لاحقًا ، فسيقوم تلقائيًا بتوحيد الصور (وفقًا لتكوين طبقاتك). يمكن أن يوفر لك هذا الجهد المبذول لإعادة تنفيذ هذا المنطق من جانب الخادم.

الخيار 2: تطبيق طبقات المعالجة المسبقة على مجموعة البيانات الخاصة بك

aug_ds = train_ds.map(
  lambda x, y: (resize_and_rescale(x, training=True), y))

باستخدام هذا الأسلوب ، يمكنك استخدام Dataset.map لإنشاء مجموعة بيانات تنتج دفعات من الصور المدمجة. في هذه الحالة:

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

يمكنك العثور على مثال على الخيار الأول في البرنامج التعليمي لتصنيف الصور . دعنا نوضح الخيار الثاني هنا.

قم بتطبيق طبقات المعالجة المسبقة على مجموعات البيانات

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

batch_size = 32
AUTOTUNE = tf.data.AUTOTUNE

def prepare(ds, shuffle=False, augment=False):
  # Resize and rescale all datasets
  ds = ds.map(lambda x, y: (resize_and_rescale(x), y), 
              num_parallel_calls=AUTOTUNE)

  if shuffle:
    ds = ds.shuffle(1000)

  # Batch all datasets
  ds = ds.batch(batch_size)

  # Use data augmentation only on the training set
  if augment:
    ds = ds.map(lambda x, y: (data_augmentation(x, training=True), y), 
                num_parallel_calls=AUTOTUNE)

  # Use buffered prefecting on all datasets
  return ds.prefetch(buffer_size=AUTOTUNE)
train_ds = prepare(train_ds, shuffle=True, augment=True)
val_ds = prepare(val_ds)
test_ds = prepare(test_ds)

تدريب نموذج

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

model = tf.keras.Sequential([
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
epochs=5
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
Epoch 1/5
92/92 [==============================] - 17s 47ms/step - loss: 1.6206 - accuracy: 0.2998 - val_loss: 1.1271 - val_accuracy: 0.5613
Epoch 2/5
92/92 [==============================] - 3s 28ms/step - loss: 1.0935 - accuracy: 0.5384 - val_loss: 1.0343 - val_accuracy: 0.5858
Epoch 3/5
92/92 [==============================] - 3s 27ms/step - loss: 0.9785 - accuracy: 0.6022 - val_loss: 0.8810 - val_accuracy: 0.6540
Epoch 4/5
92/92 [==============================] - 3s 27ms/step - loss: 0.9167 - accuracy: 0.6399 - val_loss: 0.8247 - val_accuracy: 0.6594
Epoch 5/5
92/92 [==============================] - 3s 27ms/step - loss: 0.8545 - accuracy: 0.6615 - val_loss: 0.8591 - val_accuracy: 0.6458
loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
12/12 [==============================] - 0s 13ms/step - loss: 0.9010 - accuracy: 0.6131
Accuracy 0.6130790114402771

زيادة البيانات المخصصة

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

def random_invert_img(x, p=0.5):
  if  tf.random.uniform([]) < p:
    x = (255-x)
  else:
    x
  return x
def random_invert(factor=0.5):
  return layers.Lambda(lambda x: random_invert_img(x, factor))

random_invert = random_invert()
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = random_invert(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0].numpy().astype("uint8"))
  plt.axis("off")

بي إن جي

بعد ذلك ، قم بتنفيذ طبقة مخصصة عن طريق التصنيف الفرعي .

class RandomInvert(layers.Layer):
  def __init__(self, factor=0.5, **kwargs):
    super().__init__(**kwargs)
    self.factor = factor

  def call(self, x):
    return random_invert_img(x)
_ = plt.imshow(RandomInvert()(image)[0])

بي إن جي

يمكن استخدام كلتا الطبقتين كما هو موضح في الخيارين 1 و 2 أعلاه.

باستخدام tf.image

layers.preprocessing أعلاه. أدوات layers.preprocessing مريحة. للحصول على تحكم أكثر دقة ، يمكنك كتابة خطوط أو طبقات زيادة البيانات الخاصة بك باستخدام tf.data و tf.image . قد ترغب أيضًا في التحقق من TensorFlow Addons Image: Operations و TensorFlow I / O: تحويلات مساحة اللون

نظرًا لأنه تم تكوين مجموعة بيانات الزهور مسبقًا مع زيادة البيانات ، فلنقم بإعادة استيرادها للبدء من جديد.

(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,
)

استرجع صورة للعمل معها.

09 بدا 41720

بي إن جي

دعنا نستخدم الوظيفة التالية لتصور ومقارنة الصور الأصلية والمُعزَّزة جنبًا إلى جنب.

def visualize(original, augmented):
  fig = plt.figure()
  plt.subplot(1,2,1)
  plt.title('Original image')
  plt.imshow(original)

  plt.subplot(1,2,2)
  plt.title('Augmented image')
  plt.imshow(augmented)

زيادة البيانات

تقليب الصورة

اقلب الصورة رأسيًا أو أفقيًا.

flipped = tf.image.flip_left_right(image)
visualize(image, flipped)

بي إن جي

تدرج الصورة باللون الرمادي

صورة بتدرج الرمادي.

grayscaled = tf.image.rgb_to_grayscale(image)
visualize(image, tf.squeeze(grayscaled))
_ = plt.colorbar()

بي إن جي

تشبع الصورة

تشبع صورة من خلال توفير عامل تشبع.

05 دي 89650

بي إن جي

تغيير سطوع الصورة

قم بتغيير سطوع الصورة عن طريق توفير عامل سطوع.

bright = tf.image.adjust_brightness(image, 0.4)
visualize(image, bright)

بي إن جي

مركز اقتصاص الصورة

قم بقص الصورة من المنتصف إلى جزء الصورة الذي تريده.

cropped = tf.image.central_crop(image, central_fraction=0.5)
visualize(image,cropped)

بي إن جي

قم بتدوير الصورة

قم بتدوير الصورة بمقدار 90 درجة.

rotated = tf.image.rot90(image)
visualize(image, rotated)

بي إن جي

تحولات عشوائية

يمكن أن يساعد تطبيق تحويلات عشوائية على الصور في تعميم وتوسيع مجموعة البيانات. توفر واجهة برمجة تطبيقات tf.image الحالية 8 عمليات صور عشوائية (OPs):

عمليات الصور العشوائية هذه وظيفية بحتة: يعتمد الإخراج فقط على الإدخال. هذا يجعلها سهلة الاستخدام في خطوط أنابيب الإدخال الحتمية عالية الأداء. أنها تتطلب seed قيمة أن يكون مدخلا كل خطوة. بالنظر إلى نفس seed ، فإنها ترجع نفس النتائج بغض النظر عن عدد المرات التي يتم استدعاؤها.

في الأقسام التالية سوف نقوم بما يلي:

  1. راجع أمثلة استخدام عمليات الصورة العشوائية لتحويل صورة ، و
  2. اشرح كيفية تطبيق التحويلات العشوائية على مجموعة بيانات التدريب.

قم بتغيير سطوع الصورة بشكل عشوائي

قم بتغيير سطوع image عشوائيًا من خلال توفير عامل سطوع seed . يتم اختيار عامل السطوع عشوائيًا في النطاق [-max_delta, max_delta) ويرتبط seed المحددة.

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_brightness = tf.image.stateless_random_brightness(
      image, max_delta=0.95, seed=seed)
  visualize(image, stateless_random_brightness)

بي إن جي

بي إن جي

بي إن جي

قم بتغيير تباين الصورة بشكل عشوائي

قم بتغيير تباين image عشوائيًا عن طريق توفير نطاق تباين seed . يتم اختيار نطاق التباين عشوائيًا في الفاصل الزمني [lower, upper] ويرتبط seed المعينة.

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_contrast = tf.image.stateless_random_contrast(
      image, lower=0.1, upper=0.9, seed=seed)
  visualize(image, stateless_random_contrast)

بي إن جي

بي إن جي

بي إن جي

اقتصاص الصورة بشكل عشوائي

image المحاصيل بشكل عشوائي من خلال توفير size المستهدف seed . الجزء الذي يتم اقتصاصه من image يكون في إزاحة مختار عشوائيًا ويرتبط seed المعينة.

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_crop = tf.image.stateless_random_crop(
      image, size=[210, 300, 3], seed=seed)
  visualize(image, stateless_random_crop)

بي إن جي

بي إن جي

بي إن جي

تطبيق الزيادة على مجموعة البيانات

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

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

دعنا نحدد وظيفة مفيدة لتغيير حجم الصور وإعادة قياسها. سيتم استخدام هذه الوظيفة في توحيد حجم وحجم الصور في مجموعة البيانات:

def resize_and_rescale(image, label):
  image = tf.cast(image, tf.float32)
  image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])
  image = (image / 255.0)
  return image, label

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

def augment(image_label, seed):
  image, label = image_label
  image, label = resize_and_rescale(image, label)
  image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6)
  # Make a new seed
  new_seed = tf.random.experimental.stateless_split(seed, num=1)[0, :]
  # Random crop back to the original size
  image = tf.image.stateless_random_crop(
      image, size=[IMG_SIZE, IMG_SIZE, 3], seed=seed)
  # Random brightness
  image = tf.image.stateless_random_brightness(
      image, max_delta=0.5, seed=new_seed)
  image = tf.clip_by_value(image, 0, 1)
  return image, label

الخيار 1: استخدام tf.data.experimental.Counter()

إنشاء tf.data.experimental.Counter() الكائن (دعنا نسميها counter )، و zip ورقة العمل مع (counter, counter) . وهذا يضمن أن كل صورة في مجموعة البيانات يحصل المرتبطة قيمة فريدة (الشكل (2,) ) على أساس counter أي فيما بعد يمكن الحصول على تمريرها إلى augment وظيفة مثل seed قيمة التحولات العشوائية.

# Create counter and zip together with train dataset
counter = tf.data.experimental.Counter()
train_ds = tf.data.Dataset.zip((train_datasets, (counter, counter)))

خريطة augment وظيفة لمجموعة البيانات التدريب.

train_ds = (
    train_ds
    .shuffle(1000)
    .map(augment, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

الخيار 2: استخدام tf.random.Generator

إنشاء tf.random.Generator الكائن مع intial seed القيمة. داعيا make_seeds تعمل على نفس الكائن مولد بإرجاع جديدة، فريدة من نوعها seed قيمة دائما. تعريف دالة المجمع أن 1) يدعو make_seeds وظيفة والتي 2) يمر الذي تم إنشاؤه حديثا seed قيمة في augment وظيفة للالتحولات العشوائية.

# Create a generator
rng = tf.random.Generator.from_seed(123, alg='philox')
# A wrapper function for updating seeds
def f(x, y):
  seed = rng.make_seeds(2)[0]
  image, label = augment((x, y), seed)
  return image, label

عيّن وظيفة الغلاف f لمجموعة بيانات التدريب.

train_ds = (
    train_datasets
    .shuffle(1000)
    .map(f, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

يمكن الآن استخدام مجموعات البيانات هذه لتدريب نموذج كما هو موضح سابقًا.

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

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