---
title: 'Gölge ve Kanarya Dağıtımı'
source: 'https://academia.sh/tr/kurslar/model-izleme/golge-ve-kanarya-dagitimi'
course: 'Model İzleme ve Yönetişim'
language: tr
updated: '2026-08-17T18:08:54+00:00'
license: 'CC BY-SA 4.0'
---

# Gölge ve Kanarya Dağıtımı

Yeni bir modelin yayına alınmasının kademelendirilmesi ve yeni modele giden payın hem sonucu hem de ölçüyü ne kadar oynattığının sayılması: gölge yerleşimde yeni modele 0 istek gider ama aday iki yüz satırın tamamında ölçülür ve 0,9650 çıkar, kanarya payı 0,10 olduğunda aday yalnız yirmi satırda ölçülür, çözünürlük 0,0050'den 0,0500'e çıkar ve aynı aday 1,0000 görünür. Eğitim araması iki adayı 0,9800 ile 0,9741'de ayıramazken üretimde aralarında 0,0150 fark vardır ve pay küçüldükçe bu farkın izi ölçünün altına iner.

Bir önceki konu altı derste bozulmanın **görülmesini** ölçtü: girdi kayması ateşleyen bir uyarı üretti ama isabeti düşürmedi, kavram kayması hiçbir vekil ölçüte görünmeden isabeti düşürdü, tek gören ölçü iki dönem geç geldi ve üretimden toplanan etiket yanlıydı. Altı dersin ortak kusuru şudur: hiçbirinde **görüldükten sonra ne yapılacağı** sorulmadı.

Görüldükten sonra yapılan ilk şey modeli değiştirmektir. Değiştirmenin kendisi bir risktir: yeni model üretimde ilk kez çalışır ve hakkında bilinen tek şey **eğitim kümesindeki** davranışıdır. Bu ders yeni modeli üç ayrı yerleşimde yayına alır ve tek bir soruyu sayar: **yeni modele giden pay sonucu ne kadar oynatıyor, ölçüyü ne kadar oynatıyor.** Yayın kademelendirmesinin kendisi Sürekli Tümleştirme ve Teslimat kursunda kuruldu, geri alma ve aşamalı yayın da Dayanıklılık ve Güvenilirlik kursunda ölçüldü; ikisi de burada tekrarlanmaz. Buradaki soru dağıtımın değil **ölçünün** sorusudur.

- **MY1.** Kaynak, hat ve model **kurgudur** ve ders içinde üretilir. Hiçbir dağıtım aracı, yönlendirici, deney platformu ya da izleme ürünü çağrılmaz. Tohum 20260218.
- **MY2.** Etiket, özniteliklerin gördüğü bir kurala bağlıdır: `abone_ort + 6 x isyeri > 30`. Karar eşiği bu kuraldan **ayrı bir ayardır** ve eğitimde aranır; eğitim ölçütü **dengeli isabettir**, yani **duyarlılık (recall)** ile **özgüllüğün** ortalamasıdır. Üçü de bu kursun ilk dersinde kuruldu.
- **MY3.** İzleme dönemlerinde **taban sınıf oranı 0,5342**; hiçbir isabet bu oran yazılmadan okunmaz. Dönem başına 200 satır vardır, yani dönem isabetinin en küçük adımı **0,0050**.
- **MY4.** Üretim verisi **veri kaymalıdır**: `2026-09`'dan sonra işyeri tüketimi dönem başına 0,06 büyür. Kural değişmemiştir.
- **MY5.** Yayın penceresi tek dönemdir: `2026-12`, 200 istek. Kanaryada isteklerin baştan itibaren pay kadarı yeni modele gider; bu **kurgu** bir bölüştürmedir.
- **MY6.** **Gölge** yerleşimde yeni model aynı isteği eski modele paralel puanlar, sonucu yalnız kaydedilir ve **hiçbir yanıt kullanıcıya dönmez**.
- **MY7.** Bedel **istek** ve **satır** olarak sayılır; ham süre yazılmaz.

## İki Aday, Ayıramayan Eğitim

İlk blok kaynağı, tüketim aşamasını, öznitelik yolunu ve kurgu modeli kurar; sonra üretimdeki kaymış veriyle yeniden eğitim yapar ve aramanın **ilk iki sırasını** yayın adayı olarak alır.

```python
# KURGUDUR. Olcum aginin sayac okumalari , hattin tuketim asamasi , oznitelik
# yolu ve uc agirlikli esik modeli ders icinde uretilir; hicbir ogrenme
# kitapligi , dagitim araci , deney platformu ya da izleme urunu cagrilmaz.
# Tohum 20260218.
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 satirlar():
    """Kaynak okumalari ve donem farkindan tuketim: hattin ilk uc asamasi."""
    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})
    t = {(k["abone"], k["donem"]): k["endeks"] for k in kayit}
    return [dict(k, m3=k["endeks"] - t[(k["abone"], DONEM[DONEM.index(k["donem"]) - 1])])
            for k in kayit if DONEM.index(k["donem"])]


def oznitelikler(kayitlar):
    """Agirliktan bagimsizdir ve BIR KEZ hesaplanir; tam gecmisi gorur."""
    ab, bo = {}, {}
    for k in sorted(kayitlar, key=lambda k: DONEM.index(k["donem"])):
        ab.setdefault(k["abone"], []).append((DONEM.index(k["donem"]), k["m3"]))
        bo.setdefault(k["bolge"], []).append((DONEM.index(k["donem"]), k["m3"]))

    def ort(dizi, i):
        s = [v for d, v in dizi if d < i]
        return round(sum(s) / len(s), 4) if s else 0.0

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


KURAL_ESIK, KURAL_ISYERI = 30, 6          # etiketi ureten KURAL , yani kavram
IZLEME = DONEM[6:]                        # uretimde izlenen alti donem
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)]
KARAR_IZGARA = (18, 22, 26, 30, 34)       # karar esigi AYRI bir ayardir


def etiket(o, esik=KURAL_ESIK):
    return 1 if o["abone_ort"] + KURAL_ISYERI * o["isyeri"] > esik else 0


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


def tahmin(o, w, karar):
    return 1 if puan(o, w) > karar else 0


def dengeli_isabet(kume, oz, w, karar):
    """Egitim olcutu: duyarlilik ile ozgullugun ortalamasi."""
    dp = dn = yp = yn = 0
    for k in kume:
        o = oz[(k["abone"], k["donem"])]
        t, g = tahmin(o, w, karar), etiket(o)
        if t and g:
            dp += 1
        elif t:
            yp += 1
        elif g:
            yn += 1
        else:
            dn += 1
    du = dp / (dp + yn) if dp + yn else 0.0
    oz_ = dn / (dn + yp) if dn + yp else 0.0
    return (du + oz_) / 2, round(du, 4), round(oz_, 4)


def egit(kayitlar, oz, donemler):
    """Agirlik ve karar esigi birlikte aranir: 27 x 5 = 135 aday."""
    kume = [k for k in kayitlar if k["donem"] in donemler]
    sirali = sorted(((dengeli_isabet(kume, oz, w, kr)[0], w, kr)
                     for w in IZGARA for kr in KARAR_IZGARA), key=lambda a: -a[0])
    en = sirali[0]
    return {"agirlik": en[1], "karar": en[2], "dengeli": round(en[0], 4),
            "sirali": sirali, "satir": len(kume)}


def kaydir(kayitlar, baslangic="2026-09", egim=0.06):
    """KURGU veri kaymasi: isyeri tuketimi her donem `egim` kadar buyuyor."""
    b = DONEM.index(baslangic)
    return [dict(k, m3=round(k["m3"] * (1.0 + egim * (DONEM.index(k["donem"]) - b + 1)), 4))
            if DONEM.index(k["donem"]) >= b and k["tip"] == "isyeri" else dict(k)
            for k in kayitlar]


TUM = satirlar()
OZ = oznitelikler(TUM)
TABAN = egit(TUM, OZ, DONEM[1:9])
URETIM = kaydir(TUM)                      # uretimde girdi kaymis durumda
OZU = oznitelikler(URETIM)
d, du, oz_ = dengeli_isabet([k for k in TUM if k["donem"] in DONEM[1:9]], OZ,
                            TABAN["agirlik"], TABAN["karar"])
izl = [k for k in TUM if k["donem"] in IZLEME]
e = [etiket(OZ[(k["abone"], k["donem"])]) for k in izl]
print(f"taban model {TABAN['agirlik']} karar esigi {TABAN['karar']}"
      f" dengeli isabet {TABAN['dengeli']} duyarlilik {du:.4f} ozgulluk {oz_:.4f}")
print(f"izleme {len(izl)} satir , taban sinif orani {round(1 - sum(e) / len(e), 4)}"
      f" , donem basina 200 satir , isabetin adimi 0.0050")

# Iki aday: yeniden egitilmis model ve ayni aramanin ikinci sirasi.
YE = egit(URETIM, OZU, DONEM[5:11])
A = {"ad": "A yeniden egitilmis", "agirlik": YE["agirlik"], "karar": YE["karar"],
     "egitim": YE["dengeli"]}
ik = YE["sirali"][1]
B = {"ad": "B aramanin ikincisi", "agirlik": ik[1], "karar": ik[2], "egitim": round(ik[0], 4)}
son = [k for k in URETIM if k["donem"] == "2026-12"]
for m in (A, B):
    m["ayrisan"] = sum(1 for k in son
                       if tahmin(OZU[(k["abone"], k["donem"])], m["agirlik"], m["karar"])
                       != tahmin(OZU[(k["abone"], k["donem"])], TABAN["agirlik"], TABAN["karar"]))
    print(f"aday {m['ad']} {m['agirlik']}/{m['karar']}"
          f" egitim dengeli isabeti {m['egitim']} , 2026-12'de ayrisan tahmin {m['ayrisan']}")
```

```
taban model (0.6, 0.0, 4) karar esigi 18 dengeli isabet 0.9864 duyarlilik 1.0000 ozgulluk 0.9728
izleme 1200 satir , taban sinif orani 0.5342 , donem basina 200 satir , isabetin adimi 0.0050
aday A yeniden egitilmis (0.6, 0.0, 4)/18 egitim dengeli isabeti 0.98 , 2026-12'de ayrisan tahmin 0
aday B aramanin ikincisi (0.8, 0.4, 4)/34 egitim dengeli isabeti 0.9741 , 2026-12'de ayrisan tahmin 11
```

İki aday eğitimde **0,9800** ile **0,9741** arasında durur. Aralarındaki 0,0059, altı dönemlik eğitim penceresinin 1200 satırında yaklaşık yedi satırlık bir farktır; hiçbir eğitim raporu bu ikisini güvenle sıralayamaz. Üretimdeki durumları ise ayrıdır: A eski modelle **birebir aynı ağırlık ve aynı karar eşiğini** taşır, yani `2026-12`'de ayrışan tahmini **0**'dır ve yayına alınması hiçbir şeyi değiştiremez. B ise aynı dönemde **11 tahminde** eski modelden ayrılır. Yayın kararının bütün konusu bu 11 tahmindir.

## Payın Ölçüye Yaptığı

İkinci blok üç yerleşimi aynı 200 istek üzerinde koşturur. `giden` sütunu yeni modele giden istek sayısı, `hizmet edilen` kullanıcıya dönen yanıtların isabeti, `olculen satir` adayın hakkında ölçü toplanabilen satır sayısı, `ek yanlis` ise eski modelin doğru bildiği ama yeni modelin yanlış hizmet ettiği istek sayısıdır.

```python
# Bu blok ilk bloktaki TABAN , URETIM , OZU , A , B , son , tahmin ,
# etiket ve puan tanimlarini surdurur.
def yayin(eski, yeni, oz, kume, pay, golge=False):
    """Golge: hicbir istek yeni modele gitmez , olcum yine de alinir."""
    n = 0 if golge else int(len(kume) * pay)
    olculen = len(kume) if golge else n
    hizmet = aday = ek_yanlis = 0
    for j, k in enumerate(kume):
        o = oz[(k["abone"], k["donem"])]
        g = etiket(o)
        te = tahmin(o, eski["agirlik"], eski["karar"])
        ty = tahmin(o, yeni["agirlik"], yeni["karar"])
        hizmet += ((ty if j < n else te) == g)
        ek_yanlis += (j < n and ty != g and te == g)
        aday += ((golge or j < n) and ty == g)
    return (n, round(hizmet / len(kume), 4), olculen, round(aday / olculen, 4),
            round(1 / olculen, 4), ek_yanlis)


eski_isabet = sum(1 for k in son
                  if tahmin(OZU[(k["abone"], k["donem"])], TABAN["agirlik"],
                            TABAN["karar"]) == etiket(OZU[(k["abone"], k["donem"])]))
print(f"2026-12 istek {len(son)} , eski modelin isabeti {eski_isabet / len(son)}")
print("aday  yerlesim      giden  hizmet edilen  olculen satir  aday olcusu"
      "  cozunurluk  ek yanlis")
for m in (A, B):
    for ad, pay, g in (("golge", 0.0, True), ("kanarya 0.10", 0.10, False),
                       ("kanarya 0.50", 0.50, False), ("tam gecis", 1.00, False)):
        n, h, ol, ao, cz, ey = yayin(TABAN, m, OZU, son, pay, g)
        print(f"{m['ad'][0]}     {ad:<12}  {n:>5}  {h:>13}  {ol:>13}  {ao:>11}"
              f"  {cz:>10}  {ey:>9}")
```

```
2026-12 istek 200 , eski modelin isabeti 0.98
aday  yerlesim      giden  hizmet edilen  olculen satir  aday olcusu  cozunurluk  ek yanlis
A     golge             0           0.98            200         0.98       0.005          0
A     kanarya 0.10     20           0.98             20          1.0        0.05          0
A     kanarya 0.50    100           0.98            100         0.99        0.01          0
A     tam gecis       200           0.98            200         0.98       0.005          0
B     golge             0           0.98            200        0.965       0.005          0
B     kanarya 0.10     20           0.98             20          1.0        0.05          0
B     kanarya 0.50    100           0.97            100         0.97        0.01          3
B     tam gecis       200          0.965            200        0.965       0.005          7
```

A satırları dört yerleşimde de aynıdır: hizmet edilen isabet **0,9800**, ek yanlış **0**. Bu bir başarı değil, bir **boşluğun** ölçüsüdür. Ayrışan tahmini sıfır olan bir aday için kanarya yayını, hiçbir şeyi değiştiremeyecek bir değişikliği kademelendirmek demektir; taşınan risk sıfır olduğu gibi kazanılan bilgi de sıfırdır. A'nın `kanarya 0.10` satırındaki 1,0000 bile bir bilgi değildir: yirmi satırda ölçülen bir sayıdır ve eski modelin aynı yirmi satırdaki değeri de 1,0000'dır.

B satırları asıl okumayı taşır. **Gölge yerleşimde yeni modele 0 istek gider**, hizmet edilen isabet eski modelin 0,9800'ünde kalır, hiçbir kullanıcı yeni modelin çıktısını görmez ve ek yanlış **0**'dır. Buna karşın aday **200 satırın tamamında** ölçülür ve gerçek değeri okunur: **0,9650**, yani eski modelden **0,0150** daha kötü. Bu fark, dönem çözünürlüğünün **üç adımıdır** ve bandın üstündedir.

Kanarya payı 0,10 olduğunda tablo tersine döner. Yeni modele **20 istek** gider, ama aday artık yalnız o 20 satırda ölçülebilir: ölçünün çözünürlüğü **0,0050'den 0,0500'e** çıkar, on kat kabalaşır. O yirmi satırda B'nin ölçüsü **1,0000**'dır. Gerçekte 0,9650 olan bir aday, kanaryanın en yaygın payında **hatasız** görünür. Hizmet edilen isabet de **0,9800**'de kalır, yani yayın panosuna bakan biri hiçbir şeyin değişmediğini görür. Kötü adayın izi ölçünün altına inmiştir.

Pay 0,50'ye çıkarıldığında ölçü düzelmeye başlar — çözünürlük 0,0100, adayın ölçüsü 0,9700 — ama bedeli de görünür olur: **3 istek**, eski modelin doğru bildiği hâlde yanlış yanıtlanır. Pay 1,00 kanarya değil **tam geçiştir**; ölçü tam çözünürlüğüne döner ve ek yanlış **7**'ye çıkar. Kanaryanın **geri alması** payı 0'a çekmektir ve bu, yanlış hizmet edilmiş istekleri geri getirmez. Gölgenin geri alınacak bir şeyi yoktur, çünkü hiç istek gitmemiştir.

Buradan iki tarafı olan tek bir kural çıkar. **Kanaryada ölçünün çözünürlüğü ile taşınan risk aynı sayıya, paya bağlıdır ve ters yönde hareket eder**: payı küçültmek riski küçültürken ölçüyü de körleştirir. **Gölge bu bağı koparır** — çözünürlük tam geçişinkiyle aynıdır (0,0050) ve yeni modele giden istek 0'dır. Gölgenin ödediği bedel başka bir sütundadır ve bu tabloda yoktur: her istek iki kez puanlanır, yani 200 istek için 400 çıkarım yapılır. Gölgenin ölçemediği tek şey ise **yanıtın kendisinin** yol açtığı davranıştır; puanı kimse görmediği için sonucu da kimse etkilemez.

## Özet

- Aynı eğitim araması iki adayı **0,9800** ile **0,9741**'de bırakır ve ayıramaz; üretimde biri eski modelle ayrışan tahmini **0** olan bir kopya, öbürü `2026-12`'de **11 tahminde** ayrılan gerçek bir değişikliktir. Taban sınıf oranı 0,5342 ve dönem isabetinin adımı 0,0050.
- **Gölge yerleşim yeni modele 0 istek gönderir** ve adayı yine de 200 satırın tamamında ölçer: gerçek değeri **0,9650**, eski modelden **0,0150** aşağıda ve çözünürlüğün üç adımı kadar.
- **Kanarya payı ölçüyü de böler.** Pay 0,10'da aday yalnız 20 satırda ölçülür, çözünürlük **0,0500**'e çıkar ve gerçekte kötü olan aday **1,0000** görünür; hizmet edilen isabet 0,9800'de kaldığı için panoya bakan hiçbir şey görmez.
- Payı büyütmek ölçüyü düzeltir ama bedelini yazar: 0,50'de **3**, 1,00'de **7** istek eski modelin doğru bildiği hâlde yanlış yanıtlanır. Pay 1,00 kanarya değil tam geçiştir ve geri alma bu istekleri geri getirmez.
- Kanaryada çözünürlük ile risk **aynı paya** bağlıdır ve ters yönde gider; gölge bu bağı koparır ve bedelini **çıkarım sayısında** öder: 200 istek için 400 puanlama.

## Sonraki Adım

Gölge, adayın gerçek değerini tek bir dönemde 0,9650 olarak okudu ve eski modelin 0,9800'ünden 0,0150 aşağıda buldu. Bu sayı bir karar için yeterli görünüyor, ama altında yanıtsız bir soru duruyor: 200 satırla ölçülen bir fark **ne kadar küçüldüğünde** okunamaz hâle gelir. Sonraki ders iki modelin karşılaştırmasını dönem sayısına göre süpürür, aynı adayın farkının dönemden döneme hangi bant içinde oynadığını sayar ve bu küme büyüklüğünün **ayırt edebildiği en küçük farkı** hesaplar. Bulunan sayının altında kalan her karşılaştırma sonuçsuzdur ve ders bunun bir örneğini işaretiyle birlikte gösterir.
