Özyinelemeli Sinir Ağlarına Giriş

Esma Bozkurt
8 min readApr 8, 2023

Yapay Sinir Ağlarının bir sınıfına özgü Evrişimli Sinir Ağları’nın (Convolutional Neural Networks (CNN)) katmanlardan oluştuğunu ve her katmanla birlikte ileri/geri yayılım mekanizması ile öğrenmenin gerçekleştiğini öğrenmiştik. Bu yazımda ise Özyinelemeli Sinir Ağları’ndan (Recurrent Neural Networks (RNN)) ve nasıl çalıştıklarından bahsedeceğim.

Özyinelemeli Sinir Ağları, zaman serisi şeklinde ifade edilen problemlere çözüm üretir diyebiliriz. Özellikle ses işlemede (speech to text/text to speech, müzik üretimi gibi) sıkça kullanılır çünkü ses zaman boyunca süregelen bir veridir. Doğal dil işleme alanında (özellikle metinden duygu tanıma ve duygu analizi, olumlu-olumsuz yorum gibi) ve metin çevirisinde ve seslendirilmesinde (Text Search and Analytics) de kullanılmaktadır. Aynı zamanda DNA dizilimlerinin kestirimleri gibi medikal uygulamalarda da RNN türleri (LSTM gibi) sıkça kullanılır. Dahası ilaç ve kimyasalların kodlanmasında ve üretiminde de kullanılıyor. Görüntü işlemede de her ne kadar biz evrişimli sinir ağı kullansak da bu görüntünün zaman serisi boyunca uzanmış olduğu videoların çözümlerinde de RNN kullanabiliyoruz. Bir makinenin bakım zamanının gelip gelmediğine karar verirken veya arıza oluşturup oluşturmayacağını tespit ederken (Öngörücü Bakım) de RNN kullanılabilir. Finans alanında dahi kullanılabilir. Öyleyse kullanım alanı oldukça geniş olan RNN’e bir giriş yapalım.

Klasik yapay sinir ağlarında girişlerimiz katmanlarla birlikte çıkışa ulaşıyordu ve ileri besleme yaparken tüm girişler tüm çıkışları etkiliyordu:

Burada x<T> ve y<T> ‘nin birbirine eşit olmadığı durumlarla karşılaşabiliyoruz. Zaman ve dizi etkisi dolayısıyla böyle bir modelde metin boyunca karşılaşılan farklı dizilimler öğrenilmemiş olur. Bu gibi etkenler dolayısıyla RNN kullanırız.

Burada RNN’in çalışma prensibine göre kelimeler; ilgili kelimeye 1, diğer kelimelere 0 verilirerek vektörlerle ifade edilir. Örneğin yukarıdaki cümlelerde özel isimlere 1, diğerlerine 0 verildiğini görüyoruz. Her kelime sırayla sözlüğe (vektöre) yerleştirilir. Yukarıdaki metin örneğinde kelime sayısına göre vektör uzunluğu 10000 olarak ayarlanmış. Daha sonra her kelimenin bulunduğu kısımda o kelimeye 1 diğerlerine 0 verilir ve sırayla öğrenme sağlanır. Öğrenme bu şekilde yinelenerek gerçekleşir ve her giriş için her çıkış eşit olmuş olur. Bu şekilde oluşturmuş olduğumuz yapay sinir ağının modeli değişmiş oluyor:

Burada a<0> giriş ağırlık vektörü olmuş oluyor ve y^<1> kestirimini hesaplamak için ilk giriş olan x<1> ve a<0>’ın değerlerini bilmem gerekiyor. Daha sonraki aşamada a’nın 1’den gelen değeri ile x<2> ‘nin işleme girmesiyle kestirdiğim y^<2> ve a<2> değerlerini elde ediyorum. Burada x girişlerinin her biri birer kelimeyi ifade ediyor. Bunların katman değil, zamana bağlı ilerleme olduğunu unutmayalım. Aynı zamanda ağırlıklar her bir kelime için aynı olup son andaki y^<Ty> değeri, kendisinden önceki her işleme bağlı olmuş olacak. Burada çıkış için her x giriş değerlerini biliyor olmam gerekecek. Örneğin y^<3> ü hesaplayabilmek için x<3>,x<2>,x<1>,a<1>,a<0>’ı bilmem gerekir.

Not: CNN’de elde edilen y değerleri her x giriş değerine bağlı değildi ve farklı ağırlıklar söz konusuydu.

RNN’in en büyük dezavantajı kestirimlerin her zaman kendinden önceki bilgilere bağlı olarak gerçekleşmesidir. Bazı durumlarda gelecekteki bilgileri de hesaba katmamız gerekecek ve problem oluşturacaktır.

Bu örnekteki gibi Candy’i tanımlayabilmemiz kendisinden önceki kelimelere değil, sonraki kelimelere bağlıdır ve gelecekteki bilgileri hesaba katmamızı gerektirecektir.

RNN Hesaplamaları

İlk olarak a<0> ve x<1> in işleme sokulup y^<1> ve a<1>’in hesaplanmasını inceleyelim:

Öncelikle x giriş ve a değerleri W ağırlıklarıyla çarpılarak ve bias değeri eklenerek yeni a değeri belirlenir. Daha sonra y değeri hesaplanırken de bulmuş olduğumuz yeni a değeri tekrar ağırlandırılır ve bias eklenir. Burada “g” ReLu gibi bir aktivasyon fonksiyonudur. ReLu aktivasyon fonksiyonu CNN’de sık tercih edilmesine rağmen, RNN’de pek tercih edilmemektedir. RNN’de genellikle hiperbolik tanjant (tanh) tercih edilmektedir. İşlemde a ve y hesaplanırken aynı veya farklı aktivasyon fonksiyonları tercih edilebilir. Belirttiğimiz işlemi genelleştirirsek şu ifadeleri elde ederiz:

Dolayısıyla y^<t> hesaplanırken, hesaplamış olduğum a<t> değerini kullanmaktayım. Genellikle a hesaplanırken hiperbolik tanjant (tanh) ve ReLu (nadiren de olsa) ve y çıkışları hesaplanırken de sigmoid aktivasyon fonksiyonları tercih edilmektedir. Probleme göre çıkış için softmax de kullanılabilir.

Burada Waa 100x100’lük bir matris olup a değeri de 100’lük bir vektör olmuş olsun. Girişteki kelime sayısına göre x giriş değerinin 10000’lik bir vektör olduğunu düşünürsek Wax değerini 100x10000’lik bir matris olarak ifade ederiz.

Wax ifadesini ve genel a ifadesini şu şekilde de ifade edebiliriz:

İleride daha fazla indisli ifadeler kullanacağımızdan a ve y ifadesini yazmakta zorlanacağız. Dolayısıyla ifadeyi bu şekilde basitleştirmekteyiz.

Soldan sağa doğru ilerlemiş olduğumuz bu hesaplamaları ileri besleme olarak düşünebiliriz. Peki RNN’de geriye yayılım algoritması nasıl çalışıyor biraz da bunu inceleyelim.

Öncelikle geriye yayılımda loss (yitim) değeri ve ağırlıkların güncel değerlerini kullanmamız gerekiyor. Loss fonksiyonu ile (öklid uzaklığı, ortalama kareler hatası, cross entropi vs.) kestirilen y^ ve gerçek y değeri arasındaki loss değerini hesaplayabiliriz. Peki ağırlıkları nasıl güncelleyeceğiz?

İleri yayılımda W ağırlıklarını kullanarak a ve y değerlerini, buna bağlı olarak da L değerini hesaplamıştık. Şimdi bu ağırlıkları güncellememiz gerekiyor. Bunun için de gradient descent gibi optimizasyon algoritmaları kullanacağız.

Geriye yayılımda Loss’dan geriye doğru giderek sırasıyla y ve a değerlerini hesaplayacağız. Elde edeceğimiz çıkışlar güncel Wa, Wy değerleri olacak. Daha sonra yine bu Wa, Wy değerleri kullanılarak tekrar ileri yayılım gerçekleşecek.

Özyinelemeli sinir ağları (RNN) kullanım alanlarına göre farklı tasarımlara ihtiyaç duyabilir.

Örneğin müzik üretmedeki gibi tek bir giriş ve çoklu çıkış olabilir veya duygu analizindeki gibi çoklu giriş tek çıkış şeklinde de olabilir. Bu şekilde farklı veri tiplerinin girişleri ve çıkışları için farklı RNN’ler tasarlamak mümkün olur.

RNN ile Dil Modeli ve Dizi Üretimi

Okunurken birbirine çok benzeyen ancak oldukça farklı anlamlara sahip kelime ve cümlelerle karşılaşabiliriz. Örneğin “red” ve “read” gibi farklı tense’lerde kullanılan yapılar gibi:

Burada “read” ile daha sık karşılaşacağımızı biliyoruz, o yüzden onun olasılığı daha yüksek olacaktır.

Kelime dizinlerinde de bu böyledir. Örneğin hard to ifadesinden sonra üstteki kelime ile karşılaşılma sıklığı daha yüksektir:

Aynı zamanda cümlenin bitmiş olduğunu ifade eden “nokta” ya da bir değer atamamız gerekir. Yani her kelime için bir y çıktısı elde ederken nokta için de bir y çıktısı elde etmeliyim. Noktayı ifade etmek için de EOS (end of sentence) değerini kullanacağım:

Sözlükte bulunmayan “unknow” kelimelerle de karşılaşabiliriz. Bu örnekte köpek cinsini ifade eden iki kelime var. Bunları da <<UNK>> olarak tanımlamış olmam gerekiyor:

Şimdi “Dogs live for about 14 years. <<EOS>>” cümlesindeki RNN modelini inceleyelim. Burada sözlüğün tamamını bir olasılık havuzu gibi düşünebiliriz.

Havuz P(a)’dan başlayıp P(<EOS>)’a kadar tüm kelimelerin olasılığını içerir.

Burada cümlenin ilk kelimesi dogs ve ondan önce herhangi bir kelime yok. O yüzden x<1> = 0 olacaktır. Daha sonra y^<1> kestirimini yapıyorum. Kestirdiğim değer yeni kelimenin girişi olmuş olacak. Yani x<2> = y^<1> (dogs) olmuş oluyor. Daha sonra Dogs’dan sonra live geliyor ve x<3> = y^<2> (live) olmuş oldu. Her kelimenin bir önceki kelimelere bağlı olduğunu görüyoruz. En sonda da “years” den sonra <<EOS>> gelmesi durumu var.

Burda y<2>’nin kendinden önceki y<1> ve y<3>’ün kendinden önceki y<2> ve y<1>’e bağlı bir olasılık olduğunu görmekteyiz:

Oluşturduğumuz bu model ile soldan sağa doğru yeni kelimeler öğrenmiş oluyorum ve modelin sonunda bir loss fonksiyonu ile (softmax, cross entropy vs.) elde ediyorum. Bu loss (yitim) değerinde de gerçek y ve kestirdiğimiz y’lerin arasındaki loss’u hesaplıyoruz. Genel ifadesiyle loss fonksiyonu şu şekildedir:

Örneğin burada Cross entropy loss fonksiyonunu kullanabiliriz:

Karakter Seviyeli Dil Modeli

Bu kelime seviyeli dil modeli “unknown” bilinmeyen kelimelerde bir sonraki kelimenin tahminini zorlaştırır ve hesaplamalarda hataya sebebiyet verecektir. Bunun için karakter seviyeli dil modelini kullanırız.

Örneğin buradaki iki kelime köpek cinsini belirten “unknown” bir kelimedir.

Burada x girişleri kelime değil “karakter (harf)” olacaktır. Bu modeli sıklıkla <<UNK>> kelimeleri tanımlayabilmek için kullanırız. Her bir karakteri ifade etmemiz gerekeceğinden daha uzun diziler hesaplamamızı gerektirir ve bu da işlem yükünü arttıracaktır. Dolayısıyla biz kelime seviyeli dil modelinde başarı oranımız daha yüksektir ve onu daha sık kullanırız.

Vanishing Gradients (Gradyanların Yok Olması Problemi)

Geriye yayılımda türev alırken kullandığımız aktivasyon fonksiyonunun türevinin 0 olduğu yerlerde ağırlıklar da 0’la güncellenmiş olup bilgi kaybı yaşamımıza sebep oluyordu. Dolayısıyla o kısımlarda öğrenme gerçekleşmiyordu (Vanishing Gradients). Bu problemle RNN modelinde de karşılaşabiliriz.

RNN’de bir kelime hakkında bilgi sahibi olabilmek için bir önceki kelimeye veya kelimelere yani olabildiğince yakın kelimelere bakılır. Ancak bu her zaman böyle olmayabilir.

Örneğin bu cümlede “French” tahmini yapabilmemiz için “France” kelimesi hakkında bilgi sahibi olmalıyız ancak bu bilgi yazının en başında bize verilmiştir. Yani arada birçok cümle geçmiş olabilir ve o cümlelerde farklı şehir isimleri de geçmiş olabilir.

Buradaki gibi was/were hangisini kullanacağıma karar verebilmem için de en baştaki kelimenin tekil mi çoğul mu olduğunu karar verebilmem gerekir. RNN eski geçmişten bilgi alma konusunda pek yetenekli değil yani uzun cümlelerde başarılı olamayabilir. Peki bunu nasıl öğrenebiliriz?

DO NOT PANIC!

Aslında bu problem için kullandığımız birçok yöntem var. Şimdi bu yöntemlerin ne olduğuna bakalım:

  • Gated Recurrent Units (GRU)
  • Long Short Term Memory (LSTM)
  • Bidirectional RNN
  • Deep-RNN

Yazıyı daha fazla uzatmamak adına bu yöntemlere bir sonraki yazımda yer vereceğim. Şimdilik beni takip etmeyi unutmayın, görüşmek üzere!

Kaynak: deeplearning.ai

--

--