🏷️sec_weight_decay
Artık aşırı öğrenme sorununu tanımladığımıza göre, modelleri düzenlileştirmek için bazı standart tekniklerle tanışabiliriz. Dışarı çıkıp daha fazla eğitim verisi toplayarak aşırı öğrenmeyi her zaman azaltabileceğimizi hatırlayın. Bu maliyetli, zaman alıcı veya tamamen kontrolümüz dışında olabilir ve kısa vadede koşturmayı imkansız hale getirebilir. Şimdilik, kaynaklarımızın izin verdiği kadar yüksek kaliteli veriye sahip olduğumuzu ve düzenlileştirmek tekniklerine odaklandığımızı varsayabiliriz.
Polinom bağlanım örneğimizde (:numref:sec_model_selection
), modelimizin kapasitesini sadece yerleştirilmiş polinomun derecesini ayarlayarak sınırlayabileceğimizi hatırlayın. Gerçekten de, özniteliklerin sayısını sınırlamak, aşırı öğrenme ile mücadele için popüler bir tekniktir. Bununla birlikte, öznitelikleri bir kenara atmak, iş için çok patavatsız bir araç olabilir. Polinom bağlanım örneğine bağlı kalarak, yüksek boyutlu girdilerde neler olabileceğini düşünün. Polinomların çok değişkenli verilere doğal uzantıları, basitçe değişkenlerin güçlerinin çarpımı, tek terimli olarak adlandırılır. Bir tek terimliğin derecesi, güçlerin toplamıdır. Örneğin,
Hem subsec_lin-algebra-norms
ünitesinde tanıtmıştık, ikisi de genel
Basit bir yorumlama, bir sec_linear_regression
'i canlandıralım. Kaybımız şöyle verilir:
Dahası, neden ilk olarak L2 normuyla çalıştığımızı ve örneğin L1 normuyla çalışmadığımızı sorabilirsiniz.
Aslında, diğer seçenekler geçerli ve istatistiksel bakımdan popülerdir.
:eqref:eq_linreg_batch_update
'deki gösterimi kullanırsak,
Daha önce olduğu gibi,
Karşılık gelen ek girdi cezasını,
Basit bir sentetik örnekle ağırlık sönümlenmesinin faydalarını gösterebiliriz. İlk önce, daha önce olduğu gibi biraz veri oluşturuyoruz:
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import autograd, gluon, init, np, npx
from mxnet.gluon import nn
npx.set_np()
#@tab pytorch
%matplotlib inline
from d2l import torch as d2l
import torch
from torch import nn
#@tab tensorflow
%matplotlib inline
from d2l import tensorflow as d2l
import tensorflow as tf
İlk olarak, [önceki gibi biraz veri üretiyoruz]
(
Etiketimizi, sıfır ortalama ve 0.01 standart sapma ile Gauss gürültüsü ile bozulmuş girdilerimizin doğrusal bir fonksiyonu olarak seçiyoruz. Aşırı eğitimin etkilerini belirgin hale getirmek için problemimizin boyutunu
#@tab all
n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
true_w, true_b = d2l.ones((num_inputs, 1)) * 0.01, 0.05
train_data = d2l.synthetic_data(true_w, true_b, n_train)
train_iter = d2l.load_array(train_data, batch_size)
test_data = d2l.synthetic_data(true_w, true_b, n_test)
test_iter = d2l.load_array(test_data, batch_size, is_train=False)
Aşağıda, orijinal hedef işlevine basitçe kare
İlk olarak, model parametrelerimizi rastgele ilkletmek için bir fonksiyon tanımlayacağız.
def init_params():
w = np.random.normal(scale=1, size=(num_inputs, 1))
b = np.zeros(1)
w.attach_grad()
b.attach_grad()
return [w, b]
#@tab pytorch
def init_params():
w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
return [w, b]
#@tab tensorflow
def init_params():
w = tf.Variable(tf.random.normal(mean=1, shape=(num_inputs, 1)))
b = tf.Variable(tf.zeros(shape=(1, )))
return [w, b]
Belki de bu cezayı uygulamanın en uygun yolu, tüm terimlerin karesini almak ve bunları toplamaktır.
def l2_penalty(w):
return (w**2).sum() / 2
#@tab pytorch
def l2_penalty(w):
return torch.sum(w.pow(2)) / 2
#@tab tensorflow
def l2_penalty(w):
return tf.reduce_sum(tf.pow(w, 2)) / 2
Aşağıdaki kod, eğitim kümesine bir model uyarlar ve onu test kümesinde değerlendirir. Doğrusal ağ ve kare kayıp :numref:chap_linear
bölümünden bu yana değişmedi, bu yüzden onları sadece d2l.linreg
ve d2l.squared_loss
yoluyla içe aktaracağız. Buradaki tek değişiklik, kaybımızın artık ceza terimi içermesidir.
def train(lambd):
w, b = init_params()
net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss
num_epochs, lr = 100, 0.003
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
with autograd.record():
# The L2 norm penalty term has been added, and broadcasting
# makes `l2_penalty(w)` a vector whose length is `batch_size`
l = loss(net(X), y) + lambd * l2_penalty(w)
l.backward()
d2l.sgd([w, b], lr, batch_size)
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w\'nin L2 normu:', np.linalg.norm(w))
#@tab pytorch
def train(lambd):
w, b = init_params()
net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss
num_epochs, lr = 100, 0.003
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
# The L2 norm penalty term has been added, and broadcasting
# makes `l2_penalty(w)` a vector whose length is `batch_size`
l = loss(net(X), y) + lambd * l2_penalty(w)
l.sum().backward()
d2l.sgd([w, b], lr, batch_size)
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w\'nin L2 normu:', torch.norm(w).item())
#@tab tensorflow
def train(lambd):
w, b = init_params()
net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss
num_epochs, lr = 100, 0.003
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
with tf.GradientTape() as tape:
# The L2 norm penalty term has been added, and broadcasting
# makes `l2_penalty(w)` a vector whose length is `batch_size`
l = loss(net(X), y) + lambd * l2_penalty(w)
grads = tape.gradient(l, [w, b])
d2l.sgd([w, b], grads, lr, batch_size)
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w\'nin L2 normu:', tf.norm(w).numpy())
Şimdi bu kodu lambd = 0
ile çalıştırarak ağırlık sönümünü devre dışı bırakıyoruz. Kötü bir şekilde fazla öğrendiğimizi, eğitim hatasını azalttığımızı ancak test hatasını azaltmadığımızı unutmayın---bir aşırı öğrenme ders kitabı vakası.
#@tab all
train(lambd=0)
Aşağıda, önemli ölçüde ağırlık sönümü ile çalışıyoruz. Eğitim hatasının arttığını ancak test hatasının azaldığını unutmayın. Düzenlileştirme ile beklediğimiz etki tam da budur.
#@tab all
train(lambd=3)
Ağırlık sönümü sinir ağı optimizasyonunda her yerde mevcut olduğu için, derin öğrenme çerçevesi, herhangi bir kayıp fonksiyonuyla birlikte kolay kullanım için ağırlık sönümü optimizasyon algoritmasını kendisine kaynaştırarak bunu özellikle kullanışlı hale getirir. Dahası, bu kaynaştırma, herhangi bir ek hesaplama yükü olmaksızın, uygulama marifetlerinin algoritmaya ağırlık sönümü eklemesine izin vererek hesaplama avantajı sağlar. Güncellemenin ağırlık sönümü kısmı yalnızca her bir parametrenin mevcut değerine bağlı olduğundan, optimize edicinin herhalükarda her parametreye bir kez dokunması gerekir.
:begin_tab:mxnet
Aşağıdaki kodda, ağırlık sönümü hiper parametresini, Trainer
(Eğitici) örneğimizi oluştururken doğrudan wd
aracılığıyla belirtiyoruz. Varsayılan olarak Gluon hem ağırlıkları hem de ek girdileri aynı anda azaltır. Model parametreleri güncellenirken hiper parametre wd
nin wd_mult
ile çarpılacağına dikkat edin. Bu nedenle, wd_mult
'i sıfır olarak ayarlarsak, ek girdi parametresi
:begin_tab:pytorch
Aşağıdaki kodda, optimize edicimizi başlatırken ağırlık sönümü hiper parametresini doğrudan weight_decay
aracılığıyla belirtiyoruz. PyTorch varsayılan olarak hem ağırlıkları hem de ek girdileri aynı anda azaltır. Burada ağırlık için yalnızca weight_decay
'i ayarlıyoruz, böylece ek girdi parametresi
:begin_tab:tensorflow
Aşağıdaki kodda, ağırlık sönümü hiper parametresi wd
ile bir kernel_regularizer
argümanı aracılığıyla uyguluyoruz.
:end_tab:
def train_concise(wd):
net = nn.Sequential()
net.add(nn.Dense(1))
net.initialize(init.Normal(sigma=1))
loss = gluon.loss.L2Loss()
num_epochs, lr = 100, 0.003
trainer = gluon.Trainer(net.collect_params(), 'sgd',
{'learning_rate': lr, 'wd': wd})
# Ek girdi parametresi sönümlenmedi. Ey girdi adları genellikle "bias" ile biter
net.collect_params('.*bias').setattr('wd_mult', 0)
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
with autograd.record():
l = loss(net(X), y)
l.backward()
trainer.step(batch_size)
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w\'nin L2 normu:', np.linalg.norm(net[0].weight.data()))
#@tab pytorch
def train_concise(wd):
net = nn.Sequential(nn.Linear(num_inputs, 1))
for param in net.parameters():
param.data.normal_()
loss = nn.MSELoss(reduction='none')
num_epochs, lr = 100, 0.003
# Ek girdi parametresi sönümlenmedi
trainer = torch.optim.SGD([
{"params":net[0].weight,'weight_decay': wd},
{"params":net[0].bias}], lr=lr)
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
trainer.zero_grad()
l = loss(net(X), y)
l.mean().backward()
trainer.step()
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print(' w\'nin L2 normu:', net[0].weight.norm().item())
#@tab tensorflow
def train_concise(wd):
net = tf.keras.models.Sequential()
net.add(tf.keras.layers.Dense(
1, kernel_regularizer=tf.keras.regularizers.l2(wd)))
net.build(input_shape=(1, num_inputs))
w, b = net.trainable_variables
loss = tf.keras.losses.MeanSquaredError()
num_epochs, lr = 100, 0.003
trainer = tf.keras.optimizers.SGD(learning_rate=lr)
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
with tf.GradientTape() as tape:
# `tf.keras`, özel eğitim döngüsü için katmanlardaki kayıpların
# manuel olarak alınmasını ve eklenmesini gerektirir.
l = loss(net(X), y) + net.losses
grads = tape.gradient(l, net.trainable_variables)
trainer.apply_gradients(zip(grads, net.trainable_variables))
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w\'nin L2 normu:', tf.norm(net.get_weights()[0]).numpy())
[Grafikler, ağırlık sönümünü sıfırdan uyguladığımızdakilerle aynı görünüyor]. Bununla birlikte, önemli ölçüde daha hızlı çalışırlar ve uygulanması daha kolaydır, bu fayda daha büyük problemler için daha belirgin hale gelecektir.
#@tab all
train_concise(0)
#@tab all
train_concise(3)
Şimdiye kadar, basit bir doğrusal işlevi neyin oluşturduğuna dair yalnızca bir fikre değindik. Dahası, basit doğrusal olmayan bir işlevi neyin oluşturduğu daha da karmaşık bir soru olabilir. Örneğin, çekirdek Hilbert uzayını çoğaltma (Reproducing Kernel Hilbert Spaces - RKHS), doğrusal olmayan bir bağlamda doğrusal fonksiyonlar için tanınmış araçları uygulamaya izin verir. Ne yazık ki, RKHS tabanlı algoritmalar büyük, yüksek boyutlu verilere vasat ölçeklenme eğilimindedir. Bu kitapta, derin bir ağın tüm katmanlarına ağırlık sönümü uygulamanın basit sezgisel yöntemini varsayılan olarak alacağız.
- Düzenlileştirme, aşırı öğrenme ile başa çıkmak için yaygın bir yöntemdir. Öğrenilen modelin karmaşıklığını azaltmak için eğitim kümesindeki kayıp işlevine bir ceza terimi ekler.
- Modeli basit tutmak için belirli bir seçenek,
$L_2$ ceza kullanarak ağırlık sönümlemektir. Bu, öğrenme algoritmasının güncelleme adımlarında ağırlık sönümüne yol açar. - Ağırlık sönümü işlevi, derin öğrenme çerçevelerinden optimize edicilerde sağlanır.
- Farklı parametre kümeleri, aynı eğitim döngüsü içinde farklı güncelleme davranışlarına sahip olabilir.
- Bu bölümdeki tahmin probleminde
$\lambda$ değeri ile deney yapınız. Eğitim ve test doğruluğunu$\lambda$ işlevinin bir işlevi olarak çizin. Ne gözlemliyorsunuz? - En uygun
$\lambda$ değerini bulmak için bir geçerleme kümesi kullanın. Gerçekten optimal değer bu mudur? Bu önemli mi? -
$|\mathbf{w}|^2$ yerine ceza seçimi olarak$\sum_i |w_i|$ kullansaydık ($L_1$ düzenlileştirme) güncelleme denklemleri nasıl görünürdü? -
$|\mathbf{w}|^2 = \mathbf{w}^\top \mathbf{w}$ olduğunu biliyoruz. Matrisler için benzer bir denklem bulabilir misiniz (matematikçiler buna Frobenius normu diyorlar)? - Eğitim hatası ile genelleme hatası arasındaki ilişkiyi gözden geçirin. Ağırlık sönümü, artan eğitim ve uygun karmaşıklıkta bir modelin kullanılmasına ek olarak, aşırı öğrenme ile başa çıkmak için başka hangi yolları düşünebilirsiniz?
- Bayesçi istatistikte,
$P(w \mid x) \propto P(x \mid w) P(w)$ aracılığıyla bir sonsal olasılığın ve önsel olasılığın çarpımını kullanırız.$P(w)$ 'yi düzenlileştirme ile nasıl tanımlayabilirsiniz?
:begin_tab:mxnet
Tartışmalar
:end_tab:
:begin_tab:pytorch
Tartışmalar
:end_tab:
:begin_tab:tensorflow
Tartışmalar
:end_tab: