Ders 08 / 22
İstem Yinelemesi
Ölçerek iyileştirme döngüsünün kendisi ölçü altına alınıyor. On aday değişiklik 30 kayıtlık bir doğrulama kümesinde sekiz yineleme boyunca aç gözlü aranıyor: doğrulama isabeti 0,4000'den 1,0000'a çıkıyor ve beşinci yinelemede tavana vuruyor, sınama isabeti aynı noktada 0,9333 ile en yükseğine ulaşıp sekizinci yinelemede 0,8111'e iniyor. Doğrulamadaki iki koşum farkının ortalaması 0,1037, adım kazancının ortalaması 0,0625: sekiz yinelemenin yalnızca ikisi kendi ölçüm gürültüsünden büyük. Arama başka bir koşumda tekrarlandığında sekiz adımın yalnız biri aynı yerde aynı değişikliği seçiyor. Bedel 2640 çağrıdır ve seçilen sekiz değişiklikten üçü görevle ilgisizdir.
İçindekiler
Önceki dört derste dört tasarım kararı ölçüldü ve her biri tek başına, bir defada denendi. Gerçek bir istem böyle yazılmaz. Bir istem yazılır, ölçülür, bir yeri değiştirilir, yeniden ölçülür; bu döngü sayı iyileşmez olana kadar sürer. Döngünün adı istem yinelemesidir ve bu ders döngünün kendisini ölçü altına alır.
Ölçü altına almak, önceki müfredatın Makine Öğrenmesine Giriş kursunda kurulmuş bir ayrımı buraya taşımak demektir: bir sayıya bakarak karar veriyorsan, o sayı artık senin karar verdiğin kümenin sayısıdır ve genel başarımı temsil etmez. Orada bu ayrım eğitim, doğrulama ve sınama kümesiyle kuruldu. Burada model eğitilmiyor, istem aranıyor; ama ayrım aynı ayrımdır. Her yinelemede bakılan küme doğrulama, hiç bakılmayan küme sınamadır.
- IT61. Model bir benzeticidir, tohumu 20260218’dir ve gerçek bir uç nokta çağrılmaz. Destek talepleri kurgudur.
- IT62. 120 kurgu talep ikiye ayrılır: 30 kayıt doğrulama, 90 kayıt sınama. Arama yalnız doğrulamayı görür; sınama hiçbir karara girmez.
- IT63. On aday değişiklik vardır. Beşi görevle ilgilidir (etiket kümesi, biçim kısıtı, iki örnek, iki örnek daha, olumlu bildirim), beşi ilgisizdir (nazik giriş, kısa yaz, teşekkür, not satırı, okuyucu notu). İlgisiz olanlar istemin yalnız metnini değiştirir.
- IT64. Arama aç gözlüdür: her yinelemede kalan bütün adaylar doğrulamada denenir, en iyi sayıyı veren seçilir ve isteme kalıcı olarak eklenir.
- IT65. Bedel çağrı sayısıyla yazılır. Denenen her aday, doğrulama kümesi büyüklüğü kadar çağrı harcar ve bu çağrılar geri alınamaz.
Sekiz Yinelemenin İki Sayısı
# BENZETICI -- KURGUDUR. Gercek bir model uc noktasi cagrilmaz; standart kitaplikla # yazilmis bir dil modeli benzeticisidir. Talepler de kurgudur. import math TOHUM, M32 = 20260218, 0xFFFFFFFF PENCERE, EN_UZUN = 240, 24 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): # KURGU belirtecleyici: parca en cok bes damga b = [] for s in 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 m: h = ((h ^ ord(c)) * 16777619) & M32 return h KONU = ["fatura", "ariza", "sayac", "tarife", "kesinti"] KALIP = {"fatura": ["bu ayki fatura tutari gecen aya gore cok yuksek geldi", "faturami odedim ama sistemde borc gorunuyor", "fatura ayrintisini nereden gorebilirim"], "ariza": ["evde su akmiyor bir ariza var galiba", "baglanti bozuk oldu ve hic calismiyor", "ariza kaydi actim ama ekip gelmedi"], "sayac": ["sayac okumasi yanlis girilmis endeks tutmuyor", "sayac degisimi icin randevu istiyorum", "sayac uzerindeki endeks ile fatura ayni degil"], "tarife": ["hangi tarife basamagindayim ogrenmek istiyorum", "tarife degisikligi icin ne yapmam gerekiyor", "birim ucret abone tipine gore degisiyor mu"], "kesinti": ["mahallede kesinti var ne zaman gelecek", "planli kesinti duyurusu nereden takip edilir", "aksamdan beri kesinti yasiyoruz"]} EK = ["ayrica gecen ay da ayni sorun olmustu", "bu konuda memnun degilim", "acil bilgi almam gerekiyor", "kayit numaram elimde yok"] TALEP = [] for i in range(120): r = uretec(TOHUM + i) k = KONU[ayrik(r(), [0.24, 0.22, 0.18, 0.20, 0.16])] m = KALIP[k][int(r() * 3)] if r() < 0.34: m += " " + EK[int(r() * 4)] TALEP.append({"no": 4001 + i, "metin": m, "konu": k}) KAVRAM = KONU + ["odeme", "sikayet", "bilgi", "genel"] IZ = {"fatur": "fatura", "tutar": "fatura", "ayrin": "fatura", "ariza": "ariza", "bozuk": "ariza", "calis": "ariza", "akmiy": "ariza", "sayac": "sayac", "endek": "sayac", "okuma": "sayac", "tarif": "tarife", "birim": "tarife", "abone": "tarife", "basam": "tarife", "kesin": "kesinti", "duyur": "kesinti", "mahal": "kesinti", "borc": "odeme", "odedi": "odeme", "ucret": "odeme", "memnu": "sikayet", "sorun": "sikayet", "acil": "sikayet", "bilgi": "bilgi", "ogren": "bilgi", "nered": "bilgi"} TUZAK = {"degis": "tarife", "kayit": "ariza", "yukse": "tarife", "gorun": "fatura", "ekip": "kesinti", "takip": "tarife", "giril": "fatura"} SERBEST = ["talebiniz {k} konusuyla ilgili gorunuyor", "bu kayit {k} basligina girer , ilgili ekibe yonlendirildi", "kaydiniz alindi , konuyu inceleyip donus yapacagiz"] SAYAC = [0] def coz(istem): ust, _, talep = istem.partition("Talep : ") o = [] for parca in ust.split("Ornek : ")[1:]: m, _, e = parca.partition(" => ") o.append((m.strip(), e.split(" .")[0].strip())) return o, talep def cagir(istem, tohum=TOHUM, sicaklik=0.6, en_uzun=EN_UZUN): SAYAC[0] += 1 bel = belirtecle(istem) bos = {"giris": len(bel), "cikis": 0, "yanit": ""} if len(bel) > PENCERE: return dict(bos, durum="baglam_asimi") if SAYAC[0] % 37 == 0: return dict(bos, durum="hiz_siniri") r = uretec(tohum ^ izno(istem)) ornek, talep = coz(istem) bt = belirtecle(talep) aday = [k for k in KAVRAM if k[:5] in bel] if len(aday) < 3: aday = KAVRAM p = {k: 0.15 for k in aday} for t in bt: for tablo, w in ((IZ, 1.0), (TUZAK, 1.3)): if tablo.get(t) in p: p[tablo[t]] += w for j, (m, e) in enumerate(ornek): if e in p: w = 0.5 + (j + 1) / len(ornek) for t in set(belirtecle(m)): if t in bt: p[e] += 0.30 * w e = [math.exp(p[a] / sicaklik) for a in sorted(p)] k = sorted(p)[ayrik(r(), [v / sum(e) for v in e])] y = (f"etiket : {k}" if "bicim" in bel else SERBEST[ayrik(r(), [0.42, 0.26, 0.32])].format(k=k)) cb = belirtecle(y) if len(cb) > en_uzun: cb, y = cb[:en_uzun], " ".join(cb[:en_uzun]) return {"durum": "tamam", "giris": len(bel), "cikis": len(cb), "yanit": y} def oku(y): for s in y.lower().split(): if s in KONU: return s return None DOGRULAMA, SINAMA = TALEP[:30], TALEP[30:] # 30 dogrulama , 90 sinama TABAN = "Su destek talebini yanitla . " DEGISIKLIK = [ ("etiket kumesi", "Talebi su etiketlerden birine ata : fatura , ariza , sayac , " "tarife , kesinti . "), ("bicim kisiti", "Yanitin bicimi : etiket : <deger> . "), ("iki ornek", "Ornek : fatura ayrintisini nereden gorebilirim => fatura . " "Ornek : ariza kaydi actim ama ekip gelmedi => ariza . "), ("iki ornek daha", "Ornek : sayac okumasi yanlis girilmis endeks tutmuyor => sayac . " "Ornek : hangi tarife basamagindayim ogrenmek istiyorum => tarife . "), ("olumlu bildirim", "Yanitinda yalnizca konu etiketi olsun . "), ("nazik giris", "Lutfen dikkatli davran . "), ("kisa yaz", "Yanitini kisa tut . "), ("tesekkur", "Tesekkurler . "), ("not satiri", "Not : kayit sistemine islenecek . "), ("okuyucu notu", "Yanit destek ekibi tarafindan okunacak . "), ] def olc(parcalar, kume, tohum=TOHUM): SAYAC[0] = 0 d = 0 for x in kume: s = cagir(TABAN + "".join(parcalar) + "Talep : " + x["metin"], tohum=tohum) d += oku(s["yanit"]) == x["konu"] return d / len(kume), SAYAC[0] def ara(tohum, adim=8): """Her yinelemede butun adaylari DOGRULAMA uzerinde dener, en iyisini secer.""" secili, kalan, cagri, iz = [], list(DEGISIKLIK), 0, [] for _ in range(adim): en, ad = None, None for a, parca in kalan: v, c = olc(secili + [parca], DOGRULAMA, tohum) cagri += c if en is None or v > en: en, ad = v, (a, parca) secili.append(ad[1]) kalan = [x for x in kalan if x[0] != ad[0]] dv, c1 = olc(secili, DOGRULAMA, tohum) sv, c2 = olc(secili, SINAMA, tohum) cagri += c1 + c2 iz.append((ad[0], dv, sv, cagri)) return iz d0, c0 = olc([], DOGRULAMA) s0, c1 = olc([], SINAMA) print("yineleme secilen degisiklik dogrulama sinama ayrisma toplam cagri") print(f"{0:>8} {'-':<20} {d0:>9.4f} {s0:.4f} {d0 - s0:+.4f} {c0 + c1:>12}") IZLEK = ara(TOHUM) for i, (ad, dv, sv, cg) in enumerate(IZLEK, 1): print(f"{i:>8} {ad:<20} {dv:>9.4f} {sv:.4f} {dv - sv:+.4f} {cg + c0 + c1:>12}")
yineleme secilen degisiklik dogrulama sinama ayrisma toplam cagri
0 - 0.4000 0.3778 +0.0222 120
1 not satiri 0.7000 0.5889 +0.1111 540
2 bicim kisiti 0.8000 0.5889 +0.2111 930
3 iki ornek 0.8333 0.8556 -0.0222 1290
4 etiket kumesi 0.9667 0.8556 +0.1111 1620
5 olumlu bildirim 1.0000 0.9333 +0.0667 1920
6 kisa yaz 0.9667 0.9111 +0.0556 2190
7 iki ornek daha 0.9667 0.8667 +0.1000 2430
8 tesekkur 0.9000 0.8111 +0.0889 2640
Doğrulama sütunu bir arama kaydının olağan görüntüsüdür: 0,4000’den 1,0000’a, kesintisiz yükseliş. Bu sütuna bakan biri sekiz yinelemede istemi tam isabetli hâle getirdiğini söyler. Sınama sütunu aynı hikâyeyi anlatmıyor. En yüksek sınama sayısı 0,9333 ve beşinci yinelemede geliyor; sonraki üç yineleme onu 0,8111’e indiriyor. Beşinci yinelemeden sonra yapılan her değişiklik doğrulamayı korumak için seçildi ve sınamada zarar verdi.
Ayrışma sütunu iki kümenin arasındaki farkı taşıyor. Başlangıçta +0,0222, yani iki küme neredeyse aynı şeyi söylüyor. İkinci yinelemede +0,2111’e çıkıyor: doğrulama 0,8000 derken sınama hâlâ 0,5889. Bu noktada doğrulamaya bakarak verilen her karar, kendisiyle ilgisi olmayan bir küme hakkında konuşuyor. Ayrışmanın kaynağı kümenin küçüklüğüdür — otuz kayıtta bir kaydın düzelmesi sayıyı 0,0333 oynatır ve üç kaydın rastgele düzelmesi bir iyileştirme gibi görünür.
Birinci satır bunun en açık örneğidir. Aramanın ilk seçtiği değişiklik not satırıdır: göreve hiçbir bilgi eklemeyen, etiket kümesinden, biçimden ve örnekten söz etmeyen bir cümle. Doğrulamada +0,3000 getirdi ve bütün arama boyunca ölçülen en büyük tek adım kazancı oldu. Sekiz değişiklikten üçü bu türdendir. Aç gözlü arama, sayıyı yükselten şeyi seçer; sayıyı niçin yükselttiğini sormaz.
Aramanın Kendi Güvenilirliği
IKINCI = ara(TOHUM + 1) print("ayni arama , baska kosum") for i, ((a1, *_), (a2, d2, s2, _)) in enumerate(zip(IZLEK, IKINCI), 1): print(f"{i:>2} {a1:<18} -> {a2:<18} dogrulama {d2:.4f} sinama {s2:.4f}") print(f"iki aramanin ayni sirada sectigi degisiklik: " f"{sum(a == b for (a, *_), (b, *_) in zip(IZLEK, IKINCI))}/8") sec, fd, fs = [], [], [] for ad, *_ in [(None,)] + IZLEK: if ad: sec.append(dict(DEGISIKLIK)[ad]) fd.append(abs(olc(sec, DOGRULAMA)[0] - olc(sec, DOGRULAMA, TOHUM + 1)[0])) fs.append(abs(olc(sec, SINAMA)[0] - olc(sec, SINAMA, TOHUM + 1)[0])) gd = sum(fd) / len(fd) print(f"\niki kosum farki -- dogrulama (30 kayit) ortalama {gd:.4f} , en buyuk {max(fd):.4f}") print(f"iki kosum farki -- sinama (90 kayit) ortalama {sum(fs) / len(fs):.4f} ," f" en buyuk {max(fs):.4f}") dv, sv = [d0] + [x[1] for x in IZLEK], [s0] + [x[2] for x in IZLEK] adim = [dv[i] - dv[i - 1] for i in range(1, 9)] print(f"adim kazanci iki kosum farkindan buyuk olan yineleme: " f"{sum(x > gd for x in adim)}/8 , adim kazanci ortalamasi {sum(adim) / 8:+.4f}") print(f"\ndogrulama en yuksek {max(dv):.4f} ({dv.index(max(dv))}. yineleme) ," f" sinama en yuksek {max(sv):.4f} ({sv.index(max(sv))}. yineleme)") print(f"5 -> 8 : dogrulama {dv[5]:.4f} -> {dv[8]:.4f} , sinama {sv[5]:.4f} -> {sv[8]:.4f}") print(f"ayrisma en buyuk {max(d - s for d, s in zip(dv, sv)):+.4f} , 8. yinelemede " f"{dv[8] - sv[8]:+.4f}") ilgisiz = ("nazik giris", "kisa yaz", "tesekkur", "not satiri", "okuyucu notu") print(f"arama bedeli {IZLEK[-1][3] + c0 + c1} cagri , secilen sekiz degisiklikten " f"{sum(a in ilgisiz for a, *_ in IZLEK)} tanesi gorevle ilgisiz")
ayni arama , baska kosum 1 not satiri -> kisa yaz dogrulama 0.7000 sinama 0.5667 2 bicim kisiti -> etiket kumesi dogrulama 0.6333 sinama 0.4444 3 iki ornek -> bicim kisiti dogrulama 0.7667 sinama 0.7333 4 etiket kumesi -> iki ornek dogrulama 0.9667 sinama 0.8778 5 olumlu bildirim -> nazik giris dogrulama 0.9667 sinama 0.9111 6 kisa yaz -> not satiri dogrulama 0.8667 sinama 0.7111 7 iki ornek daha -> iki ornek daha dogrulama 0.9000 sinama 0.8889 8 tesekkur -> okuyucu notu dogrulama 0.9333 sinama 0.8333 iki aramanin ayni sirada sectigi degisiklik: 1/8 iki kosum farki -- dogrulama (30 kayit) ortalama 0.1037 , en buyuk 0.1667 iki kosum farki -- sinama (90 kayit) ortalama 0.0728 , en buyuk 0.1778 adim kazanci iki kosum farkindan buyuk olan yineleme: 2/8 , adim kazanci ortalamasi +0.0625 dogrulama en yuksek 1.0000 (5. yineleme) , sinama en yuksek 0.9333 (5. yineleme) 5 -> 8 : dogrulama 1.0000 -> 0.9000 , sinama 0.9333 -> 0.8111 ayrisma en buyuk +0.2111 , 8. yinelemede +0.0889 arama bedeli 2640 cagri , secilen sekiz degisiklikten 3 tanesi gorevle ilgisiz
Üstteki çizelge aramayı aynı düzenekte, yalnız tohumu değiştirerek yeniden koşturuyor. Sekiz adımın yalnız biri aynı yerde aynı değişikliği seçiyor. İkinci koşum ilk adımda “kısa yaz”ı, ikinci adımda etiket kümesini seçiyor ve beşinci adımda “nazik giriş”e ulaşıyor. İki arama iki ayrı istem üretti; ikisi de kendi doğrulama kümesinde iyi görünüyor ve ikisi de aynı düzeneğin ürünü. Arama, aradığı şeyi değil, koşumu buluyor.
Alt bölüm bunun sayısını veriyor. Doğrulama kümesinde aynı istemin iki koşumu arasındaki fark ortalama 0,1037, en büyüğü 0,1667. Aramanın adım başına ortalama kazancı +0,0625. Sekiz yinelemenin yalnız ikisinde adım kazancı kendi ölçüm gürültüsünden büyük; kalan altı adım, kursun kuralına göre ölçülmemiş sayılır ve buna rağmen isteme kalıcı olarak eklendiler. Sınama kümesinde aynı fark ortalama 0,0728, yani üç kat büyük bir kümede ölçü gözle görülür biçimde daha durgun. Küçük doğrulama kümesi hem daha ucuzdur hem de aramanın kovalayacağı gürültüyü kendisi üretir.
Doyma noktası beşinci yinelemedir: doğrulama orada 1,0000’a vurur ve daha yükselemez, sınama da orada en yüksek değerini alır. Sonraki üç yineleme 720 ek çağrı harcayıp sınamayı 0,9333’ten 0,8111’e indiriyor. Aramanın toplam bedeli 2640 çağrıdır ve bu çağrıların büyük bölümü seçilmeyen adaylara gitti. Bir istem araması, bir ayar aramasıyla aynı yasaya tabidir: bütçe büyüdükçe doğrulamadaki kazanç sınamaya taşınmaz. Ölçülmeden değiştirilen istem bir iyileştirme değil bir tahmindir; ölçülen küme yanlışsa, ölçmek de tahmin etmektir.
Özet
- Aç gözlü arama sekiz yinelemede doğrulama isabetini 0,4000’den 1,0000’a çıkardı; sınama isabeti aynı sürede 0,3778’den en yüksek 0,9333’e çıkıp 0,8111’e indi.
- Kazanç beşinci yinelemede doydu. Sonraki üç yineleme 720 ek çağrı harcayıp sınamayı 0,1222 düşürdü; iki küme arasındaki ayrışma en büyük değerini ikinci yinelemede +0,2111 olarak aldı.
- Aramanın ilk ve en büyük adımı (+0,3000) görevle ilgisiz bir cümleden geldi; seçilen sekiz değişiklikten üçü göreve hiçbir bilgi eklemiyor.
- Doğrulamada iki koşum farkı ortalama 0,1037, adım kazancı ortalama +0,0625: sekiz yinelemenin yalnız ikisi kendi ölçüm gürültüsünden büyük. Sınamada aynı fark 0,0728.
- Aynı arama başka bir tohumla koşturulduğunda sekiz adımın yalnız biri aynı yerde aynı değişikliği seçiyor; toplam bedel 2640 çağrıdır.
Sonraki Adım
Sekiz derste istem bir tasarım nesnesine dönüştü. Bileşenlerine ayrıldı, kalıcı bir yönerge kazandı, rol ve talep düzeyinde açıldı, biçimi ve uzunluğu belirlendi, örnek aldı, kuralları olumlu yazıldı ve ölçülerek yinelendi. Her adımda değişen tek şey metin oldu ve her adımın bedeli belirteçle, çağrıyla ya da ihlalle yazıldı. Ortak yanları da açıktır: hepsi modele ne söyleneceğini düzenledi.
Hiçbiri modele nasıl düşüneceğini sormadı. Bu sekiz derste model her talebe tek bir hamlede yanıt verdi: istemi aldı, bir etiket seçti, bir cümle yazdı. Arada bir adım yoktu. Oysa iki fatura döneminin farkını hesaplayıp hangi tarifeye göre fazla ödendiğini bulmak gibi bir talep tek hamlede çözülecek bir şey değildir; birkaç ara adım ister ve o adımların modelin kendisi tarafından üretilmesi gerekir. Sonraki konu bunu ele alır ve ilk dersinde kursun ikinci iddiasını kurar: ara adım istemek belirteci katlar ve her görevde kazandırmaz. Aynı teknik çok adımlı bir hesapta kazandırırken tek adımlı bir sınıflandırmada bedeli artırıp sayıyı yerinde bırakır, ve ikisi de basılır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.