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

افهم ما هي زيادة بيانات الصورة وكيفية استخدامها باستخدام Keras لمشاريع التعلم العميق الخاصة بك

تصوير كريس لوتون on Unsplash

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

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

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

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

أنواع تكبير بيانات الصورة

يأتي تكبير الصورة بأشكال عديدة ، فيما يلي بعض الأشكال الشائعة - التحول العمودي ، التحول الأفقي ، الوجه العمودي ، التقليب الأفقي ، الدوران ، ضبط السطوع ، والتكبير / التصغير.

سأشرح أولاً تقنيات تكبير الصور المختلفة باستخدام Python و Keras. إذا كنت ترغب في المحاولة ، فتأكد من تثبيت البرامج والحزم التالية:

بمجرد تثبيت Anaconda و TensorFlow ، قم بإنشاء Jupyter Notebook جديد.

التحول العمودي

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

مصدر الصورة: https://commons.wikimedia.org/wiki/File:Qantas_Boeing_747-438ER_VH-OEI_at_LAX.jpg. هذا الملف مرخص بموجب الامتداد جميل إسناد - المشاركة على حد سواء 2.0 عام الترخيص.

يستخدم مقتطف التعليمات البرمجية التالي الامتداد ImageDataGenerator فئة في Keras لتحويل الصورة عموديًا.

ImageDataGenerator يُنشئ class من Keras دفعات من بيانات الصورة مع زيادة البيانات في الوقت الفعلي.

# --- استيراد الوحدات ---
استيراد numpy كـ np
استيراد matplotlib.pyplot كـ PLT
من tensorflow.keras.preprocessing.image استيراد load_img
من tensorflow.keras.preprocessing.image استيراد img_to_array
من tensorflow.keras.preprocessing.image استيراد ImageDataGenerator
# --- تحميل الصورة ---
image_filename = '747.jpg'
img = load_img (image_filename)
# --- تحويل الصورة إلى مصفوفة ثلاثية الأبعاد ---
image_data = img_to_array (img)
# --- تحويل إلى مصفوفة 4-D من عنصر واحد يمثل مصفوفة ثلاثية الأبعاد
# الصورة---
images_data = np.expand_dims (image_data ، المحور = 0)
# --- إنشاء مولد تكبير بيانات الصورة ---
datagen = ImageDataGenerator (width_shift_range = 0.2)
# --- تحضير المكرر ؛ يأخذ flow () مصفوفة 4D ويعيدها
# مكرر يحتوي على مجموعة من الصور ---
train_generator = تدفق البيانات (images_data، batch_size = 1)
الصفوف = 5
الأعمدة = 4
# - ارسم 5 صفوف و 4 أعمدة -
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
# --- احصل على الصورة التالية في الدفعة (صورة واحدة منذ الدفعة
# الحجم هو 1) ---
image_batch = train_generator.next ()

# --- التحويل إلى أعداد صحيحة بدون إشارة للمشاهدة ---
image = image_batch [0] .astype ('uint8')

# --- اعرض الصورة ---
محاور [ص ، ج] .imshow (صورة)
# --ضبط حجم الشكل -
fig.set_size_inches (15,10،XNUMX)

ينتج مقتطف الشفرة أعلاه الناتج التالي:

كما ترى من الإخراج أعلاه ، في كل مرة تقوم فيها باستدعاء next() طريقة من train_generator الكائن ، تحصل على صورة تم تغييرها قليلاً. في مقتطف الشفرة أعلاه ، يتم إرجاع صورة جديدة يتم إزاحتها بنسبة 20٪ بناءً على ارتفاع الصورة الأصلي في كل مرة تتصل فيها بـ next() الأسلوب:

datagen = ImageDataGenerator (width_shift_range = 0.2)

ومن المثير للاهتمام ، بالنسبة لهذا الإصدار من ImageDataGenerator (tensorflow.keras.preprocessing.image) فئة ، مع تحديد width_shift_range تقوم المعلمة بإزاحة الصورة رأسيًا ، بدلاً من أفقيًا (وهو سلوك الأقدمImageDataGeneratorمن keras.preprocessing.image وحدة). وبالمثل ، إذا كنت تريد نقل الصورة أفقيًا ، فأنت بحاجة إلى استخدام ملف height_shift_range المعلمة (انظر القسم التالي).

نلاحظ أن next() ستعيد الطريقة صورة مكبرة لعدة مرات كما تريد. في مقتطف الشفرة أعلاه ، أطلقنا عليه 20 مرة (5 صفوف ضرب 4 أعمدة).

التحول الأفقي

يمكنك الآن محاولة نقل الصورة أفقيًا باستخدام تنسيق height_shift_range المعلمة:

datagen = ImageDataGenerator (height_shift_range = 0.2)
train_generator = تدفق البيانات (images_data، batch_size = 1)
الصفوف = 5
الأعمدة = 4
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
image_batch = train_generator.next ()
image = image_batch [0] .astype ('uint8')
محاور [ص ، ج] .imshow (صورة)
fig.set_size_inches (15,10،XNUMX)

ينتج مقتطف الشفرة أعلاه الناتج التالي:

انعكاس أفقي

أحيانًا يكون من المنطقي قلب الصورة أفقيًا. في حالة الطائرة ، قد تكون مقدمة الطائرة متجهة لليسار أو لليمين:

datagen = ImageDataGenerator (أفقي_فليب = صحيح)
train_generator = تدفق البيانات (images_data، batch_size = 1)
الصفوف = 2
الأعمدة = 2
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
image_batch = train_generator.next ()
image = image_batch [0] .astype ('uint8')
محاور [ص ، ج] .imshow (صورة)
fig.set_size_inches (15,10،XNUMX)

بالنسبة إلى مقتطف الشفرة أعلاه ، يعد إنشاء أربع صور جيدًا بما يكفي لأن مقدمة الطائرة قد تكون إما متجهة لليسار أو لليمين:

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

انعكاس عمودي

تمامًا مثل التقليب الأفقي ، يمكنك أيضًا إجراء التقليب الرأسي:

datagen = ImageDataGenerator (vertical_flip = صحيح)
train_generator = تدفق البيانات (images_data، batch_size = 1)
الصفوف = 2
الأعمدة = 2
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
image_batch = train_generator.next ()
image = image_batch [0] .astype ('uint8')
محاور [ص ، ج] .imshow (صورة)
fig.set_size_inches (15,10،XNUMX)

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

تناوب

الدوران ، كما يوحي الاسم ، يقوم بتدوير صورتك. سيكون هذا مفيدًا جدًا لصورة طائرتنا. تقوم قصاصات التعليمات البرمجية التالية بتدوير الصورة بشكل عشوائي حتى 50 درجة:

datagen = ImageDataGenerator (rotation_range = 50)
train_generator = تدفق البيانات (images_data)
الصفوف = 5
الأعمدة = 4
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
image_batch = train_generator.next ()
image = image_batch [0] .astype ('uint8')
محاور [ص ، ج] .imshow (صورة)
fig.set_size_inches (15,10،XNUMX)

مع الدوران ، يُظهر الإخراج الطائرات في المواضع المختلفة - محاكاة مواقع الإقلاع والهبوط:

سطوع

تقنية أخرى للتكبير هي ضبط سطوع الصورة. يعيّن مقتطف الشفرة التالي نطاقًا من قيم إزاحة السطوع:

datagen = ImageDataGenerator (نطاق السطوع = [0.15,2.0،XNUMX])
train_generator = تدفق البيانات (images_data، batch_size = 1)
الصفوف = 5
الأعمدة = 4
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
image_batch = train_generator.next ()
image = image_batch [0] .astype ('uint8')
محاور [ص ، ج] .imshow (صورة)
fig.set_size_inches (15,10،XNUMX)

يحتوي الإخراج على سلسلة من الصور بدرجات سطوع متفاوتة:

التكبير

يمكنك أيضًا تكبير الصور أو تصغيرها:

datagen = ImageDataGenerator (zoom_range = [5,0.5،XNUMX])
train_generator = تدفق البيانات (images_data، batch_size = 1)
الصفوف = 5
الأعمدة = 4
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
image_batch = train_generator.next ()
image = image_batch [0] .astype ('uint8')
محاور [ص ، ج] .imshow (صورة)
fig.set_size_inches (15,10،XNUMX)

يظهر الإخراج الصورة بنسب التكبير المختلفة:

لاحظ أن تكبير الصور سيغير نسب العرض إلى الارتفاع للصور.

الجمع بين كل الزيادات

بالطبع ، يمكن الجمع بين جميع تقنيات التعزيز المختلفة التي ناقشتها حتى الآن:

datagen = ImageDataGenerator (width_shift_range = 0.2 ،
height_shift_range = 0.2 ،
أفقي_فليب = صحيح ،
rotation_range = 50 ،
نطاق السطوع = [0.15,2.0،XNUMX] ،
zoom_range = [5,0.5،XNUMX]
)
train_generator = تدفق البيانات (images_data، batch_size = 1)الصفوف = 8
الأعمدة = 8
شكل ، محاور = plt.subplots (صفوف ، أعمدة)
لـ r في النطاق (الصفوف):
لـ c في النطاق (الأعمدة):
image_batch = train_generator.next ()
image = image_batch [0] .astype ('uint8')
محاور [ص ، ج] .imshow (صورة)
fig.set_size_inches (15,10،XNUMX)

لاحظ أنني تركت الوجه الرأسي لأنه لا معنى له لمثالنا.

يُظهر الإخراج الآن الصورة مع الزيادات المختلفة المطبقة:

أظهرت الأقسام السابقة أساسيات زيادة بيانات الصورة وكيف يمكن تطبيقها على صورة واحدة. في التعلم العميق ، غالبًا ما نتعامل مع مجموعة من الصور. لنرى الآن كيف يمكن تطبيق تكبير الصورة على مجموعة من الصور. بالنسبة إلى الرسوم التوضيحية ، سأفترض أنه في المجلد الذي يحتوي على دفتر ملاحظات Jupyter ، لديك ملف فواكة المجلد والمجلدات الفرعية التالية:

فواكة
|__موز
| __banana1.jpg
| __banana2.jpg
| __banana3.jpg
| __ ...
|__دوريان
| __durian1.jpg
| __durian2.jpg
| __durian3.jpg
| __ ...
|__البرتقالي
| __orange1.jpg
| __orange2.jpg
| __orange3.jpg
| __ ...
|__الفراولة
| __strawberry1.jpg
| __strawberry2.jpg
| __strawberry3.jpg
| __ ...

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

لتحميل سلسلة من الصور من القرص ، يمكنك الآن استدعاء ملف flow_from_directory() طريقة ImageDataGenerator مثيل بدلاً من flow() طريقة (لتحميل الصور من الذاكرة):

train_datagen = ImageDataGenerator (
أفقي_فليب = صحيح ،
vertical_flip = صحيح ،
rotation_range = 50 ،
)
حجم_الدفعة = 8قطار_المولد = train_datagen.flow_from_directory (
'./الفاكهة'،
target_size = (224,224،XNUMX) ،
color_mode = 'rgb' ،
حجم_الدفعة = حجم_الدفعة ،
class_mode = 'categorical' ،
المراوغة = صحيح)

لاحظ أنني الآن أقوم بتعيين ملف batch_size إلى 8. سترى استخدام حجم الدُفعة قريبًا.

باستخدام أداة التكرار التي تم إرجاعها ، يمكنني العثور على ملصقات مختلفة للفواكه (موز ودوريان وبرتقال وفراولة):

class_dictionary = Train_generator.class_indices# --- إنشاء قاموس التسميات ---
class_dictionary = {value: key for key ، value in
class_dictionary.items ()}
# --- تحويل القاموس إلى قائمة ---
class_list = [قيمة _ ، القيمة في class_dictionary.items ()]
طباعة (class_list)

سترى الناتج التالي:

تم العثور على 54 صورة تنتمي إلى 4 فئات.
["موز" ، "دوريان" ، "برتقالي" ، "فراولة"]

إجمالاً ، هناك إجمالي 54 صورة في 4 مجلدات. أيضا ، class_list متغير يحتوي على قائمة الفواكه.

سأقوم الآن بطباعة مجموعة الصور المعززة التي تم إنشاؤها بواسطة ImageDataGenerator صف دراسي. سأقوم بشكل تعسفي بتعيين الصفوف على 10 ، ولكل صف ، أريد طباعة مجموعة الصور التي تم إرجاعها (وهي 8 في هذا المثال):

الصفوف = 10شكل ، محاور = plt.subplots (صفوف ، حجم_دفعة)لـ r في النطاق (الصفوف):    
# --- احصل على مجموعة الصور المعززة ---
image_batch = train_generator.next ()
# --- احصل على عدد الصور المعادة ---
images_count = image_batch [0] .shape [0]

لـ c في النطاق (images_count):
# --- التحويل إلى أعداد صحيحة بدون إشارة للمشاهدة ---
image = image_batch [0] [c] .astype ('uint8')

# --- عرض الصورة ---
محاور [ص ، ج] .imshow (صورة)

# --- اعرض ملصق الصورة ---
المحاور [r، c] .title.set_text (
class_list [np.argmax (image_batch [1] [c])])
# --- يخفي علامتي x و y ---
المحاور [r، c] .set_xticks ([])
المحاور [r، c] .set_yticks ([])
fig.set_size_inches (15,18،XNUMX)

منذ batch_size تم تعيينه الآن على 8 (ولم يعد 1) ، فإن train_generator.next() طريقة إرجاعك أ دفعة من ثماني صور معززة في كل مرة تسميها. يعتمد عدد الصور التي تم إرجاعها على batch_size التي قمت بتعيينها مسبقًا في flow_from_directory() الأسلوب:

train_generator = train_datagen.flow_from_directory (
'./الفاكهة'،
target_size = (224,224،XNUMX) ،
color_mode = 'rgb' ،
حجم_الدفعة = حجم_الدفعة ، # حجم_دفعة = 8
class_mode = 'categorical' ،
المراوغة = صحيح)

قيمة image_batch متغير (تم إرجاعه بواسطة next() طريقة) عبارة عن مجموعة مكونة من عنصرين:

  • العنصر الأول (image_batch[0]) هي مجموعة من حجم الدفعة الصور (مجموعة 4D)
  • العنصر الثاني (image_batch[1]) يحتوي على تسميات للصور

ينتج مقتطف الشفرة أعلاه الناتج التالي:

لاحظ أنه في الصف السابع ، يوجد مخططان فارغان بدون صور. تذكر أن هناك إجمالي 54 صورة في مجموعة الصور ، وبما أن كل دفعة ترجع 8 صور (لكل صف) ، فإن الصفوف السبعة الأولى ستعرض إجمالي 54 صورة (8 × 6 + 6). يوضح الشكل التالي:

لاحظ أنه يمكنك ضبط rows لأي رقم و ImageDataGenerator سيستمر الفصل في إنشاء صور معززة جديدة لك.

بناء نموذج باستخدام نقل التعلم

أنت تعرف الآن كيفية استخدام ملف ImageDataGenerator لتحميل مجموعات من الصور من القرص للزيادة. لكن كيف تستخدمه للتدريب؟ يوضح مقتطف التعليمات البرمجية التالي كيفية بناء نموذج التعلم العميق باستخدام نقل التعلم.

التعلم عن طريق النقل هو طريقة تعلم الآلة حيث يتم إعادة استخدام نموذج تم تطويره لمهمة ما كنقطة بداية لنموذج في مهمة ثانية. نقل التعلم يقلل من مقدار الوقت الذي تحتاج إلى إنفاقه في التدريب.

من نموذج الاستيراد tensorflow.keras.models
من tensorflow.keras.applications استيراد VGG16
من tensorflow.keras.layers استيراد كثيف ، GlobalAveragePooling2D
# --- عدد الثمار -
NO_CLASSES = max (train_generator.class_indices.values ​​()) + 1
# --- قم بتحميل نموذج VGG16 كنموذج أساسي للتدريب -
base_model = VGG16 (include_top = False، input_shape = (224، 224، 3))
# --- أضف طبقاتنا الخاصة -
س = base_model.output
س = GlobalAveragePooling2D () (x)
x = كثيف (1024 ، التنشيط = 'relu') (x) # أضف طبقات كثيفة لذلك
# أن النموذج يستطيع
# تعلم أكثر تعقيدا
# وظائف و
# تصنيف للأفضل
# النتائج.
x = كثيف (1024 ، التنشيط = 'relu') (x) # طبقة كثيفة 2
x = كثيف (512 ، التنشيط = 'relu') (x) # طبقة كثيفة 3
preds = كثيف (NO_CLASSES ،
التنشيط = 'softmax') (x) # الطبقة النهائية مع
# تفعيل softmax
# --- إنشاء نموذج جديد مع النموذج الأساسي الأصلي
# المدخلات ومخرجات النموذج الجديد ---
النموذج = النموذج (المدخلات = base_model.input ، المخرجات = preds)
# --- لا تدرب أول 19 طبقة - 0..18 -
للطبقة في model.layers [: 19]:
layer.trainable = خطأ
# --- تدريب بقية الطبقات - 19 فصاعدا -
للطبقة في model.layers [19:]:
layer.trainable = صحيح

# --- تجميع النموذج -
model.compile (محسن = 'آدم' ،
الخسارة = 'categorical_crossentropy' ،
المقاييس = ["الدقة"])

إن شرح كيفية عمل التعلم بالنقل هو خارج نطاق هذه المقالة. سأتركه لمقال آخر.

استخدام الصور التي تم إنشاؤها للتدريب

لاستخدام الصور المعززة للتدريب ، قم بتمرير train_generator في fit() طريقة النموذج:

# - تدريب النموذج -
step_size_train = Train_generator.n // Train_generator.batch_size
نموذج صالح(قطار_المولد,
steps_per_epoch = step_size_train ،
العهود = 15)

steps_per_epoch تعني المعلمة أساسًا عدد الخطوات الموجودة في حقبة ما - فهي تعتمد على عدد الصور التي لديك وحجم الدفعة المحدد مسبقًا. إذا قمت بتعيين هذا على رقم كبير ، فأنت تقوم بتدريب متكرر. يجب عليك تعيينه بناءً على هذه الصيغة:

عدد الصور / حجم الدفعة

في مثالنا ، لدينا 54 صورة في المجموع. وهكذا في كل حقبة ، كان ImageDataGenerator سيقوم الفصل بتحويل جميع الصور الـ 54 للتدريب. في كل حقبة ، سيحصل النموذج على أشكال مختلفة من الصور. إذا كان لديك 15 حقبة ، فسيتم إنشاء 15 × 54 اختلافًا للصور وإدخالها في نموذج التدريب.

ImageDataGenerator يسمح class لطرازك بتلقي أشكال جديدة من الصور في كل حقبة. لكن تذكر أنه يقوم فقط بإرجاع الصور المحولة ولا يضيفها إلى مجموعة الصور التي لديك.

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

زيادة بيانات الصورة للتعلم العميق المعاد نشره من المصدر https://towardsdatascience.com/image-data-augmentation-for-deep-learning-77a87fabd2bf؟source=rss—-7f60cf5620c9—4 عبر https://towardsdatascience.com/feed

<!–

->

الطابع الزمني:

اكثر من مستشارو Blockchain