הגדלת נתוני תמונה ללמידה עמוקה

הבן מהי הגדלת נתוני תמונה וכיצד להשתמש בו באמצעות Keras עבור פרויקטי הלמידה העמוקה שלך

תמונה על ידי כריס לוטון on Unsplash

אם אי פעם ניסית לבצע זיהוי תמונות באמצעות למידה עמוקה, אתה יודע את החשיבות של מערך נתונים טוב לאימון. עם זאת, לא תמיד קל למצוא מספיק תמונות לאימון, והדיוק של המודל שלך תלוי ישירות באיכות נתוני האימון.

למרבה המזל, ישנן טכניקות שבהן אתה יכול להשתמש כדי להשלים את מערך הנתונים של התמונות שהם משתמשים בהם לאימון. אחת הטכניקות נקראת הגדלת נתוני תמונה. במאמר זה, אדון במה זה הגדלת נתוני תמונה, איך זה עובד, למה זה שימושי בלמידה עמוקה ולבסוף איך לבצע הגדלת נתוני תמונה באמצעות ספריית Keras.

הגדלת נתוני תמונה היא טכניקה ש יוצר תמונות חדשות מתמונות קיימות. כדי לעשות זאת, אתה מבצע כמה שינויים קטנים בהם, כגון התאמת בהירות התמונה, או סיבוב התמונה, או הזזת הנושא בתמונה אופקית או אנכית.

טכניקות הגדלת תמונה מאפשרות לך להגדיל באופן מלאכותי את גודל ערכת האימונים שלך, ובכך לספק הרבה יותר נתונים למודל שלך לאימון. זה מאפשר לך לשפר את הדיוק של המודל שלך על ידי שיפור היכולת של המודל שלך לזהות גרסאות חדשות של נתוני האימון שלך.

סוגי הגדלת נתוני תמונה

הגדלת תמונה מגיעה בצורות רבות, הנה כמה מהנפוצות שבהן - תזוזה אנכית, תזוזה אופקית, היפוך אנכי, היפוך אופקי, סיבוב, התאמת בהירות והקטנה.

תחילה אדגים את טכניקות הגדלת התמונה השונות באמצעות Python ו-Keras. אם אתה רוצה לנסות, ודא שהתקנת את התוכנה והחבילות הבאות:

לאחר התקנת Anaconda ו-TensorFlow, צור מחברת Jupyter חדשה.

שינוי אנכי

טכניקת הגדלת התמונה הראשונה שאני רוצה להראות היא תזוזה אנכית. ה תזוזה אנכית מעביר באופן אקראי את התמונה אנכית למעלה או למטה. עבור דוגמה זו, אני הולך להשתמש בתמונה בשם 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 import load_img
מאת tensorflow.keras.preprocessing.image import img_to_array
מאת tensorflow.keras.preprocessing.image ייבוא ​​ImageDataGenerator
#---טען את התמונה---
image_filename = '747.jpg'
img = load_img(שם_קובץ_תמונה)
#---המר את התמונה למערך תלת מימד---
image_data = img_to_array(img)
#---המר למערך 4-D של אלמנט אחד של מערך 1D המייצג
# התמונה---
images_data = np.expand_dims(image_data, axis=0)
#---צור מחולל הגדלת נתוני תמונה---
datagen = ImageDataGenerator(width_shift_range=0.2)
#---הכן את האיטרטור; flow() לוקח מערך 4D ומחזיר
# איטרטור המכיל אצווה של תמונות---
train_generator = datagen.flow(images_data, batch_size=1)
שורות = 5
עמודות = 4
#---חלק 5 שורות ו-4 עמודות---
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
#---קבל את התמונה הבאה באצווה (תמונה אחת מאז האצווה
גודל אחד הוא 1)---
image_batch = train_generator.next()

#---המר למספרים שלמים ללא סימנים לצפייה---
image = image_batch[0].astype('uint8')

#---הצג את התמונה---
axes[r,c].imshow(image)
#---הגדר את גודל הדמות---
fig.set_size_inches(15,10)

קטע הקוד שלמעלה מייצר את הפלט הבא:

כפי שאתה יכול לראות מהפלט למעלה, בכל פעם שאתה מתקשר ל- next() שיטה מתוך train_generator אובייקט, תקבל תמונה ששונתה מעט. בקטע הקוד שלמעלה, תמונה חדשה המוזזת ב-20% על סמך גובה התמונה המקורי שלה מוחזרת בכל פעם שאתה קורא ל- next() שיטה:

datagen = ImageDataGenerator(width_shift_range=0.2)

מעניין, עבור גרסה זו של ImageDataGenerator (tensorflow.keras.preprocessing.image) class, תוך ציון ה 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 = datagen.flow(images_data, batch_size=1)
שורות = 5
עמודות = 4
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
axes[r,c].imshow(image)
fig.set_size_inches(15,10)

קטע הקוד שלמעלה מייצר את הפלט הבא:

היפוך אופקי

לפעמים זה הגיוני להפוך את התמונה אופקית. במקרה של מטוס, חזית המטוס עשויה להיות פונה שמאלה או ימינה:

datagen = ImageDataGenerator(horizontal_flip=נכון)
train_generator = datagen.flow(images_data, batch_size=1)
שורות = 2
עמודות = 2
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
axes[r,c].imshow(image)
fig.set_size_inches(15,10)

עבור קטע הקוד שלמעלה, יצירת ארבע תמונות מספיקה שכן חזית המטוס עשויה להיות פונה שמאלה או ימינה:

זכור שההיפוך הוא אקראי (לפעמים אתה מקבל את כל ארבע התמונות המקוריות ולפעמים אתה מקבל תמונות שהופכות אופקית). סביר להניח שארבע תמונות למעלה עשויות להיות זהות. אם זה קורה, פשוט הפעל שוב את גוש הקוד הזה.

Flip אנכי

בדיוק כמו היפוך אופקי, אתה יכול גם לבצע היפוך אנכי:

datagen = ImageDataGenerator(vertical_flip=נכון)
train_generator = datagen.flow(images_data, batch_size=1)
שורות = 2
עמודות = 2
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
axes[r,c].imshow(image)
fig.set_size_inches(15,10)

במקרה של מטוסים, אולי זה לא הגיוני להעיף את המטוס שלנו על הפוך! אם אתם מנסים לבצע זיהוי תמונה, רוב הסיכויים שתמונות המטוסים שלכם זקורות, ולכן אימון הדגם שלכם לזהות מטוסים הפוכים עשוי להיות לא נפוץ מדי. במקרים אחרים, היפוך אנכי הגיוני מאוד.

רוטציה

סיבוב, כפי שהשם מרמז, מסובב את התמונה שלך. זה יהיה מאוד שימושי עבור תמונת המטוס שלנו. קטעי הקוד הבאים מסובבים את התמונה באופן אקראי עד 50 מעלות:

datagen = ImageDataGenerator(rotation_range=50)
train_generator = datagen.flow(images_data)
שורות = 5
עמודות = 4
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
axes[r,c].imshow(image)
fig.set_size_inches(15,10)

עם סיבוב, הפלט מציג את המטוסים בעמדות השונות - המדמה את עמדות ההמראה והנחיתה:

בְּהִירוּת

טכניקת הגדלה נוספת היא התאמת בהירות התמונה. קטע הקוד הבא מגדיר טווח של ערכי שינוי בהירות:

datagen = ImageDataGenerator(טווח_בהירות=[0.15,2.0])
train_generator = datagen.flow(images_data, batch_size=1)
שורות = 5
עמודות = 4
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
axes[r,c].imshow(image)
fig.set_size_inches(15,10)

הפלט מכיל סדרה של תמונות בבהירות משתנה:

מתקרב

אתה יכול גם להגדיל או להקטין את התמונות:

datagen = ImageDataGenerator(zoom_range=[5,0.5])
train_generator = datagen.flow(images_data, batch_size=1)
שורות = 5
עמודות = 4
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
axes[r,c].imshow(image)
fig.set_size_inches(15,10)

הפלט מציג את התמונה ביחסי הזום השונים:

שימו לב שהגדלה של התמונות תשנה את יחסי הגובה-רוחב של התמונות.

שילוב של כל ההגדלות

כמובן שניתן לשלב את כל טכניקות ההגדלה השונות עליהן דיברתי עד כה:

datagen = ImageDataGenerator(width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=נכון,
rotation_range=50,
טווח_בהירות=[0.15,2.0],
zoom_range=[5,0.5]
)
train_generator = datagen.flow(images_data, batch_size=1)שורות = 8
עמודות = 8
fig, axes = plt.subplots(rows,columns)
עבור r בטווח(שורות):
עבור c בטווח (עמודות):
image_batch = train_generator.next()
image = image_batch[0].astype('uint8')
axes[r,c].imshow(image)
fig.set_size_inches(15,10)

שימו לב שעזבתי את ההיפוך האנכי מכיוון שזה לא הגיוני עבור הדוגמה שלנו.

הפלט מציג כעת את התמונה עם ההגדלות השונות שהוחלו:

הסעיפים הקודמים הראו את היסודות של הגדלת נתוני תמונה וכיצד ניתן ליישם אותה על תמונה בודדת. בלמידה עמוקה, אנו עוסקים לעתים קרובות בסט של תמונות. אז בואו נראה כעת כיצד ניתן להחיל הגדלת תמונה על סט תמונות. לצורך איורים, אני הולך להניח שבתיקיה המכילה את מחברת 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
|__ ...

כל תיקיית משנה מכילה קבוצה של תמונות. לדוגמה, ה בננה התיקיה מכילה מספר תמונות בשם banana1.jpg, banana2.jpg, וכולי. שם תיקיות המשנה ישמש כתוויות לתמונות השונות. המשמעות היא שכל הקבצים תחת ה בננה התיקייה מכילה תמונות של בננה וכן הלאה.

כדי לטעון סדרה של תמונות מהדיסק, כעת אתה קורא ל- flow_from_directory() השיטה של ImageDataGenerator מופע במקום ה flow() שיטה (לטעינת תמונות מהזיכרון):

train_datagen = ImageDataGenerator(
horizontal_flip=נכון,
vertical_flip=נכון,
rotation_range=50,
)
batch_size = 8רכבת_מחולל = train_datagen.flow_from_directory(
'./פירות',
target_size=(224,224),
color_mode='rgb',
batch_size=batch_size,
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()]
print(class_list)

תראה את הפלט הבא:

נמצאו 54 תמונות השייכות ל-4 מחלקות.
['בננה', 'דוריאן', 'כתום', 'תות']

בסך הכל יש 54 תמונות ב-4 תיקיות. וגם ה class_list המשתנה מכיל את רשימת הפירות.

כעת אדפיס את סט התמונות המוגדלות שנוצרו על ידי ImageDataGenerator מעמד. אני אקבע את השורות באופן שרירותי ל-10, ולכל שורה, אני רוצה להדפיס את קבוצת התמונות שהוחזרו (שהיא 8 בדוגמה זו):

שורות = 10fig, axes = plt.subplots(rows, batch_size)עבור r בטווח(שורות):    
#---קבל את קבוצת התמונות המוגדלות---
image_batch = train_generator.next()
#---קבל את מספר התמונות שהוחזרו---
images_count = image_batch[0].shape[0]

עבור c in range(images_count):
#---המר למספרים שלמים ללא סימנים לצפייה---
image = image_batch[0][c].astype('uint8')

#---הצג את התמונה---
axes[r,c].imshow(image)

#---הצג את התווית של התמונה---
axes[r,c].title.set_text(
class_list[np.argmax(image_batch[1][c])])
#---מסתיר את ה-x ו-y-ticks---
axes[r,c].set_xticcks([])
axes[r,c].set_yticks([])
fig.set_size_inches(15,18)

מאז batch_size מוגדר כעת ל-8 (ולא עוד 1), ה train_generator.next() השיטה תחזיר לך א קְבוּצָה של שמונה תמונות מוגדלות בכל פעם שאתה קורא לזה. מספר התמונות המוחזרות מבוסס על batch_size שהגדרת מוקדם יותר ב flow_from_directory() שיטה:

train_generator = train_datagen.flow_from_directory(
'./פירות',
target_size=(224,224),
color_mode='rgb',
batch_size=batch_size, # גודל_אצווה = 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 ייבוא ​​Dense, GlobalAveragePooling2D
#---מספר פירות---
NO_CLASSES = max(train_generator.class_indices.values()) + 1
#---טען את דגם VGG16 כדגם הבסיס לאימון---
base_model = VGG16(include_top=False, input_shape=(224, 224, 3))
#---הוסף שכבות משלנו---
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024,activation='relu')(x) # הוסף שכבות צפופות כך
# שהדגם יכול
# למד מורכב יותר
# פונקציות ו
# לסווג לטובה
# תוצאות.
x = Dense(1024,activation='relu')(x) # שכבה צפופה 2
x = Dense(512,activation='relu')(x) # שכבה צפופה 3
preds = Dense(NO_CLASSES,
activation='softmax')(x) # שכבה סופית עם
# הפעלת softmax
#---צור דגם חדש עם הדגם המקורי של דגם הבסיס
# קלט והפלט של הדגם החדש ---
model = Model(inputs = base_model.input, outputs = preds)
#---אל תאמן את 19 השכבות הראשונות - 0..18---
עבור שכבה ב-model.layers[:19]:
layer.trainable=שקר
#---להכשיר את שאר השכבות - 19 ואילך---
עבור שכבה ב-model.layers[19:]:
layer.trainable=נכון

#---להרכיב את המודל---
model.compile(optimizer='אדם',
loss='categorical_crossentropy',
מדדים = ['דיוק'])

הסבר כיצד עובדת למידת העברה היא מעבר לתחום המאמר הזה. אשאיר את זה למאמר אחר.

שימוש בתמונות שנוצרו לאימון

כדי להשתמש בתמונות המוגדלות לאימון, העבר את train_generator אל fit() שיטת המודל:

#---להכשיר את הדוגמנית---
step_size_train = train_generator.n // train_generator.batch_size
model.fit(רכבת,
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

<!–

->

בול זמן:

עוד מ יועצי בלוקצ'יין