Makine Öğrenimi Eğlencelidir! 3. Kısım: Derin Öğrenme ve Evrişimli Sinir Ağları

Atakan Yenel
Deep Learning Türkiye
12 min readMar 9, 2019

Derin Öğrenme (Deep Learning) ile ilgili sonu gelmeyen hikayeler okumaktan ve ne anlama geldiğini bilmemekten yoruldunuz mu? Hadi bunu değiştirelim!

Bu sefer fotoğraflardaki objeleri derin öğrenme kullanarak tanıyan programları nasıl yazacağımızı öğreneceğiz. Başka bir deyişle, Google Fotoğraflar’ın fotoğrafta ne olduğundan yola çıkarak fotoğraflarınızı aramanızı sağlayan kara büyüsünü açıklayacağız.

Google artık kendi fotoğraflarınızı sadece tanımından yola çıkarak aramanızı sağlıyor. Etiketlenmiş olmasa bile. Peki bu nasıl çalışıyor? (Ocean: Okyanus)

Aynı 1. ve 2. kısımdaki gibi bu kısım da makine öğrenmesine merakı olan ama nereden başlayacağını bilmeyenler için. Amaç herkes için erişilebilir olmak. Bu da çok fazla genelleme yapacağız ve çok fazla detayı atlayacağız demek ama kimin umrunda? Eğer bu yazı bir kişiyi bile makine öğrenmesiyle ilgili daha ilgili hale getirirse, görev tamamlanmış demektir.

(Eğer 1. ve 2. kısmı okumadıysanız, şimdi okuyun!)

Objeleri Derin Öğrenme ile Tanımak

Karikatürün aslına buradan ulaşabilirsiniz (xkcd #1425)

Daha önce bu ünlü xkcd karikatürünü görmüş olabilirsiniz.

Buradaki komik kısım şu; 3 yaşındaki bir çocuk bile bir kuşun fotoğrafını tanıyabilir ama bilgisayarların bunu yapmasını sağlamak 50 yılı aşkın süredir en iyi bilgisayar bilimcilerinin kafasını meşgul ediyor.

Son birkaç yılda, Derin Evrişimli Sinir Ağları (Deep Convolutional Neural Networks) kullanarak obje tanımlamaya iyi bir yaklaşım getirmeyi başardık. Bu bir bilim kurgu romanından seçilmiş rastgele birkaç kelime gibi duruyor ama teker teker baktığınızda arkasındaki fikir gerçekten anlaşılır.

Hadi o zaman — Kuşları tanımamızı sağlayan bir program yazalım.

Basit Bir Başlangıç

Kuş fotoğraflarını tanıyan bir program yazmadan önce, çok daha kolay bir şeyi tanımayı öğrenelim — el yazısıyla yazılmış bir 8'i.

2. Kısımda, sinir ağlarının nasıl bir sürü basit nöronu birbirine bağlayarak karmaşık problemleri çözebileceğini öğrenmiştik. Bir evin sahip olduğu yatak odası sayısı, ne kadar büyük olduğu ve hangi mahallede olduğu üzerinden, o evin fiyatını tahmin eden bir sinir ağı yapmıştık:

Aynı zamanda makine öğreniminde ana fikrin; aynı çok amaçlı algoritmaları, farklı veriler üzerinde uygulayarak, farklı sorunları çözmek olduğunu da biliyoruz. O zaman buradaki aynı sinir ağını el yazısını tanıması için modifiye edelim. Bu işi basitleştirmek için sadece tek bir harfi tanımaya çalışacağız — sayıyla “8”.

Makine öğrenmesi sadece elinizde veri varsa işe yarar — tercihen çok fazla veri. Bu yüzden, başlamak için sürülerce el yazısı “8”e ihtiyacımız var. Şansımıza, araştırmacılar tam da bu amaç için MNIST el yazısı veri seti oluşturmuşlar. MNIST 18x18lik format halinde 60,000 adet el yazısıyla yazılmış rakam görseli sağlıyor. Veri setindeki bazı “8"ler:

MNIST veri setinden alınmış bazı 8'ler.

Aslında Her Şey Sadece Sayıdır

2. kısımda yaptığımız sinir ağı, girdi olarak sadece 3 sayı aldı (“3” yatak odası, “2000” metrekare, vb.). Ama şimdi sinir ağında görüntü işlemek istiyoruz. Nasıl olacak da bir sinir ağına, sayılar yerine görseller göndereceğiz?

Cevap çok kolay. Bir sinir ağı girdi olarak sayı alır. Bir bilgisayar için, bir görsel sadece her bir pikselin ne kadar karanlık olduğunu gösteren bir matristir.

Bir sinir ağına görsel verebilmek için, 18x18'lik bir görüntüyü 324 sayı uzunluğunda bir dizin olarak düşüneceğiz:

324 adet girdiyi analiz edebilmek için, sinir ağımızı 324 adet girdi düğümü olacak şekilde büyüteceğiz:

Artık sinir ağımızın bir yerine iki tane çıktısı olduğunu fark edin. İlk çıktı, bir görselin “8” olma olasılığını tahmin edecek, diğeri ise “8” olmama olasılığını. Tanımlamak istediğimiz her bir tür obje için farklı bir çıktı tanımlayarak, sinir ağımızı objeleri gruplara göre sınıflandırmak için kullanabiliriz.

Sinir ağımız eskisine göre çok daha büyük (3 yerine 324 adet girdi!). Ancak herhangi bir modern bilgisayar göz kırpmadan birkaç yüz girdilik bir sinir ağının üstesinden gelebilir. Bu bir cep telefonunda bile düzgünce çalışır.

Artık geriye kalan, sinir ağımızı “8” olan ve “8” olmayan görsellerle eğitmek, böylece bize aradaki farkı söyleyebilir. Sistemi “8”lerle beslerken, ona görselin “8” olma olasılığının 100%, “8” olmama olasılığının 0% olduğunu söyleyeceğiz. Karşı örnekler için de tam tersini yapacağız.

Eğitme verimizin bir bölümü:

tatlı mı tatlı eğitme verisi…

Bu tarzda bir sinir ağını modern bir bilgisayarda birkaç dakikada eğitebiliriz. Bittiğinde, “8”leri gayet yüksek bir olasılıkla tahmin eden bir sinir ağına sahip olacağız. 1980'ler sonu görüntü tanıma dünyasına hoşgeldiniz.

Tünel Vizyonu

Görsel tanımayı kurmak için sinir ağını basitçe piksellerle beslememiz gerçekten havalı. Makine öğrenmesi sihirli bir şey. Gerçekten?

Öncelikle, iyi haber, “8” tanıma cihazımız sayının tam ortada olduğu basit görüntülerde gerçekten de iyi çalışıyor.

Şimdi kötü haber:

“8” tanıma cihazımız, eğer sayı görüntünün tam ortasında değilse hiç bir şekilde çalışmıyor. Küçücük bir pozisyon değişikliği her şeyi mahvediyor:

Bunun nedeni, ağımız sadece “8”in tam ortada olduğu bir kalıptan öğrendi. Tam ortada olmayan bir “8”in ne olduğu hakkında hiç bir fikri yok. Sadece ve sadece tek bir kalıp biliyor.

Bu gerçek hayatta çok da kullanışlı değil. Gerçek hayatta sorunlar bu kadar düz ve basit değiller. Bu yüzden sinir ağımızın “8”in tam ortada olmadığı durumlarda da çalışmasını sağlamalıyız.

Kaba Güç fikri no. 1: Kayan Pencere ile Aramak

Çoktan tam ortadaki “8”i bulan iyi bir program yarattık. Görseli daha küçük parçalara ayırıp, teker teker, tam ortada “8”e sahip daha küçük alanlar bulmaya çalışsak?

Bu yaklaşıma kayan pencere deniyor. Bu kaba güç çözümü. Sınırlı birkaç durumda iyi çalışıyor ama hiç verimli değil. Aynı görseli arka arkaya kontrol etmeniz ve farklı boyutlardaki görselleri aramanız gerekiyor. Bundan daha iyisini yapabiliriz!

Kaba Güç Fikri no. 2: Daha Çok Veri ve Derin Sinir Ağı

Ağımızı eğitirken, ona sadece tam ortada olan “8”ler gösterdik. Ya “8”in farklı boyutlarda ve farklı yerlerde olduğu görseller dahil, ağımızı daha fazla veri ile eğitirsek?

Daha çok veri toplamamıza gerek bile yok. Bizim için “8”in farklı yerlerde olduğu görseller üreten bir betik yazabiliriz.

Eğitme verimizin farklı versiyonlarını yaratarak yapay bir eğitme verisi oluşturduk. Bu çok kullanışlı bir yöntem!

Bu yöntemi kullanarak, sonsuz bir eğitim verisi tedarik edebiliriz.

Ağımızı daha büyük hale getirmek için, birkaç katman daha düğüm ekliyoruz:

Buna “derin sinir ağı” deniyor çünkü geleneksel sinir ağlarından daha çok katmana sahip.

Bu fikir 1960'lardan bu yana var. Ancak yakın zamana kadar, bu büyüklükle bir sinir ağını eğitmek çok yavaştı. Ne zaman ki normal bilgisayar işlemcimiz yerine 3 boyutlu ekran kartlarını (ki çok hızlı matris çarpımı için dizayn edilmişlerdir) kullanmayı çözdük, büyük sinir ağlarıyla çalışmak kolay bir hale geldi. Hatta Overwatch oynamak için kullandığınız NVIDIA GeForce GTX 1080 video kartı, sinir ağlarını inanılmaz derecede hızlı eğitmek için kullanılabilir.

Sinir ağımızı büyütsek ve onu çok hızlı eğitebilsek bile, bu bizi çözüme kadar götürmeyecek. Görselleri ağımızda nasıl işlediğimiz konusunda daha akıllı olmalıyız.

Bir düşünün. Bir sinir ağını, sanki görselin yukarısındaki “8” ve aşağısındaki “8” iki farklı objeymiş gibi eğitmek çok mantıklı değil.

Öyle bir çözüm olmalı ki, sinir ağımız görselin neresinde olursa olsun, “8”in aynı obje olduğunu fazladan eğitime gerek kalmadan anlayacak kadar akıllı olmalı. Şansımıza, böyle bir çözüm var!

Çözüm Evrişim

Bir insan olarak, doğal olarak bir görselin hiyerarşik ve kavramsal yapısını sezgisel olarak biliyoruz. Şu fotoğrafa göz atın:

Oğlumun sebepsiz bir fotoğrafı (not: Gerçek yazarın, çevirmenin değil :) )

Anında fotoğrafın hiyerarşisini anlayabiliyoruz:

  • Yer beton ve çim ile kaplı
  • Bir çocuk var
  • Çocuk oyuncak bir atın üzerinde oturuyor
  • At çimin üzerinde

En önemlisi, çocuk fikrini, hangi yüzeyde oturduğuna bakmazsızın tanıyabiliyoruz. Çocuğun görünebileceği her faklı yüzey için, çocuk fikrini sıfırdan öğrenmemize gerek yok.

Şu anda bizim sinir ağımız bunu yapamıyor. Görselin farklı bir yerindeki “8”in tamamen farklı bir obje olduğunu düşünüyor. Bir objeyi görselde hareket ettirmenin onu farklı bir obje yapmadığını anlayamıyor. Bu olası her pozisyon için objeyi tekrar öğrenmesini gerektiriyor. Kötü bir durum.

Sinir ağımıza dönüştürmenin değişmezliği (translation invariance) anlayışını aşılamamız gerekiyor. Görselin neresinde olursa olsun, “8”, “8”dir.

Bunu evrişim denilen bir işlem ile yapacağız. Evrişim fikri biraz bilgisayar biliminden biraz da biyolojiden geliyor (örn: Kedilerin görüntüleri nasıl işlediğini anlamak için beyinlerine garip sondalar yapan çılgın bilim adamları).

Evrişim nasıl çalışır?

Sinir ağımızı, imajlarımızla bir bütün olarak beslemek yerine, bir objenin nerede olursa olsun aynı olduğu avantajını kullanan çok daha akıllıca bir şey yapacağız.

Adım adım neler yapacağımız-

Adım 1: Görseli üst üste binen parçalara bölmek

Kayan pencere fikrimize benzer olarak, asıl görselin üzerinden bir pencere kaydıralım ve her bir sonucu ayrı bir görsel olarak kaydedelim:

Bunu yaparak asıl görselimizi aynı boyuta sahip 77 farklı görsele dönüştürdük.

Adım 2: Her bir görseli küçük bir sinir ağına beslemek

Önceden, bütün bir imajı, “8” olduğunu anlamak için sinir ağına besliyorduk. Şimdi de aynısını yapacağız ancak bunu her bir görsel parçası için ayrı ayrı yapacağız.

Bunu her bir parça için 77 defa tekrar edin.

Ancak, büyük bir hilemiz var: Her bir görsel parçası için aynı sinir ağı ağırlıklarını tutacağız. Başka bir deyişle, her bir parçaya aynı davranıyoruz. Eğer herhangi bir parçada ilginç bir şey çıkarsa, o parçayı işaretleyeceğiz.

Adım 3: Her parçanın sonucunu yeni bir dizine kaydetmek

Küçük parçaların asıl görseldeki dizilimini kaybetmek istemiyoruz. Bu yüzden her bir parçanın işlenmesinden çıkan sonucu asıl görselle aynı dizilime sahip iki boyutlu bir dizine kaydediyoruz. Şöyle görünüyor:

Ç.N: ortadaki kutuda “küçük sinir ağı” yazıyor.

Başka bir deyişle, büyük bir görselle başladık ve asıl resimde nerelerin daha ilginç olduğunu gösteren biraz daha küçük bir dizinle bitirdik.

Adım 4: Alt örnekleme

Dizinin boyutunu küçültmek için max-pooling (Tr: maksimum örnekleme) denilen bir algoritma kullanıyoruz. Adı çok havalı ama kendisi değil!

Dizindeki her 2x2lik kareye bakıp en büyük sayıyı tutacağız:

Buradaki amaç, eğer 2x2lik bir alanda ilginç bir parça bulduysak, sadece en ilginç olanını tutuyoruz. Bu en ilginç kısımları korurken dizinimizi küçültmemizi sağlıyor.

Son Adım: Tahmin etmek

Şu ana kadar, dev bir görseli görece küçük bir dizine indirgedik.

Hazır olun. Dizinimiz sadece birkaç sayı, yani onu da başka bir sinir ağına girdi olarak kullanabiliriz. Bu son sinir ağı görselin eşleşip eşleşmediğine karar verecek. Bunu yukarıdaki evrişim adımından ayırmak için, buna “tamamen bağlı” ağ diyoruz.

Baştan sona 5 adımlık hattımız böyle görünüyor:

Daha da fazla adım eklemek

Görsel işleme hattımız birkaç adımdan oluşuyor: Evrişim, max-pooling ve sonunda da tam bağlı sinir ağı.

Gerçek hayattaki problemleri çözerken, bu adımlar istediğiniz kadar birleştirilip kümelendirilebilir! 2, 3 hatta 5 tane evrişim katmanına sahip olabilirsiniz. Max-pooling algoritmasını dizini küçültmek için nerede isterseniz kullanabilirsiniz.

Ana fikir, büyük bir görsel ile başlayıp onu tek bir sonuca ulaşana kadar adım adım küçültmek. Ne kadar çok evrişim katmanına sahipseniz, ağınız da o kadar karmaşık şekilleri anlayabilir.

Örneğin, ilk katman keskin kenarları tanıyabilir, ikincisi keskin kenar bilgisini kullanarak kuş gagasını tanımlayabilir, üçüncüsü gaga bilgisini kullanarak bütün bir kuşu tanımlayabilir.

Daha gerçekçi (makalelerde görebileceğiz türden) bir derin evrişimli sinir ağı buna benzer:

Bu durumda 224x224lük bir görselle başlayıp, iki defa evrişim ve max-pooling, 3 defa daha evrişim, sonra bir daha max-pooling uygulayıp, en sonunda 2 adet tam bağlı katman elde etmişler. Sonuç olarak görsel 1000 ayrı kategoriden birine sınıflandırılmış!

Doğru Ağı Kurmak

Peki görsel sınıflandırmanızın çalışması için hangi adımları birleştirmeniz gerektiğini nasıl bileceksiniz?

Açıkcası, bunu sadece deneyerek ve test ederek bulabilirsiniz. Doğru değişkenleri ve yapıyı bulana kadar 100 tane sinir ağı eğitmeniz gerekebilir. Makine öğrenmesi çok fazla deneme yanılma içerir!

Kuş Tanıyıcımızı Kurmak

Artık bir görselin kuş olup olmadığını anlayan bir program yazacak kadar şey biliyoruz.

Her zamanki gibi, başlamak için veriye ihtiyacımız var. Bedava CIFAR10 veri seti 6,000 adet kuş görseli ve 52,000 adet kuş olmayan görsel içeriyor. Daha da fazla veriye sahip olmak için 12,000 adet kuş görseline sahip Caltech-UCSD Birds-200–2001 veri setini de ekleyeceğiz.

Birleştirilmiş veri setimizden birkaç kuş örneği:

Burada da 52,000 adet kuş olmayan görsel:

Bu veri seti bizim amacımız için uygun ama 72,000 adet düşük çözünürlükte görüntü gerçek hayat uygulamaları için hayli küçük. Eğer Google kalitesinde performans istiyorsanız, milyonlarca görüntüye ihtiyacınız var. Makine öğrenmesinde, daha fazla veriye sahip olmak, daha iyi algoritmaya sahip olmaktan neredeyse her zaman daha önemli. Artık Google’ın size neden zevkle sınırsız fotoğraf saklama alanı verdiğini biliyorsunuz. Tatlı mı tatlı verinizi istiyorlar.

Sınıflandırıcımızı yapmak için TFLearn kullanacağız. TFLearn Google’ın TensorFlow derin öğrenme kütüphanesini saran ve daha basit bir arayüz sunan bir paket. Bu paket, evrişimli sinir ağları kurmayı, katmanlarımızı tanımladığımız birkaç satırlık kod yazmak kadar kolay kılıyor.

İşte ağımızı tanımladığımız ve eğittiğimiz kod bloğu:

Eğer güçlü bir RAM’e sahip bir video kartıyla (Nvidia GeForce GTX 980 Ti gibi) eğitiyorsanız bu işlem bir saatten az sürecek. Eğer normal bir işlemci ile çalışıyorsanız, çok daha uzun sürebilir.

Eğitme devam ettikçe, doğruluğu yükselecek. İlk geçişten sonra, doğruluk %75.4'tü. 10 geçişten sonra, %91.7 oldu. 50'ye yakın geçişten sonra, %95.5'e dayandı ve fazladan eğitim etki etmedi, yani durabilirsiniz.

Tebrikler! Programımız artık görsellerdeki kuşları tanımlayabiliyor.

Ağımızı Test Etmek

Artık ağımızı eğittiğimize göre, onu kullanabiliriz! Buradaki betik tek bir görsel alıp kuş olup olmadığını tahmin ediyor.

Ağımızın ne kadar etkili olduğunu görebilmek için, onu çok fazla görselle test etmeliyiz. Yarattığımız veri setinde 15,000 görsel onaylama kısmı için arkada tutuluyordu. Bu 15,000 görseli ağımızda denediğimizde %95'lik oranla hepsini doğru tahmin etti.

Bu bayağı iyi görünüyor, değil mi? Değişir…

%95'lik doğruluk ne kadar doğru?

Ağımız %95'lik bir doğruluğu olduğunu iddia ediyor. Bu çok fazla farklı anlama gelebilir.

Örneğin, ya veri setimizin sadece %5'i kuş ve geri kalan %95'i kuş değilse? Her görsele “kuş değil” diyen bir program %95 oranla doğru olurdu. Ancak %100 işe yaramaz olurdu.

Genel doğruluktan ziyade sayılara daha yakından bakmalıyız. Bir sınıflandırma sisteminin ne kadar iyi olduğunu anlamak için, sadece başarısız olduğu zamanların oranına değil, nasıl başarısız olduğuna da bakmalıyız.

Tahminlerimizi sadece doğru veya yanlış olarak nitelendirmek yerine, onları 4 ayrı sınıfa kategoriye ayıralım.

Öncelikle, ağımızın başarıyla “kuş” olarak adlandırdığı kuşlara bakalım. Bunlara doğru pozitif deniyor:

Wow! Ağımız bir sürü farklı bir kuşu başarıyla tanıyabiliyor.

İkinci olarak, ağımızın “kuş değil” dediği, kuş olmayan görsellere bakalım. Bunlar doğru negatifler:

Atlar ve kamyonlar bizi kandıramaz!

Üçüncü olarak, “kuş” sandığımız ancak kuş olmayan görsellere bakalım. Bunlar yanlış pozitifler:

Bir çok uçak, kuş olarak tanımlanmış. Bu akla uygun.

Son olarak da, “kuş” olarak tanımlayamadığımız bazı kuş görselleri. Bunlar yanlış negatifler:

Bu kuşlar bizi kandırdı. Deve kuşları, kuş olarak sayılıyor mu ki?

15,000 görsellik onaylama setimizi kullanarak, her bir tahminimizin bu 4 kategoriye ayrılmış hali:

Neden sonucumuzu böyle parçalara bölüyoruz? Çünkü her yanlış eşit yaratılmamıştır.

MRI görüntüsünden kanseri tanımamızı sağlayan bir program yazdığımızı düşünün. Eğer kanseri belirliyorsak, yanlış pozitifleri, yanlış negatiflere tercih ederiz. Yanlış negatifler en kötü sonuç olur — Bu programın birine kanser olmadığını söylemesi ama o kişinin aslında kanser olması demek.

Genel doğruluğa bakmak yerine, hassasiyet ve duyarlılık metriklerini hesaplıyoruz. Bu metrikler bize ne kadar iyi olduğumuza dair daha anlaşılır bir resim sunuyor.

“/” => bölü

Bu kuş tahmini yaptığımız durumların %97'sinde haklıydık anlamına geliyor. Aynı zamanda, veri setindeki kuşların sadece %90'ını bulduğumuzu da söylüyor. Başka bir deyişle, her kuşu bulamayabiliriz ancak bulduğumuzda, onun kuş olduğundan fazlasıyla eminiz.

Bir Sonraki Adım

Artık derin evrişimli ağların temellerini bildiğimize göre, ellerinizi farklı mimariye sahip sinir ağlarıyla kirletmek için tflearn ile gelen örneklere göz atabilirsiniz. Çoğu içine gömülü veri setiyle geliyor, böylece kendi verinizi bulmanıza gerek yok.

Artık makine öğrenmesinin başka dallarını öğrenmeye başlamaya yetecek kadar da biliyorsunuz. Neden atari oyunları oynamayı öğrenen algoritmalara (ing. kaynak) bakmıyorsunuz?

Eğer bu yazıyı beğendiyseniz, yazarın Machine Learning is Fun! e-posta grubuna kayıt olabilirsiniz. Yazar sadece enteresan ve yeni şeyler bulduğunda mail atıyor. Bunun gibi yazılar yazdığında haberdar olmanızın en iyi yolu bu.

Ayrıca yazara Twitter ile @ageitgey, e-posta ile veya linkedIn üzerinden ulaşabilirsiniz.

Yazarın izniyle çevrilmiştir. Yazının kendisine buradan ulaşabilirsiniz. Bana da buradan e-posta ile ulaşabilirsiniz.

--

--