İçeriğe geç
academia.sh

Ders 09 / 24

Toplu Normalleştirme

Katman girdilerinin küçük toplu içinde ölçeklenmesinin izin verdiği öğrenme adımının ve bunun açtığı sızıntı kaynağının ölçülmesi: normalleştirmesiz ağ öğrenme adımı 20'de kaybı 8,6577'ye taşıyor, 60'ta 16 birimin 14'ünü öldürüp tam olarak taban çizgisini veriyor; normalleştirmeli ağ aynı adımlarda kaybı 0,7206 ve 2,3263'te tutuyor ve hiçbir adımda tek bir birim bile ölmüyor — kaybı 1,0'ın altında tutan en büyük adım 5'ten 20'ye, dört katına çıkıyor. Çıkarım koşum ortalamalarıyla yapıldığında sınama 0,7698, sınama toplusunun kendi istatistiğiyle yapıldığında 0,7937 çıkıyor; şişme 0,0238, yani altı abone. Yalnız sınama satırlarının sırası değiştirildiğinde aynı model 0,7817 veriyor, yedi abone sınıf değiştiriyor ve tek bir abonenin olasılığı 0,2273 oynuyor.

İçindekiler

Önceki dersin iki yöntemi de ağın çıktısına dokunuyordu; katmanların girdisine hiç dokunulmadı. Oysa ölçekleme bu kursun tek hazırlık adımıydı ve yalnız ilk katmana uygulandı: on iki sütun eğitim kümesinden öğrenilen ortalama ve değişkenlikle ölçeklendi. Gizli katmanın gördüğü sayıların böyle bir güvencesi yok; ağırlıklar her güncellemede değiştiği için ikinci katmanın girdi ölçeği de kayıyor.

Toplu normalleştirme bu boşluğu doldurur: bir katmanın girdileri, içinde bulunduğu küçük toplunun ortalaması ve değişkenliğiyle her adımda yeniden ölçeklenir. Bu dersin ölçüsü normalleştirmenin izin verdiği öğrenme adımıdır. İkinci ölçü bedelidir: normalleştirme eğitimde ve çıkarımda aynı sayıyı kullanmaz ve bu fark bir sızıntı kaynağıdır.

  • SA69. Küme, bölme, tohum ve ölçek önceki derslerdeki gibidir; tablo kurgudur, eğitim kümesi 300 satıra küçültülmüştür ve taban çizgisi sınamada 0,7579.
  • SA70. Ağ önceki dersteki gibi 12-16-1 ve 225 parametredir. Eğitim 30 tur, toplu boyut 20, yalın iniştir. Değişen tek şey öğrenme adımı ve normalleştirmenin olup olmadığıdır.
  • SA71. Normalleştirme gizli katmanın etkinleştirme öncesi değerlerine uygulanır; öğrenilen ölçek ve kaydırma katsayıları kullanılmaz. Sıfıra bölünmemek için değişkenliğe 10810^{-8} eklenir ve bu eşik görünür basamakta hiçbir şeyi oynatmaz.
  • SA72. Normalleştirmenin kendi türevi geri yayılıma yazılır: ortalama ve sapma toplunun bütün satırlarından geldiği için bir satırın eğimi öbür satırlara da bağlıdır.
  • SA73. Çıkarımda toplu istatistiği yoktur; eğitim boyunca 0,9 katsayılı bir koşum ortalaması biriktirilir ve çıkarımda o kullanılır. Ölü birim önceki dersteki tanımdır.
  • SA74. Denenen ayar 8‘dir: iki normalleştirme durumu çarpı dört öğrenme adımı. Bu bir arama değildir; adımlar kararlılık sınırını göstermek için seçilmiştir. Karşılaştırma çizgileri M27/K03’ten gelir: doğrusal model 0,8016, karar ağacı 0,7857.

Toplunun İçinde Ölçeklemek

Bu dersin kodu ileri geçişi ve geri yayılımı satır satır değil toplu toplu yazar, çünkü normalleştirilecek istatistik toplunun tamamından gelir. Geri yayılımdaki normalleştirme türevi bunun sonucudur: bir satırın eğimi, aynı toplunun öbür satırlarının değerlerini içerir.

# normallestirme.py — MODELDIR. Ayni KURGU abone tablosu, ayni tohum, ayni bolme;
# egitim kumesi bu konuda 300 satira kucultulmustur.
import math
import statistics

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21, 0.00), ("guney", 0.22, 17, -0.10),
         ("dogu", 0.18, 26, 0.30), ("bati", 0.14, 14, -0.05),
         ("merkez", 0.18, 23, 0.05)]


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


VERI = []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() < 0.046:
        continue
    no = 10001 + i
    r, v = uretec(TOHUM + 7000 + no), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            b[2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + no)
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn + 0.24 * (hane >= 5)
         - 0.20 * (memnun >= 4) + b[3] + 0.9 * (no - 10001) / 1399
         + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": hane, "memnuniyet": memnun, "donem": len(v), "ort_tuketim": round(ort, 2),
         "oynaklik": round(oyn, 2), "sifir_okuma": int(min(v) == 0.0),
         "supheli": int(z > 1.35)}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for q in BOLGE:
        x["b_" + q[0]] = int(b[0] == q[0])
    VERI.append(x)

r, S = uretec(TOHUM + 90000), list(range(len(VERI)))
for i in range(len(S) - 1, 0, -1):
    j = int(r() * (i + 1))
    S[i], S[j] = S[j], S[i]
K = [VERI[i] for i in S]
EGT, SIN = K[:300], K[1008:]                        # egitim 756'dan 300'e KUCULTULDU
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
ORT = {a: statistics.fmean(x[a] for x in EGT) for a in ALAN}
SAP = {a: max(1e-9, statistics.pstdev([x[a] for x in EGT])) for a in ALAN}


def olcekli(s):                             # OGRENME egitimden, UYGULAMA her kumeye
    return ([[(x[a] - ORT[a]) / SAP[a] for a in ALAN] for x in s],
            [float(x["supheli"]) for x in s])


XE, YE = olcekli(EGT)
XS, YS = olcekli(SIN)
TABAN = sum(y == 0.0 for y in YS) / len(YS)
AGAC, DOGRUSAL = 198 / len(SIN), 202 / len(SIN)     # M27/K03'un iki sayisi


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def ilklendir(tohum, bicim, kazanc=1.0):    # kazanc olcekli; her satirin son sutunu YANMA
    r, kat = uretec(tohum), []
    for g, c in bicim:
        a = math.sqrt(6.0 * kazanc / g)
        kat.append([[(r() * 2 - 1) * a for _ in range(g)] + [0.0] for _ in range(c)])
    return kat


def sira(tur):                              # toplu bolme sirasi her kosumda AYNI
    r, s = uretec(TOHUM + 500 + tur), list(range(len(XE)))
    for i in range(len(s) - 1, 0, -1):
        j = int(r() * (i + 1))
        s[i], s[j] = s[j], s[i]
    return s


def ileri_toplu(W1, W2, Xb, ist=None, norm=False):   # BIR KUCUK TOPLUNUN TAMAMI
    Z = [[sum(p * q for p, q in zip(w, x)) + w[-1] for w in W1] for x in Xb]
    mu = sd = None
    if norm:
        n, m = len(Z), len(W1)
        if ist is None:                     # EGITIM: toplunun kendi istatistigi
            mu = [sum(z[j] for z in Z) / n for j in range(m)]
            sd = [math.sqrt(sum((z[j] - mu[j]) ** 2 for z in Z) / n + 1e-8)
                  for j in range(m)]
        else:                               # CIKARIM: kosum ortalamalari
            mu, sd = ist
        Z = [[(z[j] - mu[j]) / sd[j] for j in range(m)] for z in Z]
    A = [[t if t > 0 else 0.0 for t in z] for z in Z]
    P = [sikistir(sum(p * q for p, q in zip(W2[0], a)) + W2[0][-1]) for a in A]
    return Z, mu, sd, A, P


def egim_toplu(W1, W2, Xb, Yb, norm=False):          # GERI YAYILIM
    Z, mu, sd, A, P = ileri_toplu(W1, W2, Xb, norm=norm)
    n, m, kayip = len(Xb), len(W1), 0.0
    g1 = [[0.0] * len(W1[0]) for _ in W1]
    g2 = [[0.0] * len(W2[0])]
    dZ = [[0.0] * m for _ in range(n)]
    for i in range(n):
        p = min(max(P[i], 1e-12), 1 - 1e-12)
        kayip -= Yb[i] * math.log(p) + (1 - Yb[i]) * math.log(1 - p)
        d = p - Yb[i]
        for j in range(m):
            g2[0][j] += d * A[i][j] / n
            dZ[i][j] = d * W2[0][j] * (Z[i][j] > 0)
        g2[0][-1] += d / n
    if norm:                                # normallestirmenin kendi turevi
        for j in range(m):
            s1 = sum(dZ[i][j] for i in range(n))
            s2 = sum(dZ[i][j] * Z[i][j] for i in range(n))
            for i in range(n):
                dZ[i][j] = (n * dZ[i][j] - s1 - Z[i][j] * s2) / (n * sd[j])
    for i in range(n):
        for j in range(m):
            if dZ[i][j]:
                for k, xk in enumerate(Xb[i]):
                    g1[j][k] += dZ[i][j] * xk / n
                g1[j][-1] += dZ[i][j] / n
    return g1, g2, kayip / n, mu, sd


def tahmin(W1, W2, X, ist=None, norm=False, toplu=0):
    if not toplu:
        return ileri_toplu(W1, W2, X, ist, norm)[4]
    return [p for b in range(0, len(X), toplu)
            for p in ileri_toplu(W1, W2, X[b:b + toplu], None, norm)[4]]


def dg(P, Y):
    return sum((p > 0.5) == (y > 0.5) for p, y in zip(P, Y)) / len(Y)


def olu(W1, W2, KM, KS, norm):              # hicbir egitim satirinda etkinlesmeyen birim
    A = ileri_toplu(W1, W2, XE, (KM, KS) if norm else None, norm)[3]
    return sum(all(a[j] <= 0 for a in A) for j in range(len(W1)))


W1, W2 = ilklendir(TOHUM + 1, [(len(ALAN), 16), (16, 1)])
print(f"ag {len(ALAN)}-16-1, parametre {sum(len(w) for w in W1 + W2)}, egitim {len(EGT)}, "
      f"sinama {len(SIN)}, tur 30, toplu 20")
print(f"taban {TABAN:.4f}; karsilastirma cizgileri dogrusal model {DOGRUSAL:.4f}, "
      f"karar agaci {AGAC:.4f}")
ag 12-16-1, parametre 225, egitim 300, sinama 252, tur 30, toplu 20
taban 0.7579; karsilastirma cizgileri dogrusal model 0.8016, karar agaci 0.7857

Normalleştirmenin İzin Verdiği Öğrenme Adımı

Eğitim döngüsü koşum ortalamalarını da biriktirir, çünkü çıkarımda toplu yoktur.

def egit(tohum, adim, norm=False, tur=30, toplu=20, gizli=16):
    W1, W2 = ilklendir(tohum, [(len(ALAN), gizli), (gizli, 1)])
    KM, KS, iz = [0.0] * gizli, [1.0] * gizli, []
    for t in range(tur):
        s, top = sira(t), 0.0
        for b in range(0, len(s), toplu):
            i = s[b:b + toplu]
            g1, g2, k, mu, sd = egim_toplu(W1, W2, [XE[q] for q in i],
                                           [YE[q] for q in i], norm)
            for w, g in zip(W1, g1):
                for j in range(len(w)):
                    w[j] -= adim * g[j]
            for j in range(len(W2[0])):
                W2[0][j] -= adim * g2[0][j]
            if norm:                        # kosum ortalamalari cikarim icin biriktirilir
                KM = [0.9 * a + 0.1 * b for a, b in zip(KM, mu)]
                KS = [0.9 * a + 0.1 * b for a, b in zip(KS, sd)]
            top += k * len(i)
        iz.append(top / len(s))
    return W1, W2, KM, KS, iz[-1]


print(f"{'normallestirme':>15} {'adim':>6} {'kayip 2 kosum':>16} {'sinama 2 kosum':>16} "
      f"{'olu birim':>11}")
OZ = {}
for norm in (False, True):
    for adim in (0.05, 5.0, 20.0, 60.0):
        r = [egit(TOHUM + s, adim, norm) for s in (1, 2)]
        n = [dg(tahmin(a, b, XS, (c, d), norm), YS) for a, b, c, d, _ in r]
        OZ[(norm, adim)] = n
        print(f"{'var' if norm else 'yok':>15} {adim:>6} {r[0][4]:>7.4f} {r[1][4]:>8.4f} "
              f"{n[0]:>8.4f} {n[1]:>7.4f} {olu(*r[0][:4], norm):>7}/16 "
              f"{olu(*r[1][:4], norm):>2}/16")
print(f"\ndenenen ayar {len(OZ)}; taban {TABAN:.4f}, agin sayisi {OZ[(True, 0.05)][0]:.4f}, "
      f"ayni agin ikinci kosumu {OZ[(True, 0.05)][1]:.4f}")
 normallestirme   adim    kayip 2 kosum   sinama 2 kosum   olu birim
            yok   0.05  0.3740   0.3671   0.7659  0.7817       0/16  0/16
            yok    5.0  0.3841   0.3717   0.6905  0.5992       1/16  2/16
            yok   20.0  8.6577   8.1051   0.6270  0.6190       0/16  0/16
            yok   60.0  6.0788   6.0788   0.7579  0.7579      14/16 16/16
            var   0.05  0.4020   0.3922   0.7698  0.7857       0/16  0/16
            var    5.0  0.3809   0.4014   0.7381  0.7579       0/16  0/16
            var   20.0  0.7206   0.6698   0.6984  0.6865       0/16  0/16
            var   60.0  2.3263   1.9161   0.6429  0.6587       0/16  0/16

denenen ayar 8; taban 0.7579, agin sayisi 0.7698, ayni agin ikinci kosumu 0.7857

Kayıp sütunu dersin başlığındaki sayıyı veriyor. Normalleştirmesiz ağ 5’te hâlâ ayakta, 20’de kayıp 8,6577’ye çıkıyor; normalleştirmeli ağ aynı 20’de 0,7206’da kalıyor ve 60’ta bile 2,3263’ü aşmıyor. Kaybı 1,0’ın altında tutan en büyük adım normalleştirmesiz 5, normalleştirmeli 20: dört kat. Normalleştirmenin izin verdiği şey budur.

Ölü birim sütunu farkı daha keskin gösteriyor. Normalleştirmesiz ağ 60’ta 16 birimin 14’ünü, ikinci koşumda hepsini kaybediyor ve iki koşum da tam olarak taban çizgisini veriyor. Normalleştirmeli ağ hiçbir adımda tek bir birim bile kaybetmiyor: girdinin her adımda yeniden ölçeklenmesi, etkinleştirme öncesi değerlerin kalıcı olarak sıfırın altına itilmesini engelliyor.

Sınama sütunu bir uyarı taşıyor: normalleştirme büyük adımı mümkün kılıyor ama işe yarar kılmıyor, çünkü en yüksek sayı iki ailede de en küçük adımdadır. Üçlü şudur — taban 0,7579, ağın sayısı 0,7698, aynı ağın ikinci koşumu 0,7857; ikincisi birincisinden 0,0159 yüksek ve tam olarak karar ağacının sayısına oturuyor.

Eğitimde Başka, Çıkarımda Başka

Normalleştirmenin bedeli davranışın ikiye ayrılmasıdır. Eğitimde bir satırın çıktısı yanındaki on dokuz satıra bağlıdır; çıkarımda olmamalıdır. Aşağıdaki blok çıkarımı üç yoldan yapıyor.

W1, W2, KM, KS, _ = egit(TOHUM + 1, 0.05, True)
PA = tahmin(W1, W2, XS, (KM, KS), True)                 # dogru yol: kosum ortalamalari
PB = tahmin(W1, W2, XS, norm=True, toplu=20)            # toplunun kendi istatistigi
r, S2 = uretec(TOHUM + 4242), list(range(len(XS)))
for i in range(len(S2) - 1, 0, -1):
    j = int(r() * (i + 1))
    S2[i], S2[j] = S2[j], S2[i]
PC = [0.0] * len(XS)
for k, i in enumerate(tahmin(W1, W2, [XS[q] for q in S2], norm=True, toplu=20)):
    PC[S2[k]] = i
print(f"cikarim kosum ortalamalariyla     {dg(PA, YS):.4f}")
print(f"cikarim toplunun istatistigiyle   {dg(PB, YS):.4f}  "
      f"sisme {dg(PB, YS) - dg(PA, YS):.4f} "
      f"({round((dg(PB, YS) - dg(PA, YS)) * len(SIN))} abone)")
print(f"ayni yol, sinama sirasi degisik    {dg(PC, YS):.4f}")
print(f"sinif degistiren abone: kosum ort. ile toplu ist. arasinda "
      f"{sum((a > 0.5) != (b > 0.5) for a, b in zip(PA, PB))}, "
      f"yalniz sira degisince {sum((a > 0.5) != (b > 0.5) for a, b in zip(PB, PC))}")
print(f"tek bir abonenin olasiligindaki en buyuk oynama "
      f"{max(abs(a - b) for a, b in zip(PB, PC)):.4f}")
cikarim kosum ortalamalariyla     0.7698
cikarim toplunun istatistigiyle   0.7937  sisme 0.0238 (6 abone)
ayni yol, sinama sirasi degisik    0.7817
sinif degistiren abone: kosum ort. ile toplu ist. arasinda 6, yalniz sira degisince 7
tek bir abonenin olasiligindaki en buyuk oynama 0.2273

İkinci satır ilk bakışta iyi haber gibi duruyor: 0,7698 yerine 0,7937, altı abone daha doğru. Ama o altı abone öğrenmeden gelmiyor. Sınama toplusunun ortalaması sınama satırlarının kendisinden hesaplandı; her abonenin tahmini, aynı topludaki öbür on dokuz abonenin sayılarını içeriyor.

Üçüncü satır bunu kanıtlıyor. Model aynı, ağırlıklar aynı, sınama kümesi aynı — yalnız satırların sırası değişti ve sayı 0,7937’den 0,7817’ye indi. Yedi abone sınıf değiştirdi, bir abonenin olasılığı 0,2273 oynadı. Bir modelin tahmini tahmin edilen kişiden başka kimseye bağlı olmamalıdır; burada bağlı. M27/K02’nin boru hattı dersi bir dönüşümün bütün kümeden öğrenilmesinin 0,0397 ile 0,0476 arasında şişme ürettiğini ölçmüştü; toplu normalleştirme aynı hatayı sessizce yapılabilir kılar. Doğru yol tektir: çıkarımda koşum ortalamaları.

Özet

  • Toplu normalleştirme katmanın etkinleştirme öncesi değerlerini içinde bulunduğu küçük toplunun ortalaması ve değişkenliğiyle ölçekler; türevi de toplunun tamamından gelir.
  • Kaybı 1,0’ın altında tutan en büyük öğrenme adımı normalleştirmesiz 5, normalleştirmeli 20’dir — dört kat. Normalleştirmesiz ağ 20’de kaybı 8,6577’ye taşıyor.
  • Adım 60’ta normalleştirmesiz ağın 16 biriminin 14’ü, ikinci koşumda hepsi ölüyor ve sonuç tam olarak taban çizgisi oluyor; normalleştirmeli ağda hiçbir adımda birim ölmüyor.
  • Büyük adım mümkün oluyor ama işe yaramıyor: en yüksek sınama sayısı iki ailede de en küçük adımdadır. Üçlü taban 0,7579, ağın sayısı 0,7698, ikinci koşum 0,7857’dir.
  • Çıkarım toplunun kendi istatistiğiyle yapılırsa sayı 0,7937’ye şişiyor; yalnız sınama sırası değişince 0,7817’ye iniyor ve bir olasılık 0,2273 oynuyor.

Sonraki Adım

Dokuz ders bir ağı parça parça kurdu: doğrusal olmayan ayrım, etkinleştirme, ileri geçiş, kayıp, geri yayılım, eniyileyici, kararlılık, düzenlileştirme ve normalleştirme. Her derste üç sayı yan yana durdu ve üçüncüsü — aynı ağın ikinci koşumu — hiçbir yerde birinciyle aynı çıkmadı. Kursun kuralı son dört derste doğrulandı: kapasite hiç değişmediği halde eniyileyici, öğrenme adımı, seyreltme ve normalleştirme sayıyı 0,5992 ile 0,7937 arasında gezdirdi. Kursun ikinci iddiası da sürüyor: hiçbir koşum doğrusal modelin 0,8016’sını geçmedi.

Bu ağın dokuz derste hiç değişmeyen bir yanı var. Her girdi sütunu her gizli birime bağlandı ve her bağlantı kendi ağırlığını taşıdı — ağ tam bağlı kaldı. Bu, girdi sütunlarının birbiriyle hiçbir ilişkisi yokmuş gibi davranmaktır: sütunların sırası karıştırılsa ağ aynı sonucu verirdi. Oysa gerçek girdilerin çoğunda yapı vardır; bir sayaç okuma dizisinde komşu dönemler, bir kapsama ızgarasında komşu hücreler komşudur. Sonraki konu bu yapıyı ağın kendisine yazar ve ilk soruyu bir parametre sayısıyla sorar: aynı işi tam bağlı bir katman kaç ağırlıkla, komşuluğu bilen bir katman kaç ağırlıkla yapıyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat