Derin Öğrenme ve Spotify’ın Arama Algoritması ile Kıyafet Tavsiye Sistemi Yazmak [ResNet — ANNOY]

Samed Harman
5 min readJun 12, 2021

--

Bilgisayarlı görü uygulamalarında yüksek başarı gösteren , milyonlarca resim ile eğitilmiş ve etiketlenmiş bazı CNN mimarileri olduğunu biliyoruz. Örneğin VGG, ResNet , Inception gibi. Sınıflandırma problemlerinin yanı sıra bu modeller aslında transfer öğrenme için de oldukça uygun modeller. Peki transfer öğrenme de nedir?. Bu modelleri nasıl kullanacağız?. Hadi başlayalım o halde ✨.

Nelerden bahsediyoruz?

  • Transfer Öğrenme Konsepti
  • Veriyi Yükleme
  • Veri Ön İşleme ve ResNet ile Öznitelik Çıkarımı
  • Annoy Algoritması ile En Yakın Komşuları Bulma
  • Sonuçlarımızı Görselleştirme

Transfer Öğrenme Konsepti

Transfer öğrenme konsepti , bir modelin başka bir problem için yeniden kullanılmasına dayanır diyebiliriz. Özellikle çok fazla veriye sahip olamayabileceğimiz bazı problemlerde, transfer öğreniminin yokluğunda geliştiremeyeceğimiz başarısı yüksek modeller geliştirebiliriz. Bu yazıdaki çalışmamızda transfer öğrenmeyi pre-trained yani önceden eğitilmiş , başarısı yüksek , state-of-art olarak isimlendirilen ağ modellerinden ResNet ile yapıyor olacağız.

Veriyi Yükleme

Colab üzerinde yapacağımız çalışmada öncelikle drive içerisine yüklediğimiz veri setimizi okuyalım. Veri setinde yaklaşık 6000 kadar görsel olduğu için bu proje bazında biz ilk 1000 adet resmi kullanmak için okuyalım. Ardından rastgele birkaç elemanı ekranımızda görüntülemek için matplotlib’i kullanalım. Dosya yolundan bir PIL image üretebilmek için keras içinde bulunan load_img() metodundan faydalanıyoruz.

Çıktı olarak veri setinden birkaç resim görebiliriz. Veri setimizin geriye kalan kısmında da farklı çeşitlerde görseller bulunmakta.

Resmimizi img_to_array() metodu ile bir dizi haline çevirip boyutuna baktığımızda ise:

(224, 224, 3)

gibi bir sonuç almaktayız. Buradan resimlerimizin 224x224 boyutunda ve 3 renk kanalında yani RGB formatında olduğunu anlıyoruz.

Veri Ön İşleme ve ResNet ile Öznitelik Çıkarımı

Geldik tüm olayın yüzde 90'ına falan 😁. En önemli kısım burası diye düşünüyorum. Önce bir kodu görelim , sonra satır satır bakalım neler oluyor diye.

Öncelikle öznitelik çıkarma işlemi için yani transfer öğrenme için kullanacağımız pre-trained modelimizi yüklüyoruz. ResNet50 sınıfına argüman olarak geçtiğimiz include_top=False ifadesi ile ağın üzerinde bir tam bağlı katman olmasın diyoruz. Çünkü tam bağlı katmanlar sınıflandırma problemlerinde iş yapıyor. Bize lazım değil yani , bizde sınıflandırma yok kardeşim 😏.

Sonrasında her bir resmimiz için öznitelik çıkarımı yapacağımız feature_extraction() metodumuzu yazıyoruz. Resmin dosya yolunu ve kullanacağımız modeli parametre olarak geçiyoruz. İlk iki satırı zaten yukarda görselleştirme esnasında da yapmıştık. Resmimizi, gelen dosya yolundan okuyor ve img_to_array() metodu ile bir numpy dizisi formatına çeviriyoruz.

Bir sonraki satırda ise numpy kütüphanesinin dizi boyutu genişletmeye yarayan expand_dims() metoduna elimizdeki numpy formatlı resmi veriyor ve işlemi axis = 0'da yani düşey eksende yapmasını söylüyoruz. Ardından elimizdeki verinin formatının ‘float64’ olduğundan emin olmak adına tekrar numpy dizisi formatına çeviriyoruz. Burada neden diziyi düşey eksende genişlettik derseniz cevabını bir sonraki satırda söyleyelim 😊.

Bi sonraki satırda resmimizi bir başka ön işleme metodu olan preprocess_input()’ a geçiyoruz. ResNet mimarisi bizim veri setimizden farklı bir veri seti ile eğitildiğinden dolayı metodumuz burada resimlerin ortalama RGB kanallarını çıkartarak diziyi model için uygun bir forma dönüştürmekte. Metodun keras.application.resnet50 içerisinden import edildiğine dikkat edelim. Farklı mimariler için farklı preprocess_input metotları mevcut.

ResNet mimarisi giriş için 224,224 boyutunda diziler kabul ediyor. Bunun yanı sıra modelden tahmin işlemi yapabilmek için ağ içerisinde bulunacak örnek sayısına da ihtiyaç duyuyor , bu kısma batch size diyoruz. Yukarda expand_dim()’i neden kullanmıştık diye sorduysanız , cevabı bu efendim. Dizideki bir elemanın expand_dim() ve preprocess_input() sonrası boyutu şu şekilde görüntülenecektir:

(1 , 224 , 224 , 3)

Ardından diziyi flatten() ile tek bir boyuta indirgiyoruz. Son olarak değerleri normalize ederek öznitelikleri içeren diziyi fonksiyondan geriye döndürüyoruz.

Artık özellik vektörlerimizi çıkartabiliriz. Tüm dizi içerisinde bir döngü ile 1000 adet veriyi geziyor ve feature_extraction metodumuzu çağırıyoruz. Bu işlem biraz uzun sürebileceğinden dolayı ilerleyişi görmek için tqdm_notebook metodunu kullanıyoruz. Bu metot bize işlem esnasında bir progress bar gösterecektir.

Bu işlem zaman maliyeti yarattığından dolayı oluşan bu öznitelik listesini bir dosyaya kaydetmekte fayda var. Bunun için şu metotları yazabiliriz:

Öznitelik listemiz elimizde olduğuna göre şimdi sıra vereceğimiz resme en yakın öznitelikleri içeren resmi elde etmekte. Bunun için ise Annoy (Approximate Nearest Neighboor — Yaklaşık En Yakın Komşular) algoritmasından faydalanacağız. Yüksek boyutlu dizilerde iyi bir performans sergileyen bu algoritmayı Spotify müzik önerilerinde kullanıyor. Daha fazla detaya buradan erişebilirsiniz.

Dizimizi Annoy’a vermeden önce bir dataframe olarak düzenleyelim:

Öneri olarak gelecek resimleri lokal dosyamızdan okuyarak ekrana göstereceğimiz için hangi özniteliğin hangi resme ait olduğunu bilmemiz gerekiyor. Resimlerin isimlerini de bu yüzden öznitelik değerleri ile birlikte dataframe içerisinde tutmaktayız. Şimdi hadi komşuları bulmaya 🪁.

Annoy Algoritması İle En Yakın Komşuları Bulma

Annoy en yakın komşuları bulurken bizden referans olan dizinin uzunluğunu istemekte. Uzaklık ölçütü olarak da öklid uzaklığı kullanıyoruz. Ardından her bir vektörü farklı index ile add_item()’a geçiyoruz. Ardından ağacımızın oluşması için build() metodunu çağırıyoruz. Burada Annoy’un kaç adet ağaç çizeceğini ilk parametrede verebilirsiniz ve fine tuning yapabilirsiniz. İkinci parametreyi de -1 geçerek işlemin mevcut işlemci çekirdeklerinin tamamını kullanmasını sağlayabilirsiniz.

Ardından get_nns_by_item() metodu ile en yakın komşularımızı elde ediyoruz. Bu metoda referans olacak resmimizin dataframe indeksini, istediğimiz komşu sayısını ve hesaplanan öklid mesafe değerlerinin bilgisinin döneceği parametreleri geçiyoruz. Referans resim olarak dataframe içindeki ilk elemanı kullanacağımız için değeri 0 olarak geçtik. Bu metot çalıştığında similar_img_ids değişkeninde referans resme en yakın olan 4 adet resmin isimlerinin yer aldığı bir liste yer alacak. Diğer değişkende ise mesafe bilgileri yer alıyor olacaktır.

Sonuçları Görselleştirme

Bu kod bloğunda referans resmimiz ilk satırda yer almak üzere gelen önerileri dinamik olarak görselleştiren bir yapı kurmaya çalıştık. İlk satır harici diğer satırlarda maksimum üç resim olacak şekilde en yakın komşuları görebilmekteyiz. Kodumuzun çıktısı şu şekilde olacaktır:

Komşu resimlerin altında göreceğiniz değerler ise öklid uzaklık mesafesi değerleridir. Değer 0 ‘a ne kadar yakınsa referansa daha benzer bir üründür sonucunu çıkartabiliriz. Referans resim olarak farklı tipte ürün resimleri verdiğinizde de karışık veri setinden benzer resimleri size başarıyla getireceğini gözlemleyebilirsiniz. Tabii veri setinde hiç olmayan bir resim için daha farklı çözümler düşünülmesi gerekir. Şimdilik projemiz bu kadar 🎇.

Bu yazımda ResNet ağı ve Annoy algoritması ile kendi çapımda bir öneri sistemi yazmaya çalıştım. Umarım faydalı olmuştur. Gördüğünüz eksiklikleri, hataları lütfen bana bildirin. Öneri ve görüşleriniz olursa da çekinmeyin. Veri setini edindiğiniz takdirde aşağıdaki bağlantıdan kodu Colab üzerinde çalıştırabilirsiniz. Şimdilik görüşmek üzere 🎈.

Referans aldığım kaynak:

--

--

Samed Harman
Samed Harman

Written by Samed Harman

Flutter/Android Mobile App Developer | Computer Engineer

No responses yet