# Data

## Cara mengambil

```python
from huggingface_hub import snapshot_download
DATA = snapshot_download(repo_id="fassabilf/diffusion-mcqa-pelatnas-2026",
                         repo_type="dataset")
```

## Struktur

```
train/
  train.csv              100 baris — id, t, type, choice_0..4, label
  latents/{id}.npy       100 file, (4,64,64) float16
test/
  test.csv               250 baris — id, t, choice_0..4     (TANPA type & label)
  latents/{id}.npy       250 file
sample_submission.csv    250 baris — id, label
```

Total ukuran ≈ 6 MB.

---

## ⚠️ Format latent — baca ini sebelum menulis kode

| | |
|---|---|
| Shape | `(4, 64, 64)` |
| dtype | `float16` |
| Skala | **SUDAH dikalikan `0.18215`** |

Latent yang tersimpan **siap langsung dimasukkan ke UNet**. Kamu tidak perlu
mengalikan faktor skala lagi.

Kalau kamu mau men-decode-nya dengan VAE, **bagi dulu**:

```python
x_t = np.load(f"{DATA}/test/latents/{i}.npy")          # sudah ter-scale
lat = torch.from_numpy(x_t).unsqueeze(0).to("cuda", torch.float16)

eps = unet(lat, t, encoder_hidden_states=cond).sample   # langsung, tanpa penyesuaian
img = vae.decode(lat / 0.18215).sample                  # decode: bagi dulu
```

Ini satu-satunya jebakan teknis yang sengaja kami jelaskan terang-terangan. Sisanya
adalah soalnya.

### 4 channel itu bukan RGBA

Tidak ada channel yang berarti "merah", "hijau", atau "alpha". Itu basis laten hasil
belajar VAE dan urutannya arbitrer. Menampilkan channel 0–2 sebagai RGB akan
menghasilkan gambar aneh yang tidak berarti apa-apa.

Untuk melihat sekilas isinya, notebook baseline menyediakan `latent2rgb` — proyeksi
linear `4 → 3` yang dipakai ComfyUI/A1111 untuk live preview. Kasar, tapi cukup untuk
mata, dan jauh lebih murah daripada VAE decode.

---

## Skema kolom

### `train/train.csv`

| Kolom | Tipe | Keterangan |
|---|---|---|
| `id` | int | 0–99, cocok dengan `train/latents/{id}.npy` |
| `t` | int | timestep, ∈ {50, 400, 700} |
| `type` | int | 1–5, kelompok soal |
| `choice_0` … `choice_4` | str | 5 kandidat caption, urutan sudah diacak |
| `label` | int | 0–4, indeks caption yang benar |

### `test/test.csv`

Sama, **tanpa** `type` dan **tanpa** `label`.

Kolom `type` sengaja hanya ada di train. Kalau ada di test, kamu bisa memakai
strategi berbeda per kelompok — dan itu menghapus kesulitan utamanya, yaitu bahwa
metodenya harus berlaku umum. Di train, kolom itu ada justru supaya kamu bisa
menganalisis metodemu per kelompok.

---

## Bagaimana data ini dibuat

1. Gambar adalah **foto asli berlisensi publik** (bukan hasil generate), dengan
   caption yang ditulis manusia. Dataset sumbernya sengaja tidak disebut — lihat
   halaman Rules.
2. Gambar di-resize + center-crop ke 512×512, lalu di-encode dengan VAE Stable
   Diffusion v1.4 → latent bersih `x_0`, dikalikan `0.18215`.
3. Noise ditambahkan mengikuti forward process:

   $$x_t = \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1-\bar\alpha_t}\, \varepsilon,
     \qquad \varepsilon \sim \mathcal N(0, I)$$

   dengan schedule `scaled_linear`, β ∈ [0.00085, 0.012], 1000 timestep — persis
   schedule SD 1.4.
4. Yang disimpan **hanya `x_t`**. `ε`, `x_0`, dan seed dibuang dan tidak pernah
   ditulis ke disk.
5. Empat distraktor ditambahkan, lalu urutan kelima caption diacak per soal.
   Sebaran jawaban benar di indeks 0–4 diuji merata (χ²).

Nilai ᾱ untuk timestep yang dipakai:

| t | ᾱ_t | √ᾱ_t | √(1−ᾱ_t) | SNR |
|---|---|---|---|---|
| 50 | 0.9516 | 0.9755 | 0.2201 | 19.65 |
| 400 | 0.4245 | 0.6515 | 0.7586 | 0.74 |
| 700 | 0.0825 | 0.2873 | 0.9579 | 0.090 |

Perhatikan kolom SNR. Dari t=50 ke t=700, rasio sinyal-terhadap-noise turun lebih
dari **200×**.

---

## Model

Semua komponen boleh dipakai, tanpa kecuali:

```python
SD, REV = "CompVis/stable-diffusion-v1-4", "133a221b8aa7292a167afc5127cb63fb5005638b"
```

`revision` di-pin supaya semua orang bekerja dengan bobot yang sama persis. Pakai
`variant="fp16"` agar unduhannya ~2.1 GB dan bukan ~5 GB, dan lewati safety checker
(tidak dipakai di sini).

Text encoder SD 1.4 adalah CLIP ViT-L/14 — model yang sama dengan
`openai/clip-vit-large-patch14`, tapi **ruang embedding-nya berbeda**: text encoder
mengeluarkan urutan token `(77, 768)` untuk cross-attention UNet, sedangkan
`CLIPModel.get_text_features` mengeluarkan satu vektor di ruang gabungan
gambar-teks. Jangan tertukar.