Metadata-Version: 2.4
Name: ai-model-autopsy
Version: 0.1.0
Summary: Görüntü sınıflandırma modelleri için hata analizi ve teşhis aracı
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: torch>=2.6
Requires-Dist: torchvision>=0.21
Requires-Dist: numpy>=1.26
Requires-Dist: scikit-learn>=1.4
Requires-Dist: matplotlib>=3.8
Requires-Dist: jinja2>=3.1
Requires-Dist: pillow>=12.3
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff<0.17,>=0.16.4; extra == "dev"
Requires-Dist: mypy<3,>=2.3; extra == "dev"
Requires-Dist: pip-audit>=2.7; extra == "dev"

# AI Model Autopsy

Görüntü sınıflandırma modelleri için hata analizi ve teşhis aracı. Tasarım
dokümanı için bkz. [`01_ai_model_autopsy_development_map.md`](01_ai_model_autopsy_development_map.md).

**PyTorch** tabanlıdır (dokümandaki TF/Keras'tan bilinçli bir sapma — bkz.
aşağıdaki "Dokümandan sapmalar" bölümü). v1 dokümanın ilk dört aşamasını +
kural tabanlı basit neden çıkarımını kapsıyordu; v2 buna Autopsy Score
(§18), Recommendation Engine (§14) ve gerçek embedding/Grad-CAM analizini
(§10, §16) ekledi. v3, ayrı bir kaynak doküman olan
[`03_model_mutation_testing_development_map.md`](03_model_mutation_testing_development_map.md)'yi
temel alan **Model Mutation Testing**'i ekledi: `autopsy mutate`, modeli
kontrollü biçimde bozup (weight noise/zeroing, neuron ablation, activation
replacement, layer freezing, quantization) mevcut tanı sinyallerinin bu
bozulmayı fark edip etmediğini ölçer. v4, **Run Comparison**'ı
(`autopsy compare`, iki `report.json`'u karşılaştırıp accuracy/health-score/
sınıf bazlı delta'ları ve `cause_type` küme diff'ini çıkarır), **hafif
Dataset Quality kontrollerini** (`autopsy run`'a entegre; düşük çözünürlük/
tam kopya/okunamayan dosya taraması, artık Autopsy Score'un bir alt-skoru),
**Smart Target Selection + Mutation Difficulty**'i (`autopsy mutate
--smart-target-selection`, gradyan-tabanlı saliency ile katman/kanal
seçimi + her mutant için easy/medium/hard zorluk etiketi), ayrı bir araç
olan **Dataset Contamination Detector**'ı (`autopsy contaminate`, kaynak
doküman `02_dataset_contamination_detector_development_map.md`'nin MVP'si —
train/test split'leri arasında SHA256 exact-duplicate + dHash near-duplicate
sızıntısı arar) ve **Object Detection Evaluation**'ı (`autopsy detect-eval`,
evaluation-only bir MVP — elde var olan tahmin+ground-truth kutularından
IoU-tabanlı mAP hesaplar, tam entegrasyon DEVIR §8.5'te kapsam dışı kalmaya
devam ediyor) ekledi.

## v4 Durumu: Tamamlandı

v4 yol haritasının tüm maddeleri tamamlandı:

1. ✅ [Run Comparison](#run-comparison-v4) — `autopsy compare`
2. ✅ [Dataset Quality Kontrolleri](#dataset-quality-kontrolleri-v4) — `autopsy run`'a entegre
3. ✅ [Smart Target Selection + Mutation Difficulty](#smart-target-selection-ve-mutation-difficulty-v4) — `autopsy mutate --smart-target-selection`
4. ✅ [Dataset Contamination Detector](#dataset-contamination-detector-v4) — `autopsy contaminate`
5. ✅ [Object Detection Evaluation](#object-detection-evaluation-v4) — `autopsy detect-eval` (evaluation-only MVP)
6. — AutoCNN Optimizer ilişkisi — Autopsy tarafında aksiyon gerektirmiyor (ayrı, tüketici bir proje)

v4 sonrası ek bir özellik olarak (resmi yol haritasının parçası değil):
**Input Mutation Testing** (doküman 03 §15) — modeli değil **girdiyi**
(fotoğrafı) bozar (brightness/contrast/blur/noise/crop/rotation/compression/
resize), orijinal modelin bunu fark edip etmediğini ölçer. Bkz.
[Input Mutation Testing](#input-mutation-testing-doküman-03-15).

## Kurulum

```bash
python -m venv .venv
.venv/Scripts/pip install -e ".[dev]"
```

GPU'lu bir kurulum için (CUDA 12/13 uyumlu bir sürücü varsa) torch'u ayrıca
uygun `--index-url` ile kurmanız gerekebilir; bkz.
[pytorch.org/get-started](https://pytorch.org/get-started/locally/).

## Kullanım

### Model + veri kümesi ile

```bash
autopsy run \
  --model model.pt \
  --dataset ./test \
  --output ./report
```

- `--model`: TorchScript (`torch.jit.script`/`trace` ile kaydedilmiş) dosya
  **önerilir**. Bir `state_dict` kaydıysa `--model-def paket.modul:fonksiyon`
  ile model iskeletini kuran bir fabrika fonksiyonu vermeniz gerekir. Tam
  pickled bir `nn.Module` ise `--allow-unsafe-load` gerekir (rastgele kod
  çalıştırabileceğinden yalnızca güvendiğiniz dosyalarla kullanın).
- `--dataset`: `ImageFolder` düzeninde bir dizin (her sınıf kendi alt
  klasöründe). Sınıf isimleri klasör adlarından **alfabetik sırayla**
  çıkarılır — modelin eğitimdeki sınıf sırasıyla eşleşmiyorsa
  `--class-names a,b,c` ile düzeltin.
- `--train-dataset`: opsiyonel; verilirse overfitting kontrolü (train-val
  accuracy farkı) etkinleşir.
- `--preprocess preprocess.yaml`: eğitimde kullanılan resize/normalize
  değerleri farklıysa mutlaka sağlayın:
  ```yaml
  resize: [224, 224]
  normalize:
    mean: [0.485, 0.456, 0.406]
    std: [0.229, 0.224, 0.225]
  ```
  Verilmezse ImageNet varsayılanı kullanılır ve rapora bir uyarı düşülür.
- `--output-type auto|logits|probs`: model çıktınız softmax uygulanmış
  olasılık değilse (PyTorch modellerinde yaygın), `auto` bunu tespit
  etmeye çalışır ama garantili değildir; şüphede kaldığınızda açıkça belirtin.
- `--embedding-layer LAYER_NAME` (§10): modelin belirtilen katmanından
  (örn. `features`) özellik vektörü yakalar; PCA→t-SNE ile 2 boyutlu bir
  scatter plot üretir ve "class overlap" tanısını embedding benzerliğiyle
  güçlendirir. **Yalnızca `--model-def` (state_dict) ile yüklenen canlı
  `nn.Module`'lerde güvenilir çalışır** — TorchScript modellerde
  (`torch.jit.load`) Python hook dispatch'i atlandığından ampirik bir
  self-test yapılır; desteklenmezse rapora uyarı düşülür ve bölüm sessizce
  atlanır (çökmez).
- `--gradcam-layer LAYER_NAME` (§16): hard example'lar için Grad-CAM
  overlay'i üretir (örn. `features.14` — son konvolüsyon katmanı). Aynı
  TorchScript kısıtına tabidir; `--gradcam-max-examples` (varsayılan 8) ile
  üretilecek overlay sayısı sınırlanır.

### Hazır tahminlerle (model/dataset olmadan)

Modeli veya görüntüleri paylaşamıyorsanız, doğrudan tahmin dizileriyle
çalıştırabilirsiniz:

```bash
autopsy run \
  --predictions probs.npy \
  --labels y_true.npy \
  --class-names cat,dog,bird \
  --output ./report
```

`probs.npy`: `(N, num_classes)` şeklinde logit ya da olasılık matrisi.
`labels.npy`: `(N,)` şeklinde gerçek etiketler (0-indeksli).

## Çıktı

```text
report/
├── index.html          # tek dosyalık, tüm görselleri gömülü rapor
├── report.json          # makine tarafından işlenebilir tam sonuç
├── confusion_matrix.png
└── examples/             # hard example görüntülerinin kopyaları (varsa)
    └── wrong_high_confidence/
```

`index.html` kendi kendine yeterlidir — grafikler ve örnek görüntü küçük
resimleri base64 olarak gömülüdür, harici dosyaya bağımlı değildir.

## Model Mutation Testing (v3)

"Modelimizi bozduğumuzda mevcut tanı sinyallerimiz bunu fark edebiliyor mu?"
sorusuna cevap arar. Modeli kontrollü biçimde mutasyona uğratır (her
mutasyon modelin bir kopyası üzerinde uygulanır, orijinal asla değişmez),
her mutantı aynı `run_model_inference`/`build_eval_result` hattından
geçirip orijinalle karşılaştırır, ve **mevcut tanı katmanının** (accuracy,
sınıf başına recall, ECE, Autopsy Score, `infer_causes`'ın ürettiği
`cause_type` kümesi) bu bozulmayı yakalayıp yakalamadığına bakar.

```bash
autopsy mutate \
  --model model.pt \
  --dataset ./test \
  --operators weight_noise,weight_zeroing,neuron_ablation,layer_freezing,quantization,activation_replacement \
  --mutants-per-operator 20 \
  --output ./mutation_report
```

- Model/dataset yükleme bayrakları (`--model-def`, `--allow-unsafe-load`,
  `--device`, `--preprocess`, `--class-names`, `--output-type` vb.)
  `autopsy run` ile birebir aynıdır. `--predictions`/`--labels` modu
  **yoktur** — mutasyon testi gerçek bir modeli mutasyona uğratmayı
  gerektirir.
- `--operators`: `weight_noise`, `weight_zeroing`, `neuron_ablation`,
  `layer_freezing`, `quantization` **ağırlık-seviyesindedir** —
  `model.named_parameters()` üzerinden doğrudan çalışırlar, TorchScript
  dahil her model türünde güvenle çalışır. `activation_replacement` tek
  istisna: modül ağacında gerçek bir değişiklik yaptığından (`setattr`)
  `--embedding-layer`/`--gradcam-layer` ile aynı ampirik self-test +
  zarif atlama desenine tabidir — yalnızca `--model-def` (state_dict) ile
  yüklenen canlı `nn.Module`'lerde güvenilir çalışır.
- `--mutants-per-operator`: operatör başına kaç rastgele mutant üretileceği
  (hedef katman + parametreler `--seed`'e göre deterministik seçilir).
- `--target-layers`: verilmezse modeldeki weight'li katmanlardan örneklenir.
- `--max-eval-samples`: büyük test setlerinde her mutant için tüm veri
  kümesini taramak yerine sabit boyutlu bir alt küme kullanır (performans).
- Killed/survived kararı `MutationThresholds` (accuracy düşüşü, sınıf
  recall düşüşü, ECE artışı, Autopsy Score düşüşü, yeni `cause_type`
  belirmesi) ile verilir; çöken ya da NaN/Inf üreten mutantlar **INVALID**
  sayılıp mutation-score paydasından hariç tutulur.

Çıktı:

```text
mutation_report/
├── index.html                     # tek dosyalık, tüm görselleri gömülü rapor
├── report.json                    # her mutant + özet (killed/survived/invalid, mutation_score)
├── mutation_score_by_operator.png
└── mutation_heatmap.png           # katman x operatör
```

Zayıf/güçlü bir test suite'in aynı mutant kümesinde nasıl farklı mutation
score'lara ulaştığını gösteren uçtan uca bir demo için bkz.
[`examples/mutation_demo.py`](examples/mutation_demo.py).

### Smart Target Selection ve Mutation Difficulty (v4)

```bash
autopsy mutate \
  --model model.pt --dataset ./test \
  --smart-target-selection \
  --output ./mutation_report
```

- **`--smart-target-selection`** (opt-in, varsayılan kapalı): katman/kanal
  seçimini uniform rastgele yerine gradyan-tabanlı bir "saliency" sinyaliyle
  ağırlıklandırır (Optimal Brain Damage tarzı Taylor-importance,
  `|weight · ∂L/∂w|`). Motivasyon: rastgele hedeflemenin modelin önemsiz
  köşelerini mutasyona uğratması, gerçek test-suite kör noktalarını
  gizliyordu. **Kritik mimari bulgu**: bu, `torch.autograd.grad` kullanır —
  v2/v3'ün tekrar karşılaştığı "forward/backward HOOK TorchScript'te
  atlanabilir" sorunundan (bkz. `core/hooks.py`) TAMAMEN FARKLI bir
  mekanizma olduğundan TorchScript dahil her model türünde hiçbir self-test/
  fallback gerekmeden çalışır.
  - `--saliency-max-samples` (varsayılan 256): saliency hesabında kullanılan
    örnek sayısı.
  - `--saliency-temperature` (varsayılan 2.0): ağırlıklandırmanın yumuşaklığı
    — yüksek değer uniforma yaklaşır, düşük değer en yüksek-saliency
    katmanı(ları) daha güçlü önceliklendirir.
  - Opt-in olma nedeni: mevcut `--seed` reprodüktibilitesini ve committed
    örnek raporları sessizce değiştirmemek.
  - GPU'da saliency hesaplaması cudnn'in non-deterministik kernellerini
    kullanabilir — `--seed` diğer mutasyon adımlarında tam reprodüktibilite
    sağlasa da smart-selection'ın katman dağılımı GPU'da hafifçe değişebilir.
- **Mutation Difficulty**: her mutant için `difficulty_score`/
  `difficulty_label` (`easy`/`medium`/`hard`) — "en ayırt edici sinyalin"
  (accuracy/recall/ECE/health-score delta'sı ya da yeni `cause_type`) kendi
  kill eşiğine göre normalize edilmiş oranı. `hard` (eşiğin çok altında
  survived) test suite'in **kör noktalarını** gösterir — rapor özetinde
  `hard_survived` sayacı ve HTML'de "Hard Survived" kartı + survived mutant
  listesinde difficulty badge'i olarak görünür.

### Input Mutation Testing (doküman 03 §15)

Yukarıdaki operatörler modelin **ağırlıklarını** bozar; bu ayrı kategori
modeli hiç değiştirmeden **girdiyi** (fotoğrafı) bozup orijinal modelin bunu
fark edip etmediğini ölçer — "modelimiz bulanık/karanlık/gürültülü
fotoğraflara karşı dayanıklı mı?" sorusuna cevap. Aynı `autopsy mutate`
komutu, aynı `--operators` bayrağı üzerinden, ağırlık operatörleriyle
serbestçe karıştırılarak kullanılır:

```bash
autopsy mutate \
  --model model.pt --dataset ./test \
  --operators weight_noise,input_blur,input_noise,input_compression \
  --output ./mutation_report
```

8 operatör (hepsi `input_` önekiyle, opt-in — `DEFAULT_MUTATION_OPERATORS`'a
dahil DEĞİL, yalnızca açıkça `--operators`'a eklenirse çalışır):
`input_brightness`, `input_contrast`, `input_blur`, `input_noise`,
`input_crop`, `input_rotation`, `input_compression`, `input_resize`. Her biri
saf bir PIL-uzayı dönüşümü, `--preprocess`'in Resize/ToTensor/Normalize
adımlarından ÖNCE, ham piksel uzayında uygulanır (`autopsy/mutation/
input_operators.py`) — yeni pip bağımlılığı yok (Pillow zaten torchvision'ın
transitive bağımlılığı).

- Her operatörün parametre ızgarası ayrı bir CLI bayrağıyla ayarlanabilir
  (örn. `--input-blur-radii`, `--input-noise-sigmas`) — mevcut
  `--weight-noise-sigmas` vb. ile birebir aynı desen.
- Mutantlar hiçbir katman/kanal hedeflemediğinden rapor/heatmap'te sabit bir
  pseudo-layer olan `"(girdi)"` ile görünür — `verdict.py`'nin zaten
  `layer_name=None` için kullandığı `"(bilinmiyor)"` deseniyle aynı, gerçek
  bir model katmanına karşılık gelmez.
- **Bilinçli sadeleştirmeler**: `input_crop` her zaman merkezden kırpar
  (rastgele ofset yok); `input_rotation` döndürülen köşeleri siyahla doldurur
  (`fillcolor=(0,0,0)`, ImageNet-C tarzı corruption benchmark'larının da
  yaptığı gibi bilinçli bir seçim, gizli bir varsayılan değil).
- **Performans notu**: `ImageFolder` zaten HER `__getitem__` çağrısında
  diski yeniden okuyor (caching yok) — bu, input mutasyonuna özgü yeni bir
  maliyet sınıfı DEĞİL. Gerçek ek maliyet yalnızca PIL transform'unun kendisi
  (en pahalısı JPEG round-trip + Gaussian blur).
- `--smart-target-selection` input operatörlerini etkilemez (hiçbir ağırlık/
  gradyan sinyali kullanmazlar) — saf-input çalıştırmalarında saliency
  hesaplaması otomatik olarak atlanır.

## Run Comparison (v4)

İki `autopsy run` koşusunun `report.json` çıktısını karşılaştırır — "modeli
değiştirdik, gerçekten iyileşti mi?" sorusuna cevap arar. Repo geçmişi ya da
ayrı bir depolama katmanı gerektirmez, yalnızca iki `report.json` dosyası
okur.

```bash
autopsy compare \
  --before report_a/report.json \
  --after report_b/report.json \
  --output ./compare_report
```

- `--before`/`--after`: karşılaştırılacak iki `autopsy run` çıktısının
  `report.json` yolu. Şema uyumu için aşağıdaki [Artifact şema
  versiyonlama](#artifact-şema-versiyonlama-v5) bölümüne bakın.
- Accuracy/macro-F1/weighted-F1/health-score/ECE delta'ları.
- Sınıf başına recall/precision/f1 delta'ları (bar grafik + tablo). `before`
  ve `after` farklı `class_names` kümelerine sahipse (örn. sınıf eklendi/
  çıkarıldı) çökmez — uyarı basar, yalnızca ortak sınıfları karşılaştırır.
- **`cause_type` küme diff'i** — `mutation/verdict.py`'nin
  `evaluate_mutant`'ta kullandığı `new_cause_types` deseninin (küme farkı)
  doğrudan yeniden kullanımı: yeni beliren / kaybolan / kalıcı nedenler.
- Confusion-pair kaymaları — hangi (true, predicted) çiftinin oranı en çok
  değişmiş, ilk 20.
- `verdict`: health-score delta'sına göre `improved`/`regressed`/`unchanged`.

Çıktı:

```text
compare_report/
├── index.html   # tek dosyalık, gömülü görselli rapor
└── report.json  # makine tarafından işlenebilir tam diff
```

## Historical Autopsy — N koşumluk trend (v5)

`compare` iki koşumu karşılaştırır; `autopsy history` **N koşumu** zaman
ekseninde dizip accuracy / Autopsy Score / alt skor trendini çıkarır —
"son bir aydır gidişat ne yönde?" sorusuna cevap arar.

`compare` gibi **ayrı bir depolama katmanı gerektirmez**: yeni bir
veritabanı, servis ya da kalıcı index yoktur. Koşum deposu, elinizde zaten
duran `report.json` dosyalarının kendisidir; `history` onları okur ve
hiçbirine dokunmaz.

```bash
# Bir çıktı ağacını tara (report.json'lar özyinelemeli bulunur)
autopsy history --scan ./reports --output ./history_report

# Ya da koşumları açıkça ver (ikisi birlikte de kullanılabilir)
autopsy history --runs run_a/report.json run_b/report.json --output ./history_report
```

- **Zaman ekseni** raporun kendi `generated_at` alanından gelir (şema v2).
  Alanı taşımayan eski (v1) raporlarda dosya `mtime`'ına düşülür ve bu her
  koşum için `timestamp_source` olarak **açıkça** raporlanır — kopyalanmış
  ya da checkout edilmiş dosyalarda sıranın yanıltıcı olabileceği
  saklanmaz.
- **Seriler**: accuracy · macro-F1 · weighted-F1 · Autopsy Score · ECE, artı
  her Autopsy Score **alt skoru** için ayrı bir seri. Hesaplanamamış bir alt
  skor (`N/A`) grafikte **boşluk** kalır, sıfıra çevrilmez.
- `verdict`: pencerenin ilk ve son koşumu arasındaki health-score
  delta'sına göre `improved`/`regressed`/`unchanged` — eşik `compare` ile
  aynıdır.

**Farklı şema sürümleri sessizce karışmaz.** Trend, tanımı gereği bir
geliştirme penceresine yayılmış koşumları okur; sürüm farkı istisna değil
normal durumdur. `history` bu yüzden `compare`'in [şema
guard'ını](#artifact-şema-versiyonlama-v5) **aynen** uygular:

| Durum | Davranış |
|---|---|
| Sürümsüz (v5 öncesi), okunamayan ya da ileri sürümlü rapor | Trend'in **dışında** bırakılır; gerekçesi `excluded_runs`'ta, CLI çıktısında ve HTML'de adıyla yazar |
| `autopsy.run` olmayan bir artifact (ör. bir `autopsy compare` çıktısı — o da `report.json` adıyla yazılır) | Trend'in dışında bırakılır, ne olduğu söylenir |
| Kabul edilen ama **farklı sürümlü** koşumlar | **Kısmi trend**: yalnız tüm sürümlerin ortak alanları çizilir, `KISMİ TREND` banner'ı basılır, `comparability` bloğu atlanan bölümleri adlandırır |

`comparability` `compare`'inkinin N'li karşılığıdır ve aynı invariant'ı
taşır — `partial` ayrıca hesaplanmaz, sürüm çokluğundan türer:

```json
"comparability": {
  "partial": true,
  "anchor": {"artifact": "autopsy.run", "version": 2},
  "versions_present": [1, 2],
  "compared_sections": ["autopsy_score", "class_stats", "confusion_pairs", "ece", "likely_causes", "overall_metrics"],
  "skipped_sections": [
    {"section": "generated_at", "reason": "yalnız şema v2 koşumlarında var, v1 koşumlarında yok"}
  ]
}
```

Çıktı:

```text
history_report/
├── index.html   # tek dosyalık, gömülü trend grafikli rapor
└── report.json  # autopsy.history artifact'i: seriler, koşumlar, dışlananlar
```

## Artifact şema versiyonlama (v5)

`run` · `mutate` · `contaminate` · `detect-eval` · `compare` · `history`
komutlarının ürettiği her `report.json` **kendini tanıtır**: dosyanın
kökünde bir `schema` bloğu bulunur.

```json
{
  "schema": {
    "artifact": "autopsy.run",
    "version": 2,
    "generator": {"tool": "ai-model-autopsy", "version": "0.1.0"}
  }
}
```

- `artifact`: sabit değerlerden biri (`autopsy.run` · `autopsy.mutate` ·
  `autopsy.contaminate` · `autopsy.detect_eval` · `autopsy.compare` ·
  `autopsy.history`).
- `version`: tamsayı ve **her artifact türü için bağımsız** sayar — bir
  komutun şeması genişlediğinde yalnızca kendi sayacı artar.
- `generator`: tanılama amaçlıdır; hiçbir kararın girdisi değildir.

**`autopsy compare` bu bloğa göre davranır** — bir sürüm uyuşmazlığında
sessizce "tam karşılaştırma gibi görünen" kısmi bir çıktı üretmez:

| Durum | Davranış | Exit |
|---|---|---|
| İki sürüm de var ve **eşit** | Tam karşılaştırma | 0 |
| İki sürüm de var, **farklı**, ikisi de okunabilir aralıkta | **Kısmi karşılaştırma** — yalnız iki şemanın ortak alanları; `KISMİ KARŞILAŞTIRMA` banner'ı, HTML'de uyarı şeridi, `report.json`'da `comparability` bloğu | 0 |
| Bir tarafta sürüm **yok** (v5 öncesi rapor) | Durur, tek satırlık mesaj: raporu `autopsy run` ile yeniden üretin | 1 |
| Bir taraf **daha yeni** bir sürüm | Durur: aracı güncelleyin | 1 |

Kısmi karşılaştırmada neyin karşılaştırıldığı `report.json`'da açıkça yazar:

```json
"comparability": {
  "partial": true,
  "before": {"artifact": "autopsy.run", "version": 1},
  "after":  {"artifact": "autopsy.run", "version": 2},
  "compared_sections": ["autopsy_score", "class_stats", "confusion_pairs", "ece", "likely_causes", "overall_metrics"],
  "skipped_sections": [
    {"section": "...", "reason": "after şeması v2'de var, before şeması v1'de yok"}
  ]
}
```

Yazma her zaman güncel sürümledir; eski sürüm üretme modu yoktur.

Sürüm geçmişi:

| Artifact | Sürüm | Değişiklik |
|---|---|---|
| `autopsy.run` | 1 | v5 açılışı — sürümleme öncesindeki alan kümesi |
| `autopsy.run` | 2 | `generated_at` eklendi (`autopsy history`'nin zaman ekseni) |

## Dataset Quality Kontrolleri (v4)

`autopsy run`'a entegre, hafif bir veri-kalite taraması (ayrı bir araç
değil) — model+dataset modunda `--dataset`'teki her görüntü bir kez okunup
üç şey kontrol edilir:

- **Düşük çözünürlük**: `DiagnosisThresholds.dataset_quality_min_width`/
  `_min_height` (varsayılan 64x64) altındaki görüntüler, sınıf başına
  sayılır.
- **Tam kopya**: SHA256 hash'i aynı olan dosyalar bir "duplicate group"da
  toplanır.
- **Okunamayan/bozuk dosya**: PIL ile decode edilemeyen dosyalar tespit
  edilir ve **değerlendirmeden otomatik olarak hariç tutulur** — aksi halde
  tek bir bozuk dosya inference sırasında tüm `autopsy run`'ı çökertirdi.
  Düşük çözünürlük ve tam kopyalar hariç tutulmaz, yalnızca raporlanır.

- **Boş / neredeyse-boş görüntü** (doküman 01 §17): gri ton standart sapması
  `DiagnosisThresholds.dataset_quality_empty_std_threshold` (varsayılan 1.0)
  altındaki görüntüler. Tek renk taranmış sayfa, tamamen siyah kare gibi
  örnekleri yakalar; her bulgu kendi `std` değeriyle raporlanır ki eşik
  dataset'e göre kalibre edilebilsin. Bu kontrol **her zaman** koşar — dosya
  zaten okunup decode edildiği için ek I/O getirmez.

Sonuçlar rapora üç şekilde yansır: (1) `warnings` listesine kısa özet
uyarılar, (2) Autopsy Score'un artık gerçek veriyle beslenen "Dataset
Quality" alt-skoru (önceden her zaman N/A bir placeholder'dı), (3)
`index.html`'de ayrı bir "Dataset Quality" bölümü (sınıf-başına tablo +
duplicate/unreadable/boş listeleri) ve `report.json`'da `dataset_quality`
anahtarı (`--predictions` modunda `null`). Alt skorun cezası dört terimden
oluşur: okunamayan + düşük çözünürlük + fazladan tam kopya + boş görüntü
oranı. Çözünürlük ve boşluk eşikleri için henüz bir CLI bayrağı yok —
`DiagnosisThresholds` üzerinden programatik olarak değiştirilebilir.

### Split-içi near-duplicate taraması (opt-in)

`autopsy run --near-duplicate-scan`, aynı dataset İÇİNDE dHash + Hamming
mesafesiyle yakın kopya arar. Üç bilinçli kısıt:

- **Varsayılan kapalı.** Karşılaştırma O(n²); ölçülen eğri `t ≈ 1,15e-8·n²`
  (10.000 görüntüde ~1 sn, 50.000'de ~29 sn). Bayrak verilmezse `report.json`
  bu bloğu hiç taşımaz.
- **Üst sınır `--near-duplicate-max-images` (varsayılan 50.000).** Sınır
  aşılırsa tarama sessizce değil, `skipped_reason` + `warnings` satırıyla
  atlanır.
- **Autopsy Score'a GİRMEZ.** `autopsy contaminate` için geçerli olan
  kalibrasyon uyarısı (aşağıda) burada da geçerli: düşük görsel çeşitlilikli
  bir dataset'te dHash yüz binlerce çift üretebilir. Skora bağlansaydı
  `dataset_quality` alt skoru böyle dataset'lerde anlamını yitirirdi.

Çıktı, çiftlerin listesi değil bir **mesafe histogramı**dır (mesafe → çift
sayısı): n=10.000'de çift listesi ~112 MB'a çıkabildiği için hiç
materyalize edilmez. Dar kova (Hamming `d<=2`) görüntü başına ortalama en az
bir çift içeriyorsa rapor `signal_diluted` bayrağını kaldırır ve `warnings`'e
"eşikleri kalibre etmeden bu sayıyı bulgu olarak okumayın" satırını ekler.

dHash primitifleri (`compute_dhash`, `hamming_distance`,
`find_candidate_pairs`, `distance_histogram`) `autopsy/core/hashing.py`'de
tek kaynak olarak durur; `autopsy/contamination/hashing.py` eski import
yolunu yaşatan bir re-export shim'dir.

## Dataset Contamination Detector (v4)

"Model gerçekten öğreniyor mu, yoksa test verisini bir şekilde daha önce
gördü mü?" — train/validation/test split'leri arasında exact/near-duplicate
sızıntısı arayan **ayrı bir araç** (`autopsy run`'a entegre değil, model/
dataset-under-test gerektirmez). Kaynak spesifikasyon:
`02_dataset_contamination_detector_development_map.md` (repoya kopyalanmadı,
kapsamı tam bir "ML dataset integrity auditor" — bu MVP §1-6/§11/§15/§17'sini
kapsıyor, pretrained deep-embedding/group-video-label-leakage/FAISS
ölçeklendirme bilinçli olarak kapsam dışı, aşağıya bkz.).

```bash
autopsy contaminate \
  --split train=./data/train \
  --split test=./data/test \
  --output ./contamination_report
```

- **`--split isim=yol`** (tekrarlı, en az 2 kez): her split standart
  `<yol>/<sınıf>/<görüntü>` (`ImageFolder`) düzeninde. Dizin *isimlendirmesine*
  dayalı bir varsayım YOK — mevcut `autopsy run`'ın `--dataset`/
  `--train-dataset` açıklığıyla tutarlı.
- **Exact duplicate**: SHA256 tam eşleşme. Cross-split → **CRITICAL**,
  aynı split içi → LOW (redundant veri, leakage değil).
- **Near/weak duplicate**: manuel dHash (difference hash — `imagehash`
  kütüphanesi kasıtlı olarak KULLANILMIYOR, PIL+numpy ile birkaç satır,
  yeni bağımlılık yok) + Hamming mesafesi, **iki kademeli eşik**:
  - `--near-duplicate-max-distance` (varsayılan 5): yüksek güven
    (resize/hafif JPEG sıkıştırma) → cross-split HIGH.
  - `--weak-similarity-max-distance` (varsayılan 14): düşük güven (crop/ağır
    transform — dHash'in bilinen zayıf noktası) → cross-split **REVIEW**,
    **asla CRITICAL değil**.
- **Disclaimer her zaman rapor üstünde görünür**: *"benzerlik ≠
  contamination"* — araç yalnızca piksel-düzeyi kanıt sunar, kesin "DATA
  LEAKAGE CONFIRMED" demez; REVIEW etiketli çiftler için manuel doğrulama
  önerilir.
- `--max-pairs-in-report` (varsayılan 200): `report.json`/`index.html`'e
  giren çift sayısını risk sırasına göre kırpar — sayaçlar (`report.json`'un
  `summary` alanı) hiçbir zaman kırpılmaz, `truncated_pairs_count` açıkça
  gösterilir.
- **Ölçek notu**: karşılaştırma tam (yaklaşık değil) ama vektörize/chunked —
  FAISS/LSH YOK (doküman kendi §15 "Scale"ini ayrı, ileri bir aşama olarak
  listeliyor). `--max-images-warning` (varsayılan 5000) yalnızca uyarır,
  engellemez; gerçek Rice train+test'te (12.500 görüntü) tam koşu ~40 saniye
  sürdü.
- **Kalibrasyon uyarısı (gerçek veriyle doğrulandı)**: dHash eşikleri
  **dataset'e göre kalibre edilmeli** (doküman §19'un kendi uyarısı) — Rice
  Image Dataset gibi düşük görsel çeşitliliğe sahip (küçük, benzer nesneler,
  benzer arka plan) veri kümelerinde varsayılan eşikler yüzbinlerce
  near/weak-duplicate çifti üretebilir (bu sinyal seyrelir). **Exact
  duplicate (SHA256) tespiti bundan etkilenmez** — sıfır false-positive,
  her zaman güvenilir. Nitekim bu araç gerçek Rice train/test split'inde
  **6 tam kopya cross-split** buldu (aynı görüntü farklı dosya adıyla hem
  train hem test'te) — resmi bir Kaggle split'inde bile gerçek, önceden
  bilinmeyen bir sızıntı.

## Object Detection Evaluation (v4)

**Evaluation-only, modelsiz bir MVP** — DEVIR.md §8.5'in kendi notu
`EvalResult`'ın tek-etiket-per-görüntü varsayımını değiştirmeyi gerektiren
tam bir object-detection entegrasyonunu hâlâ kapsam dışı tutuyor (yeni
dataset formatı, model adaptörü, her analizörün box-seviyesine yeniden
yorumlanması gerektirirdi). Bu komut onun yerine: **elinizde zaten olan**
tahmin + ground-truth kutularından IoU-tabanlı mAP/AP hesaplar — inference
veya training YAPMAZ (bu yüzden bilinçli olarak `detect` değil
`detect-eval`).

```bash
autopsy detect-eval \
  --predictions preds.json \
  --ground-truth gt.json \
  --output ./detection_report
```

Her iki JSON dosyası da aynı düz şema (**COCO formatı DEĞİL** —
image_id/category_id dolaylılığından kaçınmak için):

```json
[
  {"image_id": "photo1.jpg", "class_name": "person", "bbox": [10, 10, 100, 200], "score": 0.97},
  {"image_id": "photo1.jpg", "class_name": "dog", "bbox": [150, 50, 250, 180]}
]
```

- `score` yalnızca `--predictions` için zorunlu; `--ground-truth`'ta
  verilirse yoksayılır.
- `--bbox-format xyxy` (varsayılan, `[x1,y1,x2,y2]`) ya da `xywh`
  (`[x,y,genişlik,yükseklik]`).
- `--iou-threshold` (varsayılan 0.5, PASCAL VOC tarzı tek eşik — COCO'nun
  mAP@[0.5:0.95] çoklu-eşik ortalaması YOK, MVP sadeleştirmesi).
- **Eşleştirme**: skor DESC sıralı her prediction, aynı görüntüdeki
  kullanılmamış GT kutuları arasından en yüksek IoU'luyla eşleşir (COCO/
  PASCAL VOC referans implementasyonlarıyla aynı greedy yaklaşım — Hungarian/
  optimal atama değil).
- **AP**: all-point interpolation (PASCAL VOC 2010+/COCO tarzı, 11-point
  değil). GT'si olmayan ama tahmin edilmiş sınıflar `N/A` işaretlenir ve
  mAP ortalamasından hariç tutulur (etiketleme/taksonomi hatası uyarısı
  olarak raporlanır); GT'si olup hiç tahmin edilmemeyen sınıflar `AP=0.0`
  alır ve mAP'a dahil edilir (model o sınıfı tamamen kaçırmış demektir).
- `--max-examples-in-report` (varsayılan 50): false positive/negative
  listelerini kırpar (sayaçlar tam kalır).
- Yeni pip bağımlılığı YOK (`pycocotools` bilinçli olarak kullanılmadı —
  C-extension build kırılganlığı; mAP algoritması manuel, numpy ile
  implemente edildi ve elle hesaplanmış bir referans örnekle
  doğrulandı).

## Gerçek model örnekleri

Repoda gerçek modellerle üretilmiş, gerçek verili örnek raporlar bulunur:

- **Rice Image Dataset** (5 sınıflı pirinç türü sınıflandırması, ~%98
  accuracy) — [`examples/rice_report/`](examples/rice_report/index.html)
- **Face Mask Detection** (Kaggle `andrewmvd/face-mask-detection`, orijinali
  bir obje tespiti veri seti — XML kutulardan yüzler kırpılıp 3 sınıflı
  `with_mask`/`without_mask`/`mask_weared_incorrect` bir sınıflandırma
  görevine dönüştürüldü; doğal olarak çok dengesiz — `mask_weared_incorrect`
  sınıfında yalnızca 98 örnek. Autopsy'nin class-imbalance/representation-
  problem tanılarını ve Model Mutation Testing'i gerçek, zorlu bir veri
  setinde doğrulayan bir örnek):
  - `autopsy run` raporu — [`examples/face_mask_report/`](examples/face_mask_report/index.html)
  - `autopsy mutate` raporu — [`examples/face_mask_mutation_report/`](examples/face_mask_mutation_report/index.html)

## Geliştirme

```bash
.venv/Scripts/pytest tests/ -v
```

Sentetik hata senaryolarını (doküman §19 test planı — gerçek bir CNN
eğitip beklenen teşhisin çıktığını doğrular) çalıştırmak için:

```bash
.venv/Scripts/python examples/synthetic_faults.py
```

Model Mutation Testing'in "zayıf vs güçlü test suite" demosunu (03 dokümanı
§26) çalıştırmak için:

```bash
.venv/Scripts/python examples/mutation_demo.py
```

## Mimari

```
ModelAdapter ─┐
              ├─→ PredictionEngine ─→ EvalResult ─┬─→ MetricsAnalyzer
DatasetLoader ┘                                   ├─→ ConfusionAnalyzer
                                                   ├─→ ClassFailureAnalyzer
                                                   ├─→ ConfidenceAnalyzer
                                                   └─→ HardExampleMiner
                                                           │
                                                    CauseInference (heuristik)
                                                           │
                                                    ReportGenerator (HTML + JSON + PNG)
```

`EvalResult`, tüm analizörlerin paylaştığı tek veri kaynağıdır; analizörler
modele veya görüntülere hiç dokunmaz. Bu sayede `--predictions` modu model
yüklemeyi tamamen atlayabilir.

v2'de bu ilkeye bir istisna: embedding/Grad-CAM, `EvalResult` üretilirken
(`core/engine.py`'nin tek inference geçişi içinde, `core/hooks.py` üzerinden)
modele dokunmak zorunda — ama sonucu yine `EvalResult.embeddings`'e yazıp
analizörlere (`analyzers/embedding_analysis.py`) modelden bağımsız,
salt-numpy bir arayüz sunuyor.

v3'te `autopsy/mutation/` (`inspector.py`, `operators.py`, `verdict.py`,
`engine.py`) `autopsy run`'ın hiçbir koduna dokunmadan çalışır: modeli bir
kez yükler, kopyasını mutasyona uğratır, aynı `run_model_inference`/
`build_eval_result` çiftinden ve aynı analizör/`infer_causes` katmanından
geçirip orijinalle karşılaştırır. `core/hooks.py`'ye yalnızca
`activation_replacement` operatörü için eklenti yapıldı
(`supports_module_surgery`/`set_submodule_by_name`) — aynı "sabit
`isinstance` yerine ampirik self-test" ilkesiyle.

## Dokümandan sapmalar

| Doküman | Durum | Gerekçe / not |
|---|---|---|
| §5: TensorFlow/Keras MVP | PyTorch | Windows'ta TF 2.11+ CPU-only; PyTorch native CUDA desteği var |
| §10 Embedding (PCA/t-SNE/UMAP) | **v2'de var** | `--embedding-layer`; UMAP yerine PCA→t-SNE (sklearn, ek bağımlılık yok) |
| §14 Recommendation Engine | **v2'de var** | Her hipotezin `cause_type`'ına göre statik öneri listesi |
| §16 Grad-CAM | **v2'de var** | `--gradcam-layer`; SHAP eklenmedi |
| §18 Autopsy Score | **v2'de var, v4'te tamamlandı** | 0-100 sağlık skoru + alt skorlar (Dataset Quality alt-skoru v4'e kadar N/A placeholder'dı, artık gerçek veriyle besleniyor) |
| §11 Kural 3 (class overlap) | **v2'de yükseltildi** | `--embedding-layer` verilirse embedding cosine similarity + confusion birleşik kanıt; verilmezse v1'in confusion-only sürümüyle birebir aynı |
| §17 Dataset-level diagnosis | **v4'te hafif bir alt kümesi var** | Tam "proje #2" entegrasyonu (bu depoda mevcut değil) hâlâ kapsam dışı; v4 yalnızca çözünürlük/tam-kopya/okunamayan-dosya taramasını `autopsy run`'a ekledi (bkz. "Dataset Quality Kontrolleri") |
| §20 Object detection / segmentation / NLP | Yok | Kapsam dışı — image classification odağı korunuyor |
| §20 Deney/versiyon karşılaştırma | **v4'te var** | `autopsy compare` — iki `report.json`'u karşılaştırır, repo geçmişi/depolama katmanı gerektirmez |
| §20 Historical autopsy | **v5'te var** | `autopsy history` — N `report.json`'un zaman içindeki trendi; `compare` ile aynı ilke, ayrı depolama katmanı yok (bkz. "Historical Autopsy") |

**TorchScript kısıtı**: `--embedding-layer`/`--gradcam-layer`, PyTorch'ta
`register_forward_hook`/`register_full_backward_hook`'un `torch.jit.load`
ile yüklenen `RecursiveScriptModule`'lerde çalışmaması nedeniyle yalnızca
`--model-def` (state_dict) yolunda garantili çalışır. Kurulu PyTorch
sürümünde gözlenen bu davranış `tests/test_hooks.py`'de regresyon testiyle
kilitlendi — TorchScript modellerde ampirik self-test yapılır, desteklenmezse
uyarıyla atlanır (çökmez).

### Model Mutation Testing dokümanından (03) sapmalar

v3, ana tasarım dokümanından (01) değil, ayrı bir kaynak dokümandan
([`03_model_mutation_testing_development_map.md`](03_model_mutation_testing_development_map.md))
geliyor — bu yüzden ayrı bir sapma tablosu:

| Doküman (03) | Durum | Gerekçe / not |
|---|---|---|
| §9 Weight noise | **var** | `apply_weight_noise` — `model.named_parameters()` üzerinde doğrudan, TorchScript-güvenli |
| §10 Weight zeroing | **var** | `apply_weight_zeroing` — random / largest / smallest magnitude stratejileri |
| §11 Neuron ablation | **var** | `apply_neuron_ablation` — **ağırlık-seviyesinde** (kanal weight satırı + bias sıfırlama), forward hook değil |
| §12 Activation mutation | **var** | `apply_activation_replacement` — tek ağırlık-dışı operatör; `core/hooks.py`'nin ampirik self-test desenini kullanır, yalnızca `--model-def` yolunda garantili |
| §5 Layer freezing | **yeniden yorumlandı** | Bu pipeline yalnızca inference yapar (eğitim döngüsü yok) — `requires_grad=False`'un tek başına hiçbir çıktı etkisi olmaz. Bunun yerine "katman hiç öğrenmemiş gibi davransın": weight/bias taze (Kaiming-uniform benzeri) değerlerle değiştirilir |
| §14 Quantization | **var (manuel)** | `torch.ao.quantization`'ın QConfig/observer makinesi yerine manuel fp16/int8 round-trip — keyfi/TorchScript modellere karşı kırılgan değil, yeni bağımlılık gerektirmiyor |
| §13 Layer/mimari mutasyonlar (silme, bypass) | Yok | Dokümanın kendi §4 MVP sınırı: "İlk aşamada layer silme gibi mimari mutasyonları daha sonraya bırak" |
| §15 Input mutations | **var** | `input_operators.py` — 8 operatör (brightness/contrast/blur/noise/crop/rotation/compression/resize), modeli değil girdiyi bozar; aynı `autopsy mutate --operators` bayrağı üzerinden ağırlık operatörleriyle karıştırılır (bkz. "Input Mutation Testing") |
| §24 Smart/gradyan-güdümlü mutasyon seçimi | **v4'te var** | `--smart-target-selection` — gradyan-tabanlı saliency (`|weight·∂L/∂w|`), yalnızca "high gradient weights"/"important neurons" (aktivasyon-frekansı sinyali BİLİNÇLİ OLARAK yok — hook gerektirirdi, TorchScript kırılganlığını geri getirirdi) |
| §25 Mutation difficulty scoring | **v4'te var** | Her mutant için `difficulty_score`/`difficulty_label` (easy/medium/hard) — en ayırt edici sinyalin kill-eşiğine göre normalize oranı |
| §21-23 Tam robustness matrix / clustering / heatmap | **basitleştirilmiş** | `by_operator`/`by_layer` özeti + katman×operatör heatmap var; ayrı bir kategori-clustering katmanı yok |
| §30 V2 (transformer/attention/LoRA/adapter mutasyonları, dağıtık çalıştırma) | Yok | Kapsam dışı — bu proje CNN/image classification odaklı |
