{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tekrarlayan Sinir Ağları\n", "\n", "Önceki modülde, metnin zengin anlamsal temsillerini ve gömme katmanlarının üzerinde basit bir doğrusal sınıflandırıcı kullandık. Bu mimari, bir cümledeki kelimelerin toplu anlamını yakalar, ancak kelimelerin **sırasını** dikkate almaz çünkü gömme katmanlarının üzerindeki toplama işlemi, orijinal metinden bu bilgiyi kaldırır. Bu modeller kelime sıralamasını modelleyemediği için, metin oluşturma veya soru yanıtlama gibi daha karmaşık veya belirsiz görevleri çözemezler.\n", "\n", "Metin dizisinin anlamını yakalamak için, **tekrarlayan sinir ağı** veya RNN olarak adlandırılan başka bir sinir ağı mimarisi kullanmamız gerekir. RNN'de, cümlemizi ağdan bir sembol bir sembol geçiririz ve ağ bir **durum** üretir, ardından bu durumu bir sonraki sembolle birlikte tekrar ağa geçiririz.\n", "\n", "Verilen $X_0,\\dots,X_n$ token dizisi girişine göre, RNN bir sinir ağı blokları dizisi oluşturur ve bu diziyi uçtan uca geri yayılım kullanarak eğitir. Her ağ bloğu bir çift $(X_i,S_i)$ alır ve sonuç olarak $S_{i+1}$ üretir. Son durum $S_n$ veya çıktı $X_n$, sonucu üretmek için doğrusal bir sınıflandırıcıya gider. Tüm ağ blokları aynı ağırlıkları paylaşır ve tek bir geri yayılım geçişiyle uçtan uca eğitilir.\n", "\n", "Durum vektörleri $S_0,\\dots,S_n$ ağdan geçtiği için, kelimeler arasındaki sıralı bağımlılıkları öğrenebilir. Örneğin, dizide bir yerde *not* kelimesi geçtiğinde, durum vektöründeki belirli öğeleri olumsuzlayarak olumsuzlama yapmayı öğrenebilir.\n", "\n", "> Resimdeki tüm RNN bloklarının ağırlıkları paylaşıldığı için, aynı resim bir blok (sağda) olarak, ağın çıktı durumunu tekrar girişe geri döndüren bir tekrarlayan geri besleme döngüsü ile temsil edilebilir.\n", "\n", "Haber veri setimizi sınıflandırmada tekrarlayan sinir ağlarının nasıl yardımcı olabileceğini görelim.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading dataset...\n", "Building vocab...\n" ] } ], "source": [ "import torch\n", "import torchtext\n", "from torchnlp import *\n", "train_dataset, test_dataset, classes, vocab = load_dataset()\n", "vocab_size = len(vocab)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basit RNN Sınıflandırıcı\n", "\n", "Basit bir RNN durumunda, her tekrarlayan birim, birleştirilmiş giriş vektörünü ve durum vektörünü alarak yeni bir durum vektörü üreten basit bir doğrusal ağdır. PyTorch, bu birimi `RNNCell` sınıfıyla ve bu hücrelerin ağlarını ise `RNN` katmanı olarak temsil eder.\n", "\n", "Bir RNN sınıflandırıcı tanımlamak için, önce giriş kelime dağarcığının boyutunu düşürmek amacıyla bir gömme katmanı uygulayacağız ve ardından bunun üzerine bir RNN katmanı ekleyeceğiz:\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "class RNNClassifier(torch.nn.Module):\n", " def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n", " super().__init__()\n", " self.hidden_dim = hidden_dim\n", " self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n", " self.rnn = torch.nn.RNN(embed_dim,hidden_dim,batch_first=True)\n", " self.fc = torch.nn.Linear(hidden_dim, num_class)\n", "\n", " def forward(self, x):\n", " batch_size = x.size(0)\n", " x = self.embedding(x)\n", " x,h = self.rnn(x)\n", " return self.fc(x.mean(dim=1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Not:** Burada basitlik açısından eğitilmemiş bir gömme katmanı kullanıyoruz, ancak daha iyi sonuçlar için önceki birimde açıklandığı gibi Word2Vec veya GloVe gömmeleriyle önceden eğitilmiş bir gömme katmanı kullanabiliriz. Daha iyi anlamak için bu kodu önceden eğitilmiş gömmelerle çalışacak şekilde uyarlamak isteyebilirsiniz.\n", "\n", "Bizim durumumuzda, her bir grup aynı uzunlukta bir dizi doldurulmuş diziden oluşacak şekilde doldurulmuş bir veri yükleyici kullanacağız. RNN katmanı gömme tensörlerinin dizisini alacak ve iki çıktı üretecek:\n", "* $x$, her adımda RNN hücre çıktılarının dizisidir\n", "* $h$, dizinin son elemanı için nihai gizli durumdur\n", "\n", "Sonrasında, sınıf sayısını elde etmek için tam bağlantılı bir doğrusal sınıflandırıcı uygularız.\n", "\n", "> **Not:** RNN'leri eğitmek oldukça zordur, çünkü RNN hücreleri dizinin uzunluğu boyunca açıldığında, geri yayılımda yer alan katmanların sayısı oldukça fazla olur. Bu nedenle küçük bir öğrenme oranı seçmemiz ve iyi sonuçlar elde etmek için ağı daha büyük bir veri kümesinde eğitmemiz gerekir. Bu oldukça uzun sürebilir, bu yüzden GPU kullanımı tercih edilir.\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3200: acc=0.3090625\n", "6400: acc=0.38921875\n", "9600: acc=0.4590625\n", "12800: acc=0.511953125\n", "16000: acc=0.5506875\n", "19200: acc=0.57921875\n", "22400: acc=0.6070089285714285\n", "25600: acc=0.6304296875\n", "28800: acc=0.6484027777777778\n", "32000: acc=0.66509375\n", "35200: acc=0.6790056818181818\n", "38400: acc=0.6929166666666666\n", "41600: acc=0.7035817307692308\n", "44800: acc=0.7137276785714286\n", "48000: acc=0.72225\n", "51200: acc=0.73001953125\n", "54400: acc=0.7372794117647059\n", "57600: acc=0.7436631944444444\n", "60800: acc=0.7503947368421052\n", "64000: acc=0.75634375\n", "67200: acc=0.7615773809523809\n", "70400: acc=0.7662642045454545\n", "73600: acc=0.7708423913043478\n", "76800: acc=0.7751822916666666\n", "80000: acc=0.7790625\n", "83200: acc=0.7825\n", "86400: acc=0.7858564814814815\n", "89600: acc=0.7890513392857142\n", "92800: acc=0.7920474137931034\n", "96000: acc=0.7952708333333334\n", "99200: acc=0.7982258064516129\n", "102400: acc=0.80099609375\n", "105600: acc=0.8037594696969697\n", "108800: acc=0.8060569852941176\n" ] } ], "source": [ "train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)\n", "net = RNNClassifier(vocab_size,64,32,len(classes)).to(device)\n", "train_epoch(net,train_loader, lr=0.001)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Uzun Kısa Süreli Bellek (LSTM)\n", "\n", "Klasik RNN'lerin en büyük problemlerinden biri, **kaybolan gradyanlar** problemidir. RNN'ler tek bir geri yayılım geçişinde uçtan uca eğitildiği için, hatayı ağın ilk katmanlarına iletmekte zorlanır ve bu nedenle ağ, uzak tokenler arasındaki ilişkileri öğrenemez. Bu sorunu önlemenin yollarından biri, **kapılar** olarak adlandırılan **açık durum yönetimi**ni tanıtmaktır. Bu türdeki en bilinen iki mimari şunlardır: **Uzun Kısa Süreli Bellek** (LSTM) ve **Gated Relay Unit** (GRU).\n", "\n", "![Uzun kısa süreli bellek hücresine örnek gösteren bir görsel](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n", "\n", "LSTM Ağı, RNN'e benzer bir şekilde organize edilmiştir, ancak katmandan katmana geçen iki durum vardır: gerçek durum $c$ ve gizli vektör $h$. Her birimde, gizli vektör $h_i$ giriş $x_i$ ile birleştirilir ve **kapılar** aracılığıyla durum $c$ üzerinde ne olacağını kontrol eder. Her kapı, sigmoid aktivasyonuna sahip bir sinir ağıdır (çıktı aralığı $[0,1]$), ve durum vektörüyle çarpıldığında bit düzeyinde bir maske olarak düşünülebilir. Yukarıdaki resimde soldan sağa doğru şu kapılar bulunmaktadır:\n", "* **unutma kapısı**, gizli vektörü alır ve vektör $c$'nin hangi bileşenlerini unutmamız gerektiğini ve hangilerini geçirmemiz gerektiğini belirler.\n", "* **giriş kapısı**, girişten ve gizli vektörden bazı bilgileri alır ve duruma ekler.\n", "* **çıkış kapısı**, durumu $\\tanh$ aktivasyonu ile bir doğrusal katman aracılığıyla dönüştürür, ardından yeni durum $c_{i+1}$ üretmek için gizli vektör $h_i$ kullanarak bazı bileşenlerini seçer.\n", "\n", "Durum $c$'nin bileşenleri, açılıp kapatılabilen bayraklar olarak düşünülebilir. Örneğin, bir dizide *Alice* adını gördüğümüzde, bunun bir kadın karaktere atıfta bulunduğunu varsayabilir ve cümlede kadın bir isim olduğunu belirten bir bayrağı duruma yükseltebiliriz. Daha sonra *ve Tom* ifadelerini gördüğümüzde, çoğul bir isim olduğunu belirten bir bayrağı yükseltebiliriz. Böylece, durumu manipüle ederek cümle parçalarının dilbilgisel özelliklerini takip edebiliriz.\n", "\n", "> **Not**: LSTM'nin iç yapısını anlamak için harika bir kaynak, Christopher Olah'ın [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) adlı makalesidir.\n", "\n", "LSTM hücresinin iç yapısı karmaşık görünse de, PyTorch bu implementasyonu `LSTMCell` sınıfı içinde gizler ve tüm LSTM katmanını temsil etmek için `LSTM` nesnesini sağlar. Bu nedenle, LSTM sınıflandırıcısının implementasyonu, yukarıda gördüğümüz basit RNN'e oldukça benzer olacaktır:\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "class LSTMClassifier(torch.nn.Module):\n", " def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n", " super().__init__()\n", " self.hidden_dim = hidden_dim\n", " self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n", " self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n", " self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n", " self.fc = torch.nn.Linear(hidden_dim, num_class)\n", "\n", " def forward(self, x):\n", " batch_size = x.size(0)\n", " x = self.embedding(x)\n", " x,(h,c) = self.rnn(x)\n", " return self.fc(h[-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3200: acc=0.259375\n", "6400: acc=0.25859375\n", "9600: acc=0.26177083333333334\n", "12800: acc=0.2784375\n", "16000: acc=0.313\n", "19200: acc=0.3528645833333333\n", "22400: acc=0.3965625\n", "25600: acc=0.4385546875\n", "28800: acc=0.4752777777777778\n", "32000: acc=0.505375\n", "35200: acc=0.5326704545454546\n", "38400: acc=0.5557552083333334\n", "41600: acc=0.5760817307692307\n", "44800: acc=0.5954910714285714\n", "48000: acc=0.6118333333333333\n", "51200: acc=0.62681640625\n", "54400: acc=0.6404779411764706\n", "57600: acc=0.6520138888888889\n", "60800: acc=0.662828947368421\n", "64000: acc=0.673546875\n", "67200: acc=0.6831547619047619\n", "70400: acc=0.6917897727272727\n", "73600: acc=0.6997146739130434\n", "76800: acc=0.707109375\n", "80000: acc=0.714075\n", "83200: acc=0.7209134615384616\n", "86400: acc=0.727037037037037\n", "89600: acc=0.7326674107142858\n", "92800: acc=0.7379633620689655\n", "96000: acc=0.7433645833333333\n", "99200: acc=0.7479032258064516\n", "102400: acc=0.752119140625\n", "105600: acc=0.7562405303030303\n", "108800: acc=0.76015625\n", "112000: acc=0.7641339285714286\n", "115200: acc=0.7677777777777778\n", "118400: acc=0.7711233108108108\n" ] }, { "data": { "text/plain": [ "(0.03487814127604167, 0.7728)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net = LSTMClassifier(vocab_size,64,32,len(classes)).to(device)\n", "train_epoch(net,train_loader, lr=0.001)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Paketlenmiş Diziler\n", "\n", "Örneğimizde, minibatch içindeki tüm dizileri sıfır vektörleriyle doldurmak zorunda kaldık. Bu, bir miktar bellek israfına yol açsa da, RNN'ler için daha kritik olan, doldurulmuş giriş öğeleri için ek RNN hücrelerinin oluşturulmasıdır. Bu hücreler eğitim sürecine katılır, ancak önemli bir giriş bilgisi taşımaz. RNN'yi yalnızca gerçek dizi boyutuna göre eğitmek çok daha iyi olurdu.\n", "\n", "Bunu yapmak için, PyTorch'ta doldurulmuş dizilerin saklanması için özel bir format tanıtılmıştır. Diyelim ki doldurulmuş bir minibatch girişimiz şu şekilde görünüyor:\n", "```\n", "[[1,2,3,4,5],\n", " [6,7,8,0,0],\n", " [9,0,0,0,0]]\n", "```\n", "Burada 0 doldurulmuş değerleri temsil eder ve giriş dizilerinin gerçek uzunluk vektörü `[5,3,1]` şeklindedir.\n", "\n", "Doldurulmuş dizilerle RNN'yi etkili bir şekilde eğitmek için, RNN hücrelerinin ilk grubunu büyük bir minibatch ile (`[1,6,9]`) eğitmeye başlamak, ardından üçüncü dizinin işlemini sonlandırmak ve daha kısa minibatch'lerle (`[2,7]`, `[3,8]`) eğitime devam etmek istiyoruz. Bu şekilde, paketlenmiş dizi tek bir vektör olarak temsil edilir - bizim durumumuzda `[1,6,9,2,7,3,8,4,5]`, ve uzunluk vektörü (`[5,3,1]`), bu vektörden orijinal doldurulmuş minibatch'i kolayca yeniden oluşturabiliriz.\n", "\n", "Paketlenmiş dizi oluşturmak için `torch.nn.utils.rnn.pack_padded_sequence` fonksiyonunu kullanabiliriz. RNN, LSTM ve GRU dahil olmak üzere tüm tekrarlayan katmanlar, giriş olarak paketlenmiş dizileri destekler ve paketlenmiş çıktı üretir. Bu çıktı, `torch.nn.utils.rnn.pad_packed_sequence` kullanılarak çözülebilir.\n", "\n", "Paketlenmiş dizi üretebilmek için, uzunluk vektörünü ağa iletmemiz gerekir ve bu nedenle minibatch'leri hazırlamak için farklı bir fonksiyona ihtiyacımız vardır:\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def pad_length(b):\n", " # build vectorized sequence\n", " v = [encode(x[1]) for x in b]\n", " # compute max length of a sequence in this minibatch and length sequence itself\n", " len_seq = list(map(len,v))\n", " l = max(len_seq)\n", " return ( # tuple of three tensors - labels, padded features, length sequence\n", " torch.LongTensor([t[0]-1 for t in b]),\n", " torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v]),\n", " torch.tensor(len_seq)\n", " )\n", "\n", "train_loader_len = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=pad_length, shuffle=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Gerçek ağ, yukarıdaki `LSTMClassifier` ile çok benzer olacaktır, ancak `forward` geçişi hem doldurulmuş minibatch'i hem de dizi uzunluklarının vektörünü alacaktır. Gömülü temsili hesapladıktan sonra, paketlenmiş diziyi hesaplar, bunu LSTM katmanına geçirir ve ardından sonucu tekrar açarız.\n", "\n", "> **Not**: Aslında açılmış sonuç `x`'i kullanmıyoruz, çünkü sonraki hesaplamalarda gizli katmanlardan gelen çıktıyı kullanıyoruz. Bu nedenle, bu koddan açma işlemini tamamen kaldırabiliriz. Burada yerleştirme sebebimiz, ağ çıktısını daha sonraki hesaplamalarda kullanmanız gerektiğinde bu kodu kolayca değiştirebilmenizdir.\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "class LSTMPackClassifier(torch.nn.Module):\n", " def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n", " super().__init__()\n", " self.hidden_dim = hidden_dim\n", " self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n", " self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n", " self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n", " self.fc = torch.nn.Linear(hidden_dim, num_class)\n", "\n", " def forward(self, x, lengths):\n", " batch_size = x.size(0)\n", " x = self.embedding(x)\n", " pad_x = torch.nn.utils.rnn.pack_padded_sequence(x,lengths,batch_first=True,enforce_sorted=False)\n", " pad_x,(h,c) = self.rnn(pad_x)\n", " x, _ = torch.nn.utils.rnn.pad_packed_sequence(pad_x,batch_first=True)\n", " return self.fc(h[-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3200: acc=0.285625\n", "6400: acc=0.33359375\n", "9600: acc=0.3876041666666667\n", "12800: acc=0.44078125\n", "16000: acc=0.4825\n", "19200: acc=0.5235416666666667\n", "22400: acc=0.5559821428571429\n", "25600: acc=0.58609375\n", "28800: acc=0.6116666666666667\n", "32000: acc=0.63340625\n", "35200: acc=0.6525284090909091\n", "38400: acc=0.668515625\n", "41600: acc=0.6822596153846154\n", "44800: acc=0.6948214285714286\n", "48000: acc=0.7052708333333333\n", "51200: acc=0.71521484375\n", "54400: acc=0.7239889705882353\n", "57600: acc=0.7315277777777778\n", "60800: acc=0.7388486842105263\n", "64000: acc=0.74571875\n", "67200: acc=0.7518303571428572\n", "70400: acc=0.7576988636363636\n", "73600: acc=0.7628940217391305\n", "76800: acc=0.7681510416666667\n", "80000: acc=0.7728125\n", "83200: acc=0.7772235576923077\n", "86400: acc=0.7815393518518519\n", "89600: acc=0.7857700892857142\n", "92800: acc=0.7895043103448276\n", "96000: acc=0.7930520833333333\n", "99200: acc=0.7959072580645161\n", "102400: acc=0.798994140625\n", "105600: acc=0.802064393939394\n", "108800: acc=0.8051378676470589\n", "112000: acc=0.8077857142857143\n", "115200: acc=0.8104600694444445\n", "118400: acc=0.8128293918918919\n" ] }, { "data": { "text/plain": [ "(0.029785829671223958, 0.8138166666666666)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net = LSTMPackClassifier(vocab_size,64,32,len(classes)).to(device)\n", "train_epoch_emb(net,train_loader_len, lr=0.001,use_pack_sequence=True)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Not:** Eğitim fonksiyonuna geçirdiğimiz `use_pack_sequence` parametresini fark etmiş olabilirsiniz. Şu anda, `pack_padded_sequence` fonksiyonu, uzunluk dizisi tensörünün CPU cihazında olmasını gerektiriyor ve bu nedenle eğitim fonksiyonu, eğitim sırasında uzunluk dizisi verilerini GPU'ya taşımaktan kaçınmalıdır. [`torchnlp.py`](../../../../../lessons/5-NLP/16-RNN/torchnlp.py) dosyasındaki `train_emb` fonksiyonunun implementasyonuna göz atabilirsiniz.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Çift Yönlü ve Çok Katmanlı RNN'ler\n", "\n", "Örneklerimizde, tüm tekrarlayan ağlar bir yönde çalıştı; bir dizinin başından sonuna doğru. Bu doğal görünüyor, çünkü okuma ve konuşmayı dinleme şeklimizi andırıyor. Ancak, birçok pratik durumda giriş dizisine rastgele erişimimiz olduğu için, tekrarlayan hesaplamayı her iki yönde de çalıştırmak mantıklı olabilir. Bu tür ağlara **çift yönlü** RNN'ler denir ve RNN/LSTM/GRU yapıcısına `bidirectional=True` parametresini geçirerek oluşturulabilirler.\n", "\n", "Çift yönlü bir ağ ile çalışırken, her yön için birer tane olmak üzere iki gizli durum vektörüne ihtiyacımız olur. PyTorch, bu vektörleri iki kat daha büyük bir boyutta tek bir vektör olarak kodlar, bu oldukça kullanışlıdır çünkü genellikle ortaya çıkan gizli durumu tam bağlantılı bir doğrusal katmana geçirirsiniz ve katmanı oluştururken bu boyut artışını dikkate almanız yeterlidir.\n", "\n", "Tekrarlayan ağlar, tek yönlü veya çift yönlü olsun, bir dizideki belirli desenleri yakalar ve bunları durum vektörüne kaydedebilir veya çıktıya aktarabilir. Konvolüsyonel ağlarda olduğu gibi, birinci katman tarafından çıkarılan düşük seviyeli desenlerden daha yüksek seviyeli desenleri yakalamak için birinci katmanın üzerine başka bir tekrarlayan katman inşa edebiliriz. Bu bizi, bir önceki katmanın çıktısının bir sonraki katmana giriş olarak geçtiği, iki veya daha fazla tekrarlayan ağdan oluşan **çok katmanlı RNN** kavramına götürür.\n", "\n", "![Çok Katmanlı Uzun-Kısa Süreli Bellek RNN'yi gösteren bir görsel](../../../../../translated_images/tr/multi-layer-lstm.dd975e29bb2a59fe.webp)\n", "\n", "*Fernando López'in [bu harika yazısından](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) alınmış bir görsel*\n", "\n", "PyTorch, bu tür ağları oluşturmayı kolaylaştırır, çünkü RNN/LSTM/GRU yapıcısına `num_layers` parametresini geçirerek birkaç tekrarlama katmanını otomatik olarak oluşturabilirsiniz. Bu aynı zamanda gizli/durum vektörünün boyutunun orantılı olarak artacağı anlamına gelir ve tekrarlayan katmanların çıktısını işlerken bunu dikkate almanız gerekir.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Diğer Görevler için RNN'ler\n", "\n", "Bu bölümde, RNN'lerin dizi sınıflandırması için kullanılabileceğini gördük, ancak aslında metin oluşturma, makine çevirisi ve daha fazlası gibi birçok başka görevi de yerine getirebilirler. Bu görevleri bir sonraki bölümde ele alacağız.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**Feragatname**: \nBu belge, AI çeviri hizmeti [Co-op Translator](https://github.com/Azure/co-op-translator) kullanılarak çevrilmiştir. Doğruluk için çaba göstersek de, otomatik çevirilerin hata veya yanlışlıklar içerebileceğini lütfen unutmayın. Belgenin orijinal dili, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul edilmez.\n" ] } ], "metadata": { "interpreter": { "hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f" }, "kernelspec": { "display_name": "Python 3.8.12 ('py38')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.12" }, "coopTranslator": { "original_hash": "522ee52ae3d5ae933e283286254e9a55", "translation_date": "2025-08-28T14:24:46+00:00", "source_file": "lessons/5-NLP/16-RNN/RNNPyTorch.ipynb", "language_code": "tr" } }, "nbformat": 4, "nbformat_minor": 2 }