.. _sec_padding:
Dolgu ve Uzun Adımlar
=====================
Önceki :numref:`fig_correlation` örneğinde, girdimizin hem yüksekliği
hem de genişliği 3 idi ve evrişim çekirdeğimizin hem yüksekliği hem de
genişliği 2 idi, bu da :math:`2\times2` boyutlu bir çıktı gösterimi
sağladı. :numref:`sec_conv_layer` içinde genelleştirdiğimiz gibi,
girdinin şeklinin :math:`n_h\times n_w` olduğunu ve evrişim çekirdeğinin
şeklinin :math:`k_h\times k_w` olduğunu varsayarsak, çıktının şekli
:math:`(n_h-k_h+1) \times (n_w-k_w+1)` olacaktır. Bu nedenle, evrişimli
tabakanın çıktı şekli, girdinin şekli ve evrişim çekirdeğinin şekli ile
belirlenir.
Bazı durumlarda, çıktının boyutunu etkileyen dolgu ve uzun adımlı
evrişimler dahil olmak üzere teknikleri dahil ediyoruz.Motivasyon
olarak, çekirdeklerin genellikle :math:`1`'den büyük genişliğe ve
yüksekliğe sahip olduğundan, birçok ardışık evrişim uyguladıktan sonra,
girdimizden önemli ölçüde daha küçük çıktılar elde etme eğiliminde
olduğumuzu unutmayın. :math:`240 \times 240` piksel imgeyle başlarsak,
:math:`10` tane :math:`5 \times 5` evrişim katmanı imgeyi
:math:`200 \times 200` piksele indirir, imgenin :math:`\% 30`'unu
keserek atar ve orijinal imgenin sınırları hakkındaki ilginç bilgileri
yok eder. *Dolgu*, bu sorunu ele almada en popüler araçtır.
Diğer durumlarda, örneğin orijinal girdi çözünürlüğünün kullanışsız
olduğunu görürsek, boyutsallığı büyük ölçüde azaltmak isteyebiliriz.
*Uzun adımlı evrişimler*, bu örneklerde yardımcı olabilecek popüler bir
tekniktir.
Dolgu
-----
Yukarıda açıklandığı gibi, evrişimli katmanları uygularken zor bir
sorun, imgemizin çevresindeki pikselleri kaybetme eğiliminde olmamızdır.
Tipik olarak küçük çekirdekler kullandığımızdan, herhangi bir evrişim
için, yalnızca birkaç piksel kaybedebiliriz, ancak birçok ardışık
evrişimli katman uyguladığımız için bu kayıplar toplanarak artacaktır.
Bu soruna basit bir çözüm, girdi imgemizin sınırına ekstra dolgu
pikselleri eklemek, böylece imgenin etkin boyutunu arttırmaktır. Tipik
olarak, ekstra piksellerin değerlerini sıfıra ayarlarız.
:numref:`img_conv_pad` içinde, :math:`3 \times 3`'lük girdiyi
doldurarak boyutunu :math:`5 \times 5`'e yükseltiyoruz. Karşılık gelen
çıktı daha sonra bir :math:`4 \times 4` matrisine yükselir. Gölgeli
kısımlar, çıktı hesaplamasında kullanılan girdi ve çekirdek tensör
elemanlarının yanı sıra ilk çıktı elemanıdır:
:math:`0\times0+0\times1+0\times2+0\times3=0`.
.. _img_conv_pad:
.. figure:: ../img/conv-pad.svg
Dolgu ile iki boyutlu çapraz korelasyon.
Genel olarak, toplam :math:`p_h` satırlı dolgu (kabaca yarısı üstte ve
altta yarısı) ve toplam :math:`p_w` sütunlu dolgu (kabaca yarısı solda
ve sağda yarısı) eklersek, çıktının şekli şöyle olur:
.. math:: (n_h-k_h+p_h+1)\times(n_w-k_w+p_w+1).
Bu, çıktının yüksekliğinin ve genişliğinin sırasıyla :math:`p_h` ve
:math:`p_w` artacağı anlamına gelir.
Birçok durumda, girdiye ve çıktıya aynı yüksekliği ve genişliği vermek
için :math:`p_h=k_h-1` ve :math:`p_w=k_w-1`'i ayarlamak isteyeceğiz. Bu,
ağ oluştururken her katmanın çıktı şeklini tahmin etmeyi
kolaylaştıracaktır. :math:`k_h`'nın burada tek sayı olduğunu
varsayarsak, yüksekliğin her iki tarafında :math:`p_h/2` satır dolgu
olacak. Eğer :math:`k_h` çift ise, bir olasılık girdinin üstünde
:math:`\lfloor p_h/2\rfloor` ve altında :math:`\lceil p_h/2\rceil` satır
dolgu olmasıdır. Genişliğin her iki tarafını da aynı şekilde
dolduracağız.
CNN'ler genellikle 1, 3, 5 veya 7 gibi tek yükseklik ve genişlik
değerlerine sahip evrişim çekirdeklerini kullanır. Tek sayı çekirdek
boyutlarını seçmek, üstte ve altta aynı sayıda satır ve solda ve sağda
aynı sayıda sütun ile doldururken uzamsal boyutsallığı koruyabilmemiz
avantajına sahiptir.
Dahası, bu boyutsallığı hassas bir şekilde korumak için tek sayı boyutlu
çekirdekler ve dolgu kullanma uygulaması rutinsel faydalar sağlar.
Herhangi bir iki boyutlu tensör ``X`` için, çekirdeğin boyutu tek
olduğunda ve her iki taraftaki dolgu satırları ve sütunlarının sayısı
aynı olduğunda, girdiyle aynı yüksekliğe ve genişliğe sahip bir çıktı
ürettiğini, ``Y[i, j]`` çıktısının girdi ve ``X[i, j]`` ile ortalanmış
pencereli evrişim çekirdeğinin çapraz korelasyonu ile hesaplandığını
biliyoruz.
Aşağıdaki örnekte, yüksekliği ve genişliği 3 olan iki boyutlu bir
evrişimli tabaka oluşturuyoruz ve her tarafa 1 piksel dolgu uyguluyoruz.
Yüksekliği ve genişliği 8 olan bir girdi göz önüne alındığında, çıktının
yüksekliğinin ve genişliğinin de 8 olduğunu buluruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
from mxnet import np, npx
from mxnet.gluon import nn
npx.set_np()
# Kolaylık sağlamak için evrişimli katmanı hesaplamada bir fonksiyon tanımladık.
# Bu işlev, evrişimli katman ağırlıklarını başlatır
# ve girdi ve çıktıda karşılık gelen boyutsallık yükseltmelerini
# ve azaltmalarını gerçekleştirir
def comp_conv2d(conv2d, X):
conv2d.initialize()
# Burada (1, 1) grup boyutunun ve kanal sayısının her
# ikisinin de 1 olduğunu gösterir.
X = X.reshape((1, 1) + X.shape)
Y = conv2d(X)
# Bizi ilgilendirmeyen ilk iki boyutu hariç tutun: Örnekler
# ve kanallar
return Y.reshape(Y.shape[2:])
# Burada her iki tarafta 1 satır veya sütunun doldurulduğunu unutmayın,
# bu nedenle toplam 2 satır veya sütun eklidir.
conv2d = nn.Conv2D(1, kernel_size=3, padding=1)
X = np.random.uniform(size=(8, 8))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(8, 8)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import torch
from torch import nn
# Kolaylık sağlamak için evrişimli katmanı hesaplamada bir fonksiyon tanımladık.
# Bu işlev, evrişimli katman ağırlıklarını başlatır
# ve girdi ve çıktıda karşılık gelen boyutsallık yükseltmelerini
# ve azaltmalarını gerçekleştirir
def comp_conv2d(conv2d, X):
# Burada (1, 1) grup boyutunun ve kanal sayısının her
# ikisinin de 1 olduğunu gösterir.
X = X.reshape((1, 1) + X.shape)
Y = conv2d(X)
# Bizi ilgilendirmeyen ilk iki boyutu hariç tutun: Örnekler
# ve kanallar
return Y.reshape(Y.shape[2:])
# Burada her iki tarafta 1 satır veya sütunun doldurulduğunu unutmayın,
# bu nedenle toplam 2 satır veya sütun eklidir.
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
X = torch.rand(size=(8, 8))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
torch.Size([8, 8])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import tensorflow as tf
# Kolaylık sağlamak için evrişimli katmanı hesaplamada bir fonksiyon tanımladık.
# Bu işlev, evrişimli katman ağırlıklarını başlatır
# ve girdi ve çıktıda karşılık gelen boyutsallık yükseltmelerini
# ve azaltmalarını gerçekleştirir
def comp_conv2d(conv2d, X):
# Burada (1, 1) grup boyutunun ve kanal sayısının her
# ikisinin de 1 olduğunu gösterir.
X = tf.reshape(X, (1, ) + X.shape + (1, ))
Y = conv2d(X)
# Bizi ilgilendirmeyen ilk iki boyutu hariç tutun: Örnekler
# ve kanallar
return tf.reshape(Y, Y.shape[1:3])
# Burada her iki tarafta 1 satır veya sütunun doldurulduğunu unutmayın,
# bu nedenle toplam 2 satır veya sütun eklidir.
conv2d = tf.keras.layers.Conv2D(1, kernel_size=3, padding='same')
X = tf.random.uniform(shape=(8, 8))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
TensorShape([8, 8])
.. raw:: html
.. raw:: html
Evrişim çekirdeğinin yüksekliği ve genişliği farklı olduğunda, yükseklik
ve genişlik için farklı dolgu sayıları ayarlayarak çıktı ve girdinin
aynı yükseklik ve genişliğe sahip olmasını sağlayabiliriz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
# Burada yüksekliği 5 ve genişliği 3 olan bir evrişim çekirdeği
# kullanıyoruz. Yüksekliğin ve genişliğin her iki tarafındaki
# dolgu sayıları sırasıyla 2 ve 1'dir.
conv2d = nn.Conv2D(1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(8, 8)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
# Burada yüksekliği 5 ve genişliği 3 olan bir evrişim çekirdeği
# kullanıyoruz. Yüksekliğin ve genişliğin her iki tarafındaki
# dolgu sayıları sırasıyla 2 ve 1'dir.
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
torch.Size([8, 8])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
# Burada yüksekliği 5 ve genişliği 3 olan bir evrişim çekirdeği
# kullanıyoruz. Yüksekliğin ve genişliğin her iki tarafındaki
# dolgu sayıları sırasıyla 2 ve 1'dir.
conv2d = tf.keras.layers.Conv2D(1, kernel_size=(5, 3), padding='same')
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
TensorShape([8, 8])
.. raw:: html
.. raw:: html
Uzun Adım
---------
Çapraz korelasyonu hesaplarken, girdi tensörünün sol üst köşesinden
evrişim penceresi ile başlar ve ardından hem aşağı hem de sağa doğru tüm
konumların üzerinden kaydırırız. Önceki örneklerde, varsayılan olarak
bir öğeyi aynı anda kaydırırız. Ancak, bazen, ya hesaplama verimliliği
için ya da örnek seyreltmek (downsampling) istediğimiz için, penceremizi
aynı anda birden fazla öğe üzerinden hareket ettirerek ara konumları
atlıyoruz.
Kayma başına geçilen satır ve sütun sayısını *uzun adım (stride)* diye
adlandırırız. Şimdiye kadar, hem yükseklik hem de genişlik için 1'lik
adımlar kullandık. Bazen, daha büyük bir adım kullanmak isteyebiliriz.
:numref:`img_conv_stride`, dikey 3 ve yatay 2 adımlı iki boyutlu bir
çapraz korelasyon işlemi gösterir. Gölgeli kısımlar çıktı elemanlarının
yanı sıra çıktı hesaplaması için kullanılan girdi ve çekirdek tensör
elemanlarıdır: :math:`0\times0+0\times1+1\times2+2\times3=8`,
:math:`0\times0+6\times1+0\times2+0\times3=6`. İlk sütunun ikinci
elemanı çıkıldığında, evrişim penceresinin üç sıra aşağı kaydığını
görebiliriz. İlk satırın ikinci öğesi işlenince evrişim penceresi sağa
iki sütun kaydırılıyor. Evrişim penceresi girdide sağa iki sütun kaymaya
devam ettiğinde, girdi öğesi pencereyi dolduramayacağı için (başka bir
dolgu sütunu eklemediğimiz sürece) çıktı yoktur.
.. _img_conv_stride:
.. figure:: ../img/conv-stride.svg
Yükseklik ve genişlik için sırasıyla 3'lük ve 2'lik uzun adımlarla
çapraz korelasyon.
Genel olarak, yükseklik için :math:`s_h` adım ve genişlik için
:math:`s_w` adım olduğunda, çıktının şekli:
.. math:: \lfloor(n_h-k_h+p_h+s_h)/s_h\rfloor \times \lfloor(n_w-k_w+p_w+s_w)/s_w\rfloor.
:math:`p_h=k_h-1` ve :math:`p_w=k_w-1`'i ayarlarsak, çıktı şekli
:math:`\lfloor(n_h+s_h-1)/s_h\rfloor \times \lfloor(n_w+s_w-1)/s_w\rfloor`'e
sadeleşir. Bir adım daha ileri gidersek, eğer girdi yüksekliği ve
genişliği, yükseklik ve genişlik üzerindeki uzun adımlarla
bölünebilirse, çıktının şekli :math:`(n_h/s_h) \times (n_w/s_w)`
olacaktır.
Aşağıda, hem yükseklik hem de genişlik üzerindeki uzun adımları 2'ye
ayarladık, böylece girdinin yüksekliğini ve genişliğini yarıya indirdik.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
conv2d = nn.Conv2D(1, kernel_size=3, padding=1, strides=2)
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(4, 4)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
torch.Size([4, 4])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
conv2d = tf.keras.layers.Conv2D(1, kernel_size=3, padding='same', strides=2)
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
TensorShape([4, 4])
.. raw:: html
.. raw:: html
Daha sonra, biraz daha karmaşık bir örneğe bakacağız.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
conv2d = nn.Conv2D(1, kernel_size=(3, 5), padding=(0, 1), strides=(3, 4))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
(2, 2)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
torch.Size([2, 2])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
conv2d = tf.keras.layers.Conv2D(1, kernel_size=(3,5), padding='valid',
strides=(3, 4))
comp_conv2d(conv2d, X).shape
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
TensorShape([2, 1])
.. raw:: html
.. raw:: html
Kısa olması amacıyla, girdi yüksekliğinin ve genişliğinin her iki
tarafındaki dolgu sayısı sırasıyla :math:`p_h` ve :math:`p_w` olduğunda,
dolguya :math:`(p_h, p_w)` diyoruz. Özellikle, :math:`p_h = p_w = p`
olduğunda, dolgu :math:`p`'dir. Yükseklik ve genişlik üzerindeki uzun
adımlar sırasıyla :math:`s_h` ve :math:`s_w` olduğunda, uzun adıma
:math:`(s_h, s_w)` diyoruz. Özellikle, :math:`s_h = s_w = s` olduğunda,
uzun adım :math:`s`'dir. Varsayılan olarak, dolgu 0 ve uzun adım 1'dir.
Uygulamada, nadiren homojen olmayan adımlar veya dolgu kullanırız, yani
genellikle :math:`p_h = p_w` ve :math:`s_h = s_w`'dir.
Özet
----
- Dolgu, çıktının yüksekliğini ve genişliğini artırabilir. Bu,
genellikle çıktıya girdi ile aynı yükseklik ve genişlik vermek için
kullanılır.
- Uzun adım, çıktının çözünürlüğünü azaltabilir, örneğin çıktının
yüksekliğini ve genişliğini, girdinin yüksekliğinin ve genişliğinin
yalnızca :math:`1/n`'sine düşürür (:math:`n`, :math:`1`'den büyük bir
tamsayıdır).
- Dolgu ve uzun adım, verilerin boyutsallığını etkin bir şekilde
ayarlamak için kullanılabilir.
Alıştırmalar
------------
1. Bu bölümdeki son örnek için, deneysel sonuçla tutarlı olup olmadığını
görmek amacıyla çıktı şeklini matematik kullanarak hesaplayın.
2. Bu bölümdeki deneylerde diğer dolgu ve uzun adım kombinasyonlarını
deneyin.
3. Ses sinyalleri için, 2'lik bir uzun adım neye karşılık gelir?
4. 1'den büyük bir uzun adımın hesaplamalı faydaları nelerdir?
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html