flowchart TD
L["Learner<br/>(model + veri + loss + optimizer)"]:::core
FIT["fit"]:::core
EPOCH["epoch"]:::core
BATCH["batch"]:::core
HOOK["callback çağrısı<br/>before_fit · before_batch · after_batch · ..."]:::core
RUN["run_cbs<br/>(getattr + sorted by order)"]:::core
CB["Callback<br/>(order'a göre)"]:::cb
DEV["DeviceCB (order -1)"]:::cb
COMP["CompletionCB (order 0)"]:::cb
MET["MetricCB (order 1)"]:::cb
CANCEL["Cancel exceptions<br/>(CancelFit · CancelEpoch · CancelBatch)"]:::cb
OC["açık/kapalı ilkesi<br/>çekirdek KAPALI · davranış AÇIK"]:::core
MINI["miniai<br/>= fast.ai çekirdeği sıfırdan"]:::mini
L --> FIT
FIT --> EPOCH
EPOCH --> BATCH
FIT -.-> HOOK
EPOCH -.-> HOOK
BATCH -.-> HOOK
HOOK --> RUN
RUN --> CB
CB --> DEV
CB --> COMP
CB --> MET
HOOK --> CANCEL
CB --> OC
OC --> MINI
classDef core fill:#cffafe,stroke:#0891b2,stroke-width:2px,color:#1e293b;
classDef cb fill:#ffe4e6,stroke:#e11d48,stroke-width:2px,color:#1e293b;
classDef mini fill:#ffe4e6,stroke:#e11d48,stroke-width:3px,color:#1e293b;
19 Ders 16 — Learner Çerçevesi (The Learner framework)
Temeller B’nin kalbi: esnek bir eğitim çerçevesi olan Learner’ı sıfırdan kurmak. Howard katı bir eğitim döngüsünden başlar (çalışır ama hiçbir yerine müdahale edilemez), onu callback’lerle genişletir — eğitimin her adımına (before/after fit/epoch/batch) çekirdek koda dokunmadan müdahale edebileceğimiz bir sistem — ve Cancel exception’larla akış kontrolünü callback’lere taşır. run_cbs callback’leri order’a göre sıralayıp getattr ile metotlarını çağırır; cb_ctx context manager before/after/cleanup’ı tek yapıda toplar. Tüm bu sistem miniai’dir: Ders 2’de kara kutu kullandığımız fastai Learner’ın sıfırdan kurulmuş, anlaşılır çekirdeği ve Part 2’nin (L17-25) eğitim altyapısı. Tek cümleyle: Learner eğitim döngüsünü yürütür; callback’ler ise o döngüye çekirdeğe dokunmadan müdahale eden, sınırsız esneklik veren eklentilerdir.
- Ders sayfası (video): course.fast.ai — Lesson 16: The Learner framework (~86 dk)
- Seri: Practical Deep Learning for Coders — Part 2, Ders 16
- Playlist: Part 2 — Foundations to Stable Diffusion (2022)
- Notebook: course22p2 — nbs/09_learner
- Okuma süresi: ~36 dk
- 🔗 Temeller B’nin kalbi (ETAP 5): Ders 15 convolution + autoencoder’ı kurup eğitim döngüsünü hâlâ elle yazmıştık. Ders 16 o döngüyü esnek bir Learner’a dönüştürür: callback’lerle her aşamaya müdahale. Burada fast.ai’nin (ve “miniai” mini-kütüphanesinin) çekirdeği sıfırdan doğar — L17-25’in tüm eğitim altyapısı.
19.1 Bu Derste Ne Var?
Temeller B’nin kalbi: esnek bir eğitim çerçevesi olan Learner’ı sıfırdan kurmak. Howard, katı bir eğitim döngüsünden başlayıp onu callback’lerle genişletir — eğitimin her adımına (fit/epoch/batch başında ve sonunda) müdahale edebileceğimiz bir sistem. Burada fast.ai’nin (ve “miniai” mini-kütüphanesinin) çekirdeği doğar.
Üç temel fikir bu dersin omurgasını kurar:
- Learner — model + veri + loss + optimizer’ı tek nesnede toplayan ve eğitim döngüsünü (fit → epoch → batch) yürüten yapı (basit Learner → callback’li Learner).
- Callback — eğitimin belirli noktalarına (
before_fit,after_batch, …) takılan, davranışı çekirdek koda dokunmadan değiştiren eklentiler (callback fikri → run_cbs). - Cancel exceptions — bir callback’in fit/epoch/batch’i temiz biçimde iptal etmesi (
CancelFitExceptionvb.); akış kontrolü (Cancel exceptions).
“Welcome to Lesson 16, where we are working on building our first flexible training framework: the Learner.” — Howard, 0:00
Şekil 28.1 bu yolculuğu tek bir yol haritasında birleştirir: üstte çekirdek döngü (Learner → fit → epoch → batch → callback çağrısı → run_cbs), ortada callback’ler (DeviceCB, CompletionCB, MetricCB — order’a göre) ve Cancel exception’lar, altta ise hepsinin vardığı yer: açık/kapalı ilkesi (çekirdek KAPALI, davranış AÇIK) ve onun ürünü olan miniai — fast.ai çekirdeği sıfırdan.
- Geriye (Ders 2/14): Ders 2’de fastai
Learner’ı kara kutu kullandık; burada sıfırdan kuruyoruz. Ders 14’ünnn.Module+ eğitim döngüsü üstüne. - İleriye (Ders 17-25): miniai Learner, init/norm (17), accelerated SGD (18) ve tüm diffusion eğitimlerinin (19-25) altyapısı; callback’ler her şeyi mümkün kılar.
- Tek cümle: Learner eğitim döngüsünü yürütür; callback’ler ise çekirdeğe dokunmadan o döngüye müdahale eden, sonsuz esneklik veren eklentilerdir.
19.2 1. Hedef: Esnek Eğitim Çerçevesi
Howard amacı koyar: ilk esnek eğitim framework’ünü (Learner) kurmak. Ders 14-15’te eğitim döngüsünü elle yazdık ama katıydı (her şey sabit). Şimdi her adımı özelleştirilebilir hâle getireceğiz. Hedefi baştan ortaya koymak, sonraki her adımın (callback, run_cbs, Cancel) neye hizmet ettiğini netleştirir.
“We are working on building our first flexible training framework: the Learner.” — Howard, 0:00
- Geriye (Ders 2): fastai
Learner’ın (Ders 2) sıfırdan, anlaşılır versiyonu — “yeniden kur, sonra kullan” kuralının doğrudan uygulaması. - Sezgi: “Esneklik” burada soyut bir slogan değil; somut bir hedef — eğitim döngüsünü değiştirmeden ona yeni davranış ekleyebilmek. Bu hedef, callback desenini kaçınılmaz kılar.
19.3 2. Basit (Esnek Olmayan) Learner
Önce katı bir Learner: fit epoch’larda döner, one_epoch DataLoader’daki batch’lerde döner, one_batch tahmin yapar, loss hesaplar, eğitimdeyse backward + optimizer adımı atar. Çalışır ama hiçbir yerine müdahale edemezsin.
class Learner:
def __init__(self, model, dls, loss_func, lr, opt_func=optim.SGD): fc.store_attr()
def one_batch(self):
self.preds = self.model(self.xb)
self.loss = self.loss_func(self.preds, self.yb)
if self.model.training:
self.loss.backward(); self.opt.step(); self.opt.zero_grad()“We’ve seen so far this Learner which wasn’t flexible at all, but it had all the basic pieces.” — Howard, 0:45
Şekil 19.2 iki tasarımı yan yana koyar: solda katı Learner (her şey — veri yükleme, cihaza taşıma, ölçüm, ilerleme çubuğu — tek gövdeye gömülü; yeni davranış = çekirdeği değiştir), sağda esnek Learner (sade, değişmez çekirdek + ayrı ayrı takılan callback’ler; yeni davranış = yeni callback). Alt şerit dersin tasarım ilkesini özetler: açık/kapalı.
Kod
fig, (axL, axR) = plt.subplots(1, 2, figsize=(11.5, 5.5))
# ----------------------------------------------------------------------------
# SOL — KATI Learner: tek blok, davranış çekirdeğe gömülü (kirlenir)
# ----------------------------------------------------------------------------
axL.set_xlim(0, 10); axL.set_ylim(0, 10); axL.axis("off")
axL.text(5, 9.5, "KATI Learner", ha="center", va="center",
fontsize=13, weight="bold", color=COL_CYAN_800)
# tek büyük blok — her şey içinde
boxed_node(axL, 5, 5.4, 7.6, 5.2,
"fit döngüsü\n— her şey gömülü —\n\nveri yükle · cihaza taşı\nölçüm hesapla · ilerleme çubuğu\n…hepsi tek gövdede…",
fc=COL_BG, ec=COL_PRIMARY, tc=COL_TEXT, fontsize=10, lw=2.2)
# rose uyarı kutusu
boxed_node(axL, 5, 1.5, 8.0, 1.7,
"yeni davranış = çekirdeği DEĞİŞTİR\n(gövde kirlenir, kırılma riski)",
fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_ACCENT, fontsize=10, lw=2.2)
arrow_between(axL, (5, 2.85), (5, 2.40), color=COL_ACCENT, lw=2.0)
# ----------------------------------------------------------------------------
# SAĞ — ESNEK Learner: sade çekirdek + takılan callback'ler
# ----------------------------------------------------------------------------
axR.set_xlim(0, 10); axR.set_ylim(0, 10); axR.axis("off")
axR.text(5, 9.5, "ESNEK Learner", ha="center", va="center",
fontsize=13, weight="bold", color=COL_CYAN_800)
# sade çekirdek (değişmez)
boxed_node(axR, 2.7, 5.6, 3.8, 3.2,
"sade çekirdek\ndöngü\n(DEĞİŞMEZ)",
fc=COL_BG, ec=COL_PRIMARY, tc=COL_TEXT, fontsize=10.5, lw=2.4)
# ayrı callback kutuları (rose) — çekirdeğe takılı
cbs = [("DeviceCB", 7.6), ("MetricCB", 5.6), ("ProgressCB", 3.6)]
for name, yc in cbs:
boxed_node(axR, 7.4, yc, 3.2, 1.35, name,
fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_ACCENT, fontsize=10.5, lw=2.0)
arrow_between(axR, (4.6, 5.6), (5.8, yc), color=COL_ACCENT, lw=1.8,
connectionstyle="arc3,rad=0.12")
# yeni davranış vurgusu
boxed_node(axR, 5, 1.4, 8.6, 1.6,
"yeni davranış = yeni callback\n(çekirdeğe dokunma)",
fc=COL_CYAN_50, ec=COL_CYAN_700, tc=COL_CYAN_800, fontsize=10.5, lw=2.0)
# ----------------------------------------------------------------------------
# Açık/kapalı ilkesi — alt vurgu (figür geneli)
# ----------------------------------------------------------------------------
fig.text(0.5, 0.015,
"açık/kapalı ilkesi: çekirdek KAPALI (değişime) · davranış AÇIK (genişlemeye)",
ha="center", va="bottom", fontsize=11, weight="bold", color=COL_CYAN_700)
plt.tight_layout(rect=(0, 0.045, 1, 1))
plt.show()
- Geriye (Ders 5/14):
loss.backward()+opt.step()+opt.zero_grad()= Ders 5/14’ün eğitim adımı; artık bir nesnenin metodu. - Sezgi: Bu basit Learner “doğru parçalara” (model, veri, loss, optimizer, döngü) sahip — eksik olan tek şey esneklik. Çalışan ama katı bir temelden başlamak, esnekliğin tam olarak neyi çözdüğünü gösterir.
19.4 3. Neden Esnek Değil?
Sorun: bu döngüye yeni bir davranış eklemek (örn. GPU’ya taşı, metrik hesapla, erken durdur) için çekirdek kodu değiştirmen gerekir. Her yeni ihtiyaç kodu kirletir ve kırılma riskini artırır. Çözüm: döngüyü değiştirmeden müdahale edebileceğin kancalar (hooks). Şekil 19.2’ın sol panelindeki “çekirdeği DEĞİŞTİR” uyarısı tam bu sorunu işaret eder.
- İleriye: “Çekirdeğe dokunmadan genişlet” = açık/kapalı ilkesi (open-closed); callback’ler bunu sağlar — §15.
- Sezgi: Her yeni özelliği
if’lerle çekirdeğe eklersen, döngü zamanla okunamaz hâle gelir ve bir değişiklik beklenmedik yan etkiler doğurur. “Değiştirilemez çekirdek” bir kısıt değil, bir koruma — bozulamayan bir temel.
19.5 4. Callback Fikri
Callback: eğitimin belirli noktalarına (before_fit, after_batch, before_epoch, …) takılan bir nesne. Learner bu noktalara geldiğinde, kayıtlı tüm callback’lerin o isimli metodunu çağırır. Böylece davranış, çekirdek döngüye dokunmadan eklenir.
“We first of all call self.callback passing in ‘before_fit’.” — Howard, 0:45
Şekil 19.3 callback kancalarının nereye takıldığını gösterir (FLAGSHIP): iç içe çekirdek döngüler (fit → for epoch → for batch → one_batch) cyan ile sabittir; her seviyenin başında before_*, sonunda after_* kancası vardır; rose callback’ler (DeviceCB → before_batch, MetricCB → after_batch) bu kancalara takılır. Çekirdek döngü hiç değişmez; davranış kancalardan akar.
Kod
fig, ax = plt.subplots(figsize=(12.5, 6.5))
ax.set_xlim(0, 12.5)
ax.set_ylim(0, 6.5)
ax.axis("off")
ax.set_facecolor(COL_WHITE)
# ---------------------------------------------------------------------------
# İç içe döngü çerçeveleri (cyan, çekirdek döngü — SABİT)
# fit > for epoch > for batch > one_batch
# Her seviye bir kutu; before/after kancaları rose etiketlerle üst/alt kenarda.
# ---------------------------------------------------------------------------
loop_frames = [
# (x_merkez, y_merkez, w, h, başlık, before, after)
(4.3, 3.45, 6.4, 5.4, "fit (en dış)", "before_fit", "after_fit"),
(4.3, 3.30, 5.3, 4.2, "for epoch", "before_epoch", "after_epoch"),
(4.3, 3.15, 4.2, 3.0, "for batch", "before_batch", "after_batch"),
]
for (cx, cy, w, h, title, before, after) in loop_frames:
# çekirdek döngü kutusu (cyan çerçeve, açık cyan dolgu)
boxed_node(ax, cx, cy, w, h, "", fc=COL_CYAN_50, ec=COL_PRIMARY,
lw=2.2, zorder=2)
# seviye başlığı sol-üst köşede
ax.text(cx - w / 2 + 0.18, cy + h / 2 - 0.26, title, ha="left", va="center",
fontsize=10.5, color=COL_CYAN_800, weight="bold", zorder=4)
# before_* kancası — üst kenar (rose)
ax.text(cx + w / 2 - 0.18, cy + h / 2 - 0.26, before, ha="right", va="center",
fontsize=9.0, color=COL_ACCENT, weight="bold", style="italic", zorder=4)
# after_* kancası — alt kenar (rose)
ax.text(cx + w / 2 - 0.18, cy - h / 2 + 0.26, after, ha="right", va="center",
fontsize=9.0, color=COL_ACCENT, weight="bold", style="italic", zorder=4)
# ---------------------------------------------------------------------------
# En iç: one_batch çekirdeği (preds -> loss -> backward -> step) — SABİT cyan
# ---------------------------------------------------------------------------
core_y = 2.55
core_steps = ["preds", "loss", "backward", "step"]
cw, cgap = 0.92, 0.28
start_x = 4.3 - (len(core_steps) * cw + (len(core_steps) - 1) * cgap) / 2 + cw / 2
core_centers = []
for i, s in enumerate(core_steps):
x = start_x + i * (cw + cgap)
boxed_node(ax, x, core_y, cw, 0.62, s, fc=COL_BG, ec=COL_CYAN_700,
tc=COL_CYAN_800, fontsize=9.0, lw=1.8, zorder=5)
core_centers.append((x, core_y))
for (x0, y0), (x1, y1) in zip(core_centers[:-1], core_centers[1:]):
arrow_between(ax, (x0, y0), (x1, y1), color=COL_CYAN_700, lw=1.8,
mutation_scale=12, shrink=8, zorder=4)
ax.text(4.3, core_y + 0.62, "one_batch (çekirdek)", ha="center", va="bottom",
fontsize=8.5, color=COL_CYAN_700, weight="bold", style="italic", zorder=5)
# ---------------------------------------------------------------------------
# Yan panel: callback'ler kancalara takılır (rose kutular + ok)
# ---------------------------------------------------------------------------
cb_x = 9.9
callbacks = [
(5.05, "DeviceCB", "before_batch'te\nGPU'ya taşı", (7.5, 4.4)),
(3.05, "MetricCB", "after_batch'te\nbiriktir", (7.5, 2.5)),
]
for (cy, name, desc, hook_pt) in callbacks:
boxed_node(ax, cb_x, cy, 3.6, 1.05, name + "\n" + desc,
fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_TEXT,
fontsize=8.8, lw=2.0, zorder=6)
# callback -> ilgili kancaya ok (rose, kesik etki)
arrow_between(ax, (cb_x - 1.8, cy), hook_pt, color=COL_ROSE_500, lw=1.8,
mutation_scale=14, shrink=6,
connectionstyle="arc3,rad=-0.18", zorder=5)
# ---------------------------------------------------------------------------
# Açıklama notu (annotate): çekirdek koda dokunmadan müdahale
# ---------------------------------------------------------------------------
ax.text(6.25, 0.42,
"callback'ler çekirdek koda DOKUNMADAN her aşamaya (before/after) müdahale eder",
ha="center", va="center", fontsize=9.5, color=COL_ACCENT, weight="bold",
bbox=dict(boxstyle="round,pad=0.4", fc=COL_WHITE, ec=COL_ROSE_400, lw=1.4),
zorder=7)
# Lejant: cyan = çekirdek döngü (sabit), rose = callback kancası
ax.text(0.25, 6.28, "cyan: çekirdek döngü (sabit)", ha="left", va="top",
fontsize=8.5, color=COL_CYAN_800, weight="bold")
ax.text(0.25, 6.00, "rose: callback kancaları (eklenebilir davranış)", ha="left",
va="top", fontsize=8.5, color=COL_ACCENT, weight="bold")
plt.tight_layout()
plt.show()
- İleriye: Callback = “olay-güdümlü” (event-driven) tasarım; eğitim döngüsünün her aşaması bir olaydır (before_fit, after_batch, …) ve callback o olaya abone olur.
- Sezgi: Bir callback yalnızca ilgilendiği olayları yazar —
CompletionCByalnızcabefore_fit/after_batch/after_fittanımlar, diğer kancaları görmezden gelir. “Sadece ilgilendiğin yere takıl” deseni, callback’leri küçük ve bağımsız tutar.
19.6 5. Callback Taban Sınıfı ve order
Tüm callback’ler bir Callback taban sınıfından türer; bir order özniteliği vardır (çağrılma sırasını belirler, varsayılan 0). Bir callback yalnızca ilgilendiği metotları (örn. before_fit) yazar.
class Callback(): order = 0- İleriye:
order, callback’ler arası bağımlılığı yönetir (örn. cihaz taşıma metrikten önce olmalı; daha küçükorderdaha önce çalışır). fast.ai’de explicit nonzeroordertaşıyan örneklerProgressCB(order = MetricsCB.order + 1) veSingleBatchCB’dir; çoğu callback (örn.DeviceCB,MetricsCB) taban sınıftanorder = 0miras alır. - Sezgi: İki callback aynı kancaya takılıysa, hangisinin önce çalışacağı önemli olabilir (veri önce GPU’da olmalı ki metrik doğru hesaplansın).
orderbu sırayı tek sayıyla, callback’lerin birbirini bilmesine gerek kalmadan çözer.
19.7 6. run_cbs: Callback’leri Çağırmak
Çekirdek mekanizma: run_cbs bir callback listesini alır, order’a göre sıralar ve her birinde verilen isimli metodu (varsa) çağırır. getattr ile metodu isimden bulur — sistemin tüm sihri bu tek fonksiyondadır.
def run_cbs(cbs, method_nm, learn=None):
for cb in sorted(cbs, key=attrgetter('order')):
method = getattr(cb, method_nm, None)
if method is not None: method(learn)“It uses getattr to find an attribute with this name, which is ‘before_fit’.” — Howard, 5:23
Şekil 19.4 run_cbs’in çalışma akışını gösterir: solda callback’ler order’a göre küçükten büyüğe sıralanır — liste sırası rastgele olsa da çağrı sırasını order belirler (şekildeki order değerleri illüstratiftir, fast.ai’nin gerçek atamaları değil); sağda CompletionCB’nin sonucu, saydığı batch sayısının beklenenle eşleştiğini (match) doğrular. getattr metodu isimden bulur; bir callback o metodu yazmamışsa (None) atlanır.
Kod
d = E.callback_demo()
order_seq = d["order_sequence"]
batch_count = d["batch_count"]
total = d["total_batches"]
matched = d["match"]
fig, (axL, axR) = plt.subplots(1, 2, figsize=(11, 5),
gridspec_kw={"width_ratios": [1.25, 1.0]})
# -----------------------------------------------------------------------------
# SOL: order'a göre çağrı sırası (run_cbs'in GERÇEK çalışma akışı)
# -----------------------------------------------------------------------------
axL.set_title("run_cbs: order'a göre çağrı sırası", color=COL_TEXT,
fontsize=12.5, weight="bold", pad=12)
axL.set_xlim(0, 10)
axL.set_ylim(0, 10)
axL.axis("off")
# order_seq sıralı akış olarak: -1 → 0 → 1 (liste sırası rastgele olsa da)
n = len(order_seq)
y_top = 8.7
gap = 2.4
box_w, box_h = 6.4, 1.25
cx = 4.6
node_colors = [COL_CYAN_700, COL_PRIMARY, COL_CYAN_400]
for i, label in enumerate(order_seq):
y = y_top - i * gap
fc = COL_BG if i % 2 == 0 else COL_BG_ROSE
ec = node_colors[i % len(node_colors)]
viz.boxed_node(axL, cx, y, box_w, box_h, label, fc=fc, ec=ec,
fontsize=11.5)
# akış oku (bir sonrakine)
if i < n - 1:
viz.arrow_between(axL, (cx, y - box_h / 2),
(cx, y - gap + box_h / 2),
color=COL_CYAN_800, lw=2.2)
# sıralama anahtarı annotate (sol kenarda)
axL.annotate("sorted(cbs, key=order)\n+ getattr(cb, 'before_fit')",
xy=(cx - box_w / 2, y_top), xytext=(0.25, 9.3),
fontsize=9.5, color=COL_ACCENT, weight="bold", va="top",
ha="left")
# order eksenini gösteren ufak ok (yukarı = küçük order önce)
axL.annotate("", xy=(0.5, y_top - (n - 1) * gap + 0.2),
xytext=(0.5, y_top + 0.2),
arrowprops=dict(arrowstyle="-|>", color=COL_SLATE_400, lw=1.6))
axL.text(0.18, (y_top + y_top - (n - 1) * gap) / 2, "order ↑",
rotation=90, va="center", ha="center", color=COL_SLATE_400,
fontsize=9, weight="bold")
# -----------------------------------------------------------------------------
# SAĞ: CompletionCB sonucu — sayım vs beklenen + eşleşme rozeti
# -----------------------------------------------------------------------------
axR.set_title("CompletionCB sonucu", color=COL_TEXT,
fontsize=12.5, weight="bold", pad=12)
axR.set_xlim(0, 10)
axR.set_ylim(0, 10)
axR.axis("off")
# büyük sayım kutusu
viz.boxed_node(axR, 5.0, 6.6, 8.2, 2.6,
"{} batch sayıldı".format(batch_count),
fc=COL_BG, ec=COL_PRIMARY, fontsize=17)
viz.boxed_node(axR, 5.0, 4.0, 8.2, 1.5,
"= {} beklenen".format(total),
fc=COL_WHITE, ec=COL_SLATE_400, fontsize=12.5,
tc=COL_CYAN_800)
# eşleşme rozeti
badge_txt = "eşleşti ✓" if matched else "eşleşmedi ✗"
badge_fc = COL_BG_ROSE if matched else COL_WHITE
viz.boxed_node(axR, 5.0, 1.9, 5.2, 1.35, badge_txt,
fc=badge_fc, ec=COL_ACCENT, tc=COL_ACCENT, fontsize=14)
# -----------------------------------------------------------------------------
# Alt not (şekil geneli)
# -----------------------------------------------------------------------------
fig.text(0.5, 0.015,
"liste sırası rastgele ama order çağrı sırasını belirler; "
"getattr metodu isimden bulur",
ha="center", va="bottom", color=COL_SLATE_400,
fontsize=9.5, style="italic")
plt.tight_layout(rect=(0, 0.05, 1, 1))
plt.show()
- Geriye (Python):
getattr(obj, 'name')= bir niteliği isminden alma; callback sistemini mümkün kılan Python özelliği. - Sezgi:
run_cbscallback’lerin hangi metotlara sahip olduğunu bilmek zorunda değil — metot ismini bir string olarak alır,getattrile arar, varsa çağırır, yoksa sessizce geçer. Bu dinamiklik, çekirdeği callback’lerin içeriğinden tamamen bağımsız kılar.
19.8 7. CompletionCB: İlk Callback Örneği
Howard basit bir örnek gösterir: CompletionCB batch’leri sayar. before_fit sayacı sıfırlar, after_batch artırır, after_fit yazdırır. Bu callback, çekirdek döngüye hiç dokunmadan yeni bir davranış ekler.
class CompletionCB(Callback):
def before_fit(self, learn): self.count = 0
def after_batch(self, learn): self.count += 1
def after_fit(self, learn): print(f'Completed {self.count} batches')- İleriye: Metrikler, loglama, görselleştirme — hepsi bu desende ayrı callback’ler olur (yalnızca ilgilendikleri kancayı yazar).
- Sezgi:
CompletionCBsadece üç kancayı tanımlar;before_epoch,before_batchgibi diğerlerini yazmaz —run_cbsonlarıgetattr ... Noneile atlar. Bu, “en küçük callback” örneği: tek bir iş, üç satır, çekirdeğe sıfır dokunuş.
19.9 8. Basic Callback Learner
Şimdi Learner, döngünün her aşamasında self.callback('before_fit') gibi çağrılar yapar. fit, one_epoch, one_batch artık her adımda kayıtlı callback’leri tetikler. Çekirdek döngü sabit; davranış callback’lerle değişir.
class Learner():
def __init__(self, model, dls, loss_func, lr, cbs, opt_func=optim.SGD): fc.store_attr()
def one_batch(self):
self.preds = self.model(self.batch[0])
self.loss = self.loss_func(self.preds, self.batch[1])
if self.model.training:
self.loss.backward(); self.opt.step(); self.opt.zero_grad()- Geriye (Ders 14): Aynı eğitim adımı (preds → loss → backward → step); eklenen tek şey her aşamada
callback(...)çağrıları. - Sezgi: §2’deki katı Learner ile bu callback’li Learner arasındaki fark minimaldir — eğitim mantığı birebir aynı, fakat aralara serpilen
callback('before_...')/callback('after_...')çağrıları döngüyü sınırsız genişletilebilir kılar. Küçük bir ekleme, büyük bir esneklik.
19.10 9. Cancel Exceptions
Bir callback’in akışı iptal etmesi gerekebilir (örn. tek batch çalıştır, erken dur). Howard bunu özel istisnalarla yapar: CancelFitException, CancelEpochException, CancelBatchException. Bir callback bunları fırlatınca, Learner ilgili döngüyü temiz biçimde keser.
class CancelFitException(Exception): pass
class CancelBatchException(Exception): pass
class CancelEpochException(Exception): pass“CancelFitException, CancelEpochException, and CancelBatchException.” — Howard, 8:18
Şekil 19.5 bu mekanizmayı gerçek çalışan kodla gösterir: 10 batch planlanmış; bir callback 3. batch’in after_batch’inde CancelFitException fırlatır; Learner döngüyü temiz keser (çökme değil) — yalnızca 3 batch çalışır, 7’si atlanır. Akış kontrolü artık çekirdekte değil, callback’lerdedir; lr_find ve SingleBatchCB tam olarak bunu kullanır.
Kod
d = E.cancel_demo()
ran = d["ran_batches"] # 3
cancel_at = d["cancel_at"] # 3
total = d["total_without_cancel"] # 10
fig, ax = plt.subplots(figsize=(10, 4.5))
# 10 batch planlanmış: çalışanlar cyan, atlanan (durdurulan) batch'ler soluk rose-kesik
for i in range(total):
x = i
ran_batch = i < ran
if ran_batch:
ax.add_patch(plt.Rectangle((x, 0), 0.8, 1.0, facecolor=COL_PRIMARY,
edgecolor=COL_CYAN_800, linewidth=1.6, zorder=3))
ax.text(x + 0.4, 0.5, f"{i+1}", ha="center", va="center",
color=COL_WHITE, fontsize=11, weight="bold", zorder=4)
else:
ax.add_patch(plt.Rectangle((x, 0), 0.8, 1.0, facecolor=COL_BG_ROSE,
edgecolor=COL_ROSE_400, linewidth=1.4,
linestyle="--", zorder=2))
ax.text(x + 0.4, 0.5, f"{i+1}", ha="center", va="center",
color=COL_ROSE_400, fontsize=10.5, weight="bold", zorder=4)
# Cancel noktası işareti (cancel_at. batch sonunda exception fırlar)
xc = ran - 0.1
ax.axvline(xc + 0.9, ymin=0.06, ymax=0.94, color=COL_ACCENT,
linewidth=2.4, linestyle=(0, (4, 2)), zorder=5)
ax.annotate(
f"after_batch ({cancel_at}. batch):\nCancelFitException fırlatır\n→ Learner döngüyü TEMİZ keser\n(çökme değil)",
xy=(ran + 0.0, 1.02), xycoords="data",
xytext=(ran + 0.6, 1.62), textcoords="data",
fontsize=10, color=COL_TEXT, weight="bold", ha="left", va="center",
arrowprops=dict(arrowstyle="-|>", color=COL_ACCENT, lw=2.0,
connectionstyle="arc3,rad=-0.25"),
bbox=dict(boxstyle="round,pad=0.4", fc=COL_BG_ROSE, ec=COL_ROSE_500, lw=1.6),
zorder=6,
)
# Çalışan / atlanan bölge etiketleri
ax.text(ran / 2.0, -0.42, f"çalıştı: {ran} batch", ha="center", va="center",
fontsize=11, color=COL_CYAN_800, weight="bold")
ax.text((ran + total) / 2.0, -0.42, f"atlandı: {total - ran} batch (planlı {total})",
ha="center", va="center", fontsize=11, color=COL_ROSE_500, weight="bold")
ax.annotate("", xy=(ran, -0.18), xytext=(0.0, -0.18),
arrowprops=dict(arrowstyle="-", color=COL_CYAN_800, lw=2.0))
ax.annotate("", xy=(total, -0.18), xytext=(ran, -0.18),
arrowprops=dict(arrowstyle="-", color=COL_ROSE_400, lw=2.0,
linestyle="--"))
# Alt not: bu mekanizmayı kim kullanır
ax.text(total / 2.0, -0.78,
"lr_find / SingleBatchCB bu akış kontrolünü kullanır",
ha="center", va="center", fontsize=9.5, color=COL_SLATE_400,
style="italic")
ax.set_xlim(-0.4, total + 0.4)
ax.set_ylim(-1.0, 2.0)
ax.set_title(f"Cancel exception ile erken durdurma — {total} batch planlı, {ran} batch çalıştı",
fontsize=12.5, color=COL_TEXT, weight="bold", pad=12)
ax.axis("off")
plt.tight_layout()
plt.show()
- İleriye (Ders 17): lr_find (Ders 17) bir callback’tir; learning rate çok büyüyüp loss patlayınca
CancelFitExceptionile eğitimi durdurur. - Sezgi: İstisnaları “hata” için değil, kontrollü çıkış için kullanmak güçlü bir desendir: bir callback “buraya kadar yeter” diyebilir, Learner’ın context manager’ı (
cb_ctx) onu yakalar ve ilgili döngüyü sessizce keser. Erken durdurma, tek-batch testi, lr_find — hepsi bu üç istisnadan doğar.
19.11 10. DeviceCB: Pratik Bir Callback
Gerçek bir örnek: DeviceCB modeli ve her batch’i GPU’ya taşır. before_fit’te modeli, before_batch’te veriyi cihaza gönderir. GPU mantığı çekirdek döngüde değil, ayrı bir callback’te.
class DeviceCB(Callback):
def before_fit(self, learn): learn.model.to(self.device)
def before_batch(self, learn): learn.batch = to_device(learn.batch, self.device)- İleriye: Aynı desen: mixed precision (Ders 20), gradient clipping, logging — hepsi bağımsız callback.
- Sezgi: GPU’ya taşıma “her eğitimde lazım” görünse de çekirdeğe gömülmez — çünkü CPU’da çalışmak isteyebilirsin veya farklı cihaza taşıyabilirsin. Onu callback yapmak, “varsayılan ama zorunlu değil” davranışı temiz biçimde isteğe bağlı kılar.
19.12 11. Esnek Learner: Context Manager
Howard kodu daha da temizler: her aşamayı bir context manager (cb_ctx) ile sarar. before_<nm> çağrılır, iş yapılır, after_<nm> çağrılır; ilgili Cancel exception yakalanır; cleanup_<nm> her durumda çalışır.
@contextmanager
def cb_ctx(self, nm):
try:
self.callback(f'before_{nm}'); yield; self.callback(f'after_{nm}')
except globals()[f'Cancel{nm.title()}Exception']: pass
finally: self.callback(f'cleanup_{nm}')- Geriye (Python):
@contextmanager+ try/yield/finally; before/after/cleanup’ı tek yapıda toplar (DRY — kendini tekrar etme). - Sezgi:
cb_ctxüç şeyi tek desende birleştirir: olaydan öncebefore_, sonraafter_, her durumda (Cancel olsa bile)cleanup_.globals()[f'Cancel{nm.title()}Exception']ise aşama isminden ilgili istisnayı dinamik bulur —getattrdeseninin istisnalardaki kuzeni. Bir context manager, üç callback noktasını ve istisna yakalamayı tek satıra indirir.
19.13 12. Metrics Callback
Doğruluk, kayıp gibi metrikler de birer callback’tir: after_batch’te biriktir, after_epoch’ta hesapla ve yazdır. Eğitim döngüsü metrik bilmez; metrik callback’i kendi işini yapar.
- Geriye (Ders 5): accuracy (Ders 5) hesabı; artık çekirdek döngüden ayrı, yeniden kullanılabilir bir callback.
- Sezgi: Metrik mantığı (biriktir → ortalama al → yazdır) eğitim döngüsünün işi değildir — döngü yalnızca “ileri-geri-adım” yapar. Metriği callback’e taşımak, aynı çekirdeği farklı metrik setleriyle (accuracy, F1, perplexity) çalıştırmayı tek satırlık değişiklikle mümkün kılar.
19.14 13. miniai’nin Doğuşu
Howard bu Learner + callback sistemini miniai adlı minik bir kütüphaneye koyar (#|export ile). miniai, Part 2’nin geri kalanında (ve diffusion’da) kullanılacak kendi mini fast.ai’mizdir — tamamen sıfırdan, anlaşılır.
Şekil 19.6 bu doğuşu görselleştirir: üstte Ders 2’de kullandığımız fastai Learner (vision_learner/fine_tune) — kara kutu, içini görmedik; aradaki ok “from the foundations: sıfırdan kur”; altta bu derste kurduğumuz miniai çekirdeği (Learner · Callback · run_cbs · Cancel · cb_ctx). fastai’nin lr_find / OneCycle / mixed-precision’ı hep callback’tir; miniai onların üstüne kurulduğu çekirdektir.
Kod
fig, ax = plt.subplots(figsize=(11.0, 5.5))
fig.patch.set_facecolor(COL_WHITE)
ax.set_xlim(0, 100)
ax.set_ylim(0, 50)
ax.axis("off")
# =========================================================
# ÜST — Ders 2'de KULLANDIK: fastai Learner (kara kutu)
# =========================================================
ax.text(50, 47.6, "Ders 2'de KULLANDIK", ha="center", va="center",
fontsize=12.5, color=COL_CYAN_800, weight="bold")
boxed_node(ax, 50, 41.0, 58.0, 8.4,
"fastai Learner\nvision_learner( ) · fine_tune( )",
fc=COL_SLATE_300, ec=COL_SLATE_400, tc=COL_TEXT,
fontsize=11.5, lw=2.2)
ax.text(50, 41.0 - 5.6, "kara kutu — içeride ne olduğunu görmedik",
ha="center", va="center", fontsize=9.5, color=COL_SLATE_400,
weight="bold", style="italic")
# =========================================================
# OK aşağı — from the foundations: sıfırdan kur
# =========================================================
arrow_between(ax, (50, 33.6), (50, 27.2), color=COL_ACCENT, lw=3.0,
mutation_scale=22, shrink=2)
ax.text(52.5, 30.4, "from the foundations:\nsıfırdan kur", ha="left",
va="center", fontsize=10.5, color=COL_ACCENT, weight="bold")
# =========================================================
# ALT — miniai (bu derste): çekirdek makine (rose)
# =========================================================
ax.text(50, 24.0, "miniai (bu derste)", ha="center", va="center",
fontsize=12.5, color=COL_ACCENT, weight="bold")
# Çekirdek bileşen kutuları (rose) — Learner'ın altındaki makine
comp = ["Learner", "Callback", "run_cbs", "Cancel", "cb_ctx"]
xs = [13.0, 31.5, 50.0, 68.5, 87.0]
for x, name in zip(xs, comp):
boxed_node(ax, x, 17.6, 16.0, 6.4, name,
fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_TEXT,
fontsize=11, lw=2.2)
# =========================================================
# Açıklama notları
# =========================================================
ax.text(50, 9.6,
"fastai'nin lr_find / OneCycle / mixed-precision = hepsi callback;\n"
"miniai onların üstüne kurulduğu çekirdek",
ha="center", va="center", fontsize=10.0, color=COL_CYAN_700,
weight="bold")
ax.text(50, 3.4,
"Part 2'nin geri kalanı + diffusion (L17-25) miniai üstünde çalışır",
ha="center", va="center", fontsize=9.5, color=COL_SLATE_400,
weight="bold", style="italic")
plt.tight_layout()
plt.show()
- Geriye (§4.I): miniai = fastai’nin (Ders 1-8) sıfırdan, minimal versiyonu; “yeniden kur, sonra kullan” kuralının nihai ürünü.
- İleriye (Ders 17-25): Part 2’nin geri kalanı (init/norm, SGD) ve tüm diffusion eğitimleri (DDPM → DDIM → latent) miniai üstünde çalışır — yani şimdi kurduğumuz beş parça, kalan onlarca dersin altyapısıdır.
19.15 14. fast.ai Learner ile Köprü
Bu miniai Learner, Ders 2’de kullandığımız fastai Learner’ın çekirdeğidir. fastai’nin tüm callback ekosistemi (lr_find, OneCycle, mixed precision) bu desenin üstüne kuruludur. Artık fastai’yi kullanırken altında ne olduğunu biliyoruz.
- Geriye (Ders 2): Ders 2’deki
vision_learner/fine_tune’un altındaki callback makinesi tam budur — Şekil 19.6 bu kara-kutu → çekirdek geçişini gösterir. - Sezgi: fast.ai’yi “büyülü” yapan şey, onlarca yerleşik callback’tir (lr_find, OneCycle, mixed precision); ama her biri bu derste kurduğumuz
Callbacktaban sınıfından türer. Çekirdeği bildiğimiz için, beklenmedik bir davranışta nereye bakacağımızı ve kendi callback’imizi nasıl yazacağımızı biliyoruz.
19.16 15. Neden Callback Deseni Güçlü?
Callback deseni, “açık/kapalı ilkesi”ni mükemmel uygular: çekirdek eğitim döngüsü kapalı (değişmez, sade), ama davranış açık (sınırsız callback ile genişler). Yeni bir özellik = yeni bir callback; çekirdek koda hiç dokunmazsın. Bu, fast.ai’yi bu kadar esnek yapan tasarımdır.
Şekil 19.7 bu ilkeyi merkez-çevre olarak çizer: ortada çekirdek eğitim döngüsü (KAPALI: sade, değişmez, kilitli), çevrede takılan callback’ler (GPU taşıma, metrik, loglama, mixed precision, erken durdurma, progress bar) — her özellik ayrı bir callback; birini ekle/çıkar diğerlerini etkilemez. Aynı desen PyTorch Lightning / W&B callback’lerinde de standarttır.
Kod
fig, ax = plt.subplots(figsize=(10.5, 6))
# ----------------------------------------------------------------------------
# MERKEZ: çekirdek eğitim döngüsü (KAPALI: sade, değişmez)
# ----------------------------------------------------------------------------
cx, cy = 0.0, 0.0
boxed_node(
ax, cx, cy, 3.5, 1.5,
"Çekirdek eğitim döngüsü\n(KAPALI: sade, değişmez)\n🔒",
fc=COL_BG, ec=COL_CYAN_800, tc=COL_CYAN_800,
fontsize=11, lw=2.6, zorder=4,
)
# AÇIK halka başlığı (merkezin hemen üstünde)
ax.text(cx, 1.55, "AÇIK: sınırsız callback ile genişler",
ha="center", va="center", fontsize=11.5, weight="bold",
color=COL_ACCENT, zorder=5)
# ----------------------------------------------------------------------------
# ÇEVRE: takılan callback kutuları (rose) — her özellik = ayrı callback
# ----------------------------------------------------------------------------
import numpy as _np # (setup'tan np zaten var; köşe pozisyonları için kısa ad)
callbacks = [
"GPU taşıma",
"metrik",
"loglama (W&B)",
"mixed precision",
"erken durdurma",
"progress bar",
]
n = len(callbacks)
R = 3.55 # çevre yarıçapı
bw, bh = 2.05, 0.78
# üstte AÇIK etiketi olduğu için kutuları üst-orta boşluğu atlayacak şekilde diz
angles = np.linspace(90, 90 + 360, n, endpoint=False) + 30 # 30° kaydır
for ang, name in zip(angles, callbacks):
a = np.deg2rad(ang)
bxp, byp = R * np.cos(a) * 1.18, R * np.sin(a) * 0.78
boxed_node(
ax, bxp, byp, bw, bh, name,
fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_ACCENT,
fontsize=10, lw=2.0, zorder=3,
)
# callback'i çekirdeğe "tak": rose ok (çevreden merkeze)
arrow_between(
ax, (bxp, byp), (cx, cy),
color=COL_ROSE_400, lw=1.8, mutation_scale=14,
shrink=22, zorder=1,
)
# ----------------------------------------------------------------------------
# Açıklama notu: ekle/çıkar bağımsızlığı
# ----------------------------------------------------------------------------
ax.annotate(
"her özellik = ayrı callback;\nbirini ekle/çıkar diğerlerini etkilemez",
xy=(cx, cy - 0.85), xytext=(0.0, -2.95),
ha="center", va="center", fontsize=9.8, color=COL_TEXT,
weight="bold",
bbox=dict(boxstyle="round,pad=0.4", fc=COL_WHITE, ec=COL_SLATE_300, lw=1.2),
arrowprops=dict(arrowstyle="-|>", color=COL_SLATE_400, lw=1.4,
shrinkA=4, shrinkB=8),
zorder=6,
)
# Köprü notu: PyTorch Lightning / W&B aynı desen
ax.text(
0.0, 3.75,
"PyTorch Lightning / W&B callback'leri aynı desen",
ha="center", va="center", fontsize=9.6, style="italic",
color=COL_CYAN_700, zorder=6,
bbox=dict(boxstyle="round,pad=0.35", fc=COL_CYAN_50,
ec=COL_CYAN_400, lw=1.2),
)
ax.set_xlim(-5.4, 5.4)
ax.set_ylim(-3.7, 4.25)
ax.axis("off")
ax.set_facecolor(COL_WHITE)
fig.patch.set_facecolor(COL_WHITE)
plt.tight_layout()
plt.show()
- İleriye (production): Aynı desen MLOps framework’lerinde (W&B, PyTorch Lightning callbacks) standarttır; öğrenmesi builder için değerli.
- Sezgi: “Çekirdek kapalı, davranış açık” sadece şık bir tasarım değil — bakım maliyetini düşürür: yeni özellik eklemek mevcut kodu okumayı/değiştirmeyi gerektirmez, sadece yeni bir callback yazarsın. Bu yüzden olgun framework’ler (Lightning, Keras, fast.ai) hep aynı deseni seçer.
19.17 16. Kapanış
Ders 16, esnek eğitim çerçevesi Learner’ı sıfırdan kurdu: katı döngü → callback’lerle her aşamaya müdahale → Cancel exceptions ile akış kontrolü → context manager ile temizlik → miniai kütüphanesi. Bu, fast.ai’nin çekirdeği ve Part 2’nin geri kalanının eğitim altyapısıdır.
Şekil 19.8 dersin sentezidir (callback deseni merkezde): solda L16’nın parçaları (Learner, callback deseni, Cancel exceptions, miniai, getattr + order), sağda her birinin kaynağı/hedefi — Learner = Ders 2 fastai Learner’ın çekirdeği, callback deseni = PyTorch Lightning / W&B (production MLOps), Cancel = lr_find (Ders 17) durma mekanizması, miniai = Ders 10 “yeniden kur sonra kullan” + L17-25 altyapısı, getattr + order = Python dinamik nitelik → esnek olay sistemi.
Kod
fig, ax = plt.subplots(figsize=(12, 6))
ax.set_xlim(0, 12)
ax.set_ylim(0, 6)
ax.axis("off")
ax.set_facecolor(COL_WHITE)
# Başlık
ax.text(6, 5.72, "L16 = esneklik deseni", ha="center", va="center",
fontsize=15, color=COL_CYAN_800, weight="bold")
ax.text(3.0, 5.18, "L16'da", ha="center", va="center",
fontsize=11.5, color=COL_ACCENT, weight="bold")
ax.text(9.0, 5.18, "nereden / nereye", ha="center", va="center",
fontsize=11.5, color=COL_CYAN_700, weight="bold")
# Beş satır: (sol L16-parçası rose, sağ kaynak cyan)
rows = [
(
"Learner",
"Ders 2 fastai Learner'ın\nsıfırdan çekirdeği",
),
(
"callback deseni\n(açık / kapalı)",
"PyTorch Lightning / W&B\ncallback'leri (production MLOps)",
),
(
"Cancel exceptions",
"lr_find (Ders 17)\ndurma mekanizması",
),
(
"miniai",
"Ders 10 'yeniden kur sonra kullan';\nL17-25 altyapısı",
),
(
"getattr + order",
"Python dinamik nitelik →\nesnek olay sistemi",
),
]
ys = [4.45, 3.55, 2.65, 1.75, 0.85]
x_left, x_right = 3.0, 9.0
w_l, w_r, h = 3.0, 3.7, 0.72
for y, (left, right) in zip(ys, rows):
# SOL — L16 parçası (rose)
boxed_node(ax, x_left, y, w_l, h, left,
fc=COL_BG_ROSE, ec=COL_ACCENT, tc=COL_TEXT,
fontsize=10.5, lw=2.0)
# SAĞ — kaynak / köprü (cyan)
boxed_node(ax, x_right, y, w_r, h, right,
fc=COL_BG, ec=COL_PRIMARY, tc=COL_TEXT,
fontsize=9.5, lw=2.0)
# Ok: L16 parçası → kaynak/köprü
arrow_between(ax, (x_left + w_l / 2, y), (x_right - w_r / 2, y),
color=COL_CYAN_700, lw=2.0, mutation_scale=16, shrink=4)
plt.tight_layout()
plt.show()
- İleriye (Ders 17-18): miniai hazır; Ders 17 (init/norm) ve 18 (accelerated SGD) callback ve Learner üstüne kurulur; diffusion eğitimleri (19-25) de.
- Sezgi: Bu derste eğitim altyapısı olgunlaştı (model ve döngü artık ayrı soyutlama katmanları). Sıradaki dersler bu altyapıyı kullanarak asıl zorluğa döner: derin ağların neden eğitilmesinin zor olduğu (aktivasyonların patlaması/sönmesi) ve callback-tabanlı çözümleri (hook’lar, init, norm).
19.18 Bu Dersin Özeti
- Learner model + veri + loss + optimizer’ı toplar ve eğitim döngüsünü (fit → epoch → batch) yürütür (basit Learner).
- Katı bir döngü esnek değildir; yeni davranış için çekirdeği değiştirmek gerekir — kötü tasarım (neden esnek değil).
- Callback, eğitimin belirli noktalarına (
before_fit,after_batch, …) takılan, çekirdeğe dokunmadan davranış ekleyen nesnedir (callback fikri). - run_cbs callback’leri
order’a göre sıralayıpgetattrile ilgili metotlarını çağırır (run_cbs). - Cancel exceptions (Fit/Epoch/Batch) bir callback’in akışı temiz biçimde iptal etmesini sağlar (örn. lr_find) (Cancel).
- DeviceCB gibi callback’ler (GPU taşıma, metrik, log) çekirdek döngüden bağımsız, yeniden kullanılabilir (DeviceCB).
- Context manager (cb_ctx) before/after/cleanup’ı tek yapıda toplar; Cancel exception’ları yakalar (cb_ctx).
- Tüm bu sistem miniai’dir — fast.ai’nin sıfırdan, anlaşılır çekirdeği; Part 2’nin eğitim altyapısı (miniai).
Learner eğitim döngüsünü yürütür; callback’ler ise eğitimin her aşamasına (before/after fit/epoch/batch) çekirdek koda dokunmadan müdahale eden eklentilerdir — ve bu desen, Ders 2’de kullandığımız fastai Learner’ın sıfırdan kurulmuş çekirdeği olan miniai’yi oluşturur.
19.19 Kontrol Soruları
Cevap:
Learner, eğitim döngüsünün belirli noktalarında (before_fit, before_batch, after_batch, after_epoch, after_fit, …) self.callback('<isim>') çağırır. Bu çağrı run_cbs’i tetikler: kayıtlı tüm callback’leri order özniteliğine göre sıralar ve her birinde o isimli metodu (getattr(cb, method_nm, None) ile bulup, varsa) çağırır. Böylece her callback yalnızca ilgilendiği aşamalara takılır (örn. CompletionCB yalnızca before_fit/after_batch/after_fit yazar). Sonuç: davranış, çekirdek döngüye hiç dokunmadan eklenir. (Şekil 19.3 kancaları, Şekil 19.4 order’a göre çağrı sırasını gösterir.)
Cevap:
Katı döngüde yeni bir davranış (GPU’ya taşıma, metrik, erken durdurma, mixed precision) eklemek için çekirdek kodu değiştirmen gerekir; her ihtiyaç döngüyü kirletir ve hata riski artar. Callback deseni “açık/kapalı ilkesi”ni uygular: çekirdek döngü kapalı (sade, değişmez) kalır, davranış açık (yeni callback eklenerek) genişler. Her özellik bağımsız, yeniden kullanılabilir bir callback olur; birini eklemek/çıkarmak diğerlerini etkilemez. Bu, fast.ai’yi (ve PyTorch Lightning gibi framework’leri) bu kadar esnek yapan tasarımdır. (Şekil 19.2 iki tasarımı, Şekil 19.7 açık/kapalı ilkesini gösterir.)
Cevap:
CancelFitException, CancelEpochException, CancelBatchException, bir callback’in eğitim akışını temiz biçimde iptal etmesini sağlar. Bir callback bu istisnayı fırlatınca, Learner’ın context manager’ı (cb_ctx) onu yakalar ve ilgili döngüyü (fit/epoch/batch) sessizce keser — çökme değil, kontrollü çıkış. Örnek: lr_find (Ders 17) bir callback’tir; learning rate’i kademeli artırır, loss patlayınca CancelFitException fırlatıp eğitimi durdurur. Veya SingleBatchCB, tek batch sonrası CancelFitException ile hızlı test yapar. Bu, akış kontrolünü callback’lere taşır. (Şekil 19.5 10 batch’in 3’te temiz durmasını gerçek kodla gösterir.)
Cevap:
miniai, bu derste sıfırdan kurduğumuz Learner + callback sistemini (ve sonraki derslerde eklenecek init, optimizer, vb.) içeren minik bir kütüphanedir — fast.ai’nin minimal, anlaşılır çekirdeği. Ders 2’de kullandığımız fastai Learner (vision_learner/fine_tune) tam olarak bu callback makinesinin üstüne kuruludur; fastai’nin lr_find, OneCycle, mixed precision gibi tüm özellikleri birer callback’tir. Builder açısından: “from the foundations” kuralının ürünü — fast.ai’nin eğitim çekirdeğini sıfırdan kurduk, artık onu (ve callback ekleyerek genişletmeyi) tam anlıyoruz. Part 2’nin geri kalanı ve diffusion eğitimleri miniai üstünde çalışır. (Şekil 19.6 kara-kutu → çekirdek geçişini gösterir.)
19.20 Egzersizler
Egzersiz 1 (Direkt uygulama). CompletionCB’yi yaz ve bir Learner’a ver; eğitim sonunda kaç batch işlendiğini yazdırdığını gör (Şekil 19.4’in sağ panelini kendi sayımınla doğrula — §7).
Egzersiz 2 (İki-aşamalı). Kendi callback’ini yaz (örn. her epoch sonunda loss yazan); order ile bir başka callback’ten önce/sonra çalışmasını sağla (§5-6).
Egzersiz 3 (Edge case). SingleBatchCB gibi after_batch’te CancelFitException fırlatan bir callback yaz; eğitimin tek batch sonrası temiz durduğunu gözle (Şekil 19.5’in mantığını kendi callback’inle yeniden üret — §9).
Egzersiz 4 (Kavramsal). run_cbs’in getattr’ı neden kullandığını açıkla; bir callback yalnızca before_fit yazıp after_batch yazmazsa ne olur? (§6)
Egzersiz 5 (Sonraki dersin habercisi — Ders 17). Eğitim sırasında her katmanın aktivasyon istatistiklerini (ortalama/std) toplayan bir callback (hook) nasıl yazılır düşün (init/norm’a giriş — §16).
19.21 Sonraki: Ders 17 İçin Hazırlık
Ders 17: Başlatma / Normalizasyon (Initialization/normalization)
Ders 16 Learner + callback’leri (miniai) kurdu. Ders 17, bu altyapıyla derin ağların neden eğitilmesinin zor olduğunu inceler: aktivasyonların patlaması/sönmesi. Çözümler: doğru başlatma (Kaiming init) ve normalizasyon (BatchNorm/LayerNorm). Karpathy makemore 3’ün fast.ai karşılığı.
Ana konular (Ders 17):
- Hooks ile aktivasyon istatistikleri (callback)
- Aktivasyonların patlaması/sönmesi
- Kaiming (He) init — varyans koruma
- BatchNorm / LayerNorm
- Bu dersin egzersizlerini çöz (özellikle 1 ve 3 — callback + Cancel exception).
- Kendi Learner’ını callback’lerle kurup MNIST’te eğit.
- Ana cümleyi tekrar oku: “Learner döngüyü yürütür; callback’ler dokunmadan müdahale eder.”
19.22 Anahtar Kavramlar (Cheat Sheet)
| Kavram | Tanım | Howard’da |
|---|---|---|
| Learner | Model+veri+loss+optimizer’ı toplayan eğitim döngüsü | 0:00 |
| Callback | Eğitim noktalarına takılan, çekirdeğe dokunmayan eklenti | 0:45 |
before_fit / after_batch |
Callback’in takıldığı aşama isimleri | 0:45 |
| run_cbs | Callback’leri order’a göre sıralayıp metotlarını çağırır | 5:23 |
| order | Callback çağrılma sırası (varsayılan 0) | 5:23 |
| getattr | Bir niteliği isminden bulma (callback sihri) | 5:23 |
| CompletionCB | İlk örnek callback (batch sayar) | 4:30 |
| Cancel exceptions | Fit/Epoch/Batch’i temiz iptal (akış kontrolü) | 8:18 |
| DeviceCB | Model/veriyi GPU’ya taşıyan callback | — |
| cb_ctx | before/after/cleanup’ı saran context manager | — |
| miniai | Sıfırdan kurulan minimal fast.ai çekirdeği | — |
| Açık/kapalı ilkesi | Çekirdek kapalı, davranış callback ile açık | — |
19.23 ML Bağlantıları Özeti
Bu ders esnek eğitim çerçevesini sıfırdan kurar ve callback deseniyle production framework’lerine köprü atar; köprülerin özeti:
- Learner → Ders 2 fastai Learner’ın sıfırdan çekirdeği; eğitim döngüsünü toplar (köprü).
- Callback deseni → açık/kapalı ilkesi; PyTorch Lightning / W&B callback’lerinin temeli (neden güçlü).
- Cancel exceptions → akış kontrolü; lr_find (Ders 17) gibi callback’lerin durma mekanizması (Cancel).
- miniai → “yeniden kur, sonra kullan” (Ders 10); fast.ai’nin minimal versiyonu; L17-25 altyapısı (miniai).
- getattr + order → Python’un dinamik niteliğiyle esnek olay sistemi (run_cbs).
- DeviceCB / metrik CB → çekirdek döngüden bağımsız, yeniden kullanılabilir davranış (DeviceCB).
fast.ai’nin esnekliğinin sırrı callback desenidir. Eğitim döngüsünü (Learner) sade ve değişmez tutar, her aşamaya (before/after fit/epoch/batch) callback’lerle müdahale edersin — GPU taşıma, metrik, erken durdurma, hepsi ayrı eklenti, çekirdeğe dokunmadan. Bunu sıfırdan kurduk (miniai); artık Ders 2’deki fastai Learner’ın altında ne olduğunu biliyoruz.