7-bo‘lim

Hosila va gradient

Hosila - o'zgarish tezligi; gradient - eng tik yo'nalish. Ikkalasini kodda hisoblab ko'ramiz.

🕑 15 daqiqa o‘qish 📄 845 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Hosila - o'zgarish tezligi
  2. Zanjir qoidasi
  3. Ko'p o'zgaruvchili funksiya: gradient
  4. Analitik va sonli gradient
  5. Gradient tekshiruvi funksiyasi
  6. Bir qadam gradient tushish
  7. Xulosa

Yo'qotishni o'lchashni o'rgandik. Endi savol: uni kamaytirish uchun og'irliklarni qaysi tomonga siljitish kerak? Javob - hosilada.

Hosila - o'zgarish tezligi #

Hosila bitta savolga javob beradi: "x ni juda kichik miqdorga oshirsam, f(x) qanchaga o'zgaradi?"

Python
import numpy as np
Python
def f(x):
    return x ** 2


x = 3.0
h = 1e-6
ozgarish = (f(x + h) - f(x)) / h

print("f(3)      =", f(x))
print("f(3.000001) =", f(x + h))
print("o'zgarish tezligi ≈", round(ozgarish, 4))
print("formula 2x =", 2 * x)
Natija
f(3)      = 9.0
f(3.000001) = 9.000006000001001
o'zgarish tezligi ≈ 6.0
formula 2x = 6.0

x = 3 nuqtada funksiya x dan olti barobar tez o'sadi.

Hosila - urinma chiziqning qiyaligi x f(x) f(x) = x² qiyalik = 6 x = 3 qiyalik = -6 x = -3 qiyalik = 0 Musbat qiyalik - o'ngga borsang O'SADI. Manfiy - kamayadi. Kamaytirish uchun qiyalikka TESKARI tomonga yur.
Qiyalik yo'nalishni aytadi, kattaligi esa qanchalik tikligini
Python
def f(x):
    return x ** 2


def hosila_sonli(fn, x, h=1e-6):
    return (fn(x + h) - fn(x - h)) / (2 * h)


for x in [-3.0, -1.0, 0.0, 1.0, 3.0]:
    q = hosila_sonli(f, x)
    yonalish = "o'sadi" if q > 0 else ("kamayadi" if q < 0 else "tekis")
    print(f"x = {x:>5.1f}   hosila = {q:>6.2f}   o'ngga yursak {yonalish}")
Natija
x =  -3.0   hosila =  -6.00   o'ngga yursak kamayadi
x =  -1.0   hosila =  -2.00   o'ngga yursak kamayadi
x =   0.0   hosila =   0.00   o'ngga yursak tekis
x =   1.0   hosila =   2.00   o'ngga yursak o'sadi
x =   3.0   hosila =   6.00   o'ngga yursak o'sadi
Kamaytirish uchun hosilaga teskari yuring

Bu gradient tushishning butun g'oyasi:

HosilaNima qilish kerak
Musbat (+6)x ni kamaytirish
Manfiy (-6)x ni oshirish
NolAllaqachon eng past nuqtada

Ikkala holatni bitta formula qamrab oladi:

Natija
x_yangi = x - tezlik · hosila

Musbat hosilada x kamayadi, manfiyda esa oshadi - chunki manfiy sondan ayirish qo'shishga teng.

8-bo'limda aynan shu bitta satrni tarmoqning barcha og'irliklariga qo'llaymiz.

Zanjir qoidasi #

Funksiyalar ichma-ich bo'lganda hosilalar ko'paytiriladi.

Natija
y = f(g(x))   =>   dy/dx = f'(g(x)) · g'(x)
Python
def ichki(x):
    return 3 * x + 1


def tashqi(u):
    return u ** 2


def togri_funksiya(x):
    return tashqi(ichki(x))


def hosila_sonli(fn, x, h=1e-6):
    return (fn(x + h) - fn(x - h)) / (2 * h)


x = 2.0
sonli = hosila_sonli(togri_funksiya, x)
zanjir = 2 * ichki(x) * 3        # f'(g) · g'

print("f(g(2)) =", togri_funksiya(x))
print("sonli hosila:", round(sonli, 6))
print("zanjir qoidasi:", zanjir)
print("mos keladi:", bool(np.isclose(sonli, zanjir, atol=1e-4)))
Natija
f(g(2)) = 49.0
sonli hosila: 42.0
zanjir qoidasi: 42.0
mos keladi: True
Zanjir qoidasi - orqaga tarqalishning butun mohiyati

Neyron tarmoq - bu juda uzun ichma-ich funksiya:

Natija
L( sigmoid( W2 @ relu( W1 @ X + b1 ) + b2 ), y )

W1 ning yo'qotishga ta'sirini topish uchun zanjir bo'ylab orqaga yurish kerak:

Natija
dL/dW1 = dL/dA2 · dA2/dZ2 · dZ2/dA1 · dA1/dZ1 · dZ1/dW1

Beshta hosila ko'paytiriladi - va aynan shu orqaga tarqalish (backpropagation) deb ataladi.

Bu 4-bo'limdagi yo'qolayotgan gradient muammosining ham sababi: agar har ko'paytuvchi 1 dan kichik bo'lsa, ko'paytma tez nolga intiladi.

9-bo'limda bu zanjirni qadam-baqadam quramiz.

Ko'p o'zgaruvchili funksiya: gradient #

Bir necha o'zgaruvchi bo'lganda har biri bo'yicha alohida hosila olinadi. Ular birgalikda gradient vektorini tashkil qiladi.

Python
def yigindi(v):
    x, y = v
    return x ** 2 + 3 * y ** 2


def gradient_sonli(fn, v, h=1e-6):
    g = np.zeros_like(v)
    for i in range(len(v)):
        oldinga = v.copy(); oldinga[i] += h
        orqaga = v.copy(); orqaga[i] -= h
        g[i] = (fn(oldinga) - fn(orqaga)) / (2 * h)
    return g


nuqta = np.array([2.0, 1.0])
g = gradient_sonli(yigindi, nuqta)

print("f(2, 1) =", yigindi(nuqta))
print("gradient:", np.round(g, 4))
print("formula [2x, 6y]:", [2 * 2.0, 6 * 1.0])
Natija
f(2, 1) = 7.0
gradient: [4. 6.]
formula [2x, 6y]: [4.0, 6.0]
KomponentMa'nosi
4x ni oshirish f ni 4 barobar tez oshiradi
6y ni oshirish f ni 6 barobar tez oshiradi
Yo'nalish[4, 6] - eng tik ko'tarilish tomoni
Teskarisi[-4, -6] - eng tik tushish tomoni
Gradient - eng tik yo'nalish, yagona yo'nalish emas

Gradient f ni eng tez oshiradigan yo'nalishni beradi. Uning teskarisi - eng tez kamaytiradigan yo'nalish.

Lekin bu "to'g'ridan-to'g'ri eng past nuqtaga" degani emas. Gradient faqat joriy nuqtadagi mahalliy ma'lumot.

Vodiy shaklidagi funksiyada gradient tushish zigzag bilan yuradi: har qadamda u eng tik tomonga qaraydi, lekin eng tik tomon vodiyning tubiga emas, uning devoriga qarab turadi.

Bu 15-bo'limdagi momentum va Adam optimizatorlarining mavjud bo'lish sababi - ular shu zigzagni yumshatadi.

Analitik va sonli gradient #

Python
def yoqotish(w):
    """Oddiy misol: bitta og'irlikli chiziqli model."""
    X = np.array([1.0, 2.0, 3.0])
    y = np.array([2.0, 4.0, 6.0])
    bashorat = w * X
    return float(np.mean((bashorat - y) ** 2))


def analitik_gradient(w):
    X = np.array([1.0, 2.0, 3.0])
    y = np.array([2.0, 4.0, 6.0])
    return float(np.mean(2 * (w * X - y) * X))


for w in [0.0, 1.0, 2.0, 3.0]:
    h = 1e-6
    sonli = (yoqotish(w + h) - yoqotish(w - h)) / (2 * h)
    print(f"w = {w:.1f}  yo'qotish = {yoqotish(w):>7.3f}  "
          f"sonli = {sonli:>8.4f}  analitik = {analitik_gradient(w):>8.4f}")
Natija
w = 0.0  yo'qotish =  18.667  sonli = -18.6667  analitik = -18.6667
w = 1.0  yo'qotish =   4.667  sonli =  -9.3333  analitik =  -9.3333
w = 2.0  yo'qotish =   0.000  sonli =   0.0000  analitik =   0.0000
w = 3.0  yo'qotish =   4.667  sonli =   9.3333  analitik =   9.3333

w = 2 da yo'qotish nol va gradient ham nol - bu eng past nuqta. Ma'lumot aynan y = 2x bo'lgani uchun bu kutilgan natija.

Sonli gradient - haqiqiy vosita, lekin o'qitish uchun emas

Sonli gradient formulani tekshirish uchun ajoyib, lekin o'qitishda ishlatib bo'lmaydi.

Sabab - narx:

UsulHar qadamda nechta hisob
SonliHar parametr uchun ikkita to'liq oldinga tarqalish
Analitik (backprop)Bitta oldinga + bitta orqaga

Million parametrli tarmoqda sonli gradient bir qadam uchun ikki million oldinga tarqalish talab qiladi. Bu amalda imkonsiz.

Backpropagation ning butun qiymati shunda: u barcha gradientlarni bitta o'tishda hisoblaydi.

Shuning uchun tartib shunday: backprop ni yozing, sonli gradient bilan bir marta tekshiring, keyin tekshiruvni o'chiring.

Python
import time


def yoqotish_kop(w):
    """50 ta og'irlikning o'rtachasi bilan bashorat qiladigan model."""
    X = np.arange(1.0, 51.0)
    y = 2.0 * X
    return float(np.mean((np.mean(w) * X - y) ** 2))


w = np.full(50, 1.0)
h = 1e-6

boshlandi = time.perf_counter()
sonli = np.zeros(50)
for i in range(50):
    ol = w.copy(); ol[i] += h
    or_ = w.copy(); or_[i] -= h
    sonli[i] = (yoqotish_kop(ol) - yoqotish_kop(or_)) / (2 * h)
sonli_vaqt = time.perf_counter() - boshlandi

print("50 parametr uchun sonli gradient:", 2 * 50, "ta funksiya chaqiruvi")
print("gradient birinchi 3 element:", np.round(sonli[:3], 4))
print("hammasi bir xilmi:", bool(np.allclose(sonli, sonli[0])))
Natija
50 parametr uchun sonli gradient: 100 ta funksiya chaqiruvi
gradient birinchi 3 element: [-34.34 -34.34 -34.34]
hammasi bir xilmi: True

Gradient tekshiruvi funksiyasi #

Python
def gradient_tekshir(yoqotish_fn, gradient_fn, parametr, h=1e-6, chegara=1e-5):
    analitik = gradient_fn(parametr)
    sonli = np.zeros_like(parametr, dtype=np.float64)
    tekis = parametr.ravel()
    sonli_tekis = sonli.ravel()
    for i in range(tekis.size):
        eski = tekis[i]
        tekis[i] = eski + h
        yuqori = yoqotish_fn(parametr)
        tekis[i] = eski - h
        past = yoqotish_fn(parametr)
        tekis[i] = eski
        sonli_tekis[i] = (yuqori - past) / (2 * h)
    ayirma = np.abs(analitik - sonli).max()
    return ayirma < chegara, ayirma


def yoqotish_v(w):
    X = np.array([[1.0, 2.0], [3.0, 1.0], [0.5, 2.0]])
    y = np.array([5.0, 5.0, 4.5])
    return float(np.mean((X @ w - y) ** 2))


def gradient_v(w):
    X = np.array([[1.0, 2.0], [3.0, 1.0], [0.5, 2.0]])
    y = np.array([5.0, 5.0, 4.5])
    return 2.0 / len(y) * X.T @ (X @ w - y)


w = np.array([0.7, 1.3])
mos, ayirma = gradient_tekshir(yoqotish_v, gradient_v, w)
print("analitik gradient:", np.round(gradient_v(w), 6))
print("mos keladimi:", mos)
print("eng katta ayirma:", f"{ayirma:.2e}")
Natija
analitik gradient: [-4.85 -5.4 ]
mos keladimi: True
eng katta ayirma: 4.00e-10
Gradient tekshiruvida 1e-5 chegarasi

Ayirma 3.31e-10 chiqdi - bu juda yaxshi.

Amaliy mo'ljallar:

AyirmaXulosa
< 1e-7Deyarli aniq to'g'ri
1e-7 dan 1e-5 gachaOdatda to'g'ri
1e-5 dan 1e-3 gachaShubhali - tekshiring
> 1e-3Formulada xato bor

Nisbiy ayirmani ishlatish yanada ishonchli:

Natija
|analitik - sonli| / (|analitik| + |sonli|)

Chunki gradient kattaligi 1000 bo'lsa, 1e-5 mutlaq ayirma aslida juda kichik nisbiy xato.

Muhim ogohlantirish: ReLU bilan gradient tekshiruvi z = 0 atrofida yiqilishi mumkin - u yerda hosila sakraydi. Tekshiruvni tasodifiy nuqtalarda bajaring va bitta-ikkita mos kelmagan qiymatga e'tibor bermang.

Bir qadam gradient tushish #

Python
def yoqotish(w):
    X = np.array([1.0, 2.0, 3.0])
    y = np.array([2.0, 4.0, 6.0])
    return float(np.mean((w * X - y) ** 2))


def gradient(w):
    X = np.array([1.0, 2.0, 3.0])
    y = np.array([2.0, 4.0, 6.0])
    return float(np.mean(2 * (w * X - y) * X))


w = 0.0
tezlik = 0.05
for qadam in range(6):
    g = gradient(w)
    print(f"qadam {qadam}: w = {w:>7.4f}  yo'qotish = {yoqotish(w):>8.4f}  gradient = {g:>9.4f}")
    w = w - tezlik * g
Natija
qadam 0: w =  0.0000  yo'qotish =  18.6667  gradient =  -18.6667
qadam 1: w =  0.9333  yo'qotish =   5.3096  gradient =   -9.9556
qadam 2: w =  1.4311  yo'qotish =   1.5103  gradient =   -5.3096
qadam 3: w =  1.6966  yo'qotish =   0.4296  gradient =   -2.8318
qadam 4: w =  1.8382  yo'qotish =   0.1222  gradient =   -1.5103
qadam 5: w =  1.9137  yo'qotish =   0.0348  gradient =   -0.8055

w 2.0 ga yaqinlashmoqda, yo'qotish esa har qadamda taxminan uch-to'rt barobar kamayyapti - lekin qadamlar ham kichrayib boryapti, chunki gradient nolga yaqinlashadi.

Amaliy topshiriq
  1. f(x) = x² uchun x = 3 da sonli hosilani hisoblang.
  2. Uni 2x formulasi bilan solishtiring.
  3. Beshta nuqtada hosila ishorasini va ma'nosini tushuntiring.
  4. Zanjir qoidasini (3x+1)² misolida tekshiring.
  5. Ikki o'zgaruvchili funksiyaning gradientini soniy hisoblang.
  6. Gradientning ikki komponenti nimani anglatishini ayting.
  7. Analitik va sonli gradientni to'rtta w qiymatida solishtiring.
  8. Sonli gradient nima uchun o'qitishga yaramasligini hisoblang.
  9. gradient_tekshir funksiyasini yozing va ayirmani chop eting.
  10. Olti qadam gradient tushish bajarib, w ning yo'lini kuzating.

Xulosa #

  • Hosila - o'zgarish tezligi, ya'ni urinma chiziqning qiyaligi.
  • Kamaytirish uchun hosilaga teskari yuring.
  • x_yangi = x - tezlik · hosila - bitta formula ikkala holatni qamraydi.
  • Zanjir qoidasi: ichma-ich funksiyalarda hosilalar ko'paytiriladi.
  • Tarmoq - uzun ichma-ich funksiya; backprop - zanjir qoidasi.
  • Gradient - har parametr bo'yicha hosilalar vektori.
  • Gradient eng tik yo'nalish, lekin eng past nuqtaga qaramaydi.
  • Sonli gradient - tekshirish uchun, o'qitish uchun emas.
  • Ayirma 1e-5 dan katta bo'lsa - formulada xato bor.
  • Gradient nolga teng joy - eng past nuqta (yoki egar nuqtasi).

Keyingi bo'limda gradient tushishni to'liq quramiz va o'qitish tezligining ta'sirini ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.