Experiment Tracking Mimarisi: Weights&Biases + Hydra + DVC — Sweep'in Mühendisliği
ML deneylerini disipline almak: Hydra ile config-driven runs, W&B ile sweep + system metrics + offline mode, DVC ile dataset/checkpoint versioning, alias/lineage tracking. Cookbook'un 'rapor edilebilir Lab' standardı: hangi run hangi commit hash + dataset hash + W&B run ID + checkpoint sha?
Şükrü Yusuf KAYA
34 dakikalık okuma
Orta🎯 Bu ders ne için
İyi haber: cookbook'un her Lab'ı W&B + Hydra + DVC entegrasyonuyla gelir. Kötü haber: bu üçlüyü doğru kullanmak ML mühendisliğinin 'demir leblebisi'dir — yanlış kurulmuş tracking bazen hiç tracking olmamasından daha kötüdür ('run-shopping' davranışı). Bu derste doğrusunu kuruyoruz.
1. Niye Üç Ayrı Tool? (Ve Niye Hiçbiri Tek Başına Yetmiyor)#
| Aracın işi | Ne yapar | Yokken acı |
|---|---|---|
| Hydra | Config'i CLI override ile, YAML hiyerarşisinde, sweep-friendly tut | "lr=2e-5 yerine 3e-5 deneyim" → argparse'ı boz, tüm flag'leri elle yaz |
| W&B | Metrik + system telemetry + artifact log + sweep run | "şu üç run hangisi en iyi?" → terminal log dosyalarını grep'le |
| DVC | Dataset & büyük dosya versioning, lineage | "datasetin hangi versiyonu üzerinde train olmuş?" → cevap yok, run kaybolur |
Üçlünün birlikte yarattığı şey: her W&B run'ı bir Hydra config + bir DVC dataset hash ile deterministically ilişkili olur. Hangi config + hangi dataset + hangi git commit = hangi sonuç triple'ı tam doluyor.
yaml
# === configs/ — Cookbook Hydra layout (her Lab aynı şema) ===# configs/config.yaml (default)defaults: - model: llama3_8b - data: tr_alpaca - trainer: qlora - optim: adamw_8bit - logging: wandb - _self_ run: name: ${model.name}_${data.name}_${trainer.name} seed: 42 output_dir: outputs/${run.name}/${now:%Y-%m-%d_%H-%M-%S} stage: reference # spike | reference | production | research # configs/model/llama3_8b.yamlname: llama-3-8bhf_id: meta-llama/Meta-Llama-3-8Btorch_dtype: bfloat16quantization: enabled: true bnb_4bit_quant_type: nf4 bnb_4bit_use_double_quant: true bnb_4bit_compute_dtype: bfloat16 # configs/data/tr_alpaca.yamlname: tr-alpacahf_id: malhajar/alpaca-gpt4-trsplit: trainmax_seq_len: 2048packing: truetext_field: textchat_template: llama3 # configs/trainer/qlora.yamlname: qlora-r32lora: r: 32 alpha: 64 dropout: 0.05 target_modules: [q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj]training: num_epochs: 3 per_device_train_batch_size: 2 gradient_accumulation_steps: 8 learning_rate: 2.0e-4 warmup_ratio: 0.03 lr_scheduler_type: cosine gradient_checkpointing: true bf16: true logging_steps: 5 save_steps: 100 eval_steps: 100 # configs/logging/wandb.yamlproject: ftc-llama-tr-cookbookentity: ${oc.env:WANDB_ENTITY,null}mode: online # offline mode: cluster'da internet yoksatags: [${run.stage}, ${model.name}, ${trainer.name}]Hydra config layout — cookbook'un her Lab'ı bu iskeleti kullanır
Hydra'nın gücü: CLI override#
# Tek run uv run python train.py # Override uv run python train.py optim=lion trainer.training.learning_rate=1e-4 # Multi-run (Hydra'nın "multirun" özelliği) uv run python train.py -m optim=adamw_8bit,lion trainer.training.learning_rate=1e-4,2e-4,5e-4 # → 6 ayrı run, her biri kendi output_dir'inde
Cookbook'taki tipik sweep komutu (5 lr × 3 lora rank × 2 dropout = 30 run):
uv run python train.py -m \ trainer.training.learning_rate=1e-5,5e-5,1e-4,2e-4,5e-4 \ trainer.lora.r=16,32,64 \ trainer.lora.dropout=0.0,0.1
python
# === train.py — W&B + Hydra entegrasyonu (cookbook iskeleti) ===import os, json, hashlibfrom pathlib import Path import hydrafrom omegaconf import DictConfig, OmegaConfimport wandbimport torch @hydra.main(version_base=None, config_path="configs", config_name="config")def main(cfg: DictConfig): # 1) Config'i resolve et + freeze cfg = OmegaConf.to_container(cfg, resolve=True) OmegaConf.save(cfg, Path(cfg["run"]["output_dir"]) / "config.frozen.yaml") # 2) W&B init — config'in tamamı + git fingerprint git_sha = os.popen("git rev-parse HEAD").read().strip() data_hash = compute_dataset_hash(cfg["data"]) # aşağıda wandb.init( project=cfg["logging"]["project"], entity=cfg["logging"]["entity"], name=cfg["run"]["name"], tags=cfg["logging"]["tags"], mode=cfg["logging"]["mode"], config={ **cfg, "_git_sha": git_sha, "_data_sha256": data_hash, "_gpu": torch.cuda.get_device_name(0), "_torch": torch.__version__, "_cuda": torch.version.cuda, }, # cookbook standardı: her run unique ID, lineage'a bağlı id=hashlib.sha256( f"{git_sha}-{cfg['run']['seed']}-{data_hash}".encode() ).hexdigest()[:16], resume="allow", ) # 3) Sistem metriklerini agresif kaydet wandb.define_metric("step") wandb.define_metric("train/*", step_metric="step") wandb.define_metric("eval/*", step_metric="step", summary="best") wandb.define_metric("gpu_mem/peak_gb", step_metric="step", summary="max") wandb.define_metric("throughput/tokens_per_sec", step_metric="step", summary="mean") # 4) Modeli yükle, training loop model, tokenizer = build_model_and_tokenizer(cfg["model"]) dataset = build_dataset(cfg["data"], tokenizer) trainer = build_trainer(cfg["trainer"], model, dataset) # 5) Trainer callback ile metrik log'la trainer.add_callback(WandbDetailedCallback(cfg)) trainer.train() # 6) Final artifact — model + config + frozen state art = wandb.Artifact(name=f"model-{wandb.run.id}", type="model", metadata={"git_sha": git_sha, "data_sha256": data_hash}) art.add_dir(cfg["run"]["output_dir"]) wandb.log_artifact(art, aliases=["latest", cfg["run"]["stage"]]) wandb.finish() def compute_dataset_hash(data_cfg: dict) -> str: """Dataset'in 'state'ini hash'le: HF dataset id + split + version.""" key = f"{data_cfg['hf_id']}::{data_cfg['split']}::{data_cfg.get('revision', 'main')}" return hashlib.sha256(key.encode()).hexdigest()[:32] if __name__ == "__main__": main()W&B + Hydra entegrasyon iskeleti — cookbook'un her train.py'sinde
3. W&B Sweep — Hyperparameter Tarama#
W&B Sweep'in 3 modu var: , , . Cookbook'un kullanım kuralı:
gridrandombayes| Mod | Ne zaman | Bütçe |
|---|---|---|
grid | 2-3 hyperparam, exhaustive görmek istiyorum | 75 max) |
random | 5+ hyperparam, kabaca taramak istiyorum | $50-100 |
bayes | 8+ hyperparam, "en iyi" bulmak istiyorum | $100-300 |
Cookbook'taki tipik sweep config'i:
yaml
# === sweep.yaml — W&B Bayesian sweep (8B QLoRA tuning) ===program: train.pymethod: bayesmetric: name: eval/loss goal: minimize parameters: trainer.training.learning_rate: distribution: log_uniform_values min: 1.0e-5 max: 5.0e-4 trainer.lora.r: values: [8, 16, 32, 64, 128] trainer.lora.alpha: distribution: int_uniform min: 8 max: 256 trainer.lora.dropout: distribution: uniform min: 0.0 max: 0.2 trainer.training.warmup_ratio: distribution: uniform min: 0.0 max: 0.1 early_terminate: type: hyperband min_iter: 100 # 100 step görmeden agent'ı erken durdurma s: 2 # Run komutucommand: - ${env} - uv - run - python - ${program} - ${args_no_hyphens} # Hydra için "--" olmadan key=valueW&B Bayesian sweep — 8B QLoRA hyperparameter tuning
Sweep çalıştırma#
# 1) Sweep oluştur (bir kere) wandb sweep sweep.yaml # → ID: abcd1234 # 2) Agent'leri başlat (paralel) wandb agent your-entity/ftc-llama-tr-cookbook/abcd1234 & wandb agent your-entity/ftc-llama-tr-cookbook/abcd1234 & # RTX 4090 tek GPU, ama farklı saatlerde 2 process koşturmak yerine seri tercih # Tek-GPU sweep'inde: tek agent, 50-100 run # 3) Limit: 50 run, 4 saat wandb agent --count 50 your-entity/ftc-llama-tr-cookbook/abcd1234
W&B Sweep dashboard'unda parallel coordinates plot ile hangi hyperparam'ın hangi loss bandında performans yaptığını görsel olarak çıkarabilirsin. Cookbook'un her ders sonundaki "recommended hyperparams" tablosu bu sweep'lerin sonucu.
4. DVC: Dataset & Checkpoint Versioning#
W&B dataset'i de versiyonlayabilir — ama:
Artifact- W&B Artifact'ı storage'ı W&B üzerinden geçirir (büyük dataset için trafik pahalı)
- Local lineage için ekstra entegrasyon gerekir
- CI'da dataset rebuild step'i için DVC daha rahat
Cookbook'un kuralı:
- Dataset prep çıktısı (tokenized .arrow shards) → DVC track (S3/GCS/local remote)
- Final checkpoint → W&B Artifact (lineage W&B'de)
- Logs + metrics → W&B (zaten)
DVC kurulumu#
uv add --dev dvc[s3] # S3 backend için dvc init dvc remote add -d s3 s3://my-bucket/ftc-data # Dataset'i track'le dvc add data/tokenized git add data/tokenized.dvc .gitignore git commit -m "data(tokenized): TR-Alpaca + OASST-TR v1" dvc push # remote'a yükle
data/tokenized.dvcDVC pipeline (reproducible dataset prep)#
# dvc.yaml stages: tokenize: cmd: uv run python scripts/tokenize.py configs/data/tr_alpaca.yaml deps: - scripts/tokenize.py - configs/data/tr_alpaca.yaml outs: - data/tokenized/tr_alpaca build_eval_set: cmd: uv run python scripts/build_eval.py deps: - scripts/build_eval.py - data/tokenized/tr_alpaca outs: - data/eval/tr_mmlu_sample.jsonl
dvc repro5. Lineage Triple: Cookbook'un "Ben Kimim" Cevabı#
Her W&B run'ının summary'sinde, cookbook'un zorunlu kıldığı 3 alan:
_git_sha: 8b9910d2c4a5... _data_sha256: a87f5e2c4d9b... _run_id: ed85420a7c63...
Bu triple ile 6 ay sonra açıp:
- ile tam kodun versiyonunu geri al
git checkout 8b9910d2c4a5 - ile dataset'in tam versiyonunu geri al
dvc checkout - ile model + config'i geri al
wandb artifact get ed85420a7c63
Aynı sonucu bit-exact üretebilirsin. Bu cookbook'un sertifika gereksinimi.
🐛 Failure Mode Drill #4 — '20 run yaptım, hangi config en iyiydi unutmuşum'
Senaryo: 3 gün önce 20 run koştun, W&B'de hepsi sıralı duruyor ama: (a) farklı git commit'lerden geliyor → cookbook tarafından otomatik fixlenir, `_git_sha` her run'ın config'inde. (b) Bazıları farklı dataset versiyonundan — niye → `_data_sha256` farklı. (c) Bazı run'lar `stage=spike`, bazıları `stage=reference` — tag filtre ile ayır. (d) Bazılarında W&B mode=offline kalmış, hâlâ sync olmamış → `wandb sync wandb/offline-*` ile bir kerede yükle. Drill: 20 run'ından lineage triple'larını çıkar, hangi 3 tanesi 'bit-exact reproducible' kalitesinde?
6. Bench: Tracking Overhead'i Var mı?#
| Config | step/s | overhead | Notlar |
|---|---|---|---|
| Baseline (no logging) | 2.10 | 0% | sadece print |
| + W&B online | 2.08 | -1% | hostbağımlı küçük HTTP yükü |
| + W&B + system_metrics | 2.05 | -2.4% | her 15 sn GPU stats |
| + W&B + Hydra config | 2.05 | -2.4% | Hydra resolve tek seferlik |
| + W&B + Hydra + DVC track | 2.05 | -2.4% | DVC checkpoint dışında bekler |
| Full + sweep agent | 2.04 | -2.9% | tolerable |
Sonuç: Disiplinli tracking'in maliyeti ~%3 throughput. Karşılığında: tek bir sweep'te 30 run hangisi en iyi, niye en iyi, hangi dataset'le, hangi commit'te — hepsi bir click uzakta. Çok cömert bir takas.
✅ Bu dersin teslimi
- W&B hesabı aç (free tier yeterli, 100GB artifact). 2) Yukarıdaki Hydra layout'unu `configs/`'a kopyala. 3) Minik bir 100-step Llama 3.2 1B QLoRA Lab'ını koş — W&B'de run'ın config'inde `_git_sha` ve `_data_sha256`'i gör. 4) Aynı komutu seed=43 ile bir kez daha koş; W&B'de 2 run yan yana karşılaştır. Part 0 tamamlandı — Part I'e geçiyoruz: Hardware & Memory Engineering.
Sık Sorulan Sorular
Evet — cookbook hiçbiriyle anlaşmalı değil. W&B'i seçme nedeni: sweep UX'i ve system metrics agresifliği. MLflow open-source self-host için daha rahat (privacy hassas takımlar için). Aim local-first, hızlı. Cookbook'un train.py iskeleti backend-agnostic; \`wandb.init\` çağrısını \`mlflow.start_run\` ile değiştirip benzer detay seviyesini koruyabilirsin.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
İlgili İçerikler
Part 0 — Engineering Foundations
Fine-Tuning Cookbook'a Hoş Geldin: Sistematik, Stage Taksonomisi ve Reproducibility Kontratı
Öğrenmeye BaşlaPart 0 — Engineering Foundations
Reproducibility Stack: Seeds, cuDNN Flags ve Deterministic CUDA — 'Sende Niye Çalışıyor Bende Çalışmıyor' Sorununu Bitir
Öğrenmeye BaşlaPart 0 — Engineering Foundations