ניקוי תמונות מרעשים באמצעות למידת מכונה

מחבר:
בתאריך:

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

תרשים סכמטי של רשת autoencoder יראה כך:

מבנה של רשת נוירונית autoencoder

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

הרשת מורכבת משני חלקים:

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

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

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

לחץ כאן כדי להוריד את קובץ קוד המלא שנפתח במדריך

 

ייבוא הספריות הבסיסיות

import numpy as np
import matplotlib.pyplot as plt

 

ייבוא מסד הנתונים

מסד הנתונים הוא MNIST שכולל 70,000 תמונות של ספרות הכתובות בכתב יד.

# import the mnist dataset
from keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype('float32')
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1).astype('float32')

 

נוסיף לתמונות רעש

הקוד הבא מוסיף רעש אקראי לתמונות.

# add random noise
noise_factor = 0.5
x_train_noisy = x_train + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape) 
x_test_noisy = x_test + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_test.shape) 

x_train_noisy = np.clip(x_train_noisy, 0., 1.)
x_test_noisy = np.clip(x_test_noisy, 0., 1.)

# show the first 10 noisy images
rows = 1
cols = 10

fig, ax = plt.subplots(rows,cols)
for i in range(cols):
  ax[i].imshow(x_test_noisy[i].reshape(28,28))

התמונות הרועשות שנזין לרשת הנוירונית

 

בניית המודל autoencoder

נייבא מ-Keras את הספריות שישמשו לבניית המודל.

from keras.models import Sequential
from keras.engine.input_layer import Input
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import UpSampling2D
from keras.optimizers import adadelta

נבנה את המודל בשכבות:

# the autoencoder model
model = Sequential()

# encoder
model.add(Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2), padding='same'))
model.add(Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2), padding='same'))

# decoder
model.add(Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(UpSampling2D((2, 2)))
model.add(Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(UpSampling2D((2, 2)))
model.add(Conv2D(1, (3, 3), activation='sigmoid', padding='same'))

model.compile(optimizer='adadelta', loss='binary_crossentropy')

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

למודל יש שני חלקים. ה-encoder משתמש בשתי שכבות קונבולוציה ו-2 שכבות MaxPooling כדי לדחוס את המידע. ה-decoder משתמש גם הוא בשתי שכבות קונבולוציה ובנוסף בשתי שכבות UpSampling שמרחיבות את המידע לצורתו המקורית.

זה מבנה המודל:

Layer (type)                 Output Shape      Param #   
======================================================
conv2d_1 (Conv2D)            (None, 28, 28, 32)   320       
______________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 14, 32)     0         
______________________________________________________
conv2d_2 (Conv2D)            (None, 14, 14, 32)  9248      
______________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 7, 7, 32)       0         
______________________________________________________
conv2d_3 (Conv2D)            (None, 7, 7, 32)    9248      
______________________________________________________
up_sampling2d_1 (UpSampling2 (None, 14, 14, 32)     0         
______________________________________________________
conv2d_4 (Conv2D)            (None, 14, 14, 32)  9248      
______________________________________________________
up_sampling2d_2 (UpSampling2 (None, 28, 28, 32)     0         
______________________________________________________
conv2d_5 (Conv2D)            (None, 28, 28, 1)    289       
======================================================
Total params: 28,353
Trainable params: 28,353
Non-trainable params: 0

אנחנו מתחילים עם 28*28 נוירונים בקלט, שה-encoder מכווץ ל-14*14 ואח"כ ל-7*7. ה-decoder מרחיב ל-14*14 ומסיים עם מבנה של 28*28.

נריץ את המודל:

model.fit(x_train_noisy, x_train,
                epochs=10,
                batch_size=128,
                shuffle=True,
                validation_data=(x_test_noisy, x_test))

 

הערכת המודל

נעריך עד כמה המודל מצליח בניקוי התמונות בקבוצת הביקורת מרעשים.

x_pred = model.predict(x_test_noisy)

ככה זה נראה עבור 10 הספרות הראשונות:

rows = 3

fig, ax = plt.subplots(rows,cols)

for c in range(cols):
  ax[0][c].imshow(x_test[c].reshape(28,28))
  ax[1][c].imshow(x_test_noisy[c].reshape(28,28))
  ax[2][c].imshow(x_pred[c].reshape(28,28))  

שחזור התמונות על ידי הרשת הנוירונית

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

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

 

סיכום

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

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

במדריך הבא נשתמש ב-autoencoder כדי להפיק מידע דחוס במסגרת אנליזת PCA.

לכל המדריכים בנושא של למידת מכונה

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

הוסף תגובה חדשה

 

= 3 + 2