8.6. Yinelemeli Sinir Ağlarının Kısa Uygulaması
Open the notebook in Colab
Open the notebook in Colab
Open the notebook in Colab
Open the notebook in SageMaker Studio Lab

Section 8.5 RNN’lerin nasıl uygulandığını görmek için öğretici olsa da, bu uygun veya hızlı değildir. Bu bölümde, derin öğrenme çerçevesinin üst düzey API’leri tarafından sağlanan işlevleri kullanarak aynı dil modelinin nasıl daha verimli bir şekilde uygulanacağı gösterilecektir. Daha önce olduğu gibi zaman makinesi veri kümesini okuyarak başlıyoruz.

from d2l import mxnet as d2l
from mxnet import np, npx
from mxnet.gluon import nn, rnn

npx.set_np()

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
import tensorflow as tf
from d2l import tensorflow as d2l

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

8.6.1. Modelin Tanımlanması

Üst seviye API’ler, yinelemeli sinir ağlarının uygulamalarını sağlar. Yinelemeli sinir ağı tabakası rnn_layer’i tek bir gizli katman ve 256 gizli birimle inşa ediyoruz. Aslında, birden fazla katmana sahip olmanın ne anlama geldiğini henüz tartışmadık; onu Section 9.3 içinde göreceğiz. Şimdilik, birden çok katmanın, bir sonraki RNN katmanı için girdi olarak kullanılan bir RNN katmanının çıktısı anlamına geldiğini söylemek yeterlidir.

num_hiddens = 256
rnn_layer = rnn.RNN(num_hiddens)
rnn_layer.initialize()

Gizli durumu ilklemek basittir. Üye fonksiyonu begin_state’i çağırıyoruz . Bu, minigruptaki her örnek için (gizli katman sayısı, grup boyutu, gizli birim sayısı) şekilli bir ilk gizli durumu içeren liste (state) döndürür. Daha sonra tanıtılacak bazı modellerde (örneğin, uzun ömürlü kısa-dönem belleği), bu liste başka bilgiler de içerir.

state = rnn_layer.begin_state(batch_size=batch_size)
len(state), state[0].shape
(1, (1, 32, 256))
num_hiddens = 256
rnn_layer = nn.RNN(len(vocab), num_hiddens)

Şekli (gizli katman sayısı, grup boyutu, gizli birim sayısı) olan bir tensörü gizli durumu ilklemek için kullanırız.

state = torch.zeros((1, batch_size, num_hiddens))
state.shape
torch.Size([1, 32, 256])
num_hiddens = 256
rnn_cell = tf.keras.layers.SimpleRNNCell(num_hiddens,
    kernel_initializer='glorot_uniform')
rnn_layer = tf.keras.layers.RNN(rnn_cell, time_major=True,
    return_sequences=True, return_state=True)

state = rnn_cell.get_initial_state(batch_size=batch_size, dtype=tf.float32)
state.shape
TensorShape([32, 256])

Gizli bir durum ve bir girdi ile, çıktıyı güncellenmiş gizli durumla hesaplayabiliriz. rnn_layer’in “çıktı”’nın (Y) çıktı katmanlarının hesaplanmasını içermediği vurgulanmalıdır: Her bir zaman adımındaki gizli durumu ifade eder ve sonraki çıktı katmanına girdi olarak kullanılabilir.

Ayrıca, rnn_layer tarafından döndürülen güncelleştirilmiş gizli durum (state_new) minigrubun son zaman adımındaki gizli durumunu ifade eder. Sıralı bölümlemede bir dönem içinde sonraki minigrubun gizli durumunu ilklemede kullanılabilir. Birden çok gizli katman için, her katmanın gizli durumu bu değişkende saklanır (state_new). Daha sonra tanıtılacak bazı modellerde (örneğin, uzun ömürlü kısa-dönem belleği), bu değişken başka bilgiler de içerir.

X = np.random.uniform(size=(num_steps, batch_size, len(vocab)))
Y, state_new = rnn_layer(X, state)
Y.shape, len(state_new), state_new[0].shape
((35, 32, 256), 1, (1, 32, 256))
X = torch.rand(size=(num_steps, batch_size, len(vocab)))
Y, state_new = rnn_layer(X, state)
Y.shape, state_new.shape
(torch.Size([35, 32, 256]), torch.Size([1, 32, 256]))
X = tf.random.uniform((num_steps, batch_size, len(vocab)))
Y, state_new = rnn_layer(X, state)
Y.shape, len(state_new), state_new[0].shape
(TensorShape([35, 32, 256]), 32, TensorShape([256]))

Section 8.5 içindekine benzer şekilde, tam bir RNN modeli için bir RNNModel sınıfı tanımlarız. rnn_layer’in yalnızca gizli yinelemeli katmanları içerdiğini unutmayın, ayrı bir çıktı katmanı oluşturmamız gerekir.

#@save
class RNNModel(nn.Block):
    """RNN modeli."""
    def __init__(self, rnn_layer, vocab_size, **kwargs):
        super(RNNModel, self).__init__(**kwargs)
        self.rnn = rnn_layer
        self.vocab_size = vocab_size
        self.dense = nn.Dense(vocab_size)

    def forward(self, inputs, state):
        X = npx.one_hot(inputs.T, self.vocab_size)
        Y, state = self.rnn(X, state)
        # Tam bağlı katman önce `Y`'nin şeklini
        # (`num_steps` * `batch_size`, `num_hiddens`) olarak değiştirir.
        # Çıktı (`num_steps` * `batch_size`, `vocab_size`) şeklindedir.
        output = self.dense(Y.reshape(-1, Y.shape[-1]))
        return output, state

    def begin_state(self, *args, **kwargs):
        return self.rnn.begin_state(*args, **kwargs)
#@save
class RNNModel(nn.Module):
    """RNN modeli."""
    def __init__(self, rnn_layer, vocab_size, **kwargs):
        super(RNNModel, self).__init__(**kwargs)
        self.rnn = rnn_layer
        self.vocab_size = vocab_size
        self.num_hiddens = self.rnn.hidden_size
        # RNN çift yönlü ise (daha sonra tanıtılacaktır),
        # `num_directions` 2 olmalı, yoksa 1 olmalıdır.
        if not self.rnn.bidirectional:
            self.num_directions = 1
            self.linear = nn.Linear(self.num_hiddens, self.vocab_size)
        else:
            self.num_directions = 2
            self.linear = nn.Linear(self.num_hiddens * 2, self.vocab_size)

    def forward(self, inputs, state):
        X = F.one_hot(inputs.T.long(), self.vocab_size)
        X = X.to(torch.float32)
        Y, state = self.rnn(X, state)
        # Tam bağlı katman önce `Y`'nin şeklini
        # (`num_steps` * `batch_size`, `num_hiddens`) olarak değiştirir.
        # Çıktı (`num_steps` * `batch_size`, `vocab_size`) şeklindedir.
        output = self.linear(Y.reshape((-1, Y.shape[-1])))
        return output, state

    def begin_state(self, device, batch_size=1):
        if not isinstance(self.rnn, nn.LSTM):
            # `nn.GRU` gizli durum olarak bir tensör alır
            return  torch.zeros((self.num_directions * self.rnn.num_layers,
                                 batch_size, self.num_hiddens),
                                device=device)
        else:
            # `nn.LSTM` bir gizli durum çokuzu alır
            return (torch.zeros((
                self.num_directions * self.rnn.num_layers,
                batch_size, self.num_hiddens), device=device),
                    torch.zeros((
                        self.num_directions * self.rnn.num_layers,
                        batch_size, self.num_hiddens), device=device))
#@save
class RNNModel(tf.keras.layers.Layer):
    def __init__(self, rnn_layer, vocab_size, **kwargs):
        super(RNNModel, self).__init__(**kwargs)
        self.rnn = rnn_layer
        self.vocab_size = vocab_size
        self.dense = tf.keras.layers.Dense(vocab_size)

    def call(self, inputs, state):
        X = tf.one_hot(tf.transpose(inputs), self.vocab_size)
        # Daha sonra `tf.keras.layers.LSTMCell` gibi RNN ikiden fazla değer döndürür
        Y, *state = self.rnn(X, state)
        output = self.dense(tf.reshape(Y, (-1, Y.shape[-1])))
        return output, state

    def begin_state(self, *args, **kwargs):
        return self.rnn.cell.get_initial_state(*args, **kwargs)

8.6.2. Eğitim ve Tahmin

Modeli eğitmeden önce, rastgele ağırlıklara sahip bir modelle bir tahmin yapalım.

device = d2l.try_gpu()
net = RNNModel(rnn_layer, len(vocab))
net.initialize(force_reinit=True, ctx=device)
d2l.predict_ch8('time traveller', 10, net, vocab, device)
'time travellervmoopwrrrr'
device = d2l.try_gpu()
net = RNNModel(rnn_layer, vocab_size=len(vocab))
net = net.to(device)
d2l.predict_ch8('time traveller', 10, net, vocab, device)
'time travellerxxxxxxxxxx'
device_name = d2l.try_gpu()._device_name
strategy = tf.distribute.OneDeviceStrategy(device_name)
with strategy.scope():
    net = RNNModel(rnn_layer, vocab_size=len(vocab))

d2l.predict_ch8('time traveller', 10, net, vocab)
'time travellergfqvpu<unk>hqh'

Oldukça açık, bu model hiç çalışmıyor. Ardından, Section 8.5 içinde tanımlanan aynı hiper parametrelerle train_ch8’i çağırdık ve modelimizi üst düzey API’lerle eğitiyoruz.

num_epochs, lr = 500, 1
d2l.train_ch8(net, train_iter, vocab, lr, num_epochs, device)
perplexity 1.2, 132748.5 tokens/sec on gpu(0)
time traveller but now you begin to srealle the time traveller b
traveller for so it will be hove about in the other directi
../_images/output_rnn-concise_eff2f4_68_1.svg
num_epochs, lr = 500, 1
d2l.train_ch8(net, train_iter, vocab, lr, num_epochs, device)
perplexity 1.3, 290440.5 tokens/sec on cuda:0
time traveller aptereave but lothe rak alyscthat arsthes than a
travellerithe fore wescantwo snoweicalsiothroughi new yores
../_images/output_rnn-concise_eff2f4_71_1.svg
num_epochs, lr = 500, 1
d2l.train_ch8(net, train_iter, vocab, lr, num_epochs, strategy)
perplexity 1.4, 15387.2 tokens/sec on /GPU:0
time traveller fficed for arellen yus ions ablit the rerele dire
traveller mald existind fow ins al hing s all in tha rialli
../_images/output_rnn-concise_eff2f4_74_1.svg

Son bölümle karşılaştırıldığında, bu model, kodun derin öğrenme çerçevesinin üst düzey API’leriyle daha iyi hale getirilmesinden dolayı daha kısa bir süre içinde olsa da, benzer bir şaşkınlığa ulaşmaktadır.

8.6.3. Özet

  • Derin öğrenme çerçevesinin üst düzey API’leri RNN katmanının bir uygulanmasını sağlar.

  • Üst düzey API’lerin RNN katmanı, çıktının çıktı katmanı hesaplamasını içermediği bir çıktı ve güncellenmiş bir gizli durum döndürür.

  • Üst düzey API’lerin kullanılması, sıfırdan uygulama yaratmaktan daha hızlı RNN eğitimine yol açar.

8.6.4. Alıştırmalar

  1. RNN modelini üst düzey API’leri kullanarak aşırı eğitebilir misiniz?

  2. RNN modelinde gizli katman sayısını artırırsanız ne olur? Modelin çalışmasını sağlayabilecek misiniz?

  3. Bir RNN kullanarak Section 8.1 içindeki özbağlanımlı modelini uygulayın.