Ders 08 / 12
Makine Öğrenmesi için Sürekli Tümleştirme
Koşum ile yayın arasına konan kod, veri ve model kapılarının hangi bozulmayı durdurduğunun sayılması: altı bozulma sınıfından dördünü veri kapısı, üçünü model kapısı durduruyor, kod kapısı hiçbirini durdurmuyor ama öznitelik kodu değişimini üretim verisine hiç bakmadan birinci adımda yakalıyor; birim değişimi yalnız model kapısında, eğitim isabetini 0,7931'den 0,5919'a düşürerek duruyor; geç gelen satır hiçbir kapıda durmuyor çünkü eğitim satırındaki sapması tam 0,0500 ve hoşgörü katı karşılaştırmayla 0,0500; veri kapısının durdurduğu dört koşumun ikisi başvuruyla birebir aynı modeli verecekti ve sekiz koşumun sekizinde sınama isabeti 0,8067 ile taban sınıf oranının üstüne çıkamıyor.
İçindekiler
Bir önceki dersin hattı koştuğu her seferde bir model üretiyordu ve üretilen modelin yayına çıkıp çıkmayacağı hiç sorulmadı. Geç gelen satırların eksikliğiyle 1520 satır üzerinde eğitilen model de, geri doldurulmuş 1600 satırla eğitilen model de aynı 0,8067’yi rapor ediyordu; ikisi de aynı kolaylıkla yayına gidebilirdi.
Bu ders koşum ile yayın arasına kapılar koyar. Bir kapı, bir koşumu yayına çıkmadan durduran denetimdir. Üçü vardır ve üçü ayrı şeye bakar: kod kapısı yazılan koda, veri kapısı hattın girdisine, model kapısı eğitilen modelin sayılarına. Sorunun kendisi tek cümledir: Veri Mühendisliğine Giriş kursunda tanımlanan altı bozulma sınıfı bu üç kapıya nasıl dağılır ve hiçbirinin durdurmadığı sınıf hangisidir.
- ED11. Kaynak, hat, model ve kapılar kurgudur; gerçek bir öğrenme kitaplığı ya da sürekli tümleştirme ürünü çağrılmaz. Tohum 20260218.
- ED12. Sürekli tümleştirmenin kendi yordamı, tetikleyiciler, aşama sıralaması ve dağıtım biçimleri DevOps ve Platform Mühendisliği müfredatındaki Sürekli Tümleştirme ve Teslimat kursunda, hat orkestrasyonu ise Veri Hatları ve Orkestrasyon kursunda ölçüldü. Tekrarlanmaz; bu ders yalnız veri ve model kapılarını ekler.
- ED13. Altı bozulma sınıfının hiçbiri saldırı değildir; hepsi üretici tarafındaki kazalardır ve
her biri tek bir dönemi (
2026-07) bozar. - ED14. Kapılar sırayla koşar: kod 1, veri 2, model 3. Bir olayı ilk durduran kapının numarası, bozulmanın hattı ne kadar kirlettiğini de söyler.
- ED15. Kod kapısı üretim verisini hiç görmez; sabit, üç satırlık bir girdi üzerinde koşar.
- ED16. Model kapısının karşılaştırdığı başvuru, sağlam kaynakla koşulan modeldir; hoşgörüler eğitim satırında 0,0500, eğitim isabetinde 0,0100.
- ED17. Etiket dağılımı dengesizdir; taban sınıf oranı bu derste de yazılır.
- ED18. Taban çizgisi kapısız kurulumdur: hiçbir kapı yok, her koşum yayına çıkar.
- ED19. Çözünürlük: sınama kümesi 600 satır, isabetin adımı 0,0017; kaynak 2400 satır, satır oranının adımı 0,0004.
- ED20. Süre ham milisaniye olarak yazılmaz; ölçü koşum, satır ve adımdır.
Üç Kapı
İlk blok kaynağı, altı bozulma sınıfını, hattın ilk üç aşamasını ve modeli kurar. Hiçbiri bu derse özgü değildir.
# KURGUDUR. Kaynak, hat, model ve kapilar ders icinde tanimlanir; gercek bir # ogrenme kitapligi ya da surekli tumlestirme urunu 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 # ---- Alti bozulma sinifi. Hicbiri saldiri degil , hepsi uretici tarafi kazasi. BOZULMA = ["gec_gelen", "yinelenen", "sema_degisti", "birim_degisti", "eksik_bolum", "kayan_tip"] def boz(kayit, sinif, donem="2026-07"): """Tek bir donemi bozar , kalan on bir donem saglam kalir.""" yeni = [] for k in kayit: if k["donem"] != donem: yeni.append(k) elif sinif == "gec_gelen": if k["abone"] > "A040": # 40 abone bu donemde hic gelmedi yeni.append(k) elif sinif == "yinelenen": yeni.append(k) if k["abone"] <= "A060": # 60 kayit iki kez geldi yeni.append(dict(k)) elif sinif == "sema_degisti": y = dict(k) y["endeks_degeri"] = y.pop("endeks") # alan adi degisti yeni.append(y) elif sinif == "birim_degisti": yeni.append(dict(k, endeks=k["endeks"] * 1000, birim="m3")) # etiket degismedi elif sinif == "eksik_bolum": if k["bolge"] != "kuzey": # bir bolgenin bolumu yazilmadi yeni.append(k) elif sinif == "kayan_tip": yeni.append(dict(k, endeks=str(k["endeks"]))) # sayi metne dondu return yeni 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): 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, SINAMA, ESIK = DONEM[1:9], DONEM[9:], 40 def etiket(k): return 1 if k["m3"] > ESIK else 0 def oznitelikler(kayitlar, pencere=None, basamak=4): 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 return {(k["abone"], k["donem"]): { "abone_ort": ortalama(ab[k["abone"]], DONEM.index(k["donem"])), "bolge_ort": ortalama(bo[k["bolge"]], DONEM.index(k["donem"])), "isyeri": 1 if k["tip"] == "isyeri" else 0} for k in kayitlar} 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): kume = [k for k in kayitlar if k["donem"] in EGITIM] 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)) if d / len(kume) > en_iyi: en_iyi, en_iyi_w = d / len(kume), w return {"agirlik": en_iyi_w, "egitim_isabeti": round(en_iyi, 4), "egitim_satiri": len(kume)} def sina(kayitlar, model, oz): kume = [k for k in kayitlar if k["donem"] in SINAMA] 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), round(sum(1 for k in kume if etiket(k) == 0) / len(kume), 4) def kosum(kayit, pencere=None): v, _ = a1_ayikla(kayit) v, _ = a2_tekille(v) v, _ = a3_tuketim(v) oz = oznitelikler(v, pencere) m = egit(v, oz) isabet, taban = sina(v, m, oz) return m, isabet, taban, len(v)
İkinci blok üç kapıyı tanımlar ve sekiz olayı sırayla kapılardan geçirir. Yedi olay veri tarafındadır: sağlam koşum ve altı bozulma sınıfı. Sekizincisi kod tarafındadır: öznitelik penceresinin tam geçmiş yerine tek döneme indirilmesi.
# ---- KAPI 1: kod. Sabit mini girdi , uretim verisini hic gormez. MINI = [{"abone": "A001", "donem": d, "bolge": "dogu", "tip": "isyeri", "m3": v} for d, v in (("2026-02", 30), ("2026-03", 50), ("2026-04", 10))] BEKLENEN = ({"abone_ort": 40.0, "bolge_ort": 40.0, "isyeri": 1}, [0, 1, 0]) def kod_kapisi(pencere=None): oz = oznitelikler(MINI, pencere) return (oz[("A001", "2026-04")], [etiket(k) for k in MINI]) != BEKLENEN # ---- KAPI 2: veri. Hattin girdisi uzerinde bes denetim. def veri_kapisi(kayit, beklenen=2400, pay=0.05): ALAN = ("abone", "donem", "bolge", "endeks", "birim") ad = [(k["abone"], k["donem"]) for k in kayit] bulgu = [] if any(any(a not in k for a in ALAN) for k in kayit): bulgu.append("sema") if any(not isinstance(k.get("endeks"), int) for k in kayit): bulgu.append("tip") if len(ad) != len(set(ad)): bulgu.append("tekillik") if abs(len(kayit) - beklenen) / beklenen > pay: bulgu.append("satir_sayisi") if set((k["bolge"], k["donem"]) for k in kayit) != set((b, d) for b in BOLGE for d in DONEM): bulgu.append("bolum_donem") return bulgu # ---- KAPI 3: model. Egitilen model yayindaki basvuruyla karsilastirilir. def model_kapisi(m, isabet, taban, basvuru, pay=0.05, dusus=0.0100): bulgu = [] if abs(m["egitim_satiri"] - basvuru["egitim_satiri"]) / basvuru["egitim_satiri"] > pay: bulgu.append("egitim_satiri") if basvuru["egitim_isabeti"] - m["egitim_isabeti"] > dusus: bulgu.append("egitim_dususu") if m["agirlik"] != basvuru["agirlik"]: bulgu.append("agirlik_kaymasi") return bulgu, isabet <= taban KAYNAK = kaynak_uret() BASVURU = kosum(KAYNAK)[0] OLAY = [("saglam", KAYNAK, None)] + [(s, boz(KAYNAK, s), None) for s in BOZULMA] \ + [("oznitelik_kodu", KAYNAK, 1)] SONUC = {} print(f"{'olay':<15}{'kod (1)':>9}{'veri (2)':>26}{'model (3)':>18}{'ilk kapi':>10}") for ad, kay, pen in OLAY: kk = kod_kapisi(pen) vk = veri_kapisi(kay) m, isabet, taban, satir = kosum(kay, pen) mk, taban_alti = model_kapisi(m, isabet, taban, BASVURU) ilk = 1 if kk else (2 if vk else (3 if mk else 0)) SONUC[ad] = (m, isabet, taban, satir, kk, vk, mk, taban_alti, ilk) print(f"{ad:<15}{('durdurdu' if kk else '-'):>9}{(','.join(vk) or '-'):>26}" f"{(','.join(mk) or '-'):>18}{(ilk or '-'):>10}") print("hicbir kapinin durdurmadigi olay:", [a for a in SONUC if SONUC[a][8] == 0]) print("sinama isabeti taban sinif oranini gecemeyen kosum:", sum(1 for a in SONUC if SONUC[a][7]), "/", len(OLAY))
olay kod (1) veri (2) model (3) ilk kapi saglam - - - - gec_gelen - - - - yinelenen - tekillik - 2 sema_degisti - sema,tip egitim_satiri 2 birim_degisti - - egitim_dususu 3 eksik_bolum - bolum_donem egitim_satiri 2 kayan_tip - tip - 2 oznitelik_kodu durdurdu - agirlik_kaymasi 1 hicbir kapinin durdurmadigi olay: ['saglam', 'gec_gelen'] sinama isabeti taban sinif oranini gecemeyen kosum: 8 / 8
Hangi Kapı Hangi Bozulmayı Durduruyor
Dağılım eşit değildir. Veri kapısı altı sınıftan dördünü durdurur: yinelenen kaydı tekillik denetimiyle, alan adı değişimini şema ve tür denetimiyle, eksik bölümü dönem duyarlı bütünlük denetimiyle, metne dönen sayıyı tür denetimiyle. Model kapısı üçünü durdurur ve bunlardan birim değişimi yalnız orada durur: hattın girdisi kusursuz görünürken eğitim isabeti 0,7931’den 0,5919’a iner ve 0,2012‘lik düşüş, 0,0100’lük hoşgörünün yirmi katıdır.
Kod kapısı altı sınıftan hiçbirini durdurmaz ve bu bir kusur değildir. Kod kapısı üretim
verisini görmez; gördüğü tek şey üç satırlık sabit bir girdidir. Buna karşılık öznitelik penceresinin
tek döneme indirilmesini birinci adımda, kaynağa hiç dokunulmadan yakalar. Aynı değişikliği model
kapısı da yakalar, ama üçüncü adımda: seçilen ağırlık (0.6, 0.4, 0) yerine (0.6, 0.0, 0) çıktığı
için ağırlık kayması ateşler. İki kapı da doğrudur; aralarındaki fark, birinin bozulmayı hat hiç
koşmadan, öbürünün 2200 satır işlendikten sonra durdurmasıdır.
Son satır dersin en rahatsız edici sayısıdır. Sekiz koşumun sekizinde sınama isabeti taban sınıf oranını geçemiyor. Etiket dağılımı dengesizdir, taban sınıf oranı 0,7964, sınama kümesinde 0,8067; model tam olarak o sayıyı üretir. Sınama isabetini yayın ölçütü yapan bir model kapısı bu düzenekte hiçbir modeli geçirmez. Bu bir yanlış alarm değildir: modelin taban sınıf oranının üstüne hiç çıkmadığının, isabet tek başına okunduğunda görünmeyen kanıtıdır.
Hiçbir Kapının Durdurmadığı Sınıf
Tablo iki olayı durdurulmamış bırakıyor. Biri sağlam koşumdur ve durmaması beklenir. Öbürü geç gelen satırdır ve bu bir boşluktur. Üçüncü blok boşluğun nereden geldiğini ölçer.
print(f"{'olay':<15}{'kaynak':>8}{'hat':>7}{'egitim':>8}{'egt.isabet':>12}{'sinama':>8}") for ad, kay, pen in OLAY: m, isabet, taban, satir, *_ = SONUC[ad] print(f"{ad:<15}{len(kay):>8}{satir:>7}{m['egitim_satiri']:>8}" f"{m['egitim_isabeti']:>12.4f}{isabet:>8.4f}") print() G, GI, GT, *_ = SONUC["gec_gelen"] print(f"gec_gelen egitim satiri sapmasi: {abs(G['egitim_satiri'] - 1600) / 1600:.4f}" f" kapi hosgorusu: 0.0500 karsilastirma: kati") print("hosgoru 0.0400 olsaydi gec_gelen:", model_kapisi(G, GI, GT, BASVURU, pay=0.04)[0], " ayni hosgoruyle saglam kosum:", model_kapisi(SONUC["saglam"][0], SONUC["saglam"][1], SONUC["saglam"][2], BASVURU, pay=0.04)[0] or "durmadi") print("veri kapisinin durdurdugu ama basvuruyla birebir ayni modeli veren kosum:", [a for a in SONUC if a != "saglam" and SONUC[a][5] and SONUC[a][0] == BASVURU])
olay kaynak hat egitim egt.isabet sinama saglam 2400 2200 1600 0.7931 0.8067 gec_gelen 2360 2120 1520 0.7914 0.8067 yinelenen 2460 2200 1600 0.7931 0.8067 sema_degisti 2400 1800 1200 0.7892 0.8067 birim_degisti 2400 2200 1600 0.5919 0.8067 eksik_bolum 2354 2108 1508 0.7924 0.8067 kayan_tip 2400 2200 1600 0.7931 0.8067 oznitelik_kodu 2400 2200 1600 0.7925 0.8067 gec_gelen egitim satiri sapmasi: 0.0500 kapi hosgorusu: 0.0500 karsilastirma: kati hosgoru 0.0400 olsaydi gec_gelen: ['egitim_satiri'] ayni hosgoruyle saglam kosum: durmadi veri kapisinin durdurdugu ama basvuruyla birebir ayni modeli veren kosum: ['yinelenen', 'kayan_tip']
Geç gelen satır iki kapıdan da kıl payı geçiyor. Veri kapısında kaynak 2400 yerine 2360’tır; sapma 0,0167, hoşgörü 0,0500. Model kapısında eğitim satırı 1600 yerine 1520’dir; sapma tam 0,0500, hoşgörü de 0,0500. Kapıyı geçiren şey bir ölçüm değil, bir karşılaştırma işaretidir: katı eşitsizlik kullanıldığı için sınıra oturan sapma içeride sayılır. Hoşgörü 0,0400’e indirildiğinde geç gelen satır duruyor ve sağlam koşum durmuyor.
Bu, eşik tabanlı her kapının taşıdığı kırılganlıktır ve sayısı yazılmadan görülmez. Ölçülen yanlış alarmın sıfır çıkması ise kapının değil bu kümenin bir özelliğidir: kurgu kaynakta her dönem tam 200 satır taşır, yani satır sayısındaki doğal oynama sıfırdır. Doğal oynaması olan bir kaynakta aynı sıkılaştırma sağlam koşumları da durdururdu.
Kapıların bedeli son satırdadır. Veri kapısı dört koşumu durduruyor, ama bunların ikisi başvuruyla birebir aynı modeli üretecekti: yinelenen kayıt tekilleştirme aşamasında, metne dönen sayı tür dönüşümünde yutuluyor ve ikisinde de ağırlık, eğitim satırı ve eğitim isabeti değişmiyor. Kapısız kurulumda sekiz koşumun sekizi yayına çıkar ve altısı bozuktur; kapılı kurulumda altı koşum durur, ikisi geçer ve geçenlerden biri hâlâ bozuktur. Durdurulan koşumların üçte biri ise hiçbir şey kazandırmadan durdurulmuştur.
Kursun kuralı kapıya da uygulanır: yeniden üretilemeyen sayı bir ölçüm değil bir anıdır. Bir kapının yeşil olması da bir ölçüm değildir; geç gelen satır üç kapıdan da yeşil geçerek 1520 satırla eğitilmiş modeli 1600 satırlık modelin yerine yayına taşır.
Özet
- Kapılar sırayla koşar: kod 1, veri 2, model 3. Bir olayı ilk durduran kapının numarası, bozulmanın hattı ne kadar kirlettiğini de söyler.
- Altı bozulma sınıfından dördünü veri kapısı, üçünü model kapısı durdurur; birim değişimi yalnız model kapısında, eğitim isabetini 0,7931’den 0,5919’a düşürerek durur.
- Kod kapısı altı sınıftan hiçbirini durdurmaz, çünkü üretim verisini görmez; buna karşılık öznitelik kodu değişimini birinci adımda, hat hiç koşmadan yakalar.
- Geç gelen satırı hiçbir kapı durdurmaz: kaynak sapması 0,0167, eğitim satırı sapması tam 0,0500 ve hoşgörü katı karşılaştırmayla 0,0500. Hoşgörü 0,0400 olsaydı durur ve sağlam koşum durmazdı.
- Etiket dağılımı dengesizdir, taban sınıf oranı 0,7964; sekiz koşumun sekizinde sınama isabeti 0,8067 ile taban sınıf oranının üstüne çıkamaz.
- Veri kapısının durdurduğu dört koşumun ikisi başvuruyla birebir aynı modeli verecekti; kapı eklemenin bedeli, kazandırmadığı yerde de durdurmasıdır.
Sonraki Adım
Kapılardan geçen bir koşum artık bir model üretmiş sayılır, ama üretilen şeyin ne olduğu hâlâ yazılmadı. Buraya kadar model üç ağırlıktan ve bir eşikten ibaret bir sözlüktü; onu çağıran taraf alanların adını, türünü ve sırasını tahmin ederek kullanıyordu. Sonraki ders modeli paketler: ağırlığın yanına hangi alanların hangi türle beklendiğini ve karşılığında hangi alanın döneceğini yazan bir arayüz sözleşmesi koyar. Ölçü, sözleşme yazılmadığında kırılan çağırandır: alan adı ya da tür değiştiğinde kaç çağrı düşüyor, kaçı hiç düşmeden yanlış cevap veriyor ve sözleşmeyle bunların kaçı yayın öncesi yakalanıyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.