3.7. Softmaks Regresyonunun 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 3.3 içindeki derin öğrenme çerçevelerinin yüksek seviyeli API’leri doğrusal regresyon uygulamasını çok daha kolay hale getirdi, onu sınıflandırma modellerini uygulamada benzer şekilde (veya muhtemelen daha fazla) uygun bulacağız. Fashion-MNIST veri kümesine bağlı kalalım ve iş boyutunu Section 3.6 gibi 256’da tutalım.

from d2l import mxnet as d2l
from mxnet import gluon, init, npx
from mxnet.gluon import nn

npx.set_np()

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
import torch
from torch import nn
from d2l import torch as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
import tensorflow as tf
from d2l import tensorflow as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

3.7.1. Model Parametrelerini İlkleme

Section 3.4 içinde bahsedildiği gibi, softmaks regresyonunun çıktı katmanı tam bağlı bir katmandır. Bu nedenle, modelimizi uygulamak için, Sequential’a 10 çıktılı tam bağlı bir katman eklememiz yeterlidir. Yine burada, Sequential gerçekten gerekli değildir, ancak derin modelleri uygularken her yerde bulunacağından bu alışkanlığı oluşturalım. Yine, ağırlıkları sıfır ortalama ve 0.01 standart sapma ile rastgele ilkliyoruz.

net = nn.Sequential()
net.add(nn.Dense(10))
net.initialize(init.Normal(sigma=0.01))
# PyTorch, girdileri dolaylı olarak yeniden şekillendirmez. Bu yüzden,
# ağımızdaki doğrusal katmandan önceki girdileri yeniden şekillendirmek için
# düzleştirilmiş katmanı tanımlarız.
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);
net = tf.keras.models.Sequential()
net.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
weight_initializer = tf.keras.initializers.RandomNormal(mean=0.0, stddev=0.01)
net.add(tf.keras.layers.Dense(10, kernel_initializer=weight_initializer))

3.7.2. Softmaks Uygulamasına Yeniden Bakış

Önceki örneğimiz Section 3.6 içinde, modelimizin çıktısını hesapladık ve sonra bu çıktıyı çapraz entropi kaybıyla çalıştırdık. Matematiksel olarak bu, yapılacak son derece makul bir şeydir. Bununla birlikte, hesaplama açısından, üs alma, sayısal kararlılık sorunlarının bir kaynağı olabilir.

Softmaks fonksiyonunun \(\hat y_j = \frac{\exp(o_j)}{\sum_k \exp(o_k)}\)’yi hesapladığını hatırlayın; burada \(\hat y_j\) tahmin edilen olasılık dağılımı \(\hat {\mathbf y}\)’nin \(j.\) öğesidir ve \(o_j\), \(\mathbf{o}\) logitlerinin \(j.\) öğesidir. \(o_k\) değerlerinden bazıları çok büyükse (yani çok pozitifse), o zaman \(\exp(o_k)\) belirli veri türleri için sahip olabileceğimiz en büyük sayıdan daha büyük olabilir (yani taşar). Bu, paydayı (ve/veya payı) inf (sonsuz) yapar ve o zaman \(\hat y_j\) için 0, inf veya nan (sayı değil) ile karşılaşırız. Bu durumlarda çapraz entropi için iyi tanımlanmış bir dönüş değeri elde edemeyiz.

Bunu aşmanın bir yolu, softmaks hesaplamasına geçmeden önce ilk olarak \(\max(o_k)\)’yı tüm \(o_k\)’dan çıkarmaktır. Burada her bir \(o_k\)’nın sabit faktörle kaydırılmasının softmaksın dönüş değerini değiştirmediğini görebilirsiniz.

(3.7.1)\[\begin{split}\begin{aligned} \hat y_j & = \frac{\exp(o_j - \max(o_k))\exp(\max(o_k))}{\sum_k \exp(o_k - \max(o_k))\exp(\max(o_k))} \\ & = \frac{\exp(o_j - \max(o_k))}{\sum_k \exp(o_k - \max(o_k))}. \end{aligned}\end{split}\]

Çıkarma ve normalleştirme adımından sonra, bazı \(o_j - \max(o_k)\) büyük negatif değerlere sahip olabilir ve bu nedenle karşılık gelen \(\exp(o_j - \max(o_k))\) sıfıra yakın değerler alacaktır. Bunlar, sonlu kesinlik (yani, küçümenlik) nedeniyle sıfıra yuvarlanabilir, \(\hat y_j\) sıfır yapar ve \(\log(\hat y_j)\) için bize -inf verir. Geri yaymada yolun birkaç adım aşağısında, kendimizi korkutucu nan sonuçlarıyla karşı karşıya bulabiliriz.

Neyse ki, üstel fonksiyonları hesaplasak bile, nihayetinde onların loglarını (çapraz entropi kaybını hesaplarken) almayı planladığımız gerçeğiyle kurtulduk. Bu iki softmaks ve çapraz entropi operatörünü bir araya getirerek, aksi takdirde geri yayma sırasında başımıza bela olabilecek sayısal kararlılık sorunlarından kaçabiliriz. Aşağıdaki denklemde gösterildiği gibi, \(\exp(o_j - \max(o_k))\)’yi hesaplamaktan kaçınırız ve bunun yerine \(\log(\exp(\cdot))\) içini iptal ederek doğrudan \(o_j - \max(o_k)\) kullanabiliriz:

(3.7.2)\[\begin{split}\begin{aligned} \log{(\hat y_j)} & = \log\left( \frac{\exp(o_j - \max(o_k))}{\sum_k \exp(o_k - \max(o_k))}\right) \\ & = \log{(\exp(o_j - \max(o_k)))}-\log{\left( \sum_k \exp(o_k - \max(o_k)) \right)} \\ & = o_j - \max(o_k) -\log{\left( \sum_k \exp(o_k - \max(o_k)) \right)}. \end{aligned}\end{split}\]

Modelimizin çıktı olasılıklarını değerlendirmek istememiz durumunda, geleneksel softmaks işlevini el altında tutmak isteyeceğiz. Ancak softmaks olasılıklarını yeni kayıp fonksiyonumuza geçirmek yerine, akıllılık yapıp “LogSumExp numarası” kullanarak logitleri geçireceğiz, bütün softmaks ve logaritma değerlerini çapraz entropi kaybında hesaplayacağız.

loss = gluon.loss.SoftmaxCrossEntropyLoss()
loss = nn.CrossEntropyLoss(reduction='none')
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

3.7.3. Optimizasyon Algoritması

Burada, optimizasyon algoritması olarak 0.1 öğrenme oranıyla minigrup rasgele gradyan inişini kullanıyoruz. Bunun doğrusal regresyon örneğinde uyguladığımızla aynı olduğuna ve optimize edicilerin genel uygulanabilirliğini gösterdiğine dikkat edin.

trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})
trainer = torch.optim.SGD(net.parameters(), lr=0.1)
trainer = tf.keras.optimizers.SGD(learning_rate=.1)

3.7.4. Eğitim

Ardından modeli eğitirken Section 3.6 içinde tanımlanan eğitim işlevini çağırıyoruz.

num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
../_images/output_softmax-regression-concise_75d138_51_0.svg
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
../_images/output_softmax-regression-concise_75d138_54_0.svg
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
../_images/output_softmax-regression-concise_75d138_57_0.svg

Daha önce olduğu gibi, bu algoritma, bu sefer öncekinden daha az kod satırı ile, iyi bir doğruluk sağlayan bir çözüme yakınsıyor.

3.7.5. Özet

  • Yüksek seviyeli API’leri kullanarak softmaks regresyonunu çok daha öz uygulayabiliriz.

  • Hesaplama bakış açısından, softmaks regresyonunun uygulanmasının karmaşıklıkları vardır. Pek çok durumda, bir derin öğrenme çerçevesinin sayısal kararlılığı sağlamak için bu çok iyi bilinen hilelerin ötesinde ek önlemler aldığını ve bizi pratikte tüm modellerimizi sıfırdan kodlamaya çalıştığımızda karşılaşacağımız daha da fazla tuzaktan kurtardığını unutmayın.

3.7.6. Alıştırmalar

  1. Sonuçların ne olduğunu görmek için grup boyutu, dönem sayısı ve öğrenme oranı gibi hiper parametreleri ayarlamayı deneyin.

  2. Eğitim için dönem sayısını artırın. Test doğruluğu neden bir süre sonra düşüyor olabilir? Bunu nasıl düzeltebiliriz?