Ahmet Yiğit DAYI tarafından 7 Şubat 2021 tarihinde yazılmıştır.
Herkese merhaba, bugün yakın zamanlarda yayınlanmış olan Kotlin ile Derin Öğrenmeye giriş yapıyoruz.
Derin Öğrenme Nedir?
Derin öğrenme makine öğrenme yöntemlerinden biridir. Temelde beynin sinir ağlarından ilham alınarak tasarlanmıştır (yapay sinir ağları).Derin öğrenme algoritmaları, girilen veri veya veri setleri üzerinden yapay sinir ağları üzerinde analiz eder. Derin öğrenme, makine öğrenmesi yöntemleri arasında insan beynine en çok benzeyendir.
Gördüğünüz gibi aynı insan beynindeki gibi aldığı veriler arasında bağlantılar kurarak öğrenir.
Hiç düşündünüz mü? Bir e-ticaret sitesinde size önerilen ürünler karşınıza nasıl çıkıyor diye. Ya da YouTube ve Netflix gibi platformlarda "size önerilen" kısımlar neye göre belirleniyor. Makine öğrenmesi algoritmaları sayesinde! Siz bir videoyu veya bir filmi izlediğinizde; izleme süreniz, verdiğiniz geri dönüş v.s. veriler toplanarak işlenir, bu sayede sizin için en uygun içerikler karşınıza çıkar.
Bütün bu öğrenme ve çıkarım yapma kısmında yazdığımız kodların arkasında bayağı bir matematik var, şu anlık o kısma girmeyeceğim. Ancak incelemek isteyenler olursa diye link bırakıyorum. https://towardsdatascience.com/what-is-deep-learning-and-how-does-it-work-2ce44bb692ac
Derin Öğrenme hakkında temel bir fikre sahip olduğumuza göre başlayabiliriz.
KotlinDL
KotlinDL, Keras'tan (https://keras.io/) ilham alınarak oluşturulmuş, yüksek seviye derin öğrenme API'ıdır. Bu API ile sıfırdan derin öğrenme modülleri yazabilirsiniz. KotlinDL projesinin temel amacı ise Derin Öğrenme'yi JVM (Java Virtual Machine) kullanıcıları için daha kolay hale getirmek.Başlayalım!
Öncelikle yeni bir Kotlin projesi oluşturalım. Ben kotlin-dl koyuyorum ismini.
Projemizi oluşturduktan sonra build.gradle.kts dosyasının içine
Kod:
repositories {
jcenter()
maven(url = "https://kotlin.bintray.com/kotlin-datascience")
}
dependencies {
implementation ("org.jetbrains.kotlin-deeplearning:api:[KOTLIN-DL-VERSION]")
}
Nöral Ağ Oluşturmak
Nöral ağlar oluşturmak için dataset(verisetleri) kullanılır. Resim sınıflandırma için oluşturacağımız bu örneğimizde Fashion-MNIST Dataset bu dataset'i kullanacağız. Bu dataset'te yaklaşık 70.000 tane resim var. Sayı büyük gibi gelebilir ama aslında bu gibi rakamları resim sınıflandırmanın "Hello World!"u olarak düşünebilirizBizim kullanacağımız datasetteki sınıflandırmaları şimdiden yapalım.
Kod:
val stringLabels = mapOf(0 to "T-shirt/top",
1 to "Trouser",
2 to "Pullover",
3 to "Dress",
4 to "Coat",
5 to "Sandal",
6 to "Shirt",
7 to "Sneaker",
8 to "Bag",
9 to "Ankle boot"
)
İlk olarak nöral ağımızın yapısını tanımlayarak başlayalım. Nöral ağlarının temel yapı taşı layerlardır (katman). Bir nöral ağ oluşturmak için hangi layerlardan oluşacağını belirtmemiz gerekir. * Yeterli data, layer ve training (öğrenim) ile nöral ağlar, karışık sonuçları bile harika performanslarla vermeye başlar.
Burada tanımlayacağımız nöral ağ Multilayer Perceptron (MLP) olarak adlandırılır. Bu nöral ağ, multiple fully-connected layers(çoklu tamamen-bağlanmış katmanlar)'dan oluşan basit bir nöral ağdır. MLP'nin içinde bulunan her bir layer'daki nöron (neuron), kendisinden önceki tüm layer'lardan output alır ve kendi output'unu bir sonraki katmanda bulunan tüm nöronlara gönderir.
Şimdi birkaç sıralı layer'dan oluşan bir nöral ağ tanımlayalım.
Kod:
val model = Sequential.of(
Input(28,28,1),
Flatten(),
Dense(300),
Dense(100),
Dense(10)
)
İlk olarak, nöral ağa nasıl bir input (girdi) vereceğimizi belirttik. Kullanacağımız dataset'teki resimler 28 x 28 piksel, ve sadece bir renk kanalına (monochrome) sahip. Bu şekilde input 28 x 28 x 1 olacak.
Burada oluşturduğumuz ilk katman Flatten. Bu katman basitçe üç-boyutlu girdiyi tek-boyutlu'ya dönüştürür. Bizim örneğimizde 28 * 28 * 1 = 784.
Flatten'dan sonra, sıralı şekilde 3 tane Dense katmanı var. Dense katmanları, "tamamen bağlanmış katmanlar" olarak da anılır, bütün nöral ağ mimarilerinde en çok yaygın olan katmanlardır. Her bir Dense katmanı için bir boyut belirledik. Birincinin 300, ikincinin 100 ve sonuncunun 10 nöronu var.
Nöral Ağı Derleyelim
Kod:
model.use {
it.compile(
optimizer = Adam(),
loss = Losses.SOFT_MAX_CROSS_ENTROPY_WITH_LOGITS,
metric = Metrics.ACCURACY
)
}
optimizer için atadığımız Adam bir optimizasyon algoritması, giriş seviyesinde olduğundan bunu seçtik.
loss fonksiyonu, accuracy'i (doğruluğu) ayarlamak için kullanılır.
metric ise model'i eğitme ve değerlendirme sırasında durumları izlemek için kullanılır.
Artık summary() fonksiyonunu çağırıp nöral ağımızın yapısını yazdırabiliriz.
Kod:
it.summary()
INFO api.core.Sequential - =================================================================
INFO api.core.Sequential - Model: Sequential
INFO api.core.Sequential - _________________________________________________________________
INFO api.core.Sequential - Layer (type) Output Shape Param #
INFO api.core.Sequential - =================================================================
INFO api.core.Sequential - flatten_1(Flatten) [784] 0
INFO api.core.Sequential - _________________________________________________________________
INFO api.core.Sequential - dense_2(Dense) [300] 235500
INFO api.core.Sequential - _________________________________________________________________
INFO api.core.Sequential - dense_3(Dense) [100] 30100
INFO api.core.Sequential - _________________________________________________________________
INFO api.core.Sequential - dense_4(Dense) [10] 1010
INFO api.core.Sequential - _________________________________________________________________
INFO api.core.Sequential - =================================================================
INFO api.core.Sequential - Total trainable params: 266610
INFO api.core.Sequential - Total frozen params: 0
INFO api.core.Sequential - Total params: 266610
INFO api.core.Sequential - =================================================================
Bir nöral ağ tanımladık. Şimdi asıl veriyi eğitmeye başlayalım.
Nöral Ağı Eğitmek (Training)
Herhangi bir veriyi kullanmadan önce, genel olarak birtakım önişlemlerle (preprocessing) gereklidir. Bizim örneğimizde bu önişlem küçük - bütün işlemler zaten aynı boyutta, gri tonlarında. Şimdi Fashion MNIST resim arşivlerini modelimizi eğitmek üzere dataset objelerine (object) çevireceğiz.Dataset'i verdiğim linkten indirip proje içinde dataset adlı bir klasör oluşturup içine attıktan sonra önişleme başlayabiliriz.
Kod:
val (train, test) = Dataset.createTrainAndTestDatasets(
trainFeaturesPath = "datasets/mnist/train-images-idx3-ubyte.gz",
trainLabelsPath = "datasets/mnist/train-labels-idx1-ubyte.gz",
testFeaturesPath = "datasets/mnist/t10k-images-idx3-ubyte.gz",
testLabelsPath = "datasets/mnist/t10k-labels-idx1-ubyte.gz",
numClasses = 10,
::extractImages,
::extractLabels
)
val (newTrain, validation) = train.split(splitRatio = 0.95)
Şimdi modeli eğitmek için her şey hazır. Bunun için fit metodunu kullanacağız.
Kod:
model.use {
it.compile(
optimizer = Adam(),
loss = Losses.SOFT_MAX_CROSS_ENTROPY_WITH_LOGITS,
metric = Metrics.ACCURACY
)
it.summary()
it.fit(
dataset = newTrain,
epochs = 10,
batchSize = 100
)
val accuracy = it.evaluate(dataset = validation, batchSize = 100).metrics[Metrics.ACCURACY]
println("Accuracy: $accuracy")
it.save(File("src/model/my_model"))
}
fit metodundaki parametreleri açıklayalım.
Epochs: Yineleme sayısıdır. Eğitim sırasında verinin kaç kere işleneceğini belirtir.
Batch Size: Bu ise modelin parametreleri için kaç tane örnek kullanıldığını belirtir. Bizim örneğimizde bu sayı 100.
Model bir kez eğitildikten sonra, doğruluk değerini görmek yeni veriyi analiz etmek için oldukça önemlidir.
Accuracy: 0.9806665182113647
Accuracy (doğrulama) değeri ortalama bu civarlarda olmalıdır, değişkenlik gösterebilir.
Şu ana kadar derin öğrenme modelimizi oluşturduk, eğittik ve kaydettik. Şimdi modelimize daha önceden gösterilmemiş yeni bir görseli verip tahminler yapmasını sağlayalım.
Kullanacağımız görsel bu olacak. Bahsettiğim gibi bu görsel daha önceden datasette bulunmayan bir görsel, yani tam anlamıyla bir tahmin yaptıracağız.
Eğer modelinizde işlediğiniz veriyle tahminde bulunduracağınız verinin boyutu ve formatı aynıysa bir önişlem gerektirmeden tahmini yapabilirsiniz. Bizim örneğimizde bu şekilde o yüzden bir şey yapmayacağız.
Kod:
fun reshapeInput(inputData: FloatArray): Array<Array<FloatArray>> {
val reshaped = Array(
1
) { Array(28) { FloatArray(28) } }
for (i in inputData.indices) reshaped[0][i / 28][i % 28] = inputData[i]
return reshaped
}
fun main() {
InferenceModel.load(File(MODELIN_PATHI)).use {
it.reshape(::reshapeInput)
val prediction = it.predict(test.getX(0))
println("Tahmin edilen katman: $prediction. Sınıfı da aha bu: ${stringLabels[prediction]}.")
}
}
Tahmin edilen katman: 8. Sınıfı da aha bu: Bag.
Gerçek katman: 8.
Gördüğünüz gibi modelimiz daha öncesinde kendine hiç verilmemiş olan bir resmi, başarılı bir şekilde tahmin etti. Tebrikler!