Keras Subclassing API ile Derin Öğrenme

TensorFlow ile esnek ve dinamik yapay sinir ağı katmanları nasıl oluşturulur?

Tirendaz Akademi
7 min readMar 10, 2023
Freepik

Keras ile üç türlü model oluşturabilirsiniz. Bunlardan en kolayı Sequential API’dir. Bu API ile yapay zeka uzmanı olmayanlar bile kolayca basit derin öğrenme modelleri kurabilir. Ama esnek olmadığı için bu yöntemi kullanarak kompleks modeller kurmak zordur. Çok girdili ve çok çıktılı modeller kurmak için Funcional API kullanmak daha iyidir. Bu yöntem hem basittir hem de esnektir.

Hem Sequential API hem de Functional API deklaratiftir. Yani kullanmak istediğiniz katmanları ve bu katmanların nasıl bağlanacağını deklare etmekle modelin mimarisini oluşturursunuz. Daha sonra bu modeli veriler ile beslersiniz. Bu şekilde yaparak modelinizi kolayca kaydedebilir, kopyalayabilir ve paylaşabilirsiniz. Deklaratif yaklaşımda modelin tamamı, sabit katman grafiklerinden oluştuğu için hata ayıklamak oldukça basittir. Functional API nasıl kullanıldığını görmek için aşağıdaki makaleyi inceleyebilirsiniz.

Tamam, Sequential API ve Functional API’nin avantajlarını gördük ve bu API’lerin deklaratif bir yaklaşım olduğunu öğrendik. Fakat dinamik modeller kurmak için deklaratif yaklaşım uygun değildir. Örneğin, bazı modeller döngüler, koşullu dallanmalar ve diğer bazı dinamik davranışlar içerebilir. Böyle durumlarda Subclassing API kullanmak daha iyidir. Akademik araştırmalar için genellikle daha dinamik olduğu için Subclassing API kullanılır.

Sequential API vs Functional API vs Subclassing API

Bu makalede, Subclassing API ile nasıl esnek ve dinamik derin öğrenme katmanları oluşturulacağını göstereceğim.

Yapay zekaya ilginiz varsa TensorFlow ve Keras ile derin öğrenme Udemy kursumuzu inceleyebilirsiniz.

Keras Subclassing API Nedir?

Subclassing API, Keras kütüphanesinin bir parçasıdır ve yapay sinir ağı modellerinin kurulmasında kullanılır. Bu API, Keras Sequential veya Functional API’den farklı olarak, model sınıfının alt sınıf olarak tanımlanmasını ve ağın doğrudan alt sınıftan üretilmesini sağlar. Eğer araştırma projesi veya akademik çalışmalar yapacaksanız Subclassing API yaklaşımı tam size göre.

Subclassing API’nin avantajlarından biri, ağ mimarisindeki herhangi bir özelleştirme gerektiğinde daha fazla esneklik sağlamasıdır. Bununla birlikte, API’nin kullanımı, kod yazma ve hata ayıklama açısından diğer Keras API’lerine göre daha zor olabilir.

Tamam kısaca Subclassing API’ye kısaca baktık. Hadi bu API ile esnek ve dinamik katmanlar ve modeller kurabilirsiniz. Bu makalede Subclassing API ile özelleştirilmiş katmanlar nasıl oluşturulacağına odaklanacağız. Hadi basit bir katman oluşturmak ile başlayalım.

Keras Subclassing API ile Katman Oluşturma

Bu bölümde sıfırdan Subclassing API ile basit bir katman nasıl oluşturulur göreceğiz. Bildiğiniz gibi derin öğrenme modellerinde genellikle dense katman kullanılır. Dense katman kendinden önceki bütün nöronlar ile bağlantılıdır.

Dense Katmanlı bir Yapay Sinir Ağı

Hadi Subclassing API’yi kullanarak tam bağlantılı bir dense katman oluşturalım. Bunun için keras.layers.Layer sınıfından miras alan bir sınıf oluşturmamız gerekir.

Bunu göstermek için öncelikle TensorFlow ve Keras’ı import edelim.

import tensorflow as tf 
from tensorflow import keras

Şimdi Linear isminde bir sınıf oluşturalım. Dikkat edin burada, önce ağırlıkları ve bias’i tanımlayacağız daha sonra bu örnek nitelikleri ile işlem yapmak için bir call metodu tanımlayacağız.

class Linear(keras.layers.Layer):
def __init__(self, units=32, input_dim = 32):
super(Linear,self).__init__()
# Katman ağırlıklarını oluşturalım
w_init= tf.random_normal_initializer()
self.w=tf.Variable(
initial_value=w_init(shape=(input_dim,units), dtype="float32"),
trainable=True
)
# bias oluşturalım
b_init = tf.zeros_initializer()
self.b = tf.Variable(
initial_value=b_init(shape=(units,), dtype="float32"),
trainable=True
)

def call(self,inputs):
return tf.matmul(inputs, self.w) + self.b

İşte bu kadar. Subclassing API ile basit bir dense katmanı oluşturduk.

Bu esnek katmanının nasıl çalıştığını görmek için bir örnek veri alalım ve bu örnek veriyi katman üzerinden geçirelim. Hadi bir girdi verisi oluşturalım. Bunun için basitçe 1 değerlerini içeren, 2*2 boyutlarında bir matris oluşturalım.

x = tf.ones((2,2))
print(x)

# Output:
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[1., 1.],
[1., 1.]], dtype=float32)>

Bu bizim girdi verimiz olacak. Şimdi bu Linear sınıfından bir örnek alalım. Bu katmanın nöron sayısı için 4 ve girdi boyutu için 2 yazalım.

linear_layer = Linear(4, 2)

Tamam, sınıftan bir katman örneği oluşturduk. Şimdi verimizi bu katmandan geçirelim.

y = linear_layer(x)
print(y)

# Ouyput:
<tf.Tensor: shape=(2, 4), dtype=float32, numpy=
array([[ 0.06356013, -0.02136349, 0.0958024 , 0.04870867],
[ 0.06356013, -0.02136349, 0.0958024 , 0.04870867]],dtype=float32)>

Bammm. İşte Keras Subclassing API kullanarak esnek bir katman örneği oluşturduk ve katmandan örnek verileri geçirdik.

Burada ne oldu? Önce rasgele başlangıç ağırlıkları üretildi. Sonra bu değerler, x girdisi ile matris çarpımı yapıldı. Ve çıkan sonuca bir bias eklendi.

Bu katmandaki ağırlıkların ve biaslerin izlendiğini unutmayın. Hadi bu katmanda kullanılan ağırlıkları ve bias değerlerini görelim. Bunun için weights niteliğini kullanalım.

print(linear_layer.weights)

# Output:
[<tf.Variable 'Variable:0' shape=(2, 4) dtype=float32, numpy=
array([[ 0.08850016, -0.0294551 , 0.04489021, 0.01145601],
[-0.02494004, 0.0080916 , 0.0509122 , 0.03725266]],
dtype=float32)>,
<tf.Variable 'Variable:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>]

İlk kısım başlangıç ağırlıklarını ve ikinci kısım bias değerlerini gösteriyor. Hatırlarsanız bias başlangıçta sıfır değerlerinden oluşuyordu. Burada bu sıfır değerlerini görebilirsiniz.

Katman Ağırlıklarını Oluşturmak için Kısa Yol

Bir katmana ağırlık eklemek için biraz önce TensorFlow’daki Variable’ı kullandık. Katmana ağırlık eklemek için add_weight() metodunu da kullanabilirsiniz. Hadi bu metodun nasıl kullanıldığını görelim.

from tensorflow.python.ops.init_ops_v2 import Initializer
class Linear(keras.layers.Layer):
def __init__(self, units=32, input_dim = 32):
super(Linear,self).__init__()
# Ağırlıkları oluşturalım
self.w = self.add_weight(shape=(input_dim, units),
initializer="random_normal",
trainable = True)
# Bias oluşturalım
self.b = self.add_weight(shape=(units),
initializer = "zeros",
trainable = True)
def call(self,inputs):
return tf.matmul(inputs, self.w) + self.b

Harika add_weight metodunu kullanarak esnek bir katman oluşturduk. Hadi örnek verilerimizi bu katman üzerinden geçirelim.

x = tf.ones((2, 2))
linear_layer = Linear(4, 2)
y = linear_layer(x)
print(y)

# Output:
<tf.Tensor: shape=(2, 4), dtype=float32, numpy=
array([[0.07724835, 0.0008499 , 0.106326 , 0.02716313],
[0.07724835, 0.0008499 , 0.106326 , 0.02716313]], dtype=float32)>

Gördüğünüz gibi katmanın üzerinden veriler geçti ve çıktı değerleri üretildi.

Veri Boyutu Girmeden Katman Oluşturma

Yukardaki örnekte input_dim argümanını, shape parametresine geçirdik. Fakat bir çok durumda girdilerinizin boyutunu önceden bilemeyebilirsiniz. Hatta bazen katmanı örneklendirdikten sonra girdi boyutunu katmana geçirmek isteyebilirsiniz. Böyle durumlarda sınıfa bir build metodu ekleyip ağırlıkları bu metotta oluşturabilirsiniz. Hadi bunun nasıl yapıldığını görelim.

class Linear(keras.layers.Layer):
def __init__(self, units=32):
super(Linear,self).__init__()
self.units = units
# Ağırlıkları oluşturma
def build(self,input_shape):
self.w = self.add_weight(shape=(input_shape[-1],self.units),
initializer = "random_normal",
trainable = True)
self.b = self.add_weight(shape = (self.units,),
initializer = "random_normal",
trainable = True)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b

Bu katmanda call metodu çağırıldığında build metodu otomatik olarak çalışacak. Şimdi bu sınıftan bir katman örneği alalım.

linear_layer = Linear(32)

Dikkat edin bu örnekte girdinin boyutunu yazmadık. Sadece nöron sayısını belirledik. Şimdi girdimizi katmana verelim.

y = linear_layer(x)
print(y)

# Output:
<tf.Tensor: shape=(2, 32), dtype=float32, numpy=
array([[ 0.12529299, -0.0561902 , 0.03834991, -0.07893594, 0.00859061,
0.08317355, -0.05678261, 0.0037364 , -0.04070574, -0.12113686,
0.03729274, 0.01368941, -0.05131226, 0.03087646, -0.02225749,
0.04070945, 0.01450459, 0.08193067, 0.0622445 , 0.1920329 ,
-0.0106803 , -0.07432184, 0.003447 , 0.11814891, -0.07613041,
0.01972482, -0.08320747, 0.13414364, 0.00047702, -0.15275721,
0.09923995, -0.06166402],
[ 0.12529299, -0.0561902 , 0.03834991, -0.07893594, 0.00859061,
0.08317355, -0.05678261, 0.0037364 , -0.04070574, -0.12113686,
0.03729274, 0.01368941, -0.05131226, 0.03087646, -0.02225749,
0.04070945, 0.01450459, 0.08193067, 0.0622445 , 0.1920329 ,
-0.0106803 , -0.07432184, 0.003447 , 0.11814891, -0.07613041,
0.01972482, -0.08320747, 0.13414364, 0.00047702, -0.15275721,
0.09923995, -0.06166402]], dtype=float32)>

Bammm. Girdimizin boyutunu girmeden katmandan verileri geçirdik. Harika, girdi boyutunu bilmediğimiz durumlarda nasıl katman oluşturacağımızı gördük.

Katmanlardan Oluşan Bloklar

Bazen art arda gelen katmanları birleştirmek isteyebilirsiniz. Yani veriler bir katmana girsin sonra bu katmandan çıkan değerler diğer bir katmana girsin şeklinde devam etsin. Hadi bir katmanın örneğinin diğer bir katmana girdi olarak geçtiği bir senaryo düşünelim.

Bu senaryo aslında aşağıdaki makalede anlattığım çok katmanlı bir perceptron yani kısaca MLP.

Hadi art arda gelen katmanlardan oluşan bir sinir ağı inşa edelim.

class MLPBlock(keras.layers.Layer):
def __init__(self):
super(MLPBlock, self).__init__()
# Katmanları tanımlayalım
self.linear_1 = Linear(32)
self.linear_2 = Linear(32)
self.linear_3 = Linear(1)

# Katman işlemlerini tanımlayalım
def call(self, inputs):
x = self.linear_1(inputs)
x = tf.nn.relu(x)
x = self.linear_2(x)
x = tf.nn.relu(x)
return self.linear_3(x)

Tamam, böylece art arda katmanlardan oluşan ve bu katmanların birbirine bağlandığı bir blok oluşturduk. Bu yaklaşım, dıştaki katmanın içteki katmanın ağırlıklarını kullanmasını sağlar. Şimdi bu sınıftan bir örnek alalım.

mlp = MLPBlock()

Bu sınıfa bir veri verelim.

y = mlp(tf.ones(shape=(3, 64)))

Tamam, veriler 3 katmanlı bloktan geçti. Hadi ağırlıklara bakalım.

print(mlp.weights)

# Output:
[<tf.Variable 'mlp_block/linear_5/Variable:0' shape=(64, 32) dtype=float32, numpy=
array([[ 0.03181227, -0.03552845, -0.00532066, ..., 0.12079153,
-0.07475913, 0.0099043 ],
[ 0.0015341 , -0.02581516, -0.03239488, ..., 0.0370282 ,
0.02811593, -0.03380568],
[-0.00715649, 0.0582541 , 0.04256558, ..., 0.0377348 ,
0.10212301, -0.03072884],
...,
[ 0.05020842, -0.10764688, 0.00189259, ..., -0.0117731 ,
0.02547028, -0.06487002],
[-0.00168144, -0.01505039, -0.0209573 , ..., -0.01630844,
-0.0164077 , -0.07637613],
[-0.05147887, 0.09903259, 0.01605012, ..., 0.02922877,
0.0156203 , 0.07475672]], dtype=float32)>,
<tf.Variable 'mlp_block/linear_5/Variable:0' shape=(32,) dtype=float32, numpy=
array([-0.01699487, 0.01961638, 0.04468011, -0.07827999, 0.06531694,
0.04750273, -0.01846105, -0.04750106, 0.04930599, 0.03066118,
-0.13191342, -0.00432053, 0.04816367, 0.11426394, 0.01057771,
0.07847259, -0.05077245, 0.08985738, 0.02169767, -0.02449624,
0.00086025, 0.01822815, -0.01215468, 0.01937916, -0.0667214 ,
0.05271372, 0.02958361, -0.08584312, -0.00931098, -0.07165599,
-0.05130129, 0.01846607], dtype=float32)>,
....
....
....

Bammm. Gördüğünüz gibi her üç katman için ağırlıklar ve biasler hesaplandı.

Unutmayın, TensorFlow blok katmanlar oluştururken, __init__() fonksiyonunda katmanları oluşturmanızı ve call metodunda ağırlıkların hesaplanmasını öneriyor.

Bu yazının daha ayrıntılı anlatımını aşağıdaki videoda bulabilirsiniz.

Son Sözler

Tebrikler. Bu makalede Keras Subclassing API ile nasıl esnek katmanlar oluşturabileceğinizi öğrendiniz. Keras Subclassing API ile esnek loss ve metrik fonksiyonları da oluşturabilirsiniz. Bu yazıda kullandığım notebooka buradan ulaşabilirsiniz.

Makaleyi okuduğunuz için teşekkür ederim. Bu yazıyı beğendiyseniz aşağıdaki alkış tuşuna bir kaç kez basmayı ve arkadaşlarınız ile paylaşmayı unutmayın. Hadi bağlanalım: YouTube | Udemy | Twitter | Instagram 😊

Aşağıdaki makaleler de dikkatinizi çekebilir:

Gelecek yazılarda görüşmek üzere. Şimdilik hoşça kalın.

--

--