In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

تكثير البيانات (data augmentation)

Note: قامت مجموعة المتطوعين في مشروع Tensorflow بترجمة هذا المحتوى. نظرًا لأن هذه الترجمات تعتمد على قاعدة أقصى الجهد (best-effort) ، فلا نضمن أنها انعكاس دقيق وحديث [للمحتوى الرسمي باللغة الإنجليزية](https://www.tensorflow.org/?hl=en). إذا كانت لديك اقتراحات لتحسين هذه الترجمة ، يرجى إرسال "Pull request" إلى مشروع [tensorflow/docs-l10n](https://github.com/tensorflow/docs-l10n). للتطوع أو مراجعة ترجمات المجموعة يرجى ارسال ايميل إلى docs@tensorflow.org.

لمحة

يبيّن هذا الدفتر التعليمي الطرق المستخدمة في معالجة البيانات و تكثيرها باستعمال `tf.image`. تعتبر طريقة تكثير البيانات واحدة من الطّرق الشائعة لتحسين نتائج النماذج و تجنّب الوقوع في مشكلة الإفراط في التّعلم (overfitting)، أنظر في محتوى الدورة التعليمية حول مشكلتَي [الإفراط و التفريط في التعلّم](https://www.tensorflow.org/tutorials/keras/overfit_and_underfit?hl=ar) و كيفية معالجتهما.

إعداد بيئة العمل


In [ ]:
!pip install git+https://github.com/tensorflow/docs

In [ ]:
try:
  %tensorflow_version 2.x
except:
  pass

import urllib

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras import layers
AUTOTUNE = tf.data.experimental.AUTOTUNE

import tensorflow_docs as tfdocs
import tensorflow_docs.plots

import tensorflow_datasets as tfds

import PIL.Image

import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['figure.figsize'] = (12, 5)

import numpy as np
لنستكشف و نختبر طرق تكثير البيانات على صورة واحدة ثمّ سنقوم بعد ذلك بتكثير مجموعة بيانات كاملة.
ابدأ بتنزيل [هذه الصورة](https://commons.wikimedia.org/wiki/File:Felis_catus-cat_on_snow.jpg)، الملتقطة من قبل المصوّر Von.grzanka، لنستعملها في تجربة طرق تكثير البيانات.

In [ ]:
image_path = tf.keras.utils.get_file("cat.jpg", "https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg")
PIL.Image.open(image_path)
تحميل الصورة و تحويلها إلى Tensor.

In [ ]:
image_string=tf.io.read_file(image_path)
image=tf.image.decode_jpeg(image_string,channels=3)
سنستخدم الوظيفة التّالية لرسم و مقارنة الصورة الأصلية مع الصورة الناتجة عن عمليّة التكثير جنبا إلى جنب.

In [ ]:
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)

كثِّر صورة واحدة

نعرض في الأقسام التّالية عدّة طرق لتكثير الصورة.

قلب الصورة

قم بقلب الصورة عموديّا أو أفقيّا.

In [ ]:
flipped = tf.image.flip_left_right(image)
visualize(image, flipped)

حوّل الصورة إلى التدرّج الرمادي

قم بتحويل الصورة إلى التدرّج الرمادي هكذا:

In [ ]:
grayscaled = tf.image.rgb_to_grayscale(image)
visualize(image, tf.squeeze(grayscaled))
plt.colorbar()

إشباع الصورة

قم بإشباع الصورة من خلال توفير عامل إشباع بالطريقة التّالية:

In [ ]:
saturated = tf.image.adjust_saturation(image, 3)
visualize(image, saturated)

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

قم بتغيير درجة سطوع الصورة عن طريق توفير عامل سطوع بالطريقة التّالية:

In [ ]:
bright = tf.image.adjust_brightness(image, 0.4)
visualize(image, bright)

تدوير الصورة

قم بتدوير الصورة 90 درجة للحصول على صورة أخرى بالطريقة التّالية:

In [ ]:
rotated = tf.image.rot90(image)
visualize(image, rotated)

اقتصاص الصورة في المنتصف

قم باقتصاص الصورة في المنتصف إلى الحدّ الذّي تريده بالطريقة التّالية:

In [ ]:
cropped = tf.image.central_crop(image, central_fraction=0.5)
visualize(image,cropped)
أنظر في تفاصيل دليل حزمة الوظائف `tf.image` للتعرّف على المزيد من تقنيات تكثير البيانات.

قم بتكثير مجموعة بيانات ثمّ درّب نموذجًا عليها

نعرض في التّالي كيفية تدريب نموذج على مجموعة بيانات مكثّرة. Note: المشكل الذيّ سنقوم بحلّه هنا هو مُصطنع نوعا ما. فنحن ندرّب نموذج شبكة عصبية ، ذي طبقات متّصلة بالكامل ، ليكون أداءه جيّدا و ثابتا أمام التغييرات التي قد تطرئ على صورة ما (shift invariant). بالنسبة للنماذج التي تتعلّم من الصّور، من الأفضل استخدام الطبقات التلافيفية (convolution layers) بدلاً من الطبقات المتّصلة بالكامل.

In [ ]:
dataset, info =  tfds.load('mnist', as_supervised=True, with_info=True)
train_dataset, test_dataset = dataset['train'], dataset['test']

num_train_examples= info.splits['train'].num_examples
اكتب الوظيفة التّالية ، `augment` ، لتكثير الصّور. ثم قم باستعمالها على مجموعة البيانات. بهذه الطريقة يمكننا تكثير البيانات على الطاير.

In [ ]:
def convert(image, label):
  image = tf.image.convert_image_dtype(image, tf.float32) # Cast and normalize the image to [0,1]
  return image, label

def augment(image,label):
  image,label = convert(image, label)
  image = tf.image.convert_image_dtype(image, tf.float32) # Cast and normalize the image to [0,1]
  image = tf.image.resize_with_crop_or_pad(image, 34, 34) # Add 6 pixels of padding
  image = tf.image.random_crop(image, size=[28, 28, 1]) # Random crop back to 28x28
  image = tf.image.random_brightness(image, max_delta=0.5) # Random brightness

  return image,label

In [ ]:
BATCH_SIZE = 64
# Only use a subset of the data so it's easier to overfit, for this tutorial
NUM_EXAMPLES = 2048
أنشئ مجموعة البيانات المكثّرة

In [ ]:
augmented_train_batches = (
    train_dataset
    # Only train on a subset, so you can quickly see the effect.
    .take(NUM_EXAMPLES)
    .cache()
    .shuffle(num_train_examples//4)
    # The augmentation is added here.
    .map(augment, num_parallel_calls=AUTOTUNE)
    .batch(BATCH_SIZE)
    .prefetch(AUTOTUNE)
)
و أنشئ مجموعة بيانات غير مُكثّرة للمقارنة.

In [ ]:
non_augmented_train_batches = (
    train_dataset
    # Only train on a subset, so you can quickly see the effect.
    .take(NUM_EXAMPLES)
    .cache()
    .shuffle(num_train_examples//4)
    # No augmentation.
    .map(convert, num_parallel_calls=AUTOTUNE)
    .batch(BATCH_SIZE)
    .prefetch(AUTOTUNE)
)
جهّز مجموعة **بيانات التحقُّق** (validation set). هذه الخطوة لا تتغير إن استخدمت عمليّة تكثير البيانات أم لا.

In [ ]:
validation_batches = (
    test_dataset
    .map(convert, num_parallel_calls=AUTOTUNE)
    .batch(2*BATCH_SIZE)
)
أنشئ و جمّع (compile) النموذج. يتكوّن نموذج الشبكة العصبيّة من طبقتين متّصلتين بالكامل. للتبسيط ، لا نستعمل في هذا النموذج طبقة تلافيفية (convolution layer).

In [ ]:
def make_model():
  model = tf.keras.Sequential([
      layers.Flatten(input_shape=(28, 28, 1)),
      layers.Dense(4096, activation='relu'),
      layers.Dense(4096, activation='relu'),
      layers.Dense(10)
  ])
  model.compile(optimizer = 'adam',
                loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
                metrics=['accuracy'])
  return model
درّب النموذج **من دون** تكثير:

In [ ]:
model_without_aug = make_model()

no_aug_history = model_without_aug.fit(non_augmented_train_batches, epochs=50, validation_data=validation_batches)
درّب النموذج باستعمال تكثير البيانات:

In [ ]:
model_with_aug = make_model()

aug_history = model_with_aug.fit(augmented_train_batches, epochs=50, validation_data=validation_batches)

الإستنتاج :

في هذا المثال، يبلغ النموذج المدربّ باستعمال البيانات المكثّرة (augmented data) درجة دقّة تقارب 95% على بيانات التحقّق. هذا أعلى بقليل (+1%) من دقّة النموذج المدرّب من دون إستعمال تقنية تكثير البيانات (non-augmented data).

In [ ]:
plotter = tfdocs.plots.HistoryPlotter()
plotter.plot({"Augmented": aug_history, "Non-Augmented": no_aug_history}, metric = "accuracy")
plt.title("Accuracy")
plt.ylim([0.75,1])
أمّا بالنسبة لقيمة الخسارة، فمن الواضح أنّ النموذج المدرّب بدون تكثير يعاني من مشكلة الإفراط في التعلّم (overfitting). في المقابل ، النموذج المدربّ بالبيانات المكثّرة ، رغم أنّه أبطأ بعض الشئ ، إلاّ أنّه يُتِمُّ عمليّة التدريب بشكل صحيح و لا يعاني من مشكلة الإفراط في التعلّم.

In [ ]:
plotter = tfdocs.plots.HistoryPlotter()
plotter.plot({"Augmented": aug_history, "Non-Augmented": no_aug_history}, metric = "loss")
plt.title("Loss")
plt.ylim([0,1])