İçeriğe geç
academia.sh

Ders 06 / 12

Model Kayıt Defteri

Bir modelin yaşam döngüsü aşamalarının ve her aşama geçişinin hangi koşuma bağlandığının sayılması: on altı koşumluk bir kayıtta yalnız iki ayrı ağırlık üçlüsü çıkıyor, üretimdeki üçlüyü on iki koşum birebir taşıyor ve bu on iki koşum kendi sonucunu 0,7950 ile 0,8067 gibi iki ayrı sayıyla bildiriyor. Kayıt defteri olmadan üretimdeki modelin hangi koşumdan geldiğini bulmak için on altı kaydın tamamına bakılıyor ve arama on iki adaydan aşağı inmiyor, geri alınacak önceki üretim koşumu ise hiç bulunamıyor; dört aşama ve beş geçişi koşum kimliğine bağlayan defterle iki sorunun ikisi de tek kayıt okunarak yanıtlanıyor ve defterin bedeli yirmi bir kayıttır.

İçindekiler

Beş kalem sabitlendi ve üç koşum artık aynı sayıyı veriyor. Yeniden üretilebilirlik sorusunun yanıtı budur, ama bir soruyu daha açar: elde duran model hangi koşumdan geldi. Eğitilmiş bir modelin taşıdığı tek şey ağırlıklarıdır; ağırlıklar kendilerini üreten veri sürümünü, öznitelik penceresini ya da sınama bölünmesini içlerinde taşımaz.

Bu ders o boşluğu ölçer. Bir modelin denenmekte mi, sınanmakta mı yoksa iş görmekte mi olduğu bilgisi ve o duruma hangi koşumla gelindiği, modelin dosyasında değil ayrı bir kayıtta durur. Model kayıt defteri (model registry) tam olarak bu kayıttır: aşamaları ve aşamalar arasındaki geçişleri koşum kimliğine bağlar. Ölçülecek olan, o bağın bir soruya yanıt verirken kaç kayıt okuttuğudur.

  • YU57. Kaynak, hattın ilk üç aşaması, kurgu model ve kayıt defteri kurgudur; gerçek bir öğrenme kitaplığı ya da kayıt defteri ürünü çağrılmaz. Tohum 20260218.
  • YU58. Koşum, belirli ayarlarla yürütülmüş tek bir eğitim işidir ve bir kimlik taşır. Model o koşumun ürettiği ağırlık üçlüsüdür ve kimlik taşımaz.
  • YU59. Aşama, modelin yaşam döngüsündeki durumudur. Burada dördü sayılır: aday, sinamada, uretimde, arsivde. Geçiş, bir modeli bir aşamadan öbürüne taşıyan kayıttır ve bir koşum kimliğine bağlıdır.
  • YU60. Taban çizgisi deftersiz kurulumdur: koşumlar bir yerde kayıtlıdır, ama hiçbir aşama bir koşuma bağlı değildir. Bir aşamadaki modelden koşuma gitmenin tek yolu ağırlığı eşleştirmektir.
  • YU61. 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; bu derste iki koşum aynı modeli taşıyıp farklı sayı bildirecektir.
  • YU62. Koşum kaydının kendisi ve veri sürümleme bu konunun önceki derslerinde ele alındı; burada eklenen tek şey aşama geçişinin koşuma bağlanmasıdır. Soyağacı yordamı Veri Mühendisliğine Giriş kursunda ölçüldü ve tekrarlanmaz.
  • YU63. Kayıt defteri on altı koşumluk bir kayıt üzerinde kurulur. Koşumlar dört öznitelik penceresi, iki ızgara boyu ve iki sınama bölünmesinin birleşimidir.
  • YU64. Çözünürlük: tam sınama kümesi 600 satır, adım 1/600 = 0,0017. Bu derste aynı ağırlığın bildirdiği iki sayı arasındaki fark 0,0117, yani adımın altı katından büyük.

Modelin Kimliği Yoktur

Eğitilmiş bir model bir yordamın çıktısıdır ve çıktı, kendisini üreten yordamı içermez. Burada model üç sayıdan ibarettir; gerçek bir kurulumda çok daha büyük olur, ama durum değişmez. Modelin içinde hangi veriyle eğitildiği, hangi öznitelik penceresinin seçildiği ya da sınamanın hangi dönemler üzerinde yapıldığı yazmaz. Bu bilgiyi taşıyan tek şey koşum kaydıdır, ve model ile koşum arasındaki bağ ayrıca kurulmadıkça yoktur.

Bağ kurulmadığında yapılabilecek tek şey eşleştirmedir: elde duran ağırlıkları koşum kaydındaki ağırlıklarla karşılaştırıp hangisinin tuttuğuna bakmak. Bu yöntemin sessiz bir varsayımı vardır — her koşumun farklı bir model ürettiği. Aşağıdaki bloklar o varsayımı sınayacaktır. İlk blok kaynağı, hattın modele bakan ilk üç aşamasını ve kurgu modeli kurar.

# KURGUDUR. Olcum aginin sayac okumalari, hattin ilk uc asamasi ve esik tabanli
# model ders icinde tanimlanir; gercek bir ogrenme kitapligi ya da model kayit
# defteri urunu cagrilmaz. Defter de ders icinde bir kayit listesi olarak kurulur.
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; pencere=n -> son n donem."""
    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)

Aynı Ağırlığı Üreten On İki Koşum

İkinci blok on altı koşumluk bir kayıt üretir. Koşumlar birbirinden gerçekten farklıdır: dört ayrı öznitelik penceresi, iki ayrı ızgara boyu ve iki ayrı sınama bölünmesi denenmiştir. Sonra kayıt üretilen ağırlık üçlüsüne ve bildirilen sınama isabetine göre gruplanır.

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

# Kosum kaydi: dort oznitelik penceresi x iki izgara boyu x iki sinama bolunmesi.
OZ = {p: oznitelikler(S, p) for p in (None, 1, 2, 3)}
KAYIT = []
for p in (None, 1, 2, 3):
    for aday in (27, 21):
        for don in (SINAMA, DONEM[10:]):
            m = egit(S, OZ[p], IZGARA[:aday])
            KAYIT.append({"kimlik": f"K{len(KAYIT) + 1:02d}", "pencere": p, "aday": aday,
                          "donem": len(don), "agirlik": m["agirlik"],
                          "sinama": sina(S, m, OZ[p], donemler=don)})

grup = {}
for k in KAYIT:
    grup.setdefault((k["agirlik"], k["sinama"]), []).append(k["kimlik"])
print("\nkosum:", len(KAYIT), " farkli agirlik uclusu:",
      len(set(k["agirlik"] for k in KAYIT)), " farkli (agirlik , sinama):", len(grup))
print(f"{'agirlik':<16}{'sinama':>8}{'kosum':>7}   kimlikler")
for (w, s), ks in grup.items():
    print(f"{str(w):<16}{s:>8.4f}{len(ks):>7}   {','.join(ks)}")
satir: 2200  etiket dagilimi: {0: 1752, 1: 448}  taban sinif orani: 0.7964  sinamada: 0.8067

kosum: 16  farkli agirlik uclusu: 2  farkli (agirlik , sinama): 4
agirlik           sinama  kosum   kimlikler
(0.6, 0.4, 0)     0.8067      6   K01,K03,K09,K11,K13,K15
(0.6, 0.4, 0)     0.7950      6   K02,K04,K10,K12,K14,K16
(0.6, 0.0, 0)     0.8067      2   K05,K07
(0.6, 0.0, 0)     0.7950      2   K06,K08

On altı ayrı koşum yalnız iki ayrı ağırlık üçlüsü üretiyor. Eşleştirmenin varsayımı burada çöker: elde (0.6, 0.4, 0) duran biri, koşum kaydının tamamını okusa bile on iki aday bulur ve arama daha aşağı inmez. Bu bir kusur değil, aramanın doğal sonucudur — sonlu bir ızgarada gezinen her eğitim işi aynı adaya varabilir ve çoğu zaman varır.

Tablonun taşıdığı ikinci sayı daha ağırdır. Aynı (0.6, 0.4, 0) üçlüsünü taşıyan on iki koşumun altısı sonucunu 0,8067, altısı 0,7950 diye bildiriyor. İkisi de doğrudur; farkı yapan şey modelin kendisi değil, koşumun sınamayı kaç dönem üzerinde yaptığıdır. Yani üretimdeki model için “isabeti neydi” diye sorulduğunda, ağırlıklardan gidilerek verilecek yanıt 0,0117 genişliğinde bir aralıktır ve bu çözünürlüğün altı katından büyüktür. Etiket dengesizliği bunu daha da sakıncalı kılar: sınamada taban sınıf oranı 0,8067 olduğu için iki sayı da çoğunluk sınıfının bandındadır ve aradaki farkı bir başarım farkı sanmak yanıltıcıdır.

Aşamalar ve Geçişlerin Bağlandığı Koşum

Kayıt defteri modelin dosyasına dokunmaz; onun yerine ayrı bir kayıt tutar ve bu kayıt bir aşamayı bir koşum kimliğine bağlar. Dört aşama ile bunlar arasındaki geçişler dizisi defterin içeriğidir; her geçiş satırı hangi koşumun hangi aşamaya taşındığını söyler. Üçüncü blok defteri kurar ve iki soruyu iki kurulumda yanıtlar.

# Model kayit defteri: dort asama ve asamalar arasi gecisler. Her gecis BIR KOSUMA baglidir.
ASAMA = ("aday", "sinamada", "uretimde", "arsivde")
GECIS = [("K03", "aday", "sinamada"), ("K03", "sinamada", "uretimde"),
         ("K11", "aday", "sinamada"), ("K11", "sinamada", "uretimde"),
         ("K03", "uretimde", "arsivde")]
GUNCEL = {}
for kim, _, hedef in GECIS:
    GUNCEL[hedef] = kim
URETIMDEKI = next(k for k in KAYIT if k["kimlik"] == GUNCEL["uretimde"])["agirlik"]

esleyen = [k for k in KAYIT if k["agirlik"] == URETIMDEKI]
skor = sorted(set(k["sinama"] for k in esleyen))
print("uretimdeki agirlik:", URETIMDEKI, " defterdeki gecis:", len(GECIS))
print(f"\n{'soru':<34}{'defterisiz bakilan':>20}{'defterisiz yanit':>19}"
      f"{'defterli':>10}{'yanit':>7}")
print(f"{'bu agirlik hangi kosumdan geldi':<34}{len(KAYIT):>20}"
      f"{str(len(esleyen)) + ' aday':>19}{1:>10}{GUNCEL['uretimde']:>7}")
print(f"{'geri alinacak: onceki uretim':<34}{len(KAYIT):>20}{'yok':>19}"
      f"{1:>10}{GUNCEL['arsivde']:>7}")
print("\nayni agirligi tasiyan kosum:", len(esleyen), " bildirdikleri farkli sinama:",
      len(skor), "->", " .. ".join(f"{x:.4f}" for x in skor),
      " fark:", round(skor[-1] - skor[0], 4))
print("defterin bedeli: kosum kaydi", len(KAYIT), "+ gecis kaydi", len(GECIS),
      "=", len(KAYIT) + len(GECIS), "kayit ;", "asama:", len(ASAMA))
uretimdeki agirlik: (0.6, 0.4, 0)  defterdeki gecis: 5

soru                                defterisiz bakilan   defterisiz yanit  defterli  yanit
bu agirlik hangi kosumdan geldi                     16            12 aday         1    K11
geri alinacak: onceki uretim                        16                yok         1    K03

ayni agirligi tasiyan kosum: 12  bildirdikleri farkli sinama: 2 -> 0.7950 .. 0.8067  fark: 0.0117
defterin bedeli: kosum kaydi 16 + gecis kaydi 5 = 21 kayit ; asama: 4

Birinci satır aşama geçişinin ne kazandırdığını gösterir. Deftersiz kurulumda on altı kaydın tamamına bakılır ve elde on iki aday kalır; arama bakılan kayıt sayısı kadar iş yapıp hiç daralmaz. Defterli kurulumda uretimde aşaması bir koşum kimliğine bağlı olduğu için tek kayıt okunur ve yanıt K11’dir. Kazanılan şey on beş kayıtlık bir tasarruf değildir; kazanılan şey tekil bir yanıttır, ve deftersiz kurulumda o yanıt kayıt sayısı ne olursa olsun elde edilemez.

İkinci satır daha keskindir. Geri alma gerektiğinde sorulan soru “önceki üretim koşumu hangisiydi” olur ve deftersiz kurulumda bunun yanıtı yalnız zor değil, yoktur: eldeki tek şey şu anda yerinde duran ağırlıklardır ve önceki modelin ağırlıkları yerine yazılmıştır. Defterde ise K03’ün uretimde aşamasından arsivde aşamasına geçtiği kayıtlıdır; geri dönülecek koşum tek kayıtta okunur. Aşamaların değeri modelin nerede olduğunu söylemelerinden çok, nereden geldiğini ve nereye dönüleceğini söylemelerindedir.

Defterin bedeli son satırdadır ve mütevazıdır: on altı koşum kaydı ve beş geçiş kaydı, toplam 21 kayıt. Bu bedel modelin kendisine dokunmaz, ağırlıkları büyütmez, çıkarımı yavaşlatmaz; yalnızca her aşama geçişinde bir satır yazılmasını zorunlu kılar. Yazılmadığında kaybedilen şey de tam olarak bu dersin ölçtüğü şeydir: üretimdeki sayının kime ait olduğu.

Özet

  • Eğitilmiş bir model yalnız ağırlıklarını taşır; kendisini üreten veri sürümünü, öznitelik penceresini ya da sınama bölünmesini içinde taşımaz, dolayısıyla kimliği yoktur.
  • On altı ayrı koşum yalnız iki ayrı ağırlık üçlüsü üretiyor; üretimdeki üçlüyü 12 koşum birebir taşıdığı için ağırlık eşleştirerek yapılan arama tekil bir yanıta hiç ulaşmıyor.
  • Aynı üçlüyü taşıyan koşumlar sonuçlarını 0,7950 ve 0,8067 diye bildiriyor; aradaki 0,0117 çözünürlüğün altı katından büyüktür ve etiket dengesizliği (taban oranı 0,7964, sınamada 0,8067) bu farkı başarım farkı sanmayı kolaylaştırır.
  • Dört aşama ve beş geçişi koşum kimliğine bağlayan defterle “üretimdeki model hangi koşumdan geldi” sorusu tek kayıtta yanıtlanıyor, deftersiz kurulumda 16 kayıt okunup 12 aday kalıyor.
  • Geri alma sorusunun deftersiz kurulumda yanıtı yoktur; defterde arşiv geçişi tek kayıtta önceki üretim koşumunu veriyor ve defterin toplam bedeli 21 kayıttır.

Sonraki Adım

Altı derste model yeniden üretilebilir kılındı. Koşumun kendisi kaydedildi ve sürümlendi, aynı ada verilen iki farklı içerik ayrıldı, öznitelik iki yerde iki kez hesaplanmaktan çıkıp tek yerde hesaplanır oldu, hangi kalemin sabitlenmesinin üç koşumu aynılaştırdığı sayıldı ve her aşama geçişi bir koşum kimliğine bağlandı. Artık üretimde duran bir sayının kime ait olduğu ve nasıl yeniden elde edileceği yazılıdır.

Yazılı olmayan tek şey, bu modelin oraya nasıl gideceğidir. Altı dersin hiçbirinde eğitimin kendisi uçtan uca bir hat olarak kurulmadı, hiçbir kapı yeni bir veri sürümünün ya da düşen bir ölçütün yayına çıkmasını durdurmadı, ve model bir çağıranın kullanabileceği bir arayüz olarak hiç paketlenmedi. Sonraki konu bu üç boşluğu sırayla kapatır: eğitim hattının adımlarını ve uçtan uca yeniden koşturulabilirliğini sayar, kod, veri ve model kapılarının hangi bozulmayı durdurduğunu ölçer, ve arayüz sözleşmesi yazılmadığında kaç çağıranın kırıldığını yazar.

İ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