.. _sec_sequence:
Dizi Modelleri
==============
Netflix'te film izlediğinizi düşünün. İyi bir Netflix kullanıcısı
olarak, filmlerin her birini dürüstçe değerlendirmeye karar
veriyorsunuz. Sonuçta, iyi bir film iyi bir filmdir, ve siz onlardan
daha fazla izlemek istiyorsunuz, değil mi? Görünüşe göre, bu işler o
kadar basit değil. İnsanların filmler hakkındaki görüşleri zamanla
oldukça önemli ölçüde değişebilir. Aslında, psikologların bazı etkiler
için koydukları isimler bile vardır:
- Başkasının fikrine dayalı olarak “çapalama” vardır. Örneğin, Oscar
ödüllerinden sonra, ilgili filmin reytingleri hala film aynı olmasına
rağmen yükselir. Bu etki, ödül unutulana kadar birkaç ay boyunca
devam eder. Bu etkinin yarım puandan fazla reyting yükselttiği
gösterilmiştir :cite:`Wu.Ahmed.Beutel.ea.2017`.
- İnsanların yeni normal olarak geliştirilmiş veya kötüleşmiş bir
durumu kabul etmek için hızla adapte olduğu *zevksel uyarlama*
vardır. Örneğin, birçok iyi film izledikten sonra, bir sonraki filmin
eşit derecede iyi veya daha iyi olması beklentisi yüksektir. Bu
nedenle, harika filmler izlendikten sonra ortalama bir film bile kötü
sayılabilir.
- Mevsimsellik vardır. Çok az izleyici Ağustos ayında Noel Baba filmi
izlemek ister.
- Bazı durumlarda, filmler yapımdaki yönetmenlerin veya aktörlerin
yanlış davranışlarından dolayı sevilmeyen hale gelir.
- Bazı filmler kült filmlere dönüşmüştür, çünkü neredeyse komik bir
şekilde kötüydüler. *Outer Space* ve *Troll 2* bu nedenle yüksek
derecede şöhret elde etti.
Kısacası, film reytinglerinde sabitlik dışında her şey vardır. Böylece,
zamansal dinamikleri kullanmak daha doğru film önerilerine yol açtı
:cite:`Koren.2009`. Tabii ki, dizi verileri sadece film
derecelendirmeleri ile ilgili değildir. Aşağıda daha fazla örnek
görebilirsiniz.
- Birçok kullanıcı, uygulamaları açtıkları zamana göre son derece özel
davranışlara sahiptir. Örneğin, sosyal medya uygulamaları kullanımı
öğrencilerde okul zamanından sonra çok daha yaygındır. Borsa alım
satım uygulamaları piyasalar açık olduğunda daha yaygın olarak
kullanılır.
- Yarının hisse senedi fiyatlarını tahmin etmek, dün kaçırdığımız bir
hisse senedi fiyatının boşluklarını doldurmaktan çok daha zordur, her
ne kadar ikisi de bir sayıyı tahmin etme meselesi olsa da. Sonuçta,
öngörü, geçmişe görüden çok daha zordur. İstatistiklerde, ilki
(bilinen gözlemlerin ötesinde tahmin) *dışdeğerleme (extrapolation)*
olarak adlandırılırken, ikincisi (mevcut gözlemler arasındaki tahmin)
*aradeğerleme (interpolation)* olarak adlandırılır.
- Müzik, konuşma, metin ve videolar doğaları gereği dizilidir. Eğer
onlarda yer değişimine verseydik, çok az anlam ifade ederlerdi.
*Köpek adamı ısırdı* manşeti, kelimelerin aynı olmasına rağmen, *adam
köpeği ısırdı* manşetinden çok daha az şaşırtıcıdır.
- Depremler son derece ilişkilidir, yani büyük bir deprem sonrası güçlü
deprem olmayan zamana kıyasla çok daha fazla, çok daha küçük artçı
şoklar vardır. Aslında depremler uzamsal olarak ilişkilidir, yani
artçı şoklar genellikle kısa bir süre içinde ve yakın bir yerde
meydana gelir.
- Twitter kavgalarında, dans düzenlerinde ve tartışmalarda
görülebileceği gibi, insanlar birbirleri ile ardışık bir şekilde
etkileşime girerler.
İstatistiksel Araçlar
---------------------
Dizi verileriyle uğraşmak için istatistiksel araçlara ve yeni derin
sinir ağı mimarilerine ihtiyacımız var. İşleri basit tutmak için örnek
olarak :numref:`fig_ftse100` içinde gösterilen hisse senedi fiyatını
(FTSE 100 endeksi) kullanalım.
.. _fig_ftse100:
.. figure:: ../img/ftse100.png
:width: 400px
Yaklaşık 30 yıldan fazla sürenin FTSE 100 endeksi.
Fiyatları :math:`x_t` ile gösterelim, yani *zaman adım*
:math:`t \in \mathbb{Z}^+`'de :math:`x_t` fiyatını gözlemliyoruz. Bu
kitaptaki diziler için :math:`t`'nin genellikle ayrık olacağını ve
tamsayılara veya alt kümesine göre değişeceğini unutmayın. :math:`t`.
günde borsada iyi kazanmak isteyen bir borsa simsarının :math:`x_t`
üzerinden tahmin ettiğini varsayalım:
.. math:: x_t \sim P(x_t \mid x_{t-1}, \ldots, x_1).
Özbağlanımlı Modeller
~~~~~~~~~~~~~~~~~~~~~
Bunu başarmak için, simsarımız :numref:`sec_linear_concise` içinde
eğittiğimiz gibi bir regresyon modelini kullanabilir. Sadece bir büyük
sorun var: Girdilerimizin adedi, :math:`x_{t-1}, \ldots, x_1`,
:math:`t`'ye bağlı olarak değişir. Yani, karşılaştığımız veri miktarı
ile sayı artar ve bunu hesaplamalı olarak işlenebilir hale getirmek için
bir yaklaşıma ihtiyacımız vardır. Bu bölümde konuların çoğu
:math:`P(x_t \mid x_{t-1}, \ldots, x_1)`'nin verimli bir şekilde nasıl
tahmin edileceği etrafında dönecektir. Kısacası, aşağıdaki gibi iki
stratejiye indirgeniyor.
İlk olarak, potansiyel olarak oldukça uzun dizinin
:math:`x_{t-1}, \ldots, x_1` gerçekten gerekli olmadığını varsayalım. Bu
durumda kendimizi :math:`\tau` uzunluğunda bir süre ile memnun edebilir
ve sadece :math:`x_{t-1}, \ldots, x_{t-\tau}` gözlemlerini
kullanabiliriz. İlk faydası, artık argüman sayısının en azından
:math:`t > \tau` için her zaman aynı olmasıdır. Bu, yukarıda
belirtildiği gibi derin bir ağı eğitmemizi sağlar. Bu tür modeller,
kelimenin tam anlamıyla kendileri üzerinde bağlanım gerçekleştirdikleri
için *özbağlanımlı modeller* olarak adlandırılacaktır.
:numref:`fig_sequence-model` içinde gösterilen ikinci strateji, geçmiş
gözlemlerin :math:`h_t`'sının bir özetini tutmak ve aynı zamanda
:math:`\hat{x}_t`'in tahmine ek olarak :math:`h_t`'yı güncellemektir.
Bu, bizi :math:`\hat{x}_t = P(x_t \mid h_{t})` ile :math:`x_t`'i tahmin
eden ve dahası :math:`h_t = g(h_{t-1}, x_{t-1})` formunu güncelleyen
modellere yönlendirir. :math:`h_t` asla gözlenmediğinden, bu modellere
*saklı özbağlanımlı modeller* de denir.
.. _fig_sequence-model:
.. figure:: ../img/sequence-model.svg
Saklı özbağlanımlı model.
Her iki durumda da eğitim verilerinin nasıl oluşturulacağına dair açık
bir soru ortaya çıkıyor. Kullanıcı tipik olarak tarihsel gözlemleri
kullanarak, şu ana kadar verilen gözlemlere dayanarak bir sonraki
gözlemi tahmin eder. Açıkça zamanın hareketsiz kalmasını beklemeyiz.
Bununla birlikte, genel varsayım, :math:`x_t`'in özgül değerlerinin
değişebileceği halde, en azından dizinin dinamiklerinin değişmeyeceği
yönündedir. Bu mantıklı, çünkü yeni dinamikler adı gibi yeni ve bu
nedenle şimdiye kadar sahip olduğumuz verileri kullanarak tahmin
edilemezler. İstatistikçiler değişmeyen dinamiklere durağan derler. Ne
olursa olsun, böylece aşağıdaki ifade aracılığıyla tüm diziyi
tahminleyebiliriz:
.. math:: P(x_1, \ldots, x_T) = \prod_{t=1}^T P(x_t \mid x_{t-1}, \ldots, x_1).
Sürekli sayılar yerine kelimeler gibi ayrık nesnelerle uğraştığımızda da
yukarıdaki hususların hala geçerli olduğunu unutmayın. Tek fark, böyle
bir durumda :math:`P(x_t \mid x_{t-1}, \ldots, x_1)`'yi tahmin etmek
için bir regresyon modeli yerine bir sınıflandırıcı kullanmamız
gerektiğidir.
Markov Modelleri
~~~~~~~~~~~~~~~~
Özbağlanımlı bir modelde :math:`x_t`'yi tahmin etmek için
:math:`x_{t-1}, \ldots, x_1` yerine sadece
:math:`x_{t-1}, \ldots, x_{t-\tau}` kullandığımız yaklaşımı hatırlayın.
Bu yaklaşım doğru olduğunda, dizinin bir *Markov koşulu* karşıladığını
söyleriz. Özellikle, eğer :math:`\tau = 1` ise, bir *birinci dereceden
Markov modeli*\ miz vardır ve :math:`P(x)` şöyle ifade edilir:
.. math:: P(x_1, \ldots, x_T) = \prod_{t=1}^T P(x_t \mid x_{t-1}) \text{ where } P(x_1 \mid x_0) = P(x_1).
Bu tür modeller özellikle :math:`x_t` yalnızca ayrı bir değer
varsayıldığında iyi çalışır, çünkü bu durumda dinamik programlama zincir
boyunca değerleri tam olarak hesaplamak için kullanılabilir. Örneğin,
:math:`P(x_{t+1} \mid x_{t-1})`'in verimli bir şekilde hesaplanmasını
sağlayabiliriz:
.. math::
\begin{aligned}
P(x_{t+1} \mid x_{t-1})
&= \frac{\sum_{x_t} P(x_{t+1}, x_t, x_{t-1})}{P(x_{t-1})}\\
&= \frac{\sum_{x_t} P(x_{t+1} \mid x_t, x_{t-1}) P(x_t, x_{t-1})}{P(x_{t-1})}\\
&= \sum_{x_t} P(x_{t+1} \mid x_t) P(x_t \mid x_{t-1})
\end{aligned}
Sadece geçmiş gözlemlerin çok kısa bir tarihini hesaba katmamız
gerektiği gerçeğini kullanabiliriz:
:math:`P(x_{t+1} \mid x_t, x_{t-1}) = P(x_{t+1} \mid x_t)`. Dinamik
programlama detaylarına girmek bu bölümün kapsamı dışındadır. Kontrol ve
pekiştirmeli öğrenme algoritmaları bu tür araçları kapsamlı olarak
kullanır.
Nedensellik
~~~~~~~~~~~
Prensipte, :math:`P(x_1, \ldots, x_T)`'nin ters sırada açılmasında
yanlış bir şey yoktur. Sonuçta, koşullandırma ile her zaman aşağıdaki
gibi yazabiliriz:
.. math:: P(x_1, \ldots, x_T) = \prod_{t=T}^1 P(x_t \mid x_{t+1}, \ldots, x_T).
Aslında, eğer bir Markov modelimiz varsa, bir ters koşullu olasılık
dağılımı da elde edebiliriz. Bununla birlikte, birçok durumda, veriler
için doğal bir yön vardır, yani zaman içinde ileriye giderler.
Gelecekteki olayların geçmişi etkilemeyeceği açıktır. Bu nedenle, eğer
:math:`x_t`'i değiştirirsek, :math:`x_{t+1}`'nin ilerlemesine ne
olacağını etkileyebiliriz ama tersi değil. Yani, :math:`x_t`'i
değiştirirsek, geçmiş olayların üzerindeki dağılım değişmez. Sonuç
olarak, :math:`P(x_t \mid x_{t+1})`'den ziyade
:math:`P(x_{t+1} \mid x_t)`'yi açıklamak daha kolay olmalıdır. Örneğin,
bazı durumlarda :math:`\epsilon` gürültüsü için
:math:`x_{t+1} = f(x_t) + \epsilon`'yi bulabildiğimiz gösterilmiştir,
oysa tersi doğru değildir :cite:`Hoyer.Janzing.Mooij.ea.2009`. Bu
harika bir haber, çünkü tipik olarak tahmin etmekle ilgilendiğimiz ileri
yöndür. Peters ve diğerlerinin kitabı bu konuda daha fazla açıklama
yapmaktadır :cite:`Peters.Janzing.Scholkopf.2017`. Bizse sadece
yüzeyine bakıyoruz.
Eğitim
------
Bu kadar çok istatistiksel aracı inceledikten sonra, bunu pratikte de
deneyelim. Biraz veri üreterek başlıyoruz. İşleri basit tutmak için,
:math:`1, 2, \ldots, 1000` adımları için biraz gürültülü bir sinüs
fonksiyonu kullanarak dizi verimizi üretiyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import autograd, gluon, init, np, npx
from mxnet.gluon import nn
npx.set_np()
T = 1000 # Toplamda 1000 nokta oluşturun
time = np.arange(1, T + 1, dtype=np.float32)
x = np.sin(0.01 * time) + np.random.normal(0, 0.2, (T,))
d2l.plot(time, [x], 'time', 'x', xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_3_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l
T = 1000 # Toplamda 1000 nokta oluşturun
time = torch.arange(1, T + 1, dtype=torch.float32)
x = torch.sin(0.01 * time) + torch.normal(0, 0.2, (T,))
d2l.plot(time, [x], 'time', 'x', xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_6_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
%matplotlib inline
import tensorflow as tf
from d2l import tensorflow as d2l
T = 1000 # Toplamda 1000 nokta oluşturun
time = tf.range(1, T + 1, dtype=tf.float32)
x = tf.sin(0.01 * time) + tf.random.normal([T], 0, 0.2)
d2l.plot(time, [x], 'time', 'x', xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_9_0.svg
.. raw:: html
.. raw:: html
Ardından, böyle bir diziyi modelimizin üzerinde eğitebileceği
özniteliklere ve etiketlere dönüştürmemiz gerekiyor. :math:`\tau` gömme
boyutuna dayanarak, verileri :math:`y_t = x_t` ve
:math:`\mathbf{x}_t = [x_{t-\tau}, \ldots, x_{t-1}]` çiftleri halinde
eşleriz. Dikkatli okuyucu, bunun bize :math:`\tau` adet daha az veri
örneği verdiğini fark etmiş olabilir, çünkü ilk :math:`\tau` için
yeterli geçmişe sahip değiliz. Basit bir düzeltme, özellikle dizi
uzunsa, bu ilk birkaç terimi atmaktır. Alternatif olarak diziye
sıfırlarla dolgu yapabiliriz. Burada eğitim için sadece ilk 600
öznitelik-etiket çiftini kullanıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
tau = 4
features = np.zeros((T - tau, tau))
for i in range(tau):
features[:, i] = x[i: T - tau + i]
labels = x[tau:].reshape((-1, 1))
batch_size, n_train = 16, 600
# Eğitim için yalnızca ilk `n_train` tane örnek kullanılır
train_iter = d2l.load_array((features[:n_train], labels[:n_train]),
batch_size, is_train=True)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
tau = 4
features = torch.zeros((T - tau, tau))
for i in range(tau):
features[:, i] = x[i: T - tau + i]
labels = x[tau:].reshape((-1, 1))
batch_size, n_train = 16, 600
# Eğitim için yalnızca ilk `n_train` tane örnek kullanılır
train_iter = d2l.load_array((features[:n_train], labels[:n_train]),
batch_size, is_train=True)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
tau = 4
features = tf.Variable(tf.zeros((T - tau, tau)))
for i in range(tau):
features[:, i].assign(x[i: T - tau + i])
labels = tf.reshape(x[tau:], (-1, 1))
batch_size, n_train = 16, 600
# Eğitim için yalnızca ilk `n_train` tane örnek kullanılır
train_iter = d2l.load_array((features[:n_train], labels[:n_train]),
batch_size, is_train=True)
.. raw:: html
.. raw:: html
Burada mimariyi oldukça basit tutuyoruz: Sadece iki tam bağlı katmanlı
bir MLP, ReLU etkinleştirmesi ve kare kaybı.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
# Basit bir MLP
def get_net():
net = nn.Sequential()
net.add(nn.Dense(10, activation='relu'),
nn.Dense(1))
net.initialize(init.Xavier())
return net
# Square loss
loss = gluon.loss.L2Loss()
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
# Ağın ağırlıklarını ilkleme işlevi
def init_weights(m):
if type(m) == nn.Linear:
nn.init.xavier_uniform_(m.weight)
# Basit bir MLP
def get_net():
net = nn.Sequential(nn.Linear(4, 10),
nn.ReLU(),
nn.Linear(10, 1))
net.apply(init_weights)
return net
# Not: `MSELoss` karesel hatayı 1/2 çarpanı olmadan hesaplar
loss = nn.MSELoss(reduction='none')
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
# Basmakalıp MLP mimarisi
def get_net():
net = tf.keras.Sequential([tf.keras.layers.Dense(10, activation='relu'),
tf.keras.layers.Dense(1)])
return net
# Not: `MeanSquaredError` karesel hatayı 1/2 çarpanı olmadan hesaplar
loss = tf.keras.losses.MeanSquaredError()
.. raw:: html
.. raw:: html
Şimdi modeli eğitmeye hazırız. Aşağıdaki kod esas olarak
:numref:`sec_linear_concise` gibi, önceki bölümlerdeki eğitim
döngüsüyle aynıdır. Bu yüzden, çok fazla ayrıntıya girmeyeceğiz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train(net, train_iter, loss, epochs, lr):
trainer = gluon.Trainer(net.collect_params(), 'adam',
{'learning_rate': lr})
for epoch in range(epochs):
for X, y in train_iter:
with autograd.record():
l = loss(net(X), y)
l.backward()
trainer.step(batch_size)
print(f'epoch {epoch + 1}, '
f'loss: {d2l.evaluate_loss(net, train_iter, loss):f}')
net = get_net()
train(net, train_iter, loss, 5, 0.01)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
[21:56:23] src/base.cc:49: GPU context requested, but no GPUs found.
epoch 1, loss: 0.042136
epoch 2, loss: 0.034722
epoch 3, loss: 0.028815
epoch 4, loss: 0.027013
epoch 5, loss: 0.026379
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train(net, train_iter, loss, epochs, lr):
trainer = torch.optim.Adam(net.parameters(), lr)
for epoch in range(epochs):
for X, y in train_iter:
trainer.zero_grad()
l = loss(net(X), y)
l.sum().backward()
trainer.step()
print(f'epoch {epoch + 1}, '
f'loss: {d2l.evaluate_loss(net, train_iter, loss):f}')
net = get_net()
train(net, train_iter, loss, 5, 0.01)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 1, loss: 0.066216
epoch 2, loss: 0.058680
epoch 3, loss: 0.057771
epoch 4, loss: 0.055117
epoch 5, loss: 0.054249
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train(net, train_iter, loss, epochs, lr):
trainer = tf.keras.optimizers.Adam()
for epoch in range(epochs):
for X, y in train_iter:
with tf.GradientTape() as g:
out = net(X)
l = loss(y, out)
params = net.trainable_variables
grads = g.gradient(l, params)
trainer.apply_gradients(zip(grads, params))
print(f'epoch {epoch + 1}, '
f'loss: {d2l.evaluate_loss(net, train_iter, loss):f}')
net = get_net()
train(net, train_iter, loss, 5, 0.01)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
epoch 1, loss: 0.211639
epoch 2, loss: 0.097174
epoch 3, loss: 0.053595
epoch 4, loss: 0.049805
epoch 5, loss: 0.048818
.. raw:: html
.. raw:: html
Tahmin
------
Eğitim kaybı küçük olduğu için modelimizin iyi çalışmasını bekleriz.
Bunun pratikte ne anlama geldiğini görelim. Kontrol edilmesi gereken ilk
şey, modelin sadece bir sonraki adımında ne kadar iyi tahmin
edebildiğidir, yani *bir adım sonrasını tahmin*.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
onestep_preds = net(features)
d2l.plot([time, time[tau:]], [x.asnumpy(), onestep_preds.asnumpy()], 'time',
'x', legend=['data', '1-step preds'], xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_51_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
onestep_preds = net(features)
d2l.plot([time, time[tau:]], [x.detach().numpy(), onestep_preds.detach().numpy()], 'time',
'x', legend=['data', '1-step preds'], xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_54_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
onestep_preds = net(features)
d2l.plot([time, time[tau:]], [x.numpy(), onestep_preds.numpy()], 'time',
'x', legend=['data', '1-step preds'], xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_57_0.svg
.. raw:: html
.. raw:: html
Bir adım sonrası tahminler, beklediğimiz gibi güzel görünüyor. 604
(``n_train + tau``) gözlemin ötesinde bile tahminler hala güvenilir
görünüyor. Bununla birlikte, burada küçük bir sorun var: Sıra verilerini
yalnızca 604 zaman adımına kadar gözlemlersek, gelecekteki tüm bir adım
önde gelen tahminler için girdileri almayı umut edemeyiz. Bunun yerine,
her seferinde bir adım ileriye doğru ilerlemeliyiz:
.. math::
\hat{x}_{605} = f(x_{601}, x_{602}, x_{603}, x_{604}), \\
\hat{x}_{606} = f(x_{602}, x_{603}, x_{604}, \hat{x}_{605}), \\
\hat{x}_{607} = f(x_{603}, x_{604}, \hat{x}_{605}, \hat{x}_{606}),\\
\hat{x}_{608} = f(x_{604}, \hat{x}_{605}, \hat{x}_{606}, \hat{x}_{607}),\\
\hat{x}_{609} = f(\hat{x}_{605}, \hat{x}_{606}, \hat{x}_{607}, \hat{x}_{608}),\\
\ldots
Genel olarak, :math:`x_t`'ye kadar gözlenen bir dizi için :math:`t+k`
zaman adımında tahmin edilen çıktı :math:`\hat{x}_{t+k}`,
:math:`k`\ *-adım tahmin* olarak adlandırılır. :math:`x_{604}`'ya kadar
gözlemlediğimizden, :math:`k`-adım tahminimiz
:math:`\hat{x}_{604+k}`'dir. Başka bir deyişle, çok ileriki tahminler
için kendi tahminlerimizi kullanmak zorunda kalacağız. Bakalım ne kadar
iyi gidecek.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
multistep_preds = np.zeros(T)
multistep_preds[: n_train + tau] = x[: n_train + tau]
for i in range(n_train + tau, T):
multistep_preds[i] = net(
multistep_preds[i - tau:i].reshape((1, -1)))
d2l.plot([time, time[tau:], time[n_train + tau:]],
[x.asnumpy(), onestep_preds.asnumpy(),
multistep_preds[n_train + tau:].asnumpy()], 'time',
'x', legend=['data', '1-step preds', 'multistep preds'],
xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_63_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
multistep_preds = torch.zeros(T)
multistep_preds[: n_train + tau] = x[: n_train + tau]
for i in range(n_train + tau, T):
multistep_preds[i] = net(
multistep_preds[i - tau:i].reshape((1, -1)))
d2l.plot([time, time[tau:], time[n_train + tau:]],
[x.detach().numpy(), onestep_preds.detach().numpy(),
multistep_preds[n_train + tau:].detach().numpy()], 'time',
'x', legend=['data', '1-step preds', 'multistep preds'],
xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_66_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
multistep_preds = tf.Variable(tf.zeros(T))
multistep_preds[:n_train + tau].assign(x[:n_train + tau])
for i in range(n_train + tau, T):
multistep_preds[i].assign(tf.reshape(net(
tf.reshape(multistep_preds[i - tau: i], (1, -1))), ()))
d2l.plot([time, time[tau:], time[n_train + tau:]],
[x.numpy(), onestep_preds.numpy(),
multistep_preds[n_train + tau:].numpy()], 'time',
'x', legend=['data', '1-step preds', 'multistep preds'],
xlim=[1, 1000], figsize=(6, 3))
.. figure:: output_sequence_ce248f_69_0.svg
.. raw:: html
.. raw:: html
Yukarıdaki örnekte görüldüğü gibi, tam bir felaket. Tahminler birkaç
tahminden sonra oldukça hızlı bir şekilde bir sabite sönümlenir. Peki
algoritma neden bu kadar kötü çalıştı? Bu sonuç hataların birikmesinden
kaynaklanmaktadır. 1. adımdan sonra hatamızın
:math:`\epsilon_1 = \bar\epsilon` olduğunu varsayalım. Şimdi 2. adımda
*girdi* :math:`\epsilon_1` tarafından dürtülüyor ve bazı :math:`c`
sabiti için :math:`\epsilon_2 = \bar\epsilon + c \epsilon_1` formunda
hatalar görüyoruz. Hata, gerçek gözlemlerden oldukça hızlı bir şekilde
uzaklaşabilir. Bu yaygın bir olgudur. Örneğin, önümüzdeki 24 saat için
hava tahminleri oldukça doğru olma eğilimindedir ama bunun ötesinde
doğruluk hızla azalır. Bu bölümde ve sonrasında bunun iyileştirilmesi
için olası yöntemleri tartışacağız.
:math:`k = 1, 4, 16, 64` için tüm dizideki tahminleri hesaplayarak
:math:`k` adım ilerideki tahminlerdeki zorluklara daha yakından bir göz
atalım.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
max_steps = 64
features = np.zeros((T - tau - max_steps + 1, tau + max_steps))
# Sütun `i` (`i` < `tau`), `i + 1` ile `i + T - tau - max_steps + 1`
# arasındaki zaman adımları için `x`'ten gözlemlerdir.
for i in range(tau):
features[:, i] = x[i: i + T - tau - max_steps + 1]
# Sütun `i` (`i` >= `tau`), 'i + 1' ile `i + T - tau - max_steps + 1`
# arasındaki zaman adımları için (`i - tau + 1`)-adım ileriki tahminlerdir.
for i in range(tau, tau + max_steps):
features[:, i] = net(features[:, i - tau:i]).reshape(-1)
steps = (1, 4, 16, 64)
d2l.plot([time[tau + i - 1: T - max_steps + i] for i in steps],
[features[:, tau + i - 1].asnumpy() for i in steps], 'time', 'x',
legend=[f'{i}-step preds' for i in steps], xlim=[5, 1000],
figsize=(6, 3))
.. figure:: output_sequence_ce248f_75_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
max_steps = 64
features = torch.zeros((T - tau - max_steps + 1, tau + max_steps))
# Sütun `i` (`i` < `tau`), `i + 1` ile `i + T - tau - max_steps + 1`
# arasındaki zaman adımları için `x`'ten gözlemlerdir.
for i in range(tau):
features[:, i] = x[i: i + T - tau - max_steps + 1]
# Sütun `i` (`i` >= `tau`), 'i + 1' ile `i + T - tau - max_steps + 1`
# arasındaki zaman adımları için (`i - tau + 1`)-adım ileriki tahminlerdir.
for i in range(tau, tau + max_steps):
features[:, i] = net(features[:, i - tau:i]).reshape(-1)
steps = (1, 4, 16, 64)
d2l.plot([time[tau + i - 1: T - max_steps + i] for i in steps],
[features[:, tau + i - 1].detach().numpy() for i in steps], 'time', 'x',
legend=[f'{i}-step preds' for i in steps], xlim=[5, 1000],
figsize=(6, 3))
.. figure:: output_sequence_ce248f_78_0.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
max_steps = 64
features = tf.Variable(tf.zeros((T - tau - max_steps + 1, tau + max_steps)))
# Sütun `i` (`i` < `tau`), `i + 1` ile `i + T - tau - max_steps + 1`
# arasındaki zaman adımları için `x`'ten gözlemlerdir.
for i in range(tau):
features[:, i].assign(x[i: i + T - tau - max_steps + 1].numpy())
# Sütun `i` (`i` >= `tau`), 'i + 1' ile `i + T - tau - max_steps + 1`
# arasındaki zaman adımları için (`i - tau + 1`)-adım ileriki tahminlerdir.
for i in range(tau, tau + max_steps):
features[:, i].assign(tf.reshape(net((features[:, i - tau: i])), -1))
steps = (1, 4, 16, 64)
d2l.plot([time[tau + i - 1: T - max_steps + i] for i in steps],
[features[:, tau + i - 1].numpy() for i in steps], 'time', 'x',
legend=[f'{i}-step preds' for i in steps], xlim=[5, 1000],
figsize=(6, 3))
.. figure:: output_sequence_ce248f_81_0.svg
.. raw:: html
.. raw:: html
Bu, gelecekte daha da ileriyi doğru tahmin etmeye çalıştıkça, tahminin
kalitesinin nasıl değiştiğini açıkça göstermektedir. 4 adım ilerideki
tahminler hala iyi görünse de, bunun ötesinde herhangi birşey neredeyse
işe yaramaz.
Özet
----
- Aradeğerleme ve dışdeğerleme arasında zorluk bakımında oldukça fark
vardır. Sonuç olarak, bir diziniz varsa, eğitim sırasında verilerin
zamansal sırasına daima saygı gösterin, yani gelecekteki veriler ile
asla eğitmeyin.
- Dizi modelleri tahmin için özel istatistiksel araçlar gerektirir. İki
popüler seçenek özbağlanımlı modeller ve saklı-değişken özbağlanımlı
modellerdir.
- Nedensel modellerde (örn. ileriye akan zaman), ileri yönün tahmin
edilmesi genellikle ters yönden çok daha kolaydır.
- :math:`t`'ye kadar gözlenen bir dizi için, :math:`t+k` zaman
adımındaki tahmin edilen çıktı :math:`k`\ *-adım tahmin* olur.
:math:`k`'yı artırarak daha da ileriki zaman için tahmin ettiğimizde,
hatalar birikir ve tahminin kalitesi genellikle dramatik bir şekilde
bozulur.
Alıştırmalar
------------
1. Bu bölümün deneyindeki modeli geliştirin.
1. Geçmiş 4 gözlemden daha fazlasını mı dahil ediyor musunuz?
Gerçekten kaç taneye ihtiyacınız var?
2. Gürültü olmasaydı kaç tane geçmiş gözleme ihtiyacınız olurdu?
İpucu: :math:`\sin` ve :math:`\cos`'u diferansiyel denklem olarak
yazabilirsiniz.
3. Toplam öznitelik sayısını sabit tutarken eski gözlemleri de dahil
edebilir misiniz? Bu doğruluğu artırır mı? Neden?
4. Sinir ağı mimarisini değiştirin ve performansını değerlendirin.
2. Bir yatırımcı satın almak için iyi bir yatırım bulmak istiyor.
Hangisinin iyi olacağına karar vermek için geçmiş dönemlere bakıyor.
Bu stratejide ne yanlış gidebilir ki?
3. Nedensellik metinler için de geçerli midir? Peki ne dereceye kadar?
4. Verinin dinamiğini yakalamak için gizli bir özbağlanımlı modelin ne
zaman gerekli olabileceğine dair bir örnek verin.
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html