İçeriğe geç
academia.sh

Ders 14 / 22

Uzun Süreli Bellek

Üç yazma politikasının aynı 48 görevlik ikinci kümede ölçülmesi: her adımın gözlemini ayrı kayıt yapmak 74 kayıt biriktiriyor ve 44 adım kazandırıyor, görev başına tek yanıt kaydı yazmak 24 kayıtla 199 adım kazandırıyor ama başarımı 0,9167'den 0,5833'e düşürüyor, plana giren gözlemleri tek kayıtta birleştiren seçici politika ise yine 24 kayıtla 118 adım kazandırıyor. Kazandıran şey kayıt sayısı değil kaydın birimidir.

İçindekiler

Kısa süreli bellek pencereyle sınırlıdır, ama asıl kayıp sınırda değil: döngü bittiği anda o bağlamın tamamı silinir. Ajan sayacı okur, endeks farkını hesaplar, tarifeyi uygular ve yanıtı verir. Aynı abone başka bir soruyla döndüğünde sayaç yeniden okunur.

Uzun süreli bellek (long-term memory) bu boşluğu doldurur: döngüden bağımsız yaşayan, sonraki görevlerin okuyabildiği bir kayıt kümesi. Buradaki soru neyin geri getirileceği değildir — parçalama, sıralama ve erişim isabeti Gömme Vektörleri ve Erişim Artırılmış Üretim kursunda ölçüldü, tekrarlanmaz. Buradaki soru neyin yazılacağıdır: aynı geri çağırma düzeneğiyle üç yazma politikası koşturulur, her birinde saklanan kayıt sayısı ile sonraki görevlerde kazanılan adım yan yana basılır.

  • AB61. Kod bir benzeticidir; gerçek bir model uç noktası, araç sunucusu ya da bellek servisi çağrılmaz. Ortam, araçlar ve görevler kurgudur, tohum 20260218.
  • AB62. Bellek bir kayıt listesidir; her kayıt aranabilir bir metin ve alanlarıdır. Gözlem ve yanıt kayıtları abone koduyla, belge kayıtları soru metniyle anahtarlanır.
  • AB63. Geri çağırma tek okumadır: istekle ortak belirteci en çok olan kayıt döner, eşitlikte en son yazılan.
  • AB64. Üç yazma politikası: her adım (her adımın gözlemi ayrı kayıt), yalnız sonuç (görev başına tek yanıt kaydı), seçici (planın adımlarına giren gözlemler tek kayıtta birleşir).
  • AB65. Geri çağrılan alanlar başlangıç durumuna yazılır, çıktısı bilinen adım atlanır; plan tümüyle bellekten karşılanırsa döngü hiç başlamaz.
  • AB66. Kayıtlar 24 görevlik ilk kümeden yazılır; ölçüm aynı abonelere sorulan 48 yeni soruda yapılır. Adım bütçesi 8, taban çizgisi belleksiz döngüdür.

Döngü Bittiğinde Geriye Kalan

Aşağıdaki blok ortak tanımı kurar ve tek bir aboneye iki ayrı soru sorar.

# KURGU ortam ve KURGU ajan. Gercek bir model ucu, arac sunucusu ya da bellek
# servisi cagrilmaz. Abone kayitlari, belgeler ve gorevler kurgudur, 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


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


def belirtecle(m):
    b = []
    for s in str(m).lower().replace(",", " , ").split():
        while len(s) > 5:
            b.append(s[:5])
            s = s[5:]
        b.append(s)
    return b


def izno(m):
    h = 2166136261
    for c in str(m):
        h = ((h ^ ord(c)) * 16777619) & M32
    return h


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
ABONE = {}
for i in range(60):
    r = uretec(TOHUM + 31 * i)
    onceki = 10000 + int(r() * 80000)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "onceki": onceki, "simdiki": onceki + int(r() * 70)}
BASAMAK, USTU = ((10, 4), (25, 7), (40, 11)), 16
ISYERI_KAT = 2
BELGE = {"TR01": "tarife basamaklari 10 25 40 metrekup ve ustu",
         "TR02": "isyeri abonesinde birim ucret iki katidir",
         "SY01": "endeks farki tuketimi verir sayac donusu 100000 eklenir",
         "AR01": "ariza kaydi acildiginda saha ekibi iki gun icinde gider",
         "KS01": "planli kesinti duyurusu bir hafta once yayimlanir"}

CAGRI = [0]                              # arac cagri sayaci


def _bedel(m3, tip):
    kalan, alt, top = m3, 0, 0
    for ust, birim in BASAMAK:
        dilim = min(kalan, ust - alt)
        if dilim <= 0:
            break
        top += dilim * birim
        kalan -= dilim
        alt = ust
    top += kalan * USTU
    return top * (ISYERI_KAT if tip == "isyeri" else 1)


def t_sayac_oku(abone=None, **_):
    a = ABONE.get(abone)
    if a is None:
        return {"hata": "abone yok"}
    return {"onceki": a["onceki"], "simdiki": a["simdiki"], "tip": a["tip"],
            "bolge": a["bolge"]}


def t_tuketim(onceki=None, simdiki=None, **_):
    if onceki is None or simdiki is None:
        return {"hata": "eksik alan"}
    f = simdiki - onceki
    return {"m3": f + 100000 if f < 0 else f}


def t_tarife(m3=None, tip="mesken", **_):
    if m3 is None:
        return {"hata": "eksik alan"}
    return {"tutar": _bedel(m3, tip)}


def t_belge(anahtar=None, **_):
    if not anahtar:
        return {"hata": "eksik alan"}
    ab = set(belirtecle(anahtar))
    en, kod = -1, None
    for k, m in BELGE.items():
        o = len(ab & set(belirtecle(m)))
        if o > en:
            en, kod = o, k
    return {"kod": kod, "metin": BELGE[kod]} if en > 0 else {"hata": "bulunamadi"}


def t_kayit(abone=None, sutun=None, deger=None, **_):
    if not (abone and sutun and deger is not None):
        return {"hata": "eksik alan"}
    return {"yazildi": True, "abone": abone, "sutun": sutun, "deger": deger}


ARAC = {
    "sayac_oku":  {"islev": t_sayac_oku, "alan": ("abone",), "yan_etki": False},
    "tuketim":    {"islev": t_tuketim, "alan": ("onceki", "simdiki"), "yan_etki": False},
    "tarife":     {"islev": t_tarife, "alan": ("m3", "tip"), "yan_etki": False},
    "belge_ara":  {"islev": t_belge, "alan": ("anahtar",), "yan_etki": False},
    "kayit_yaz":  {"islev": t_kayit, "alan": ("abone", "sutun", "deger"), "yan_etki": True},
}
ARAC_ADI = list(ARAC)


def cagir_arac(ad, durum):
    """Sema disindaki alanlar suzulur; eksik alan aracin kendi hatasidir."""
    CAGRI[0] += 1
    if ad not in ARAC:
        return {"hata": "arac yok"}
    kw = {a: durum[a] for a in ARAC[ad]["alan"] if a in durum}
    return ARAC[ad]["islev"](**kw)


GOREV = []
for i in range(24):
    r = uretec(TOHUM + 9973 * i)
    ab = f"A{1 + int(r() * 60):03d}"
    t = ayrik(r(), [0.30, 0.22, 0.20, 0.28])
    if t == 0:
        GOREV.append({"ad": f"G{i + 1:02d}", "tur": "bedel", "abone": ab,
                      "istek": f"{ab} abonesinin bu donem bedeli nedir",
                      "dizi": ("sayac_oku", "tuketim", "tarife")})
    elif t == 1:
        GOREV.append({"ad": f"G{i + 1:02d}", "tur": "tuketim", "abone": ab,
                      "istek": f"{ab} abonesinin bu donem tuketimi kac metrekup",
                      "dizi": ("sayac_oku", "tuketim")})
    elif t == 2:
        GOREV.append({"ad": f"G{i + 1:02d}", "tur": "belge", "abone": ab,
                      "istek": "sayac donusunde endeks farki nasil hesaplanir",
                      "dizi": ("belge_ara",)})
    else:
        GOREV.append({"ad": f"G{i + 1:02d}", "tur": "kayit", "abone": ab,
                      "istek": f"{ab} abonesinin bedelini hesapla ve kayda yaz",
                      "dizi": ("sayac_oku", "tuketim", "tarife", "kayit_yaz")})


def dogru_yanit(g):
    a = ABONE[g["abone"]]
    f = a["simdiki"] - a["onceki"]
    m3 = f + 100000 if f < 0 else f
    if g["tur"] == "tuketim":
        return m3
    if g["tur"] == "belge":
        return "SY01"
    return _bedel(m3, a["tip"])


def gorme(d):
    return max(0.34, 0.80 - 0.09 * (d - 1))    # dogru araci secme payi, derinlikle duser


def ajan(g, en_cok_adim=8, tohum=TOHUM, oz_elestiri=False, onay=False):
    """KURGU ajan dongusu. Gercek bir model cagrilmaz; arac secimi gorevin
    dizisine ve derinlige bagli tek bir cekilisten gelir."""
    r = uretec(tohum ^ izno(g["ad"]))
    alan = {"abone": g["abone"], "anahtar": g["istek"], "sutun": "bedel"}
    iz, adim, bel, hata = [], 0, 0, 0
    dizi, k = g["dizi"], 0
    while adim < en_cok_adim:
        adim += 1
        bel += 60 + 22 * len(iz)
        hedef = dizi[k] if k < len(dizi) else None
        if hedef is None:                          # is bitti , ajan durmali
            if r() < 0.88:
                return {"bitti": True, "adim": adim, "iz": iz, "belirtec": bel,
                        "hata": hata, "yanit": alan.get("sonuc"),
                        "onay": alan.get("onay", 0)}
            sec = ARAC_ADI[int(r() * len(ARAC_ADI))]
        else:
            sec = hedef if r() < gorme(k + 1) else ARAC_ADI[int(r() * len(ARAC_ADI))]
        if ARAC[sec]["yan_etki"] and onay:
            alan["onay"] = alan.get("onay", 0) + 1
        if sec == "kayit_yaz":
            alan["deger"] = alan.get("sonuc")
        s = cagir_arac(sec, alan)
        iz.append((sec, "hata" in s))
        bel += 30
        if "hata" in s:
            hata += 1
            if oz_elestiri:
                bel += 40
            continue
        alan.update({kk: vv for kk, vv in s.items() if kk != "hata"})
        if sec == "tuketim":
            alan["sonuc"] = s["m3"]
        if sec == "tarife":
            alan["sonuc"] = s["tutar"]
        if sec == "belge_ara":
            alan["sonuc"] = s["kod"]
        if sec == hedef:
            k += 1
    return {"bitti": False, "adim": adim, "iz": iz, "belirtec": bel, "hata": hata,
            "yanit": alan.get("sonuc"), "onay": alan.get("onay", 0)}


CAGRI[0] = 0
g1 = GOREV[4]
g2 = dict(g1, ad="G05b", tur="tuketim", dizi=("sayac_oku", "tuketim"),
          istek=f"{g1['abone']} abonesinin bu donem tuketimi kac metrekup")
print("gorev kumesi:", {t: sum(g["tur"] == t for g in GOREV)
                        for t in ("bedel", "tuketim", "belge", "kayit")})
print(g1["abone"], "iki ayri soru:", [x[0] for x in ajan(g1)["iz"]],
      [x[0] for x in ajan(g2)["iz"]], "; arac cagrisi", CAGRI[0])
gorev kumesi: {'bedel': 6, 'tuketim': 8, 'belge': 7, 'kayit': 3}
A026 iki ayri soru: ['sayac_oku', 'tuketim', 'tarife'] ['sayac_oku', 'tuketim'] ; arac cagrisi 5

Aynı abonenin sayacı iki kez okundu. İkinci sorunun ilk iki adımı birincinin birebir tekrarıdır; beş araç çağrısının ikisi yeni bilgi getirmiyor. Kayıp döngünün kusuru değil, kalıcı bir yazma yerinin olmamasıdır.

Üç Yazma Politikası

Ajan döngüsünün tek farkı, başlangıç durumunun bellekten gelmesi ve çıktısı bilinen adımın atlanmasıdır.

PLAN = {"bedel": (("sayac_oku", "tuketim", "tarife"),
                  "{a} abonesinin bu donem bedeli nedir"),
        "tuketim": (("sayac_oku", "tuketim"),
                    "{a} abonesinin bu donem tuketimi kac metrekup"),
        "belge": (("belge_ara",), "sayac donusunde endeks farki nasil hesaplanir"),
        "kayit": (("sayac_oku", "tuketim", "tarife", "kayit_yaz"),
                  "{a} abonesinin bedelini hesapla ve kayda yaz")}
TUR = ("bedel", "tuketim", "belge", "kayit")
CIKTI = {"sayac_oku": ("onceki", "simdiki", "tip", "bolge"), "tuketim": ("m3",),
         "tarife": ("tutar",), "belge_ara": ("kod",)}
SONUC = {"tuketim": "m3", "tarife": "tutar", "belge_ara": "kod"}


def sonraki_kume(n=48):
    """Ayni abonelere sorulan YENI sorular; recete GOREV ile birebir ayni."""
    k = []
    for i in range(n):
        r = uretec(TOHUM + 7919 * (i + 101))
        ab = GOREV[int(r() * 24)]["abone"]
        t = TUR[ayrik(r(), [0.30, 0.22, 0.20, 0.28])]
        k.append({"ad": f"H{i + 1:02d}", "tur": t, "abone": ab,
                  "dizi": PLAN[t][0], "istek": PLAN[t][1].format(a=ab)})
    return k


def geri_cagir(bellek, istek):
    """Tek okuma: ortak belirteci en cok olan, esitlikte en son yazilan kayit."""
    b, en, kayit = set(belirtecle(istek)), 0, None
    for metin, alanlar in bellek:
        o = len(b & set(belirtecle(metin)))
        if o >= en and o > 0:
            en, kayit = o, alanlar
    return kayit


def ajan_b(g, bellek, tohum=TOHUM, en_cok_adim=8):
    """Ortak dongunun tek farki: baslangic durumu bellekten gelir ve
    ciktisi zaten bilinen adim atlanir."""
    r = uretec(tohum ^ izno(g["ad"]))
    kayit = geri_cagir(bellek, g["istek"])
    c = {"adim": 0, "okundu": kayit is not None, "alan": len(kayit or {}),
         "kayit": [], "yolda": {}}
    alan = {"abone": g["abone"], "anahtar": g["istek"], "sutun": "bedel"}
    alan.update(kayit or {})
    if "sonuc" in alan:
        return dict(c, yanit=alan["sonuc"])
    adim, k, dizi = 0, 0, g["dizi"]
    while k < len(dizi) and dizi[k] in CIKTI and all(x in alan for x in CIKTI[dizi[k]]):
        alan["sonuc"] = alan.get(SONUC.get(dizi[k]), alan.get("sonuc"))
        k += 1
    if k == len(dizi):
        return dict(c, yanit=alan.get("sonuc"))
    while adim < en_cok_adim:
        adim += 1
        hedef = dizi[k] if k < len(dizi) else None
        if hedef is None:
            if r() < 0.88:
                break
            sec = ARAC_ADI[int(r() * len(ARAC_ADI))]
        else:
            sec = hedef if r() < gorme(k + 1) else ARAC_ADI[int(r() * len(ARAC_ADI))]
        if sec == "kayit_yaz":
            alan["deger"] = alan.get("sonuc")
        s = cagir_arac(sec, alan)
        gozlem = {x: s[x] for x in CIKTI.get(sec, ()) if x in s}
        c["kayit"].append(gozlem)
        if "hata" in s:
            continue
        alan.update({kk: vv for kk, vv in s.items() if kk != "hata"})
        if sec in SONUC:
            alan["sonuc"] = s[SONUC[sec]]
        if sec == hedef:
            c["yolda"].update(gozlem)
            k += 1
    return dict(c, adim=adim, yanit=alan.get("sonuc"))


def kosum(politika, tohum=TOHUM, n=48):
    """Once ilk kume kosulur ve politikaya gore yazilir, sonra yeni kume."""
    bellek = []
    for g in GOREV:
        s = ajan_b(g, [], tohum)
        ah = g["istek"] if g["tur"] == "belge" else g["abone"]
        yaz = (s["kayit"] if politika == "her adim" else [s["yolda"]]
               if politika == "secici" else [{"sonuc": s["yanit"]}]
               if politika == "yalniz sonuc" else [])
        bellek += [(ah + " " + " ".join(f"{x} {v}" for x, v in a.items()), a)
                   for a in yaz if None not in a.values()]
    CAGRI[0] = 0
    adim = dogru = okuma = isabet = alan = 0
    for g in sonraki_kume(n):
        s = ajan_b(g, bellek, tohum)
        d = s["yanit"] == dogru_yanit(g)
        adim, dogru, okuma = adim + s["adim"], dogru + d, okuma + s["okundu"]
        alan, isabet = alan + s["alan"], isabet + (d and s["okundu"])
    return (len(bellek), okuma, alan, isabet / max(okuma, 1), adim, CAGRI[0], dogru / n)


POL = ("belleksiz", "her adim", "yalniz sonuc", "secici")
print("politika       kayit okuma alan  isabet  adim cagri basarim | 2. kosum")
for p in POL:
    a, b = kosum(p), kosum(p, TOHUM + 1)
    print(f"{p:<14} {a[0]:>5} {a[1]:>5} {a[2]:>4} {a[3]:>7.4f} {a[4]:>5} {a[5]:>5}"
          f"  {a[6]:>6.4f} | {b[4]:>4} adim  {b[6]:.4f}")
politika       kayit okuma alan  isabet  adim cagri basarim | 2. kosum
belleksiz          0     0    0  0.0000   212   166  0.9167 |  222 adim  0.8958
her adim          74    47   99  0.8936   168   132  0.8958 |  176 adim  0.8542
yalniz sonuc      24    45   45  0.5556    13    10  0.5833 |   14 adim  0.6250
secici            24    47  166  0.8511    94    74  0.8542 |   96 adim  0.8958

Taban çizgisi 48 görevi 212 adım ve 166 araç çağrısıyla bitiriyor, başarım 0,9167. Üç politika bu satırın üstüne kurulur.

Yalnız sonuç en çarpıcı satırdır. 24 kayıtla 212 adımı 13’e indiriyor, yani 199 adım kazandırıyor; araç çağrısı 166’dan 10’a düşüyor. Ama başarım 0,5833’e iniyor. Nedeni şudur: kayıt, abone koduyla anahtarlanmış bir yanıttır, oysa yanıt bir soruya aittir. Abonenin tüketim yanıtı saklanır, sonraki görev aynı abonenin bedelini sorar; değer doğru, soru başkadır.

Her adım politikası 74 kayıt biriktiriyor, üç katı, ve yalnızca 44 adım kazandırıyor (212’den 168’e). Sebep okuma sütununda görünür: 47 okumanın getirdiği toplam alan 99, okuma başına iki alan. Her adımın gözlemi ayrı bir kayıt olduğu için tek okuma tek adımın çıktısını getiriyor. Seçici politika aynı 24 kayıtla 118 adım kazandırıyor (212’den 94’e) ve 47 okumada 166 alan getiriyor; plana giren gözlemler tek kayıtta birleştiği için bir okuma bütün ön koşulları taşıyor.

Kayıt Sayısı Değil Kaydın Birimi

Tablonun iki sıralaması çakışmıyor. Kayıt sayısına göre en cömert politika her adımdır, kazanılan adıma göre yalnız sonuçtur; seçici ise her adımın üçte biri kadar kayıtla onun 2,68 katı adım kazandırıyor. Belirleyici olan kaç kayıt yazıldığı değil, bir kaydın hangi birimi kapsadığıdır: bir adım mı, bir görev mi, bir varlığın bütün alanları mı.

Hangi farkın bulgu sayılacağını ikinci koşum söylüyor. Taban çizgisi 0,9167 ve 0,8958 veriyor, iki koşum farkı 0,0417. Yalnız sonucun kaybı iki koşumda 0,3334 ve 0,2708, ikisi de bandın çok üstünde ve ölçülmüştür. Seçicinin kaybı ise bir koşumda 0,0625, ötekinde 0,0000; bandın etrafında salınıyor ve ölçülmemiş sayılır — 118 adımlık kazancın bir başarım bedeli olduğu bu kurulumda gösterilemedi.

Kural sadedir: belleğe soruya bağlı bir yanıt yazmak, o yanıtı soru değiştiğinde yanlış hâle getirir. Yazılması gereken şey sorudan bağımsız gözlemdir — sayaç okuması, abone tipi, belge kodu. Yanıtın her görevde yeniden üretilmesi, yanlış yanıttan ucuzdur.

Özet

  • Döngü bittiğinde kısa süreli bellek silinir; aynı abonenin sayacı sonraki soruda yeniden okunur.
  • Ölçülen şey erişim değil yazma kararıdır: aynı geri çağırma düzeneğiyle üç politika üç ayrı sonuç veriyor.
  • Yalnız sonuç 24 kayıtla 199 adım kazandırıyor ama başarımı 0,9167’den 0,5833’e düşürüyor; kayıp iki koşum farkının sekiz katıdır ve ölçülmüştür.
  • Her adım 74 kayıtla 44, seçici 24 kayıtla 118 adım kazandırıyor; okuma başına gelen alan 99’a karşı 166’dır.
  • Kayıt sayısı değil kaydın birimi belirleyicidir; soruya bağlı yanıt yerine gözlem yazmak yanlış yanıtı ortadan kaldırır.

Sonraki Adım

Bu ders belleği görevler arasında ele aldı. Görev içinde sorun tersine döner: bağlam silinmiyor, büyüyor, ve pencere dolduğunda bir şeyin atılması gerekiyor. Atma kararı yazma kararının aynasıdır. Sonraki ders sıkıştırmanın iki yolunu ölçer: gözlemleri özetlemek ve yalnız ilgili olanı tutmak. Sıkıştırma oranı arttıkça taşınan belirteç düşer, ama düşen her alan bir sonraki adımın girdisi olabilir. Ölçülecek olan bu ikisidir: kazanılan belirteç ve atılan alanın gerektiği görev sayısı.

İ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