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 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.