8-bo‘lim

Gradient tushish

Og'irliklarni qadam-baqadam to'g'rilash - o'qitish tezligi, yaqinlashish va uchraydigan nosozliklar.

🕑 13 daqiqa o‘qish 📄 848 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Algoritm
  2. Bitta parametr
  3. O'qitish tezligining ta'siri
  4. Ko'p parametr - vektor shaklida
  5. To'xtash mezoni
  6. Mahalliy minimum
  7. O'qitish tezligi jadvali
  8. Xulosa

Gradient qaysi tomonga yurishni aytadi. Gradient tushish

  • shu yo'nalishda kichik qadamlar tashlab, eng past nuqtaga

borish.

Algoritm #

Natija
1. Bashorat qil          (oldinga tarqalish)
2. Xatoni o'lcha         (yo'qotish funksiyasi)
3. Gradientni hisobla    (orqaga tarqalish)
4. Og'irliklarni siljit: w = w - tezlik · gradient
5. Takrorla
Bir xil funksiya, uch xil o'qitish tezligi juda kichik yetib bormaydi to'g'ri tez va barqaror juda katta sakraydi va uzoqlashadi O'qitish tezligi - eng muhim giperparametr Boshlash uchun 0.01 yoki 0.001; keyin 3 yoki 10 barobar oshirib/kamaytirib sinang. Yo'qotish o'sib ketsa - tezlik juda katta. Umuman qimirlamasa - juda kichik.
Bitta son butun o'qitishning taqdirini hal qiladi

Bitta parametr #

Python
import numpy as np


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


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


def tushish(w0, tezlik, qadamlar):
    w = w0
    tarix = [w]
    for _ in range(qadamlar):
        w = w - tezlik * gradient(w)
        tarix.append(w)
    return np.array(tarix)
Python
tarix = tushish(0.0, 0.02, 20)
for i in [0, 1, 2, 5, 10, 20]:
    w = tarix[i]
    print(f"qadam {i:>2}: w = {w:.6f}  yo'qotish = {yoqotish(w):.6f}")
Natija
qadam  0: w = 0.000000  yo'qotish = 30.000000
qadam  1: w = 0.600000  yo'qotish = 14.700000
qadam  2: w = 1.020000  yo'qotish = 7.203000
qadam  5: w = 1.663860  yo'qotish = 0.847426
qadam 10: w = 1.943505  yo'qotish = 0.023938
qadam 20: w = 1.998404  yo'qotish = 0.000019

Yigirma qadamda w 2.0 ga deyarli aynan yetdi.

O'qitish tezligining ta'siri #

Python
for tezlik in [0.001, 0.02, 0.06, 0.07]:
    tarix = tushish(0.0, tezlik, 30)
    oxirgi = tarix[-1]
    holat = "yaqinlashdi" if abs(oxirgi - 2.0) < 0.01 else "yaqinlashmadi"
    print(f"tezlik = {tezlik:<7} 30 qadamdan keyin w = {oxirgi:>12.6f}  {holat}")
Natija
tezlik = 0.001   30 qadamdan keyin w =     0.729084  yaqinlashmadi
tezlik = 0.02    30 qadamdan keyin w =     1.999955  yaqinlashdi
tezlik = 0.06    30 qadamdan keyin w =     2.000000  yaqinlashdi
tezlik = 0.07    30 qadamdan keyin w =     2.000000  yaqinlashdi
Juda katta tezlikda yo'qotish portlaydi

Yuqoridagi misolda 0.07 hali ham ishladi. Chegarani oshirib ko'ramiz - va nima bo'lishini kuzatamiz.

Bu masalada gradient w ga chiziqli bog'liq, shuning uchun aniq chegara mavjud: tezlik 2/λ dan oshsa, jarayon uzoqlashadi (λ - egrilik).

Amaliy tarmoqda bunday formula yo'q, lekin belgilar bir xil:

BelgiSabab
Yo'qotish o'sib boryaptiTezlik juda katta
Yo'qotish nan bo'ldiTezlik juda katta (portladi)
Yo'qotish sakrab-sakrab tushyaptiTezlik biroz katta
Yo'qotish juda sekin tushyaptiTezlik juda kichik
Yo'qotish umuman qimirlamayaptiTezlik juda kichik yoki gradient nol

Birinchi ikkitasini ko'rsangiz - tezlikni o'n barobar kamaytiring va qaytadan boshlang.

Python
for tezlik in [0.1, 0.2, 0.3]:
    tarix = tushish(0.0, tezlik, 20)
    oxirgi = tarix[-1]
    yoq = yoqotish(oxirgi)
    holat = "portladi" if (not np.isfinite(yoq)) or yoq > 1e6 else "barqaror"
    print(f"tezlik = {tezlik:<5} oxirgi w = {oxirgi:>18.4f}  {holat}")
Natija
tezlik = 0.1   oxirgi w =             2.0000  barqaror
tezlik = 0.2   oxirgi w =      -2097150.0000  portladi
tezlik = 0.3   oxirgi w = -152191670029.7612  portladi

0.1 va 0.2 orasida chegara yotibdi. Undan oshgach w har qadamda kattalashib, yo'qotish cheksizlikka intiladi.

Ko'p parametr - vektor shaklida #

Python
def chiziqli_yoqotish(w, X, y):
    return float(np.mean((X @ w - y) ** 2))


def chiziqli_gradient(w, X, y):
    n = len(y)
    return 2.0 / n * X.T @ (X @ w - y)


gen = np.random.default_rng(42)
X = gen.normal(0, 1, (100, 3))
haqiqiy_w = np.array([2.0, -1.0, 0.5])
y = X @ haqiqiy_w + gen.normal(0, 0.1, 100)

w = np.zeros(3)
tezlik = 0.1
for qadam in range(201):
    if qadam % 50 == 0:
        print(f"qadam {qadam:>3}: w = {np.round(w, 4)}  "
              f"yo'qotish = {chiziqli_yoqotish(w, X, y):.6f}")
    w = w - tezlik * chiziqli_gradient(w, X, y)

print("haqiqiy w:", haqiqiy_w)
Natija
qadam   0: w = [0. 0. 0.]  yo'qotish = 4.085068
qadam  50: w = [ 1.9999 -0.9927  0.4791]  yo'qotish = 0.009907
qadam 100: w = [ 2.0003 -0.993   0.4794]  yo'qotish = 0.009906
qadam 150: w = [ 2.0003 -0.993   0.4794]  yo'qotish = 0.009906
qadam 200: w = [ 2.0003 -0.993   0.4794]  yo'qotish = 0.009906
haqiqiy w: [ 2.  -1.   0.5]

Model haqiqiy og'irliklarni deyarli aniq topdi. Yo'qotish noldan katta qolgani - shovqin sababli.

Yo'qotish nolga tushmasligi normal

Ma'lumotga normal(0, 0.1) shovqin qo'shilgan edi. Model shovqinni bashorat qila olmaydi - va qilmasligi ham kerak.

Qolgan yo'qotish taxminan shovqin dispersiyasiga teng:

Natija
0.1² = 0.01

Kuzatilgan qiymat 0.0099 - kutilganga juda yaqin.

Bu muhim mo'ljal: agar yo'qotish shovqin darajasidan pastga tushsa, model shovqinni yodlab olyapti - ya'ni haddan ortiq moslashuv (16-bo'lim).

Shuning uchun "yo'qotish nolga tushdi" degan natija odatda yaxshi emas, yomon xabar.

Python
print("shovqin dispersiyasi:", 0.1 ** 2)
print("qolgan yo'qotish:    ", 0.009906)
print("nisbat:", round(0.009906 / 0.01, 3))
Natija
shovqin dispersiyasi: 0.010000000000000002
qolgan yo'qotish:     0.009906
nisbat: 0.991

To'xtash mezoni #

Python
def chiziqli_yoqotish(w, X, y):
    return float(np.mean((X @ w - y) ** 2))


def chiziqli_gradient(w, X, y):
    return 2.0 / len(y) * X.T @ (X @ w - y)


gen = np.random.default_rng(42)
X = gen.normal(0, 1, (100, 3))
y = X @ np.array([2.0, -1.0, 0.5]) + gen.normal(0, 0.1, 100)

w = np.zeros(3)
oldingi = float("inf")
for qadam in range(1, 501):
    w = w - 0.1 * chiziqli_gradient(w, X, y)
    joriy = chiziqli_yoqotish(w, X, y)
    if abs(oldingi - joriy) < 1e-9:
        print(f"{qadam}-qadamda to'xtadi (o'zgarish 1e-9 dan kichik)")
        break
    oldingi = joriy

print("yakuniy yo'qotish:", round(joriy, 6))
Natija
65-qadamda to'xtadi (o'zgarish 1e-9 dan kichik)
yakuniy yo'qotish: 0.009906
MezonIzoh
Belgilangan qadamlar soniEng oddiy, lekin ko'r-ko'rona
Yo'qotish o'zgarmay qolsaYuqoridagi usul
Gradient normasi kichik bo'lsanp.linalg.norm(g) < eps
Tekshiruv to'plamida yomonlashsaEarly stopping (16-bo'lim)

Oxirgisi amalda eng muhimi - u haddan ortiq moslashuvni ham to'xtatadi.

Mahalliy minimum #

Python
def qiyin(w):
    return float(w ** 4 - 3 * w ** 3 + 2)


def qiyin_gradient(w):
    return float(4 * w ** 3 - 9 * w ** 2)


for boshlanish in [-1.0, 0.5, 3.0]:
    w = boshlanish
    for _ in range(300):
        w = w - 0.01 * qiyin_gradient(w)
    print(f"boshlanish {boshlanish:>5.1f}  ->  w = {w:>8.4f}  f(w) = {qiyin(w):>10.4f}")
Natija
boshlanish  -1.0  ->  w =  -0.0337  f(w) =     2.0001
boshlanish   0.5  ->  w =   2.2500  f(w) =    -6.5430
boshlanish   3.0  ->  w =   2.2500  f(w) =    -6.5430

Uchta boshlanish - ikki xil natija. -1.0 dan boshlangan jarayon w = 0 atrofida qotib qoldi, qolgan ikkitasi esa haqiqiy minimumga (w = 2.25) yetdi.

Boshlanish nuqtasi natijaga ta'sir qiladi

Yuqorida faqat -1.0 dan boshlangan jarayon w = 0 atrofida qotib qoldi - u yerda gradient nolga juda yaqin (w = 0 bu funksiyaning egar nuqtasi).

0.5 dan boshlangan jarayon esa undan chiqib ketdi: u yerda gradient -1.75, ya'ni yetarlicha katta. Ya'ni egar nuqtasidan qochish boshlanish nuqtasiga juda nozik bog'liq.

Neyron tarmoqlarda bu doim shunday: yo'qotish yuzasi ko'p o'lchovli va juda notekis. Har o'qitish boshqa minimumga tushadi.

Amaliy oqibatlari:

FaktNima qilish kerak
Har urug' boshqa natija beradiBir necha urug' bilan sinang
"Global minimum" topilmaydiVa bu kerak ham emas
Yaxshi mahalliy minimumlar ko'pAmalda ular yetarli

Chuqur tarmoqlarda haqiqiy muammo mahalliy minimumlar emas, egar nuqtalari - gradient nolga yaqin, lekin bu minimum ham emas. Momentum (15-bo'lim) aynan shulardan chiqishga yordam beradi.

O'qitish tezligi jadvali #

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


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


w_qatiy, w_pasayuvchi = 0.0, 0.0
for qadam in range(1, 41):
    w_qatiy -= 0.05 * gradient(w_qatiy)
    tezlik = 0.05 / (1 + 0.05 * qadam)
    w_pasayuvchi -= tezlik * gradient(w_pasayuvchi)

print(f"qat'iy tezlik:    w = {w_qatiy:.8f}  yo'qotish = {yoqotish(w_qatiy):.3e}")
print(f"pasayuvchi tezlik: w = {w_pasayuvchi:.8f}  yo'qotish = {yoqotish(w_pasayuvchi):.3e}")
Natija
qat'iy tezlik:    w = 2.00000000  yo'qotish = 0.000e+00
pasayuvchi tezlik: w = 2.00000000  yo'qotish = 2.548e-18
Tezlikni pasaytirish har doim ham foydali emas

Bu misolda qat'iy tezlik yaxshiroq natija berdi - chunki masala oddiy va tezlik allaqachon to'g'ri tanlangan.

Pasayuvchi tezlik (learning rate schedule) boshqa holatda foydali: yo'qotish minimum atrofida sakrab turganda.

VaziyatJadval kerakmi
Oddiy masala, to'g'ri tezlikYo'q
Minimum atrofida sakrashHa
Katta tarmoq, uzoq o'qitishHa - deyarli har doim
Mini-paketli o'qitishHa - shovqin tufayli

Keng tarqalgan jadvallar: har N davrda 0.1 ga ko'paytirish (step decay), kosinus jadvali, yoki yo'qotish to'xtaganda kamaytirish (reduce on plateau).

15-bo'limdagi Adam optimizatori tezlikni qisman o'zi moslashtiradi - shuning uchun u bilan jadval kamroq kerak bo'ladi.

Amaliy topshiriq
  1. Bitta parametrli gradient tushishni yozing va 20 qadam bajaring.
  2. w va yo'qotish qanday o'zgarganini jadvalda ko'rsating.
  3. To'rtta turli tezlikda natijani solishtiring.
  4. Tezlikni oshirib, portlash chegarasini toping.
  5. Uchta parametrli chiziqli modelni o'qiting.
  6. Qolgan yo'qotishni shovqin dispersiyasi bilan solishtiring.
  7. Yo'qotish o'zgarmay qolganda to'xtaydigan sikl yozing.
  8. w⁴ - 3w³ + 2 uchun turli boshlanishlardan tushing.
  9. Nima uchun natijalar farq qilganini tushuntiring.
  10. Qat'iy va pasayuvchi tezlikni solishtiring.

Xulosa #

  • Gradient tushish: bashorat → xato → gradient → siljish → takror.
  • w = w - tezlik · gradient - butun algoritm shu satrda.
  • O'qitish tezligi - eng muhim giperparametr.
  • Yo'qotish o'sib ketsa yoki nan bo'lsa - tezlikni 10 barobar kamaytiring.
  • Chegaradan oshgan tezlik jarayonni uzoqlashtiradi.
  • Yo'qotish shovqin darajasida to'xtashi - normal.
  • Yo'qotish nolga tushsa - model shovqinni yodlagan bo'lishi mumkin.
  • To'xtash mezoni: o'zgarish kichik bo'lganda yoki tekshiruvda yomonlashganda.
  • Boshlanish nuqtasi natijaga ta'sir qiladi - bir necha urug' bilan sinang.
  • Chuqur tarmoqda asosiy to'siq - mahalliy minimum emas, egar nuqtalari.

Keyingi bo'limda orqaga tarqalishni quramiz - gradientni tarmoqning barcha og'irliklari uchun hisoblaymiz.

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.