Conv2D Sınıfı ile Katman Oluşturma

Merhabalar, derin öğrenme ile ilgili çeşitli projelerin kodlarını incelerken dikkatimi çeken bir kullanımı sizlere sormak istedim. Bir ağın katmanlarının oluştururken kullanılan Conv2D sınıfında şu tarz bir kullanım karşıma çıkıyor;

x2 = tf.keras.layers.Conv2D(64, (3,3), activation='relu', kernel_initializer="he_normal", padding="same")(x1)
.
.
x3 = tf.keras.layers.Conv2D(64, (3,3), activation='relu', kernel_initializer="he_normal", padding="same")(x2)
.
.

Yukarıdaki örnek kullanımda x2 değişkeni ile Conv2D() sınıfını kullanarak bir nesne tanımlıyoruz anladığım kadarıyla. Normalde nesne = Sinif(prm1, prm2, ...) şeklinde tanımlıyoruz. Bahsettiğim örnekte şöyle bir durum var nesne = Sinif(prm1, prm2, ...)(prm3). Belki ben yanlış algılamış olabilirim. prm3 yazdığım kısmı parametre olarak alıyor anladığım kadarıyla, yanlışım varsa lütfen düzeltin.

Merak ettiğim şey ise prm3’ü neden sınıf parantezleri içerisinde yazmıyoruz. Kullanım kolaylığı ve okunabilirlik açısından mı?

Merhaba,

eğer kastettiğiniz kısım (3,3) paramı ise, bu convulutional learning de yanlış hatırlamıyorsam, verinin kaça kaçlık bölümünde inceleme (recursion) yapılacağını gösteriyor. örnegğin bazı durumlarda bu (12,12) veya (32,32) de olabililyor. bu param x2 instance’ının paramı yani.
umarım sorunu doğru anlamış, doğru cevap verebilmişimdir.

1 Beğeni

Yok hocam onu kastetmiyorum.

x2 = ...Conv2D(prm1, prm2, ....)(x1)

Yukarıdaki satırda en sonda yazılan x1’i neden Conv2D sınıf parantezleri dışında yazıyorlar diye merak ettim. Güzel anlatamamışım galiba kusura bakmayın.

Merhaba Keras’ta birkaç farklı stil ile model oluşturabilmektesiniz. Bunlardan biri sizin kullandığınız fonksiyonel stildir. Her bir katmanı bir matematiksel fonksiyon olarak düşünebilirsiniz; mesela layers.Conv2D(64, (3,3)). Bu “fonksiyon” bir girdiyle çağrıldığında ileri besleme işini yapar (feed-forward). O işlemi nasıl yapacağı tabii layer’a kalmış; linear bir katmansa wT x + b’den ibarettir, sizdeki gibi Conv2D ise işin içinde konvolüsyonlar vardır, gibi.

Dolayısıyla modelinizi bu fonksiyonel tarz ile oluştururken evvela bir girdiniz oluyor; kodunuzun evveli gözükmüyor ama sizdeki galiba x1 oluyor. keras.Input ile ilklendirilebilir:

inp = keras.Input(shape=(28, 28))

Sonra bunu alıp bir parametre olarak ilk katmana paslıyoruz:

x_2 = keras.layers.Conv2D(64, (3,3)(inp)

Sonra da pool’layalım mesela (bir başka katman):

x_3 = keras.layers.GlobalAveragePooling2D()(x_2)

Şimdi de son bir dense (linear) katman koyup modeli sonlandıralım:

out = keras.layers.Dense(5)(x_3)

Bu fonksiyonlar silsilesi ile input’tan output’a çizilen yol bellidir; bir katman kendinden öncekini hatırlar gibi düşünürüz. Matematikteki fonksiyon kompozisyonu gibi, “f o g” mevzuları. (Yani şu üsttekilerin input’tan sonrası tek satırda da yazılabilirdi istenirse:

inp = keras.Input(shape=(28, 28))
out = keras.layers.Dense(5)(keras.layers.GlobalAveragePooling2D()(keras.layers.Conv2D(64, (3,3)(inp)))

Ama tabii üstteki daha iyi.)

Asıl modeli ise Keras’a input ve output, yani başlangıç ve sonlanış sembolik değerlerini tutan değişkenleri bildirerek şöyle oluşturuyoruz, o oradan modelin yolunu anlıyor:

model = keras.Model(inp, out)

Burada bitiyor. Dikkat çekilmesi gereken nokta, şu ana kadar hiçbir katmanın gerçekten bir iş yapmamış olmasıdır. Yani herhangi bir gerçek veri işlenmiş değil; bunları (inp, x_2, …, out) sembolik olarak düşünüyoruz: modelin yolunu çiziyorlar. Ancak gerçek veriyle model eğitilip tahmine tutulduğunda matematiksel feed-forward (ve gerekli backpropagation’lar) gerçekleşir.

Bu stili bir de Sequential stil ile kıyaslayalım:

model = keras.Sequential(
    [
        keras.layers.Conv2D(64, (3,3)),
        keras.layers.GlobalAveragePooling2D(),
        keras.layers.Dense(5),
    ]
)

İki model matematiksel olarak birbirine denktir, programatik olarak farklı yollarla oluşturuldular. Bu ikincisi biraz daha doğal gelebilir kişiye. Fonksiyonel stilin çalışabilmesini sağlayan, yani sizin de bahsettiğiniz, nesne oluşturulduktan sonra tekrar (...) ile çağrılması mevzusu, katmanların __call__ özel metoduna sahip olmaları sayesindedir.

Fonksiyonel stil neden tercih edilsin? Daha esnek olduğunu söylüyorlar, her şeyi bir anda bir listeye tıkmak durumunda değilsiniz zira; ara output’larla Keras’ın izin verdiği ölçüde çok ilginç şeyler yapabilirsiniz: mesela kendiniz size has yeni bir model peşindesiniz diyelim. Onun getirdiği yenilikleri/trick’leri Sequential stil ile yapmak zor olabilir zira ara output’lara erişemiyorsunuz, biraz daha “otomatik” oluyor. Ama bazen de boşuna uzun uzun yazmak istemeyebilirsiniz; mesela üstteki örnek özelinde Sequential daha kısa bir şekilde halloldu. Aralarındaki seçim ve model oluşturma stilleri için üstteki linkleri ve genel olarak onların barındığı dokümantasyonu ziyaret edebilirsiniz.

3 Beğeni

Cevap için çok teşekürler. İki stille de bir şeyler yazmaya çalıştım, fonksiyonel stil uzun oluyor ama daha anlamlı geliyor baktığımda. Sequential’de anlaşılıyor fakat acemi olduğum için fonksiyonel stil daha kullanışlı geldi.

İncelediğim proje şuydu. Burada bana ilginç gelen bir diğer nokta ise 11. satırdaki for döngüsü. Toplamda 2 kez dönen bu döngüde x’in üst üste 2 kez tanımlanması bir anlam ifade ediyor mu? x tanımlandığı an Conv2D çalışıyorsa belki olabilir. 11. satır ile ilgili fikriniz nedir hocam?

1 Beğeni

En başta gelen x, ki kendisi fonksiyona parametre olarak geliyor, asıl input’tur. Şimdi ne yapmak lazım? Tüm katmanlardan bunu geçirmek lazım. For döngüsüyle değil de alt alta ne kadar layer varsa o kadar satırda yazsak, mesela yukarıdaki fonksiyonel stilin açılmış hali gibi yazabilirdik kodu. Yani linklediğiniz kodu şöyle yazardık:

# if'leri göz ardı ettim müsaadenizle
x_2 = k.layers.Conv2D(...)(x)
x_3 = k.layers.BatchNormalization()(x_2)
x_4 = k.activations.relu(x_3)

x_5 = k.layers.Conv2D(...)(x_4)
x_6 = k.layers.BatchNormalization()(x_5)
x_7 = k.activations.relu(x_6)

# artık `n` kaç ise o koddaki, o kadar tekrar ederiz.
# değişkense ama, tekrar edemeyiz tabi! çünkü kaç olduğunu kestiremiyoruz.
...

Ama kod tekrarını sevmeyiz, hele de ne kadar tekrar edeceğimiz değişken ise! (n). Dolayısıyla for kullanırız. Peki o zaman x_2 = k.layers.Conv2D(x) dedik diyelim for’un içerisinde. Ama for tekrar döndüğünde x_2’yi kaybettik, yeniden aynı değer atanır ona. Dolayısıyla çözüm x = k.layers.Conv2D(x) demektir; asıl input olan x, sonrasında ara output oluyor, en sonda ise nihai output olur.

1 Beğeni