İçeriğe geç
academia.sh

Ders 05 / 12

Ortam Sabitleme

Bir koşumu ikinci kez aynı sonuca ulaştıran kalemlerin tek tek sayılması: sabitlemesiz kurulumda üç koşum aynı ağırlığı bulduğu hâlde 0,8067, 0,7955 ve 0,8078 gibi üç ayrı sınama isabeti veriyor, çünkü okunan satır, öznitelik penceresi, yuvarlama basamağı, aranan ızgara ve sınama bölünmesi her koşumda oynuyor. Beş kalemden üçü sabitlendiğinde üç koşum birebir aynı çıkıyor, ızgara ile yuvarlama sabitlenmese de sonuç değişmiyor ve teker teker sınandığında katkısı ölçülebilen yalnız iki kalem kalıyor. Sabitlemenin kendi bedeli on beş kalem kaydı, on sekiz fazladan aday değerlendirmesi ve altmış fazladan satır okumasıdır.

İçindekiler

Öznitelik deposu bir kalemi tek yere indirdi ve o kalemin isabete kaç puan taşıdığı ölçüldü. Ama bir koşumun sonucunu belirleyen tek şey öznitelik kodu değildir. Aynı iş ikinci kez koşturulduğunda okunan veri kesiti, sınamaya ayrılan dönemler, aranan ağırlık ızgarası ve ara sayıların kaç basamağa yuvarlandığı da değişmiş olabilir. Hiçbiri kayıt altında değildir, hiçbiri hata sayılmaz, ve hepsi birden sonucu oynatır.

Ortam sabitleme (environment pinning) bu kalemlerin her birini bir koşumdan öbürüne değişmez tutmaktır. Bu ders sabitlemeyi (pinning) bir alışkanlık olarak değil bir ölçü olarak ele alır ve üç soru sorar: hangi kalemin sabitlenmesi üç koşumu birebir aynı yapıyor, sabitlemenin kendi bedeli ne, ve katkısı gösterilemeyen bir sabitleme ne söylemiş oluyor.

  • YU49. Kaynak, hattın ilk üç aşaması ve eşik tabanlı model kurgudur. Tohum 20260218, çıktı koşumdan bağımsızdır.
  • YU50. Sabitleme, bir kalemin koşumdan koşuma aynı kalmasını güvence altına almaktır. Burada beş kalem sayılır: veri sürümü, öznitelik kodu, sınama bölünmesi, ızgara ve yuvarlama. Hiçbir donanım, çalışma zamanı ya da bağımlılık adı yazılmaz; kalemler türleriyle anılır.
  • YU51. Tur, sabitlenmemiş kalemleri belirli bir yönde oynatan sayıdır ve üç tur aynı işin üç ayrı koşumunu temsil eder. Tur bir rastgelelik değil, yeniden üretilebilir bir kaydırmadır.
  • YU52. Taban çizgisi sabitlemesiz kurulumdur: beş kalemin hiçbiri sabit değildir ve koşumun neyi okuduğunu söyleyen hiçbir kayıt yoktur.
  • YU53. Etiket dengesizdir: {0: 1752, 1: 448}, taban sınıf oranı 0,7964, sınama kümesinde 0,8067. İsabet tek başına okunduğunda yanıltır.
  • YU54. Koşum değişkenliği ve ayar bütçesi Denetimli Öğrenme kursunda ölçüldü ve tekrarlanmaz; burada sayılan tek şey hangi kalemin sabitlenmesinin koşumu aynılaştırdığıdır.
  • YU55. Öznitelik penceresinin etkisi bir önceki derste ölçüldü ve burada girdi olur: pencere 1’de isabet 0,7800, pencere 2 ve üstünde 0,8067.
  • YU56. Çözünürlük: tam sınama kümesi 600 satır, adım 1/600 = 0,0017. Bu derste koşumlar arası en geniş fark 0,0123, yani adımın yedi katından büyük ve ölçülmüştür.

Sabitlenmemiş Kurulumun Üç Sayısı

Bir koşumun sonucu üç katmandan gelir: hangi veriyi okuduğu, veriyi hangi kodla işlediği ve sonucu hangi kümede ölçtüğü. Her biri kayıt altına alınmadığında sessizce kayabilir, ve kaymanın belirtisi bir hata iletisi değil başka bir sayıdır. Aşağıdaki blok kaynağı, hattın modele bakan ilk üç aşamasını, kurgu modeli ve beş sabitleme kalemini kurar; kosum işlevi sabitlenmeyen her kalemi tur numarasına göre oynatır.

# KURGUDUR. Olcum aginin sayac okumalari, hattin ilk uc asamasi ve esik tabanli
# model ders icinde tanimlanir; gercek bir ogrenme kitapligi, calisma zamani
# ya da bagimlilik yoneticisi cagrilmaz.
TOHUM, M32 = 20260218, 0xFFFFFFFF


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


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def kaynak_uret():
    kayit = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            kayit.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                          "endeks": e, "birim": "m3"})
    return kayit


def a1_ayikla(kayit):
    ZOR = ("abone", "donem", "bolge", "endeks", "birim")
    tut = [k for k in kayit if all(a in k for a in ZOR)]
    return tut, len(kayit) - len(tut)


def a2_tekille(kayit):
    gor, tut = set(), []
    for k in kayit:
        ad = (k["abone"], k["donem"])
        if ad in gor:
            continue
        gor.add(ad)
        tut.append(k)
    return tut, len(kayit) - len(tut)


def a3_tuketim(kayit):
    """Donem farkindan tuketim. Onceki donem yoksa satir hesaplanamaz."""
    tablo = {(k["abone"], k["donem"]): k for k in kayit}
    cikti, dusen = [], 0
    for k in kayit:
        i = DONEM.index(k["donem"])
        if i == 0:
            continue
        onceki = tablo.get((k["abone"], DONEM[i - 1]))
        if onceki is None:
            dusen += 1
            continue
        try:
            f = int(k["endeks"]) - int(onceki["endeks"])
        except (TypeError, ValueError):
            dusen += 1
            continue
        cikti.append(dict(k, m3=f))
    return cikti, dusen


EGITIM = DONEM[1:9]        # 2026-02 .. 2026-09
SINAMA = DONEM[9:]         # 2026-10 .. 2026-12
ESIK = 40                  # bu m3 uzerindeki tuketim "yuksek" sayilir


def satirlar():
    v, _ = a1_ayikla(kaynak_uret())
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    return v


def etiket(k):
    return 1 if k["m3"] > ESIK else 0


def oznitelikler(kayitlar, pencere=None, basamak=4):
    """pencere=None -> tam gecmis; basamak -> ara ortalamalarin yuvarlanmasi."""
    sirali = sorted(kayitlar, key=lambda k: DONEM.index(k["donem"]))
    ab, bo = {}, {}
    for k in sirali:
        ab.setdefault(k["abone"], []).append((DONEM.index(k["donem"]), k["m3"]))
        bo.setdefault(k["bolge"], []).append((DONEM.index(k["donem"]), k["m3"]))

    def ortalama(dizi, i):
        secili = [v for d, v in dizi if (d < i and (pencere is None or d >= i - pencere))]
        return round(sum(secili) / len(secili), basamak) if secili else 0.0

    oz = {}
    for k in kayitlar:
        i = DONEM.index(k["donem"])
        oz[(k["abone"], k["donem"])] = {
            "abone_ort": ortalama(ab[k["abone"]], i),
            "bolge_ort": ortalama(bo[k["bolge"]], i),
            "isyeri": 1 if k["tip"] == "isyeri" else 0}
    return oz


IZGARA = [(a, b, c) for a in (0.6, 0.8, 1.0) for b in (0.0, 0.2, 0.4) for c in (0, 4, 8)]


def puan(o, w):
    return w[0] * o["abone_ort"] + w[1] * o["bolge_ort"] + w[2] * o["isyeri"]


def egit(kayitlar, oz, izgara=None, esik=ESIK, donemler=None):
    izgara = IZGARA if izgara is None else izgara
    donemler = EGITIM if donemler is None else donemler
    kume = [k for k in kayitlar if k["donem"] in donemler]
    en_iyi, en_iyi_w = -1.0, None
    for w in izgara:
        d = sum(1 for k in kume
                if (1 if puan(oz[(k["abone"], k["donem"])], w) > esik else 0) == etiket(k))
        o = d / len(kume)
        if o > en_iyi:
            en_iyi, en_iyi_w = o, w
    return {"agirlik": en_iyi_w, "egitim_isabeti": round(en_iyi, 4),
            "aday": len(izgara), "egitim_satiri": len(kume)}


def sina(kayitlar, model, oz, esik=ESIK, donemler=None):
    donemler = SINAMA if donemler is None else donemler
    kume = [k for k in kayitlar if k["donem"] in donemler]
    d = sum(1 for k in kume
            if (1 if puan(oz[(k["abone"], k["donem"])], model["agirlik"]) > esik else 0)
            == etiket(k))
    return round(d / len(kume), 4)


# ---- Yeniden uretilebilirlik: bes sabitleme kalemi.
# Sabitlenmeyen her kalem tur'a gore oynar; sabitlenen kalem her turda ayni kalir.
KALEM = ("veri_surumu", "oznitelik_kodu", "bolunme", "izgara", "yuvarlama")


def ayar(sabit, tur):
    return {"satir_kirpma": 0 if "veri_surumu" in sabit else 20 * tur,
            "pencere": None if "oznitelik_kodu" in sabit else (None if tur == 0 else 12 - tur),
            "basamak": 4 if "yuvarlama" in sabit else max(4 - tur, 0),
            "aday": len(IZGARA) if "izgara" in sabit else len(IZGARA) - 6 * tur,
            "donemler": SINAMA if "bolunme" in sabit else DONEM[9 + (tur % 2):]}


def kosum(kayitlar, sabit, tur=0):
    kay = kayitlar if "veri_surumu" in sabit else kayitlar[: len(kayitlar) - 20 * tur]
    pencere = None if "oznitelik_kodu" in sabit else (None if tur == 0 else 12 - tur)
    basamak = 4 if "yuvarlama" in sabit else max(4 - tur, 0)
    izgara = IZGARA if "izgara" in sabit else IZGARA[: len(IZGARA) - 6 * tur]
    donemler = SINAMA if "bolunme" in sabit else DONEM[9 + (tur % 2):]
    oz = oznitelikler(kay, pencere, basamak)
    m = egit(kay, oz, izgara)
    return {"agirlik": m["agirlik"], "egitim": m["egitim_isabeti"],
            "sinama": sina(kay, m, oz, donemler=donemler)}

İkinci blok taban çizgisini koşturur: hiçbir kalem sabit değil, üç tur, üç sonuç.

import collections

S = satirlar()
dag = collections.Counter(etiket(k) for k in S)
print("satir:", len(S), " etiket dagilimi:", dict(sorted(dag.items())),
      " taban sinif orani:", round(dag[0] / len(S), 4),
      " sinamada:", round(sum(1 for k in S if k["donem"] in SINAMA and etiket(k) == 0)
                          / sum(1 for k in S if k["donem"] in SINAMA), 4))
print("sabitleme kalemi:", len(KALEM), "->", ", ".join(KALEM))

print(f"\n{'tur':<5}{'satir':>7}{'pencere':>9}{'basamak':>9}{'aday':>6}"
      f"{'sinama satiri':>15}{'agirlik':>18}{'sinama':>9}")
TABAN = []
for t in range(3):
    a, r = ayar(set(), t), kosum(S, set(), t)
    kalan = len(S) - a["satir_kirpma"]
    TABAN.append(r["sinama"])
    print(f"{t:<5}{kalan:>7}{str(a['pencere'] or 'tam'):>9}{a['basamak']:>9}{a['aday']:>6}"
          f"{sum(1 for k in S[:kalan] if k['donem'] in a['donemler']):>15}"
          f"{str(r['agirlik']):>18}{r['sinama']:>9.4f}")
print("uc kosum birebir ayni mi:", len(set(TABAN)) == 1, " farkli sonuc:", len(set(TABAN)),
      " en genis fark:", round(max(TABAN) - min(TABAN), 4))
satir: 2200  etiket dagilimi: {0: 1752, 1: 448}  taban sinif orani: 0.7964  sinamada: 0.8067
sabitleme kalemi: 5 -> veri_surumu, oznitelik_kodu, bolunme, izgara, yuvarlama

tur    satir  pencere  basamak  aday  sinama satiri           agirlik   sinama
0       2200      tam        4    27            600     (0.6, 0.4, 0)   0.8067
1       2180       11        3    21            396     (0.6, 0.4, 0)   0.7955
2       2160       10        2    15            588     (0.6, 0.4, 0)   0.8078
uc kosum birebir ayni mi: False  farkli sonuc: 3  en genis fark: 0.0123

Üç koşum üç ayrı sayı veriyor ve en geniş fark 0,0123, çözünürlüğün yedi katından büyük. Asıl söylenmesi gereken ağırlık sütunudur: üç koşum da (0.6, 0.4, 0) üçlüsünü buluyor. Öğrenilen model aynı; değişen yalnızca o modelin hangi sayıyla rapor edildiğidir. Birinci koşumun 0,8067’si ile üçüncünün 0,8078’i aynı modelin iki ayrı anısıdır ve ikisi de savunulabilir görünür, çünkü hangi kesitte ölçüldükleri yazılı değildir.

sinama satiri sütunu bunu tamamlar. Bölünme sabit olmadığı için ikinci koşum yalnız 396 satırda ölçülüyor; onun adımı 1/396 = 0,0025’tir. Üç sayı yalnızca farklı değil, farklı paydayla üretilmiş sayılardır. Etiket dengesizliği yanlış okumayı büyütür: sınamada taban sınıf oranı 0,8067 olduğu için üç sayının üçü de çoğunluk sınıfını söyleyen bir kurulumun bandındadır.

Kaç Kalem Yeter

Üçüncü blok kalemleri listedeki sırayla teker teker sabitler ve her adımda üç koşumu yeniden başlatır. Sorulan şey tek: eklenen kalem üç sonucu birebir aynı yapıyor mu.

def uc_kosum(sabit):
    return [kosum(S, set(sabit), t)["sinama"] for t in range(3)]


print(f"{'sabitlenen':<12}{'eklenen kalem':<17}{'uc kosum':>28}{'ayni mi':>9}")
for n in range(len(KALEM) + 1):
    r = uc_kosum(KALEM[:n])
    print(f"{n:<12}{('-' if n == 0 else KALEM[n - 1]):<17}"
          f"{'[' + ', '.join(f'{x:.4f}' for x in r) + ']':>28}"
          f"{('evet' if len(set(r)) == 1 else 'hayir'):>9}")
sabitlenen  eklenen kalem                        uc kosum  ayni mi
0           -                    [0.8067, 0.7955, 0.8078]    hayir
1           veri_surumu          [0.8067, 0.7950, 0.8067]    hayir
2           oznitelik_kodu       [0.8067, 0.7950, 0.8067]    hayir
3           bolunme              [0.8067, 0.8067, 0.8067]     evet
4           izgara               [0.8067, 0.8067, 0.8067]     evet
5           yuvarlama            [0.8067, 0.8067, 0.8067]     evet

Aynılık üçüncü kalemde geliyor: veri sürümü, öznitelik kodu ve bölünme sabitlendiğinde üç koşum [0,8067, 0,8067, 0,8067] veriyor. Dördüncü ve beşinci kalemler eklendiğinde sonuç değişmiyor, çünkü değişecek bir şey kalmamıştır. Buradan iki okuma çıkar: ızgara ile yuvarlamanın sabitlenmesi bu ölçüme hiçbir şey katmıyor, ve listenin uzunluğu değil içeriği belirleyici — iki kalem sabitlenmiş bir kurulum hâlâ üç ayrı sayı veriyor, üç kalem sabitlenmiş olan vermiyor.

Katkısı Ölçülemeyen Sabitleme

Sıralı ekleme her kalemin payını ayrı göstermez, çünkü sonraki kalemler zaten aynılaşmış bir sonucun üstüne biner. Dördüncü blok tersini yapar: beş kalemin hepsini sabitler, sonra tek bir kalemi serbest bırakır. Bir kalemin katkısı ancak serbest bırakıldığında sonuç değiştiğinde ölçülmüş sayılır. Aynı blok sabitlemenin kendi bedelini de yazar.

print(f"{'sabitlenmeyen tek kalem':<24}{'uc kosum':>28}{'katkisi olculdu mu':>20}")
for kalem in KALEM:
    r = uc_kosum([k for k in KALEM if k != kalem])
    print(f"{kalem:<24}{'[' + ', '.join(f'{x:.4f}' for x in r) + ']':>28}"
          f"{('evet' if len(set(r)) > 1 else 'hayir'):>20}")

# Sabitlemenin kendi bedeli: her kosumda yazilan kalem , degerlendirilen aday , okunan satir.
bos, tam = [ayar(set(), t) for t in range(3)], [ayar(set(KALEM), t) for t in range(3)]
print(f"\n{'bedel':<24}{'sabitlemesiz':>14}{'sabitlenmis':>13}")
print(f"{'yazilan kalem kaydi':<24}{0:>14}{len(KALEM) * 3:>13}")
print(f"{'degerlendirilen aday':<24}{sum(a['aday'] for a in bos):>14}"
      f"{sum(a['aday'] for a in tam):>13}")
print(f"{'okunan satir':<24}{sum(len(S) - a['satir_kirpma'] for a in bos):>14}"
      f"{sum(len(S) - a['satir_kirpma'] for a in tam):>13}")
print(f"{'farkli sonuc':<24}{len(set(uc_kosum([]))):>14}"
      f"{len(set(uc_kosum(KALEM))):>13}")
sabitlenmeyen tek kalem                     uc kosum  katkisi olculdu mu
veri_surumu                 [0.8067, 0.8064, 0.8078]                evet
oznitelik_kodu              [0.8067, 0.8067, 0.8067]               hayir
bolunme                     [0.8067, 0.7950, 0.8067]                evet
izgara                      [0.8067, 0.8067, 0.8067]               hayir
yuvarlama                   [0.8067, 0.8067, 0.8067]               hayir

bedel                     sabitlemesiz  sabitlenmis
yazilan kalem kaydi                  0           15
degerlendirilen aday                63           81
okunan satir                      6540         6600
farkli sonuc                         3            1

Tek tek sınandığında katkısı ölçülebilen yalnız iki kalem kalıyor: veri sürümü ve bölünme. Kalan üçü serbest bırakıldığında üç koşum hâlâ birebir aynı; bu ölçüm onların sabitlenmesinden kazanılan hiçbir şeyi gösteremiyor. Bu, o üç sabitlemenin gereksiz olduğu anlamına gelmez, tam olarak şu anlama gelir: verdikleri güvence ölçülmemiş bir güvencedir. Bir kurulumun “beş kalemi de sabitliyoruz” demesi, o beş kalemin beşinin de sonuca dokunduğunu göstermez; gösterilmiş olan yalnızca ikisidir.

Öznitelik kodu satırı bunu en iyi anlatan yerdir. Bu kalem serbest bırakıldığında pencere 11 ve 10’a iner ve önceki dersten bilinen süpürme, pencere 2 ve üstünde sonucun değişmediğini söyler. Yani kalem burada yeterince sarsılmadığı için katkısı görünmüyor; aynı kalem pencere 1’e düştüğünde isabeti 0,8067’den 0,7800’e taşıdığı ölçülmüştü. “Katkısı ölçülemedi” bir kalemin özelliği değil, o sınamanın özelliğidir.

Bedel tablosu takasın öbür yanıdır. Sabitlenmiş kurulum koşum başına beş kalem kaydı yazar, üç koşumda 15 kayıt; sabitlemesiz kurulumda bu sayı sıfırdır ve sorunun kaynağı odur. Sabitleme işten de tasarruf ettirmez: ızgara her koşumda tam boyunda kaldığı için değerlendirilen aday 63’ten 81’e, veri sürümü kırpılmadığı için okunan satır 6540’tan 6600’e çıkar. Karşılığında alınan tek şey son satırdır — üç koşum üç ayrı sonuç yerine tek sonuç verir. Kursun kuralı bu satırın bedelini savunur: yeniden üretilemeyen bir sayı bir ölçüm değil, bir anıdır.

Özet

  • Sabitlemesiz kurulumda üç koşum aynı ağırlık üçlüsünü bulduğu hâlde 0,8067, 0,7955 ve 0,8078 veriyor; öğrenilen model aynı, değişen yalnızca sayının hangi kesitte ölçüldüğüdür.
  • Bölünme sabit olmadığında ikinci koşum 396 satırda ölçülüyor; üç sayı farklı paydayla üretildiği için yan yana konmaları bile hatalıdır. Etiket dengesizliği (taban oranı 0,7964, sınamada 0,8067) bu yanlış okumayı büyütür.
  • Beş kalemden üçü sabitlendiğinde üç koşum birebir aynı çıkıyor; ızgara ile yuvarlama sabitlenmese de sonuç değişmez, yani sabitleme listesinin uzunluğu değil içeriği belirleyicidir.
  • Kalemler tek tek serbest bırakıldığında katkısı ölçülebilen yalnız veri sürümü ve bölünme kalır; kalan üçü ölçülmemiş bir güvence verir ve bu, sınamanın sarsma gücüyle ilgilidir.
  • Sabitlemenin bedeli üç koşumda 15 kalem kaydı, 63 yerine 81 aday değerlendirmesi ve 6540 yerine 6600 satır okumasıdır; karşılığında üç ayrı sonuç tek sonuca iner.

Sonraki Adım

Beş kalem sabitlendi ve üç koşum artık aynı sayıyı veriyor. Ama bu sayıyı üreten koşumun hangisi olduğu hâlâ hiçbir yerde yazmıyor. Elde ağırlık üçlüsünden başka bir şey taşımayan bir model duruyor ve üç koşum da aynı üçlüyü bulduğu için o model kendisini üreten koşumu işaret etmiyor. Bir modelin denenmekte mi, sınanmakta mı yoksa iş görmekte mi olduğu ve o aşamaya ne zaman taşındığı da aynı boşluktadır. Sonraki ders bu boşluğu sayar: bir aşamadaki modelin hangi koşumdan geldiğini bulmak için kaç kayda bakıldığını, kayıt defteriyle bu sayının kaça indiğini ve aynı sonucu veren koşumların birbirinden nasıl ayrıldığını ölçer.

İ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