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.