عامر ابراهيم نشر 22 أغسطس 2021 أرسل تقرير نشر 22 أغسطس 2021 لدي مجموعة بيانات صغيرة لصور (حوالي 2000 عينة فقط)، وأعرف أن هناك تكنيك يسمى Data Augmentation يسمح لنا بزيادة حجم البيانات عن طريق التلاعب بها، لذا هل هناك طريقة للقيام بذلك في تنسرفلو Tensorflow؟ 1 اقتباس
1 Ali Haidar Ahmad نشر 22 أغسطس 2021 أرسل تقرير نشر 22 أغسطس 2021 (معدل) نعم يمكنك القيام بذلك من خلال الكلاس الرائع ImageDataGenerator في تنسرفلو وكيراس. حيث يقوم هذا التابع بتوليد صور جديدة من البيانات الأصلية (يقوم بأخذ صورة ثم يطبق عليها مجموعة من التحويلات مثل زيادة السطوع أو تقليله أو قلب الصورة رأسياً أو أفقياً أو تدويرها أو إزاحة البكسلات . إلخ). وروعته في أنه يقوم بتوليد الصور الجديدة في ال real-time أي بقوم بإنتاجها أثناء تدريب النموذج. وتضمن لك أن النموذج سيتلقى صوراً مختلفة في كل epoch وأيضاً يجب أن تعلم أنه لايقوم بإضافة الصور الجديدة إلى مجموعة البيانات الأصلية (ومن المنطقي جداً حدوث هذا لأنه قد يؤدي إلى ال OF على الصورة). وميزة أخرى لـ ImageDataGenerator هي أنه يتطلب استخدام ذاكرة أقل. حيث يقوم بإنشاء batches بدلاً من توليد كامل مجموعة البيانات ووضعها كلها في الذاكرة. ويمكن إنشائه بالشكل التالي: dataGen=tf.keras.preprocessing.image.ImageDataGenerator( rotation_range=0, width_shift_range=0.0, height_shift_range=0.0, brightness_range=None, shear_range=0.0, zoom_range=0.0, channel_shift_range=0.0, fill_mode="nearest", cval=0.0, horizontal_flip=False, vertical_flip=False, rescale=None, data_format=None, validation_split=0.0 ) هذا الكلاس نحدد له العمليات التي نريد تنفيذها على الصور، فبالنسبة لأول وسيط وهو rotation_range فهو يقوم بتدوير الصورة الأصلية بدرجة معينة نقوم بتحديدها (من 0 إلى 360). لكن عندما يتم تدوير الصورة، ستتحرك بعض وحدات البكسل خارج الصورة وتترك مساحة فارغة يجب ملؤها. يمكنك ملء ذلك بطرق مختلفة مثل القيمة الثابتة "constant" أو أقرب قيم البكسل "nearest" .. إلخ. يتم تحديد هذا في وسيطة fill_mode والقيمة الافتراضية هي "nearest" والتي تقوم ببساطة باستبدال المساحة الفارغة بأقرب قيم للبكسل. أيضاً قد لا يكون الكائن دائماً في وسط الصورة. للتغلب على هذه المشكلة ، يمكننا إزاحة وحدات البكسل في الصورة إما أفقياً أو رأسياً، ويتم ذلك عن طريق إضافة قيمة ثابتة معينة لجميع وحدات البكسل، ويمكننا القيام بذلك من خلال الوسيطة height_shift_range للإزاحة الرأسية و width_shift_range للإزاحة الأفقية للصورة. إذا كانت القيمة رقم float، فسيشير ذلك إلى النسبة المئوية لعرض أو ارتفاع الصورة المراد إزاحتها. بخلاف ذلك ، إذا كانت القيمة عدد صحيح، فسيتم إزاحة العرض أو الارتفاع ببساطة بواسطة قيم البكسل العديدة هذه. يعد قلب الصور أيضاً تقنية رائعة ويمكننا القيام بذلك من خلال الوسيط horizo1ntal_flip و vertical_flip للقلب على طول المحور الرأسي أو الأفقي. ومع ذلك، يجب أن تكون هذه التقنية وفقاً للكائن الموجود في الصورة. على سبيل المثال ، لن يكون القلب الرأسي للسيارة أمراً منطقياً لأنه في البيانات الحقيقية لن يتم اختبار هكذا حالات. أيضاً brightness_range يغير سطوع الصورة بشكل عشوائي. إنها أيضاً تقنية لزيادة البيانات مفيدة للغاية لأن الكائن الخاص بنا لن يكون في حالة إضاءة مثالية في معظم الأوقات. لذلك، يصبح من الضروري تدريب نموذجنا على الصور تحت ظروف الإضاءة المختلفة. ويقبل قائمة من قيمتين عائمتين float ويختار قيمة إزاحة السطوع من هذا النطاق. أيضاً تمثل القيمة 0.0 حالة عدم إضافة أي سطوع بينما القيمة 1.0 تمثل أعظم سطوع. أيضاً يمكنك عمل zoom in و zoom out للصورة من خلال الوسيط zoom_range حيث تعطيه قائمة بقيمتين تحددان الحد الأدنى والحد الأعلى لعملية ال zoom. أو إذا قمت بتحديد قيمة عائمة، فسيتم إجراء التكبير / التصغير في النطاق:[1-zoom_range ، 1 + zoom_range]. أي قيمة أصغر من 1 سيتم تكبير الصورة. في حين أن أي قيمة أكبر من 1 سيتم تصغيرها. أيضاً تسمح لك الوسيطة shear_range بتنفيذ عملية غريبة نوعاً ما فهي تشبه إلى حدما عملية التدوير لكنها تمدد الصورة (تمديد للبكسلات) وأيضاً يجب أن تحدد له درجة لكن هذه الدرجة لاتمثل درجة الدوران وإنما درجة تسمى درجة "القص" أو الميل (ليس لدي فكرة جيدة عنها). أيضاً هناك الوسيطة channel_shift_range التي تسمح لك بتطبيق إزاحة أيضاً لكن على قنوات الصورة. الوسيطة fill_mode كما قلنا من أجل تحديد الآلية التي سيتم فيه تعويض البكسلات التي انتقلت (تغير مكانها). أما cval فتستخدم مع fill mode في حالة اخترنا التكنيك constant وذلك من أجل تحديد القيمة التي نريد التعويض بها (قيمة float طبعاً). أما الوسيطة rescale فهي تمنحنا القدرة على عملي standaraization للصورة (توحيد قيمها لتكون ضمن المجال 0 ل 1) وهذه العملية ضرورية دوماً. أما الوسيط data_format فهو لتحديد ترتيب أبعاد الصورة أي لتحديد فيما إذا كانت القناة هي أخر بعد "channels_last" أو أول بعد"channels_first" . أما الوسيط الأخير فيسمح لنا بأخذ جزء من البيانات ك validation data. الآن بعد أن تقوم بتحديد هذه الوسطاء لباني الصف هذا، كل ماعليك فعله هو استخدام التايع flow_from_directory لقراءة الصور مباشرةً من المجلد وتنفيذ ال augmantaion أثناء تدريب الشبكة العصبية على بيانات التدريب. ويتوقع التابع أن الصور التي تنتمي إلى فئات مختلفة موجودة في مجلدات مختلفة ولكنها داخل نفس المجلد الأصلي. وهذا التابع له الشكل التالي: ImageDataGenerator.flow_from_directory( directory, # المسار الخاص بالمجلد target_size=(256, 256), # حجم الصور color_mode="rgb", # النمط "grayscale", "rgb", "rgba". Default: "rgb" classes=None, # الفئات ويمكنك تحديدها أولا أي أنه اختياري ['dogs', 'cats'] مثلاً class_mode="categorical", batch_size=32, # حجم الباتش للبيانات shuffle=True, # خلط البيانات أو لا save_to_dir=None, # إذا اردت الاحتفاظ بالصور التي تم توليدها ضع له مسار مجلد ليحفظها فيهم save_format="png", # الامتداد الذي تريد حفظ الصور فيه في حال أردت حفظها follow_links=False, subset=None, interpolation="nearest", # تحديد الطريقة التي سيتم فيها تصغير الصورة في حالة كانت أكبر من الحجم المحدد أو أصغر منه ) بالنسبة للوسيط subset يجب أن تحدد في هذه الوسيطة إما ("training" أو "validation") وذلك في حالة كنت قد حدد جزءاً من البيانات ك validation في باني الكلاس. أما class_mode فهو يحدد نوع البيانات التي لديك أي binary أي أن لديك فئتين وبالتالي سيكون لدينا 1D binary labels، أو categorical سيكون لدينا 2D one-hot encoded labels أو sparse سيكون 1D integer labels. أو None وبالتالي هنا لن يقوم بتوليد ال labels للصور لن ينتج عن المُنشئ سوى مجموعات من بيانات الصورة ، وهو أمر مفيد للاستخدام مع model.predict ()). الآن دعنا نرى تطبيقاً عملياً: from keras.models import Sequential from keras.layers import Dense,Conv2D,Dropout,MaxPooling2D,Flatten from keras.preprocessing.image import ImageDataGenerator import cv2 import numpy as np from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D from keras.layers import Activation, Dropout, Flatten, Dense from keras import backend as K ######################################### obj = ImageDataGenerator( rescale=1. / 255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) train_generator = obj.flow_from_directory( '/content/safe/train', target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary') # validation data val_datagen = ImageDataGenerator(rescale=1. / 255) validation_generator = val_datagen.flow_from_directory( '/content/safe/val', target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary') """ Found 2039 images belonging to 2 classes. Found 384 images belonging to 2 classes. """ print(train_generator.class_indices) # {'ClosedFace': 0, 'OpenFace': 1} # Number of Training and Validation Samples nb_train_samples = 2039 nb_validation_samples = 384 ################################## Bulding Model ###############################3 #Instantiation model = Sequential() #1st Convolutional Layer model.add(Conv2D(32, (3, 3), input_shape=(100,100,3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) #2nd Convolutional Layer model.add(Conv2D(32, (3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) #3rd Convolutional Layer model.add(Conv2D(64, (3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) #Passing it to a Fully Connected layer model.add(Flatten()) # 1st Fully Connected Layer model.add(Dense(64)) model.add(Activation('relu')) # Add Dropout to prevent overfitting model.add(Dropout(0.5)) #Output Layer model.add(Dense(1)) model.add(Activation('sigmoid')) # compile model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy']) # Fitting epochs = 15 batch_size = 16 model.fit_generator( train_generator, steps_per_epoch=nb_train_samples // batch_size, epochs=15, validation_data=validation_generator, validation_steps=nb_validation_samples // batch_size) #fit أيضاً يمكنك استخدام الدالة أيضاً في حالة كانت بياناتك موجودة ضمن Dataframe يمكنك استخدام flow_from_dataframe بنفس الطريقة مع اختلاف بسيط وهو تمرير الداتافريم الخاص بك وتحديد العمود الذي يحوي أسماء الملفات والعمود الذي يحوي ال labels: ImageDataGenerator.flow_from_dataframe( dataframe, directory=None, x_col="filename", y_col="class", weight_col=None, target_size=(256, 256), color_mode="rgb", classes=None, class_mode="categorical", batch_size=32, shuffle=True, seed=None, save_to_dir=None, save_prefix="", save_format="png", subset=None, interpolation="nearest", validate_filenames=True, ) تم التعديل في 22 أغسطس 2021 بواسطة Ali Haidar Ahmad اقتباس
السؤال
عامر ابراهيم
لدي مجموعة بيانات صغيرة لصور (حوالي 2000 عينة فقط)، وأعرف أن هناك تكنيك يسمى Data Augmentation يسمح لنا بزيادة حجم البيانات عن طريق التلاعب بها، لذا هل هناك طريقة للقيام بذلك في تنسرفلو Tensorflow؟
1 جواب على هذا السؤال
Recommended Posts
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.