2.4. Hesaplama (Kalkülüs)¶ Open the notebook in SageMaker Studio Lab
Bir çokgenin alanını bulmak, eski Yunanlıların bir çokgeni üçgenlere böldüğü ve alanlarını topladığı en az 2.500 yıl öncesine kadar gizemli kalmıştı. Bir daire gibi kavisli şekillerin alanını bulmak için, eski Yunanlılar bu şekillerin içine çokgenler yerleştirdiler. Fig. 2.4.1’de gösterildiği gibi, eşit uzunlukta daha fazla kenarı olan çizili bir çokgen daireye bayağı yaklaşır. Bu işlem tüketme yöntemi olarak da bilinir.
Fig. 2.4.1 Tüketme yöntemiyle bir dairenin alanını bulun.¶
Aslında, tüketme yöntemi integral hesabının (şurada açıklanacaktır Section 18.5) kaynaklandığı yerdir. 2.000 yıldan fazla bir müddetten sonra, diğer kalkülüs alanı, diferansiyel (türevsel) kalkülüs icat edildi. Diferansiyel kalkülüsün en kritik uygulamaları arasındaki optimizasyon problemleri bir şeyin nasıl en iyi şekilde yapılacağına kafa yorar. Section 2.3.10.1’de tartışıldığı gibi, bu tür sorunlar derin öğrenmede her yerde bulunur.
Derin öğrenmede, modelleri daha fazla veri gördükçe daha iyi ve daha iyi olmaları için arka arkaya güncelleyerek eğitiyoruz. Genellikle, daha iyi olmak, “modelimiz ne kadar kötü?” sorusuna cevap veren bir skor olan kayıp (yitim) fonksiyonunu en aza indirmek anlamına gelir. Bu soru göründüğünden daha zekicedir. Sonuçta, gerçekten önemsediğimiz, daha önce hiç görmediğimiz veriler üzerinde iyi performans gösteren bir model üretmektir. Ancak modeli yalnızca gerçekten görebildiğimiz verilere uydurabiliriz. Böylece modellerin uydurulması görevini iki temel kaygıya ayırabiliriz: (i) Eniyileme: Modellerimizi gözlemlenen verilere uydurma süreci; (ii) Genelleme: Geçerliliği onları eğitmek için kullanılan kesin veri örnekleri kümesinin ötesine geçen modellerin nasıl üretileceğinde bize rehberlik eden matematiksel ilkelerin ve uygulayıcılarının bilgeliği.
Daha sonraki bölümlerde optimizasyon problemlerini ve yöntemlerini anlamanıza yardımcı olmak için burada, derin öğrenmede yaygın olarak kullanılan diferansiyel hesaplama hakkında bir tutam bilgi veriyoruz.
2.4.1. Türev ve Türev Alma¶
Hemen hemen tüm derin öğrenme optimizasyon algoritmalarında önemli bir adım olan türevlerin hesaplanmasını ele alarak başlıyoruz. Derin öğrenmede, tipik olarak modelimizin parametrelerine göre türevi alınabilen kayıp fonksiyonlarını seçeriz. Basitçe ifade etmek gerekirse, bu, her parametre için, o parametreyi sonsuz derecede küçük bir miktarda arttırırsak veya azaltırsak kaybın ne kadar hızlı artacağını veya azalacağını belirleyebileceğimiz anlamına gelir.
Girdi ve çıktıların her ikisi de skaler olan \(f: \mathbb {R} \rightarrow \mathbb{R}\) fonksiyonumuz olduğunu varsayalım. \(f\)’nin türevi şöyle tanımlanır:
eğer bu limit varsa. \(f'(a)\) varsa, \(f\)’nin \(a\)’da türevlenebilir olduğu söylenir. \(f\), bir aralığın her sayısında türevlenebilirse, o zaman bu fonksiyon bu aralıkta türevlenebilir. \(f'(x)\)’in (2.4.1)’deki türevini \(f(x)\)’in \(x\)’e göre anlık değişim oranı olarak yorumlayabiliriz. Sözde anlık değişim oranı, \(x\) cinsinden \(h\) \(0\)’a yaklaşırken değişimini temel alır.
Türevleri açıklamayı için bir örnekle deneyelim. \(u = f(x) = 3x^2-4x\) tanımlayın.
%matplotlib inline
from matplotlib_inline import backend_inline
from d2l import mxnet as d2l
from mxnet import np, npx
npx.set_np()
def f(x):
return 3 * x ** 2 - 4 * x
%matplotlib inline
import numpy as np
from matplotlib_inline import backend_inline
from d2l import torch as d2l
def f(x):
return 3 * x ** 2 - 4 * x
%matplotlib inline
import numpy as np
from matplotlib_inline import backend_inline
from d2l import tensorflow as d2l
def f(x):
return 3 * x ** 2 - 4 * x
\(x = 1\) diye ayarlayıp \(h\) değerinin \(0\) değerine yaklaşmasına izin verince \(\frac{f(x+h) - f(x)}{h}\) (2.4.1)’in sayısal sonucu \(2\)’ye yaklaşır. Bu deney matematiksel bir kanıt olmasa da, daha sonra \(u'\) türevinin \(x=1\) olduğunda \(2\) olduğunu göreceğiz.
def numerical_lim(f, x, h):
return (f(x + h) - f(x)) / h
h = 0.1
for i in range(5):
print(f'h={h:.5f}, numerik limit={numerical_lim(f, 1, h):.5f}')
h *= 0.1
h=0.10000, numerik limit=2.30000
h=0.01000, numerik limit=2.03000
h=0.00100, numerik limit=2.00300
h=0.00010, numerik limit=2.00030
h=0.00001, numerik limit=2.00003
def numerical_lim(f, x, h):
return (f(x + h) - f(x)) / h
h = 0.1
for i in range(5):
print(f'h={h:.5f}, numerik limit={numerical_lim(f, 1, h):.5f}')
h *= 0.1
h=0.10000, numerik limit=2.30000
h=0.01000, numerik limit=2.03000
h=0.00100, numerik limit=2.00300
h=0.00010, numerik limit=2.00030
h=0.00001, numerik limit=2.00003
def numerical_lim(f, x, h):
return (f(x + h) - f(x)) / h
h = 0.1
for i in range(5):
print(f'h={h:.5f}, numerik limit={numerical_lim(f, 1, h):.5f}')
h *= 0.1
h=0.10000, numerik limit=2.30000
h=0.01000, numerik limit=2.03000
h=0.00100, numerik limit=2.00300
h=0.00010, numerik limit=2.00030
h=0.00001, numerik limit=2.00003
Kendimizi türevler için birkaç eşdeğer gösterimle tanıştıralım. \(y = f(x)\) verildiğinde, \(x\) ve \(y\) sırasıyla \(f\) işlevinin bağımsız ve bağımlı değişkenleridir. Aşağıdaki ifadeler eşdeğerdir:
burada \(\frac{d}{dx}\) ve \(D\) sembolleri türev alma işlevini gösteren türev alma operatörleridir. Yaygın işlevlerin türevini alma için aşağıdaki kuralları kullanabiliriz:
\(DC = 0\) (\(C\) bir sabit),
\(Dx^n = nx^{n-1}\) (üs kuralı, \(n\) bir gerçel sayı),
\(De^x = e^x\),
\(D\ln(x) = 1/x.\)
Yukarıdaki yaygın işlevler gibi birkaç basit işlevden oluşan bir işlevin türevini alırken için aşağıdaki kurallar bizim için kullanışlı olabilir. \(f\) ve \(g\) işlevlerinin ikisinin de türevlenebilir ve \(C\)’nin sabit olduğunu varsayalım, elimizde sabit çarpım kuralı,
toplam kuralı
çarpım kuralı
ve bölme kuralı vardır.
Şimdi \(u' = f'(x) = 3 \frac{d}{dx} x^2-4\frac{d}{dx}x = 6x-4\)’ı bulmak için yukarıdaki kurallardan birkaçını uygulayabiliriz. Bu nedenle, \(x = 1\) atadığımız da, \(u' = 2\) değerine sahibiz: Sayısal sonucun \(2\)’ye yaklaştığı, bu bölümdeki önceki denememiz tarafından desteklenmektedir. Bu türev aynı zamanda \(u = f(x)\) eğrisine \(x = 1\)’deki teğet doğrusunun eğimidir.
Türevlerin bu tür yorumunu görselleştirmek için Python’da popüler bir
çizim kütüphanesi olan matplotlib
’i kullanacağız. matplotlib
tarafından üretilen şekillerin özelliklerini yapılandırmak için birkaç
işlev tanımlamamız gerekir. Aşağıdaki use_svg_display
işlevi, daha
keskin görüntülü svg şekilleri çıktısı almak için matplotlib
paketini özelleştirir. #@save
yorumunun, aşağıdaki işlev, sınıf veya
ifadelerin d2l
paketine kaydedildiği ve böylece daha sonra yeniden
tanımlanmadan doğrudan çağrılabilecekleri (örneğin,
d2l.use_svg_display()
) özel bir terim olduğuna dikkat edin.
def use_svg_display(): #@save
"""Jupyter içinde şekli göstermek için svg formatı kullan"""
backend_inline.set_matplotlib_formats('svg')
Şekil boyutlarını belirtmek için set_figsize
fonksiyonunu
tanımlarız. Burada doğrudan d2l.plt
’yi kullandığımıza dikkat edin,
çünkü içe aktarma komutu, from matplotlib import pyplot as plt
,
önsöz bölümündeki d2l
paketine kaydedilmek üzere işaretlenmişti.
def set_figsize(figsize=(3.5, 2.5)): #@save
"""Şekil ebatını matplotlib için ayarla"""
use_svg_display()
d2l.plt.rcParams['figure.figsize'] = figsize
Aşağıdaki set_axes
işlevi, matplotlib
tarafından üretilen
şekillerin eksenlerinin özelliklerini ayarlar.
#@save
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
"""Eksenleri matplotlib için ayarla."""
axes.set_xlabel(xlabel)
axes.set_ylabel(ylabel)
axes.set_xscale(xscale)
axes.set_yscale(yscale)
axes.set_xlim(xlim)
axes.set_ylim(ylim)
if legend:
axes.legend(legend)
axes.grid()
Şekil biçimlendirmeleri için bu üç işlevle, kitap boyunca birçok eğriyi
görselleştirmemiz gerekeceğinden, çoklu eğrileri kısa ve öz olarak
çizmek için plot
işlevini tanımlıyoruz.
#@save
def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
ylim=None, xscale='linear', yscale='linear',
fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
"""Veri noktalarını çiz."""
if legend is None:
legend = []
set_figsize(figsize)
axes = axes if axes else d2l.plt.gca()
# `X` (tensor veya liste) 1 eksenli ise True değeri döndür
def has_one_axis(X):
return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
and not hasattr(X[0], "__len__"))
if has_one_axis(X):
X = [X]
if Y is None:
X, Y = [[]] * len(X), X
elif has_one_axis(Y):
Y = [Y]
if len(X) != len(Y):
X = X * len(Y)
axes.cla()
for x, y, fmt in zip(X, Y, fmts):
if len(x):
axes.plot(x, y, fmt)
else:
axes.plot(y, fmt)
set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
Şimdi \(u = f(x)\) fonksiyonunu ve \(y = 2x - 3\) teğet doğrusunu \(x=1\)’de çizebiliriz, burada \(2\) katsayısı teğet doğrusunun eğimidir.
x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Teget dogrusu (x=1)'])
x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Teget dogrusu (x=1)'])
x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Teget dogrusu (x=1)'])
2.4.2. Kısmi Türevler¶
Şimdiye kadar sadece tek değişkenli fonksiyonların türevinin alınması ile uğraştık. Derin öğrenmede, işlevler genellikle birçok değişkene bağlıdır. Bu nedenle, türev alma fikirlerini bu çok değişkenli fonksiyonlara genişletmemiz gerekiyor.
\(y = f(x_1, x_2, \ldots, x_n)\), \(n\) değişkenli bir fonksiyon olsun. \(y\)’nin \(i.\) parametresi \(x_i\)’ye göre kısmi türevi şöyledir:
\(\frac{\partial y}{\partial x_i}\)’ı hesaplarken, \(x_1, \ldots, x_{i-1}, x_{i+1}, \ldots, x_n\)’ı sabitler olarak kabul eder ve \(y\)’nin \(x_i\)’ye göre türevini hesaplayabiliriz. Kısmi türevlerin gösterimi için aşağıdakiler eşdeğerdir:
2.4.3. Gradyanlar (Eğimler)¶
Fonksiyonun gradyan vektörünü elde etmek için çok değişkenli bir fonksiyonun tüm değişkenlerine göre kısmi türevlerini art arda bitiştirebiliriz. \(f : \mathbb{R}^n \rightarrow \mathbb{R}\) işlevinin girdisinin \(n\) boyutlu bir vektör, \(\mathbf{x} = [x_1, x_2, \ldots, x_n]^\top\) olduğunu varsayalım ve çıktı bir skalerdir. \(\mathbf{x}\)’e göre \(f(\mathbf{x})\) fonksiyonunun gradyanı, \(n\) tane kısmi türevli bir vektördür:
belirsizlik olmadığında, \(\nabla_{\mathbf{x}} f(\mathbf{x})\) genellikle \(\nabla f(\mathbf{x})\) ile değiştirilir.
\(\mathbf{x}\) bir \(n\) boyutlu vektör olsun, aşağıdaki kurallar genellikle çok değişkenli fonksiyonların türevini alırken kullanılır:
Her \(\mathbf{A} \in \mathbb{R}^{m \times n}\) için, \(\nabla_{\mathbf{x}} \mathbf{A} \mathbf{x} = \mathbf{A}^\top\),
Her \(\mathbf{A} \in \mathbb{R}^{n \times m}\) için, \(\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} = \mathbf{A}\),
Her \(\mathbf{A} \in \mathbb{R}^{n \times n}\) için, \(\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} \mathbf{x} = (\mathbf{A} + \mathbf{A}^\top)\mathbf{x}\),
\(\nabla_{\mathbf{x}} \|\mathbf{x} \|^2 = \nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{x} = 2\mathbf{x}\).
Benzer şekilde, herhangi bir \(\mathbf{X}\) matrisi için, \(\nabla_{\mathbf{X}} \|\mathbf {X} \|_F^2 = 2\mathbf{X}\) olur. Daha sonra göreceğimiz gibi, gradyanlar derin öğrenmede optimizasyon algoritmaları tasarlamak için kullanışlıdır.
2.4.4. Zincir kuralı¶
Bununla birlikte, bu tür gradyanları bulmak zor olabilir. Bunun nedeni, derin öğrenmedeki çok değişkenli işlevlerin genellikle bileşik olmasıdır, bu nedenle bu işlevlerin türevleri için yukarıda belirtilen kuralların hiçbirini uygulamayabiliriz. Neyse ki, zincir kuralı bileşik işlevlerin türevlerini almamızı sağlar.
Önce tek değişkenli fonksiyonları ele alalım. \(y = f(u)\) ve \(u=g(x)\) işlevlerinin her ikisinin de türevlenebilir olduğunu varsayalım, bu durumda zincir kuralı şunu belirtir:
Şimdi dikkatimizi, fonksiyonların keyfi sayıda değişkene sahip olduğu daha genel bir senaryoya çevirelim. \(y\) türevlenebilir fonksiyonunun \(u_1, u_2, \ldots, u_m\) değişkenlerine sahip olduğunu varsayalım, burada her türevlenebilir fonksiyon \(u_i\), \(x_1, x_2, \ldots, x_n\) değişkenlerine sahiptir. \(y\) değerinin \(x_1, x_2, \ldots, x_n\)’nin bir işlevi olduğuna dikkat edin. Sonra bütün \(i = 1, 2, \ldots, n\) için, zincir kuralı şunu gösterir:
2.4.5. Özet¶
Diferansiyel kalkülüs ve integral kalkülüs, ilki derin öğrenmede her yerde bulunan optimizasyon problemlerine uygulanabilen iki analiz dalıdır.
Bir türev, bir fonksiyonun değişkenine göre anlık değişim hızı olarak yorumlanabilir. Aynı zamanda fonksiyonun eğrisine teğet doğrusunun eğimidir.
Gradyan, bileşenleri çok değişkenli bir fonksiyonun tüm değişkenlerine göre kısmi türevleri olan bir vektördür.
Zincir kuralı, bileşik fonksiyonların türevlerini almamızı sağlar.
2.4.6. Alıştırmalar¶
\(y = f(x) = x^3 - \frac{1}{x}\) fonksiyonunu ve \(x = 1\) olduğunda teğet doğrusunu çizin.
\(f(\mathbf{x}) = 3x_1^2 + 5e^{x_2}\) fonksiyonunun gradyanını bulun.
\(f(\mathbf{x}) = \|\mathbf{x}\|_2\) fonksiyonunun gradyanı nedir?
\(u = f(x, y, z)\) ve \(x = x(a, b)\), \(y = y(a, b)\) ve \(z = z(a, b)\) olduğu durum için zincir kuralını yazabilir misiniz?