16-bo‘lim

Haddan ortiq moslashuv

Model yodlab olganini qanday aniqlash va unga qarshi to'rtta chora.

🕑 15 daqiqa o‘qish 📄 1 113 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Ma'lumotni bo'lish
  2. Haddan ortiq moslashuvni ko'rish
  3. 1-chora: erta to'xtatish
  4. 2-chora: L2 regularizatsiya
  5. 3-chora: dropout
  6. 4-chora: ko'proq ma'lumot
  7. Model hajmi
  8. Xulosa

Model o'qitish to'plamida mukammal, yangi ma'lumotda esa yomon ishlashi mumkin. Bu haddan ortiq moslashuv (overfitting) - amaliy mashinali o'qitishning asosiy muammosi.

Ma'lumotni bo'lish #

Python
import numpy as np


def sigmoid(z):
    return 1.0 / (1.0 + np.exp(-z))


class Tarmoq:
    def __init__(self, olchamlar, urug=42, l2=0.0, dropout=0.0):
        gen = np.random.default_rng(urug)
        self.q = len(olchamlar) - 1
        self.l2 = l2
        self.dropout = dropout
        self.gen = np.random.default_rng(urug + 1000)
        self.W = [gen.normal(0, np.sqrt(2.0 / olchamlar[i]),
                             (olchamlar[i], olchamlar[i + 1])) for i in range(self.q)]
        self.b = [np.zeros(olchamlar[i + 1]) for i in range(self.q)]

    def oldinga(self, X, oqitish=False):
        A = X
        kesh = {"A0": X}
        for i in range(self.q):
            Z = A @ self.W[i] + self.b[i]
            if i == self.q - 1:
                A = sigmoid(Z)
            else:
                A = np.maximum(0.0, Z)
                if oqitish and self.dropout > 0:
                    maska = (self.gen.uniform(0, 1, A.shape) > self.dropout)
                    A = A * maska / (1.0 - self.dropout)
                    kesh[f"M{i+1}"] = maska
            kesh[f"Z{i+1}"] = Z
            kesh[f"A{i+1}"] = A
        return A, kesh

    def qadam(self, X, y, tezlik):
        A, kesh = self.oldinga(X, oqitish=True)
        n = len(y)
        dZ = (A - y) / n
        for i in range(self.q - 1, -1, -1):
            dW = kesh[f"A{i}"].T @ dZ + self.l2 * self.W[i]
            db = dZ.sum(axis=0)
            if i > 0:
                dA = dZ @ self.W[i].T
                if self.dropout > 0 and f"M{i}" in kesh:
                    dA = dA * kesh[f"M{i}"] / (1.0 - self.dropout)
                dZ = dA * (kesh[f"Z{i}"] > 0)
            self.W[i] -= tezlik * dW
            self.b[i] -= tezlik * db

    def yoqotish(self, X, y, eps=1e-12):
        A, _ = self.oldinga(X)
        A = np.clip(A, eps, 1 - eps)
        return float(-np.mean(y * np.log(A) + (1 - y) * np.log(1 - A)))

    def aniqlik(self, X, y):
        A, _ = self.oldinga(X)
        return float(((A > 0.5).astype(float) == y).mean())


def shovqinli_malumot(n=200, belgilar=20, urug=0):
    """Faqat dastlabki 2 belgi ma'noli, qolganlari - sof shovqin."""
    gen = np.random.default_rng(urug)
    X = gen.normal(0, 1, (n, belgilar))
    y = ((X[:, 0] + X[:, 1]) > 0).astype(float).reshape(-1, 1)
    # 10% yorliqni ataylab buzamiz
    buzuq = gen.choice(n, size=n // 10, replace=False)
    y[buzuq] = 1.0 - y[buzuq]
    return X, y


def boling(X, y, ulush=0.7, urug=0):
    gen = np.random.default_rng(urug)
    tartib = gen.permutation(len(X))
    chegara = int(len(X) * ulush)
    o, t = tartib[:chegara], tartib[chegara:]
    return X[o], y[o], X[t], y[t]
Python
X, y = shovqinli_malumot(300)
Xo, yo, Xt, yt = boling(X, y)
print("o'qitish:", Xo.shape, " tekshiruv:", Xt.shape)
print("o'qitishda 1 lar ulushi:", round(float(yo.mean()), 3))
print("tekshiruvda 1 lar ulushi:", round(float(yt.mean()), 3))
Natija
o'qitish: (210, 20)  tekshiruv: (90, 20)
o'qitishda 1 lar ulushi: 0.452
tekshiruvda 1 lar ulushi: 0.544
Tekshiruv to'plami - muqaddas

Tekshiruv to'plami modelning hech qachon ko'rmagan ma'lumoti bo'lishi kerak.

Buni buzishning uch usuli bor va uchalasi ham keng tarqalgan:

XatoNima bo'ladi
Normalizatsiyani butun to'plamda hisoblashTekshiruv statistikasi o'qitishga "sizib" o'tadi
Giperparametrni tekshiruvda tanlashTekshiruv aslida o'qitish to'plamiga aylanadi
Bir necha marta tekshirib, eng yaxshisini tanlashXuddi shunday

Uchinchisi eng nozik: siz 20 xil model sinasangiz va eng yaxshi tekshiruv natijasini tanlasangiz - o'sha natija haddan ortiq optimistik bo'ladi.

To'g'ri yechim - uchta to'plam:

To'plamVazifasi
O'qitish (60-80%)Og'irliklarni topish
Validatsiya (10-20%)Giperparametrlarni tanlash
Test (10-20%)Faqat bir marta, oxirida

Test to'plamini oxirigacha umuman ochmang.

Haddan ortiq moslashuvni ko'rish #

Python
X, y = shovqinli_malumot(300)
Xo, yo, Xt, yt = boling(X, y)

t = Tarmoq([20, 64, 64, 1], urug=1)
print("davr   o'qitish        tekshiruv")
for davr in range(1, 3001):
    t.qadam(Xo, yo, 0.1)
    if davr in (100, 300, 600, 1000, 2000, 3000):
        print(f"{davr:>5}   {t.yoqotish(Xo, yo):.4f} / {t.aniqlik(Xo, yo):.3f}   "
              f"{t.yoqotish(Xt, yt):.4f} / {t.aniqlik(Xt, yt):.3f}")
Natija
davr   o'qitish        tekshiruv
  100   0.2350 / 0.933   0.4800 / 0.778
  300   0.0448 / 1.000   0.6287 / 0.778
  600   0.0110 / 1.000   0.8405 / 0.778
 1000   0.0044 / 1.000   0.9841 / 0.767
 2000   0.0015 / 1.000   1.1556 / 0.767
 3000   0.0008 / 1.000   1.2481 / 0.767
Klassik haddan ortiq moslashuv egri chizig'i davrlar yo'qotish o'qitish tekshiruv eng yaxshi nuqta bu yerda to'xtash kerak HADDAN ORTIQ MOSLASHUV o'qitish yaxshilanadi, tekshiruv yomonlashadi Model umumiy qoidani emas, aniq namunalarni yodlab olyapti.
Ikki egri chiziq ajralgan payt - to'xtash vaqti
Belgilarni tanish

Yuqoridagi jadvalda hamma narsa ko'rinadi:

DavrO'qitish yo'q. / aniqlikTekshiruv yo'q. / aniqlik
1000.235 / 0.9330.480 / 0.778
3000.045 / 1.0000.629 / 0.778
6000.011 / 1.0000.841 / 0.778
30000.0008 / 1.0001.248 / 0.767

O'qitish yo'qotishi 0.235 dan 0.0008 ga tushdi - ya'ni 300 barobar yaxshilandi. Tekshiruv yo'qotishi esa 0.480 dan 1.248 ga ko'tarildi.

Ya'ni 100-davrdan keyingi butun o'qitish - zarar.

Ma'lumotning 10% yorlig'i ataylab buzilgan edi. 300-davrda o'qitish aniqligi 100% - ya'ni model o'sha noto'g'ri yorliqlarni ham yodlab oldi. Bu yangi ma'lumotga umuman yordam bermaydi.

Uchta belgi:

BelgiXulosa
O'qitish yo'qotishi tushyapti, tekshiruv o'syaptiHaddan ortiq moslashuv
Ikkalasi ham yuqoriYetarli moslashmagan - model kichik
Ikkalasi ham past va yaqinYaxshi

1-chora: erta to'xtatish #

Python
X, y = shovqinli_malumot(300)
Xo, yo, Xt, yt = boling(X, y)

t = Tarmoq([20, 64, 64, 1], urug=1)
eng_yaxshi, eng_yaxshi_davr, sabr = float("inf"), 0, 0
for davr in range(1, 3001):
    t.qadam(Xo, yo, 0.1)
    tekshiruv = t.yoqotish(Xt, yt)
    if tekshiruv < eng_yaxshi - 1e-4:
        eng_yaxshi, eng_yaxshi_davr, sabr = tekshiruv, davr, 0
    else:
        sabr += 1
        if sabr >= 200:
            print(f"{davr}-davrda to'xtatildi (200 davr yaxshilanish yo'q)")
            break

print(f"eng yaxshi davr: {eng_yaxshi_davr}, tekshiruv yo'qotishi: {eng_yaxshi:.4f}")
Natija
292-davrda to'xtatildi (200 davr yaxshilanish yo'q)
eng yaxshi davr: 92, tekshiruv yo'qotishi: 0.4798

Eng yaxshi natija 92-davrda bo'lgan - ya'ni 3000 davr o'qitishning 97% i behuda edi.

Erta to'xtatish - eng arzon regularizatsiya

U hech qanday qo'shimcha hisob talab qilmaydi va deyarli har doim yordam beradi.

ParametrMa'nosi
sabr (patience)Necha davr yaxshilanishsiz kutiladi
Odatiy qiymat10-50 davr (bu misolda 200)
Eng yaxshi og'irliklarni saqlashMajburiy - aks holda foydasi yo'q

Oxirgi qator muhim: to'xtaganda modelning og'irliklari eng yaxshi holatda emas, u yerdan 200 davr o'tgan.

To'g'ri amaliyot: eng yaxshi natija ko'rsatilganda og'irliklarning nusxasini saqlang va oxirida shuni qaytaring.

2-chora: L2 regularizatsiya #

Natija
L_yangi = L + (lambda/2) · Σ w²
dW_yangi = dW + lambda · W
Python
X, y = shovqinli_malumot(300)
Xo, yo, Xt, yt = boling(X, y)

for l2 in [0.0, 0.001, 0.01, 0.05, 0.2]:
    t = Tarmoq([20, 64, 64, 1], urug=1, l2=l2)
    for _ in range(3000):
        t.qadam(Xo, yo, 0.1)
    ogirlik_normasi = float(np.sqrt(sum(float((W ** 2).sum()) for W in t.W)))
    print(f"l2 = {l2:<6} o'qitish: {t.aniqlik(Xo, yo):.3f}  "
          f"tekshiruv: {t.aniqlik(Xt, yt):.3f}  ‖W‖ = {ogirlik_normasi:>7.3f}")
Natija
l2 = 0.0    o'qitish: 1.000  tekshiruv: 0.767  ‖W‖ =  17.505
l2 = 0.001  o'qitish: 1.000  tekshiruv: 0.756  ‖W‖ =  13.642
l2 = 0.01   o'qitish: 1.000  tekshiruv: 0.789  ‖W‖ =   5.146
l2 = 0.05   o'qitish: 0.952  tekshiruv: 0.833  ‖W‖ =   3.137
l2 = 0.2    o'qitish: 0.548  tekshiruv: 0.456  ‖W‖ =   0.000
L2 nima qiladi

Yo'qotishga og'irliklar kvadratining yig'indisi qo'shiladi. Natijada model kichik og'irliklarni afzal ko'radi.

Nima uchun bu yordam beradi: katta og'irlik - bu "bu belgi juda muhim" degan qat'iy qaror. Shovqinli ma'lumotda bunday qat'iylik xato bo'lib chiqadi.

Jadvalda bog'liqlik aniq:

lambda‖W‖O'qitishTekshiruv
017.51.0000.767
0.053.10.9520.833
0.20.0000.5480.456

0.05 da tekshiruv aniqligi eng yuqori - o'qitish aniqligi tushgan bo'lsa ham.

Oxirgi qator - haddan ortiq regularizatsiya: og'irliklar normasi aynan nolga tushdi. Model butunlay o'chdi va aniqlik 0.456 - tasodifiy taxmindan ham yomonroq.

Ya'ni lambda ham giperparametr va u validatsiya to'plamida tanlanadi.

3-chora: dropout #

Python
X, y = shovqinli_malumot(300)
Xo, yo, Xt, yt = boling(X, y)

for p in [0.0, 0.2, 0.5, 0.8]:
    t = Tarmoq([20, 64, 64, 1], urug=1, dropout=p)
    for _ in range(3000):
        t.qadam(Xo, yo, 0.1)
    print(f"dropout = {p:<5} o'qitish: {t.aniqlik(Xo, yo):.3f}  "
          f"tekshiruv: {t.aniqlik(Xt, yt):.3f}")
Natija
dropout = 0.0   o'qitish: 1.000  tekshiruv: 0.767
dropout = 0.2   o'qitish: 1.000  tekshiruv: 0.822
dropout = 0.5   o'qitish: 1.000  tekshiruv: 0.844
dropout = 0.8   o'qitish: 0.919  tekshiruv: 0.822

Dropout 0.5 da tekshiruv aniqligi 0.767 dan 0.844 ga ko'tarildi - eng yaxshi natija. Diqqat qiling: o'qitish aniqligi baribir 1.000 bo'lib qoldi, chunki dropout bashorat rejimida o'chiriladi.

Dropout - faqat o'qitishda

Dropout har qadamda neyronlarning bir qismini tasodifiy o'chiradi. Bu modelni bitta neyronga tayanmaslikka majbur qiladi.

Ikkita muhim tafsilot bor va ikkalasini ham unutish oson:

Birinchi: bashorat qilishda dropout o'chirilishi kerak. Kodda bu oqitish=True bayrog'i bilan hal qilingan.

Agar uni unutsangiz, model har chaqiruvda boshqa javob beradi - va aniqlik tushadi.

Ikkinchi: 1 / (1 - p) ga bo'lish (inverted dropout). Usiz o'qitishdagi va bashoratdagi chiqishlar turli masshtabda bo'ladi.

pFaol neyronlarTuzatuvchi koeffitsient
0.280%1 / 0.8 = 1.25
0.550%1 / 0.5 = 2.0

Gradient tekshiruvi (11-bo'lim) dropout bilan ishlamaydi - uni sinashdan oldin dropout=0 qo'ying.

Python
X, y = shovqinli_malumot(300)
Xo, yo, Xt, yt = boling(X, y)
t = Tarmoq([20, 32, 1], urug=1, dropout=0.5)
for _ in range(500):
    t.qadam(Xo, yo, 0.1)

a1, _ = t.oldinga(Xt[:3], oqitish=False)
a2, _ = t.oldinga(Xt[:3], oqitish=False)
b1, _ = t.oldinga(Xt[:3], oqitish=True)
b2, _ = t.oldinga(Xt[:3], oqitish=True)

print("bashorat rejimi barqarormi:", bool(np.allclose(a1, a2)))
print("o'qitish rejimi barqarormi:", bool(np.allclose(b1, b2)))
Natija
bashorat rejimi barqarormi: True
o'qitish rejimi barqarormi: False

4-chora: ko'proq ma'lumot #

Python
for n in [100, 300, 1000, 3000]:
    X, y = shovqinli_malumot(n)
    Xo, yo, Xt, yt = boling(X, y)
    t = Tarmoq([20, 64, 64, 1], urug=1)
    for _ in range(2000):
        t.qadam(Xo, yo, 0.1)
    print(f"n = {n:>5}  o'qitish: {t.aniqlik(Xo, yo):.3f}  "
          f"tekshiruv: {t.aniqlik(Xt, yt):.3f}  farq: "
          f"{t.aniqlik(Xo, yo) - t.aniqlik(Xt, yt):+.3f}")
Natija
n =   100  o'qitish: 1.000  tekshiruv: 0.567  farq: +0.433
n =   300  o'qitish: 1.000  tekshiruv: 0.767  farq: +0.233
n =  1000  o'qitish: 1.000  tekshiruv: 0.763  farq: +0.237
n =  3000  o'qitish: 0.989  tekshiruv: 0.781  farq: +0.207
Ko'proq ma'lumot - eng ishonchli chora

Farq +0.433 dan +0.207 ga tushdi - ikki barobardan ko'proq yaxshilanish.

Lekin diqqat qiling: farq yo'qolmadi. 64 neyronli ikki qatlamli model 3000 namunani ham 2000 davrda deyarli to'liq yodlab oldi (0.989).

Ya'ni ko'proq ma'lumot yordam beradi, lekin u yolg'iz yetarli emas - regularizatsiya yoki erta to'xtatish bilan birga ishlatiladi.

Amaliy tartib:

ChoraNarxiSamarasi
Ko'proq ma'lumotQimmatEng yuqori
Ma'lumotni kengaytirish (augmentation)ArzonYuqori
Erta to'xtatishBepulO'rtacha
L2 / dropoutBepulO'rtacha
Modelni kichraytirishBepulO'rtacha

Diqqat: n = 3000 da ham tekshiruv aniqligi 0.781 - va u 0.9 dan oshmaydi. Sabab: ma'lumotning 10% yorlig'i ataylab buzilgan. Hech qanday model bu shovqindan nariga o'ta olmaydi.

Bu muhim tushuncha: har ma'lumot to'plamining nazariy chegarasi bor. Uni ortda qoldirish - haddan ortiq moslashuv belgisi, yaxshi model belgisi emas.

Model hajmi #

Python
X, y = shovqinli_malumot(300)
Xo, yo, Xt, yt = boling(X, y)

for olchamlar in [[20, 4, 1], [20, 16, 1], [20, 64, 64, 1], [20, 128, 128, 128, 1]]:
    t = Tarmoq(olchamlar, urug=1)
    parametrlar = sum(W.size for W in t.W) + sum(b.size for b in t.b)
    for _ in range(2000):
        t.qadam(Xo, yo, 0.1)
    print(f"{str(olchamlar):<24} parametrlar: {parametrlar:>6}  "
          f"o'qitish: {t.aniqlik(Xo, yo):.3f}  tekshiruv: {t.aniqlik(Xt, yt):.3f}")
Natija
[20, 4, 1]               parametrlar:     89  o'qitish: 0.948  tekshiruv: 0.711
[20, 16, 1]              parametrlar:    353  o'qitish: 1.000  tekshiruv: 0.778
[20, 64, 64, 1]          parametrlar:   5569  o'qitish: 1.000  tekshiruv: 0.767
[20, 128, 128, 128, 1]   parametrlar:  35841  o'qitish: 1.000  tekshiruv: 0.711

Eng katta va eng kichik modellar bir xil yomon natija berdi (0.711), o'rtadagi [20, 16, 1] esa eng yaxshisini (0.778).

Bu klassik U shakli: juda kichik model yetarli o'rganmaydi, juda katta model yodlab oladi. Optimal hajm o'rtada yotadi va uni validatsiya to'plamida qidirasiz.

Amaliy topshiriq
  1. Ma'lumotni o'qitish va tekshiruvga bo'ling.
  2. Nima uchun uchta to'plam kerakligini tushuntiring.
  3. 3000 davr o'qitib, ikki yo'qotishning ajralishini kuzating.
  4. Eng yaxshi tekshiruv davrini toping.
  5. Erta to'xtatishni sabr bilan yozing.
  6. Beshta l2 qiymatida og'irlik normasini va aniqlikni solishtiring.
  7. Haddan ortiq regularizatsiya nima ekanini ko'rsating.
  8. To'rtta dropout qiymatida natijani solishtiring.
  9. Dropout bashorat rejimida barqaror ekanini tekshiring.
  10. Ma'lumot hajmini oshirib, farqning kamayishini o'lchang.

Xulosa #

  • Haddan ortiq moslashuv: o'qitish yaxshilanadi, tekshiruv yomonlashadi.
  • Tekshiruv to'plami muqaddas - unda giperparametr tanlamang.
  • To'g'risi - uchta to'plam: o'qitish, validatsiya, test.
  • Model shovqinli yorliqlarni ham yodlab oladi.
  • Erta to'xtatish - bepul va deyarli har doim yordam beradi.
  • Eng yaxshi og'irliklarning nusxasini saqlang.
  • L2 kichik og'irliklarni afzal ko'radi; lambda juda katta bo'lsa - model o'qimaydi.
  • Dropout faqat o'qitishda; 1/(1-p) ga bo'lishni unutmang.
  • Ko'proq ma'lumot - eng ishonchli chora.
  • Har to'plamning nazariy chegarasi bor - undan oshish yodlash belgisi.

Keyingi bo'limda ma'lumotni tayyorlashni ko'ramiz: normalizatsiya va masshtablash.

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.