AutoEncoder Nedir? TensorFlow ile nasıl uygulanır?

Source: Deep Learning on Medium


Go to the profile of Burak Toy

Merhaba, bu yazımda sizlere AutoEncoder’ları anlatacak, ve TensorFlow ile AutoEncoder mantığı kullanarak yüz resimleri ile bir örnek yapacağım.

Projenin GitHub sayfasına buradan ulaşabilirsiniz.

AutoEncoder’lar, ‘unsupervised’ öğrenme çeşididir. Bu öğrenme şeklinde girilen verinin(input) ve çıkan verinin(output) boyutları aynıdır. Daha iyi anlamak için aşağıdaki resmi inceleyebilirsiniz.

Burada input(I ile gösterilmiş), encoder(kırmızı ile gösterilmiş) aracılığıyla sıkıştırılır ve ‘bottleneck’ de denilen, sıkıştırılmış veri elde edilir. Bu, bazı problemlerde bir ‘Dense’ katmanına, bazılarında ise ‘Convolution2D’ katmanına tekabül eder. (Y0 ve Y1 olarak gösterilmiş)

Daha sonrasında decoder(mavi ile gösterilmiş) bu sıkıştırılmış veriyi alır ve girilen ile aynı boyutta bir dizi(Z ile gösterilmiş) oluşturur. Bizim problemimizde bu (48, 48, 3) boyutundaki bir resim.

Bu iki resim de anlamanıza yardımcı olacaktır, ama ben böyle konularda kodu görmeden tam olarak anlayamam, size de benzeri olabilir. O yüzden anlamadıysanız endişe etmeyin, kod size anlatacaktır.

Loss fonksiyonu olarak da “Binary Crossentropy(sigmoid ile) veya “Mean Squared Error” kullanılabilir. Output katmanında aktivasyon olarak linear bırakabilir ya da sigmoid kullabilirsiniz. Karar sizin.


Artık kod üzerinden ilerleyebiliriz.

Veri Seti

Veri seti olarak bu sayfadaki veriyi kullanacağım. FIFA19 oyuncularının resimlerinin olduğu bir ‘.csv’ dosyası içeriyor. Aşağıdaki kodu kullanarak link üzerinden resimleri indirdim.

İndirilmiş veriye buradan ulaşabilirsiniz. Önce bütün kodda kullanacağım kütüphaneleri import edeceğim.

import os
import cv2
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

from tqdm import tqdm
from sklearn.model_selection import train_test_split

Şimdi eğitim yapacağımız veriyi uygun bir biçime sokmalıyız. Bu yüzden verileri yüklerken kullanacağımız DataLoader sınıfını tanımlayacağız.

class DataLoader:
def __init__(self, data_dir: str, img_shape: tuple):
self.data_dir = data_dir
self.xs, self.ys, self.channels = img_shape

def load_images(self):
try:
x_data = np.load("x_data.npy")
except FileNotFoundError:
x_data = []

for img_p in tqdm(os.listdir(self.data_dir)):
if img_p.endswith(".jpg"):
img_path = os.path.join(self.data_dir, img_p)
 img = cv2.imread(img_path)
img = cv2.resize(img, (self.xs, self.ys))

if self.channels == 1:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

x_data.append(img)

x_data = np.array(x_data)
np.save("x_data.npy", x_data)

if self.channels == 1:
x_data = np.expand_dims(x_data, axis=-1)
 return x_data

Sınıfı tanımladık ve bazı değerleri “self”e atadık. Daha sonra resimleri okuyacak bir load_images fonksiyonu tanımladık. Bu fonksiyon eğer varsa “x_data.npy” dosyasından işlenmiş resimleri yüklüyor, yoksa kendisi işleyerek bu dosyayı oluşturuyor. Bu kodu tek bir fonksiyon ile de yazabilirdik, ama ben bu şekilde kod yazmayı daha çok seviyorum, gözüme daha hoş geliyor.

Şimdi sıra encoder ve decoder modellerini tanımlamakta!

class Network:
def __init__(self, image_placeholder, bottleneck_placeholder, img_shape: tuple = (48, 48, 1)):
self.xs, self.ys, self.channels = img_shape
self.bottleneck_placeholder = bottleneck_placeholder
self.image_pc = image_placeholder

self.bottleneck_size = bottleneck_placeholder.shape[-1]

self.encoder = self.get_encoder()
self.decoder = self.get_decoder(self.bottleneck_placeholder)

def get_encoder(self):
with tf.variable_scope("encoder"):
x = tf.layers.conv2d(self.image_pc, 128, (3, 3), strides=2, activation=tf.nn.relu,
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.batch_normalization(x, momentum=0.8)
x = tf.layers.conv2d(x, 256, (3, 3), strides=1, activation=tf.nn.relu,
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.conv2d(x, 512, (3, 3), strides=2, activation=tf.nn.relu,
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.max_pooling2d(x, (3, 3), strides=2)
x = tf.layers.batch_normalization(x, momentum=0.8)
x = tf.layers.conv2d(x, 1024, (3, 3), strides=1, activation=tf.nn.relu,
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
return x

def get_decoder(self, bl_pc):
with tf.variable_scope("decoder"):
x = tf.layers.conv2d_transpose(bl_pc, 1024, (3, 3), strides=2, activation=tf.nn.relu, padding="SAME",
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.conv2d(x, 64, (2, 2), strides=1, activation=tf.nn.relu)
x = tf.layers.batch_normalization(x, momentum=0.8)
x = tf.layers.conv2d_transpose(x, 512, (3, 3), strides=2, activation=tf.nn.relu, padding="SAME",
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.conv2d_transpose(x, 256, (3, 3), strides=2, activation=tf.nn.relu, padding="SAME",
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.batch_normalization(x, momentum=0.8)
x = tf.layers.conv2d_transpose(x, 128, (3, 3), strides=2, activation=tf.nn.relu, padding="SAME",
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.batch_normalization(x, momentum=0.8)
x = tf.layers.conv2d_transpose(x, 64, (3, 3), strides=1, activation=tf.nn.relu, padding="SAME",
kernel_regularizer=tf.keras.regularizers.l2(5e-4))
x = tf.layers.conv2d_transpose(x, self.channels, (3, 3), strides=2, activation=None, padding="SAME")

return x

Burada her şey açık, yine aynı şeyi yaptık. Bazı değerleri “self”e atadık. Daha sonra modelleri oluşturduk. Model yapılarıyla, teknikleriyle oynayıp daha güzel sonuçlar elde edebilirsiniz. Belki pixelwise normalization ya da minibatch standard deviation gibi yöntemler de performansı arttırabilir.

Bu kodda özellikle bahsetmek istediğim dört şey var.

  • Burada sıkıştırılmış veri (2, 2, 1024) boyutunda, siz bununla oynayabilir, Dense katmanı ekleyebilir ve sonuçları gözlemleyebilirsiniz.
  • Ben decoder’ın output katmanına aktivasyon olarak None(linear) verdim, siz sigmoid ya da tanh da deneyebilirsiniz.
  • Ayrıca ben l2 kernel regularizer da kullandım, performansı arttırdı. Siz de çıkarıp/değiştirip kendiniz kontrol edebilirsiniz.
  • Ben decoder’a input olarak “bottleneck_placeholder” vermek istedim, ama siz self.decoder = self.get_decoder(self.encoder) şeklinde kullanarak “bottleneck_placeholder”ı ortadan kaldırabilirsiniz. Ama buna bağlı olarak ilerki kodlarda bazı değişiklikler yapmanız gerekecek.

Uyarı !

Eğer modelleri değiştirecekseniz lütfen encoder’ın input ve decoder’ın output katmanlarının shapelerinin aynı olmasına dikkat edin.

Şimdi eğitimi gerçekleştirecek ‘TrainAutoEncoderModel’ sınıfını tanımlayabiliriz.

Aslında TensorFlow’u her şeyi loglayacak şekilde yazdım, ama yine de yapılanları özet geçeyim.

“__init__” Fonksiyonunda

  • Bazı değerler “self”e atandı.
  • Veri seti train/test olarak ayrıldı.
  • Bazı gerekli klasörler oluşturuldu.
  • TensorFlow için placeholder’lar oluşturuldu.
  • Model Oluşturuldu.
  • Loss(kayıp) tanımlandı.
  • TensorBoard ayarlandı.
  • Learning Rate Decay(Öğrenme Değeri Düşüşü ?) ayarlandı.
  • Optimizer ayarlandı.
  • Session’u kaydetmemizi sağlayacak “Saver” oluşturuldu.

“test_model” Fonksiyonunda

  • Test veri setinden batch olarak alınan resimler kullanılarak outputlar oluşturuldu.
  • TensorBoard’a yazıldı
  • Random seçilen 1 resim kaydedildi.
  • Yeni batch ile tekrar edildi.

“train_model” Fonksiyonunda

  • Session açıldı ve initialize edildi.
  • Eğer varsa eğitilmiş model yüklendi.
  • TensorBoard’un verilerini yazacak obje tanımlandı.
  • Train veri setinden batch olarak alınan resimler kullanılarak loss hesaplandı ve bilinen son 25 loss değerinin ortalaması alınarak tqdm kütüphanesi yardımıyla ekrana basıldı.
  • TensorBoard’a yazıldı.
  • Her epoch sonunda ‘test_model’ fonksiyonu yardımıyla test_loss(test veri setindeki loss’un ortalaması) hesaplandı, ve ekrana basıldı. Eğer epoch sayısı 5’in katı ise session kaydedildi.
  • Eğitim sonunda session bir kez daha kaydedildi ve session kapatıldı.

“give_examples” Fonksiyonunda

  • Session açıldı ve initialize edildi.
  • Eğer varsa eğitilmiş modeli yükledi.
  • Veri setinden random olarak seçilmiş n tane resimden output üretildi ve “fig.png” olarak kaydedildi.

Çalıştırma Vakti!

if __name__ == '__main__': 
dl = DataLoader("dataset", (48, 48, 3))
X_data = dl.load_images()

trainer = TrainAutoEncoderModel(X_data, (48, 48, 3), decay_steps=200, lr=0.001, model_dir="autoencoder_model/",
epochs=50, batch_size=128, dir2save="predicted_images/")
trainer.train_model()
trainer.give_examples()

En sona bu kod blokunu da eklemeniz takdirde eğitime başlayabilirsiniz!

Umarım her şeyi açık ve net anlatabilmişimdir. Sorunuz olursa lütfen sormaktan çekinmeyin, elimden geldiğince cevaplayacağım.

Kaynaklar