6.5. Ortaklama¶ Open the notebook in SageMaker Studio Lab
Çoğu zaman, imgeleri işledikçe, gizli temsillerimizin konumsal çözünürlüğünü yavaş yavaş azaltmak istiyoruz, böylece ağda ne kadar yükseğe çıkarsak, her gizli düğümün hassas olduğu alım alanı (girdide) o kadar büyük olur.
Genellikle esas görevimiz bize imge hakkında küresel bir soru sormaktadır, örn. bir kedi içeriyor mu? Bu nedenle tipik olarak son katmanımızın birimleri tüm girdiye karşı hassas olmalıdır. Bilgiyi kademeli olarak toplayarak, daha kaba eşlemeler üreterek, en sonunda küresel bir gösterimi öğrenme amacını gerçekleştiriyoruz ve bunu yaparken evrişimli ara katmanlardaki işlemlerin tüm avantajlarını tutuyoruz.
Dahası, kenarlar gibi (Section 6.2 içinde tartışıldığına
benzer) alt seviye öznitelikleri tespit ederken, genellikle
temsillerimizin yer değiştirmelerden etkilenmez olmasını isteriz.
Örneğin, siyah beyaz arasında keskin gösterimli bir X
imgesini alıp
tüm imgeyi bir pikselle sağa kaydırırsak, yani
Z[i, j] = X[i, j + 1]
, yeni imgenin çıktısı çok farklı olabilir.
Kenar bir piksel ile kaydırılmış olacaktır. Gerçekte, nesneler neredeyse
hiç bir zaman aynı yerde olmaz. Aslında, bir tripod ve sabit bir
nesneyle bile, deklanşörün hareketi nedeniyle kameranın titreşimi her
şeyi bir piksel kaydırabilir (üst düzey kameralar bu sorunu gidermek
için özel özelliklerle donatılmıştır).
Bu bölümde, evrişimli katmanların konuma duyarlılığını azaltmak ve gösterimleri uzaysal örnek seyreltmek gibi ikili amaçlara hizmet eden ortaklama katmanları tanıtılmaktadır.
6.5.1. Maksimum Ortaklama ve Ortalama Ortaklama¶
Ortaklama işlemcileri, evrişimli katmanlar gibi, sabit şekilli pencerenin (bazen ortaklama penceresi olarak da bilinir) geçtiği her konum için tek bir çıktı hesaplayarak, uzun adımına göre girdideki tüm bölgelere kaydırılan sabit şekilli bir pencereden oluşur. Bununla birlikte, evrişimli katmandaki girdi ve çekirdeklerin çapraz korelasyon hesaplamasının aksine, ortaklama katmanı hiçbir parametre içermez (çekirdek yoktur). Bunun yerine, ortaklama uygulayıcıları gerekircidir (determinist) ve genellikle ortaklama penceresindeki öğelerin maksimum veya ortalama değerini hesaplar. Bu işlemler sırasıyla maksimum ortaklama (kısaca ortaklama) ve ortalama ortaklama olarak adlandırılır.
Her iki durumda da, çapraz korelasyon uygulayıcısında olduğu gibi, ortaklama penceresinin girdi tensörünün sol üstünden başlayarak girdi tensörünün soldan sağa ve yukarıdan aşağıya doğru kayması olarak düşünebiliriz. Ortaklama penceresinin vurduğu her konumda, maksimum veya ortalama ortaklamanın kullanılmasına bağlı olarak, pencerede girdi alt tensörünün maksimum veya ortalama değerini hesaplar.
Fig. 6.5.1 \(2 \times 2\) şeklinde bir ortaklama penceresi ile maksimum ortaklama. Gölgeli kısımlar, ilk çıktı elemanı ve çıktı hesaplaması için kullanılan girdi tensör elemanlarıdır: \(\max(0, 1, 3, 4)=4\).¶
Fig. 6.5.1 içindeki çıktı tensör 2’lik yüksekliğe ve 2’lik genişliğe sahiptir. Dört öğe, her ortaklama penceresindeki maksimum değerden türetilir:
Ortaklama penceresi şeklindeki \(p \times q\) ortaklama katmanına \(p \times q\) ortaklama katmanı denir. Ortaklama işlemi \(p \times q\) ortaklama olarak adlandırılır.
Bu bölümün başında belirtilen nesne kenarı algılama örneğine dönelim.
Şimdi \(2\times 2\) maksimum ortaklama için girdi olarak evrişimli
tabakanın çıktısını kullanacağız. Evrişimli katman girdisini X
ve
ortaklama katmanı çıktısını Y
olarak düzenleyelim. X[i, j]
ve
X[i, j + 1]
veya X[i, j + 1]
ve X[i, j + 2]
değerleri farklı
olsa da olmasa da, ortaklama katmanı her zaman Y[i, j] = 1
çıktısını
verir. Yani, \(2\times 2\) maksimum ortaklama katmanını kullanarak,
evrişimli katman tarafından tanınan desenin yükseklik veya genişlik
olarak birden fazla eleman yine de hareket edip etmediğini tespit
edebiliriz.
Aşağıdaki kodda, pool2d
işlevinde ortaklama katmanının ileri
yaymasını uyguluyoruz. Bu işlev Section 6.2 içindeki
corr2d
işlevine benzer. Ancak, burada çekirdeğimiz yok, çıktıyı
girdideki her bölgenin maksimumu veya ortalaması olarak hesaplıyoruz.
from d2l import mxnet as d2l
from mxnet import np, npx
from mxnet.gluon import nn
npx.set_np()
def pool2d(X, pool_size, mode='max'):
p_h, p_w = pool_size
Y = np.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j] = X[i: i + p_h, j: j + p_w].max()
elif mode == 'avg':
Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
return Y
import torch
from torch import nn
from d2l import torch as d2l
def pool2d(X, pool_size, mode='max'):
p_h, p_w = pool_size
Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j] = X[i: i + p_h, j: j + p_w].max()
elif mode == 'avg':
Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
return Y
import tensorflow as tf
def pool2d(X, pool_size, mode='max'):
p_h, p_w = pool_size
Y = tf.Variable(tf.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w +1)))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j].assign(tf.reduce_max(X[i: i + p_h, j: j + p_w]))
elif mode =='avg':
Y[i, j].assign(tf.reduce_mean(X[i: i + p_h, j: j + p_w]))
return Y
İki boyutlu maksimum ortaklama tabakasının çıktısını doğrulamak için
Fig. 6.5.1 içinde girdi tensörü X
’i inşa ediyoruz.
X = np.array([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
pool2d(X, (2, 2))
array([[4., 5.],
[7., 8.]])
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
pool2d(X, (2, 2))
tensor([[4., 5.],
[7., 8.]])
X = tf.constant([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
pool2d(X, (2, 2))
<tf.Variable 'Variable:0' shape=(2, 2) dtype=float32, numpy=
array([[4., 5.],
[7., 8.]], dtype=float32)>
Ayrıca, ortalama ortaklama katmanıyla da deney yapalım.
pool2d(X, (2, 2), 'avg')
array([[2., 3.],
[5., 6.]])
pool2d(X, (2, 2), 'avg')
tensor([[2., 3.],
[5., 6.]])
pool2d(X, (2, 2), 'avg')
<tf.Variable 'Variable:0' shape=(2, 2) dtype=float32, numpy=
array([[2., 3.],
[5., 6.]], dtype=float32)>
6.5.2. Dolgu ve Uzun Adım¶
Evrişimli katmanlarda olduğu gibi, ortaklama katmanları da çıktının
şeklini değiştirebilir. Ayrıca daha önce olduğu gibi, girdiyi
dolgulayarak ve uzun adımı ayarlayarak istenen çıktı şeklini elde etmek
için işlemi değiştirebiliriz. Derin öğrenme çerçevesinden yerleşik iki
boyutlu maksimum ortaklama katmanı aracılığıyla ortaklama katmanlarında
dolgu ve uzun adımların kullanımını gösterebiliriz. İlk olarak dört
boyutlu şekle sahip bir X
girdi tensörü inşa ediyoruz, burada
örneklerin sayısı (iş boyutu) ve kanalların sayısının her ikisi de
1’dir.
X = np.arange(16, dtype=np.float32).reshape((1, 1, 4, 4))
X
array([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]]])
X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
X
tensor([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]]])
Dikkat edilecek bir husus tensorflow’un kanallar son sıra (son eksen) girdileri tercih ettiği ve ona göre optimize edildiğidir.
X = tf.reshape(tf.range(16, dtype=tf.float32), (1, 4, 4, 1))
X
<tf.Tensor: shape=(1, 4, 4, 1), dtype=float32, numpy=
array([[[[ 0.],
[ 1.],
[ 2.],
[ 3.]],
[[ 4.],
[ 5.],
[ 6.],
[ 7.]],
[[ 8.],
[ 9.],
[10.],
[11.]],
[[12.],
[13.],
[14.],
[15.]]]], dtype=float32)>
Varsayılan olarak, çerçevenin yerleşik sınıfındaki örnekteki uzun adım
ve ortaklama penceresi aynı şekle sahiptir. Aşağıda, (3, 3)
şeklindeki bir ortaklama penceresi kullanıyoruz, bu nedenle varsayılan
olarak (3, 3)
’lük bir adım şekli alıyoruz.
pool2d = nn.MaxPool2D(3)
# Ortaklama katmanında model parametresi olmadığı için parametre
# ilkleme fonksiyonunu çağırmamız gerekmez
pool2d(X)
array([[[[10.]]]])
pool2d = nn.MaxPool2d(3)
pool2d(X)
tensor([[[[10.]]]])
pool2d = tf.keras.layers.MaxPool2D(pool_size=[3, 3])
pool2d(X)
<tf.Tensor: shape=(1, 1, 1, 1), dtype=float32, numpy=array([[[[10.]]]], dtype=float32)>
Uzun adım ve dolgu manuel olarak belirtilebilir.
pool2d = nn.MaxPool2D(3, padding=1, strides=2)
pool2d(X)
array([[[[ 5., 7.],
[13., 15.]]]])
Tabii ki, keyfi bir dikdörtgen ortaklama penceresi belirleyebilir ve sırasıyla yükseklik ve genişlik için dolguyu ve uzun adımı belirtebiliriz.
pool2d = nn.MaxPool2D((2, 3), padding=(0, 1), strides=(2, 3))
pool2d(X)
array([[[[ 5., 7.],
[13., 15.]]]])
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)
tensor([[[[ 5., 7.],
[13., 15.]]]])
Tabii ki, keyfi bir dikdörtgen ortaklama penceresi belirleyebilir ve sırasıyla yükseklik ve genişlik için dolguyu ve uzun adımı belirtebiliriz.
pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(0, 1))
pool2d(X)
tensor([[[[ 5., 7.],
[13., 15.]]]])
paddings = tf.constant([[0, 0], [1,0], [1,0], [0,0]])
X_padded = tf.pad(X, paddings, "CONSTANT")
pool2d = tf.keras.layers.MaxPool2D(pool_size=[3, 3], padding='valid',
strides=2)
pool2d(X_padded)
<tf.Tensor: shape=(1, 2, 2, 1), dtype=float32, numpy=
array([[[[ 5.],
[ 7.]],
[[13.],
[15.]]]], dtype=float32)>
Tabii ki, keyfi bir dikdörtgen ortaklama penceresi belirleyebilir ve sırasıyla yükseklik ve genişlik için dolguyu ve uzun adımı belirtebiliriz.
paddings = tf.constant([[0, 0], [0, 0], [1, 1], [0, 0]])
X_padded = tf.pad(X, paddings, "CONSTANT")
pool2d = tf.keras.layers.MaxPool2D(pool_size=[2, 3], padding='valid',
strides=(2, 3))
pool2d(X_padded)
<tf.Tensor: shape=(1, 2, 2, 1), dtype=float32, numpy=
array([[[[ 5.],
[ 7.]],
[[13.],
[15.]]]], dtype=float32)>
6.5.3. Çoklu Kanal¶
Çok kanallı girdi verilerini işlerken, ortaklama katmanı, girdileri bir
evrişimli katmanda olduğu gibi kanallar üzerinden toplamak yerine her
girdi kanalını ayrı ayrı ortaklar. Bu, ortaklama katmanının çıktı
kanallarının sayısının girdi kanalı sayısıyla aynı olduğu anlamına
gelir. Aşağıda, 2 kanallı bir girdi oluşturmak için kanal boyutundaki
X
ve X + 1
tensörleri birleştiriyoruz.
X = np.concatenate((X, X + 1), 1)
X
array([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]],
[[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.],
[13., 14., 15., 16.]]]])
X = torch.cat((X, X + 1), 1)
X
tensor([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]],
[[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.],
[13., 14., 15., 16.]]]])
Bunun, kanallar son sıra sözdizimi nedeniyle TensorFlow için son boyut boyunca bir birleştirme gerektireceğini unutmayın.
X = tf.concat([X, X + 1], 3) # Concatenate along `dim=3` due to channels-last syntax
Gördüğümüz gibi, çıktı kanallarının sayısı ortaklamadan sonra hala 2’dir.
pool2d = nn.MaxPool2D(3, padding=1, strides=2)
pool2d(X)
array([[[[ 5., 7.],
[13., 15.]],
[[ 6., 8.],
[14., 16.]]]])
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)
tensor([[[[ 5., 7.],
[13., 15.]],
[[ 6., 8.],
[14., 16.]]]])
paddings = tf.constant([[0, 0], [1,0], [1,0], [0,0]])
X_padded = tf.pad(X, paddings, "CONSTANT")
pool2d = tf.keras.layers.MaxPool2D(pool_size=[3, 3], padding='valid',
strides=2)
pool2d(X_padded)
<tf.Tensor: shape=(1, 2, 2, 2), dtype=float32, numpy=
array([[[[ 5., 6.],
[ 7., 8.]],
[[13., 14.],
[15., 16.]]]], dtype=float32)>
Tensorflow ortaklama çıktısının ilk bakışta farklı göründüğünü, ancak sayısal olarak aynı sonuçların MXNet ve PyTorch’teki gibi temsil edildiğini unutmayın. Fark, boyutlulukta yatmaktadır ve çıktıyı dikey olarak okumak, diğer uygulamalarla aynı çıktıyı verir.
6.5.4. Özet¶
Ortaklama penceresinde girdi öğelerini alarak, maksimum ortaklama işlemi çıktı olarak maksimum değeri atar ve ortalama ortaklama işlemi ortalama değeri çıktı olarak atar.
Bir ortaklama tabakasının en önemli avantajlarından biri, evrişimli tabakanın konumuna aşırı duyarlılığını hafifletmektir.
Ortaklama katmanı için dolgu ve uzun adım belirtebiliriz.
Uzamsal boyutları (örn. genişlik ve yükseklik) azaltmak için 1’den büyük bir uzun adımla birlikte maksimum ortaklama kullanılabilir.
Ortaklama katmanının çıktı kanalı sayısı, girdi kanallarının sayısıyla aynıdır.
6.5.5. Alıştırmalar¶
Bir evrişim tabakasının özel bir durumu olarak ortalama ortaklama uygulayabilir misiniz? Eğer öyleyse, yapınız.
Bir evrişim tabakasının özel bir durumu olarak maksimum ortaklama uygulayabilir misiniz? Eğer öyleyse, yapınız.
Ortaklama katmanının hesaplama maliyeti nedir? Ortaklama katmanına girdi boyutunun \(c\times h\times w\) olduğunu, ortaklama penceresinin \(p_h\times p_w\) bir şekle sahip, \((p_h, p_w)\) dolgulu ve \((s_h, s_w)\) uzun adımlı olduğunu varsayalım.
Neden maksimum ortaklama ile ortalama ortaklamanın farklı çalışmasını beklersiniz?
Ayrı bir minimum ortaklama katmanına ihtiyacımız var mıdır? Onu başka bir işlemle değiştirebilir misiniz?
Ortalama ve maksimum ortaklama arasında düşünebileceğiniz başka bir işlem var mıdır (İpucu: Softmaks’i anımsayın)? Neden o kadar popüler olmayacaktır?