Indigo
Model bahasa kecil GPT-style yang dibangun dari nol (tanpa library transformers) sebagai proyek pembelajaran. Backend PyTorch; tersedia juga varian TensorFlow/Keras terpisah. Bobot disimpan dalam format aman .safetensors.
Arsitektur
| Komponen | Nilai default |
|---|---|
| Tipe | Decoder-only transformer (pre-LN, SDPA) |
| Parameter | ~0.81M (default) |
| Layer / Head | 4 / 4 |
| Dimensi embedding | 128 |
| Konteks (block_size) | 128 token |
| Tokenizer | char (karakter) atau bpe (byte-pair encoding) |
| Weight tying | Ya (output head = token embedding) |
| Aktivasi | GELU (MLP) |
| Attention | Multi-head causal self-attention + KV-cache |
Struktur file
indigo/
model.py Arsitektur GPT (CausalSelfAttention, MLP, Block, GPT, sampling)
common.py Utilitas bersama (clean_text, meta save/load, morphological analysis)
bpe.py Tokenizer BPE level-byte minimal
tokenizer.py Tokenizer karakter (char-level)
train.py Training loop (best-checkpoint, resume, split val, cosine LR schedule)
generate.py Generasi teks (top-k, top-p, repetition penalty, guard kamus)
pipeline.py Pipeline end-to-end (data collection β training β manifest β finalize/push)
eval.py Evaluasi batched antar-checkpoint (nats/token, nats/karakter)
audit_kamus.py Audit wordlist kamus terhadap KBBI daring
out/
indigo_best.safetensors Bobot terbaik (dipilih berdasarkan validasi)
indigo_best_meta.json Metadata terbaik
indigo.safetensors Bobot checkpoint akhir
indigo_meta.json Metadata akhir
indigo_optimizer.pt State optimizer (untuk resume)
run_info.json Info run terakhir yang di-finalize
data/
sample.txt Teks contoh Indonesia (training default)
kamus_id.txt Wordlist Indonesia (~70K kata, gitignored)
prefiks.txt Daftar prefiks Indonesia untuk morphological guard
sufixs.txt Daftar sufiks Indonesia untuk morphological guard
Persyaratan
torch>=2.0
safetensors>=0.4
Install:
pip install -r requirements.txt
train.py β Training Model
Script utama untuk melatih model GPT dari nol.
Argumen
| Argumen | Tipe | Default | Deskripsi |
|---|---|---|---|
--data |
str (nargs+) | data/sample.txt |
Path file/folder teks untuk training. Bisa banyak, spasi-separated. Folder akan dicari rekursif untuk file .txt. |
--out |
str | out |
Folder output checkpoint (.safetensors + _meta.json + _optimizer.pt). |
--steps |
int | 2000 |
Jumlah total langkah training. |
--batch-size |
int | 32 |
Jumlah sampel per batch. Batch lebih besar β gradient lebih stabil tapi butuh lebih banyak VRAM. |
--block-size |
int | 128 |
Panjang konteks token per sampel (sequence length). Semakin besar β model bisa lihat lebih jauh tapi butuh lebih banyak memori. |
--lr |
float | 3e-4 |
Learning rate maksimum. Cosine decay dari lr ini ke 10% lr selama training. |
--warmup |
int | 100 |
Jumlah langkah warmup linear sebelum cosine decay dimulai. |
--weight-decay |
float | 0.1 |
L2 regularization / weight decay untuk AdamW optimizer. |
--dropout |
float | 0.1 |
Dropout rate (0.0 = nonaktif). Membantu mencegah overfitting pada data kecil. |
--n-layer |
int | 4 |
Jumlah blok transformer bertumpuk. Lebih banyak layer β model lebih dalam tapi lebih lambat. |
--n-head |
int | 4 |
Jumlah head per attention layer. Harus habis membagi --n-embd. |
--n-embd |
int | 128 |
Dimensi embedding / hidden size. Parameter β 12 Γ n_layer Γ n_embdΒ². |
--tokenizer |
char/bpe |
char |
Jenis tokenizer. char = cepat, bpe = lebih efisien untuk teks panjang. |
--vocab-size |
int | 512 |
Ukuran vocab untuk BPE (diabaikan jika --tokenizer char). |
--eval-interval |
int | 200 |
Evaluasi validasi setiap N langkah. Set 0 untuk skip validasi. |
--eval-iters |
int | 20 |
Jumlah batch untuk estimasi loss validasi. |
--seed |
int | 1337 |
Seed random untuk reproduktibilitas. |
--val-fraction |
float | 0.1 |
Proporsi file untuk validasi (split per-file, bukan per-karakter). |
--init-from |
str | None |
Path checkpoint untuk melanjutkan training (resume). Muat model + optimizer + step. |
--device |
auto/cpu/cuda |
auto |
Device training. auto = CUDA jika tersedia, else CPU. |
Contoh
# Training dasar
python train.py --data data/sample.txt --steps 2000
# Training dengan BPE tokenizer
python train.py --data data/teks.txt --tokenizer bpe --vocab-size 512
# Model lebih besar, training lebih lama
python train.py --data data/ --n-layer 6 --n-head 8 --n-embd 256 --steps 5000
# Resume dari checkpoint
python train.py --init-from out/indigo_best.safetensors --steps 1000
# Tanpa validasi (data hanya 1 file)
python train.py --data data/combined.txt --val-fraction 0 --eval-interval 0
Output
out/indigo_best.safetensors+out/indigo_best_meta.jsonβ checkpoint terbaik (val loss minimum)out/indigo.safetensors+out/indigo_meta.jsonβ checkpoint akhirout/indigo_optimizer.ptβ state optimizer (untuk resume)
Learning Rate Schedule
Step 0 β warmup: linear dari 0 β lr_max
Step warmup β total: cosine decay dari lr_max β 0.1 Γ lr_max
Formula cosine: 0.1 Γ lr + 0.45 Γ lr Γ (1 + cos(Ο Γ progress))
generate.py β Generasi Teks
Generate teks dari checkpoint Indigo dengan berbagai opsi sampling.
Argumen
| Argumen | Tipe | Default | Deskripsi |
|---|---|---|---|
--ckpt |
str | out/indigo_best.safetensors |
Path ke file checkpoint model. |
--prompt |
str | "" |
Teks awal (prompt) untuk memulai generasi. |
--max-new |
int | 300 |
Jumlah token baru yang akan dihasilkan (bukan panjang total). |
--temperature |
float | 0.8 |
Skala randomness: 0.0 β greedy, 0.8 β standar, >1.0 β random. |
--top-k |
int | 40 |
Batasi sampling ke k token teratas. 0 = nonaktif. |
--top-p |
float | 1.0 |
Nucleus sampling: batasi kumulatif probabilitas. 1.0 = nonaktif. |
--repetition-penalty |
float | 1.0 |
Penalti pengulangan token. 1.0 = nonaktif, >1.0 = kurangi pengulangan. |
--seed |
int | None |
Seed random. None = tidak ditentukan (random setiap kali). |
--device |
auto/cpu/cuda |
auto |
Device untuk inferensi. |
--guard |
str | None |
Path file kamus (satu kata per baris). Generate beberapa kandidat β pilih yang rasio kata dikenal tertinggi. |
--guard-prefiks |
str | None |
Path file prefiks Indonesia. Default: data/prefiks.txt bila ada. |
--guard-sufiks |
str | None |
Path file sufiks Indonesia. Default: data/sufiks.txt bila ada. |
--guard-tries |
int | 5 |
Jumlah kandidat generate saat --guard aktif. |
--guard-min |
float | 0.6 |
Rasio kata dikenal minimum. Berhenti generate lebih awal jika tercapai. |
Contoh
# Generasi dasar
python generate.py --prompt "Indigo" --max-new 300
# Sampling lebih random
python generate.py --prompt "hello" --temperature 1.0 --top-k 60 --top-p 0.9
# Dengan guard kamus (pilih output paling koheren)
python generate.py --prompt "kepekaan" --max-new 120 --guard data/kamus_id.txt
# Repetition penalty untuk mengurangi pengulangan
python generate.py --prompt "cerita" --repetition-penalty 1.2 --max-new 200
Guard Kamus
Saat --guard aktif, generate.py akan:
- Generate
--guard-trieskandidat teks (seed berbeda tiap kandidat) - Untuk setiap kandidat, hitung rasio kata yang dikenal kamus
- Pilih kandidat dengan rasio tertinggi
- Berhenti lebih awal jika rasio >=
--guard-min
Kata berimbuhan dicek lewat formula morfologi:
- Hapus sufiks β cek akar
- Hapus prefiks β cek akar (+ asimilasi:
meny-βs,pem-βp)
pipeline.py β Pipeline End-to-End
Rangkai semua tahap: kumpul data β training β evaluasi β manifest β finalize β push.
Argumen
| Argumen | Tipe | Default | Deskripsi |
|---|---|---|---|
--tag |
str | wajib | Nama run. Semua artefak disimpan di runs/<tag>/. |
--data |
str (nargs*) | [] |
File/folder teks lokal tambahan (banyak, spasi-separated). |
--hf-dataset |
str | None |
Repo dataset HF untuk menarik file teks (mis. adyoi/indigo). |
--hf-patterns |
str (nargs*) | ["*.txt", "*.md"] |
Pola file yang diambil dari HF. |
--format-qa |
flag | False |
Auto-convert Alpaca JSON (instruction/output) ke .txt sebelum training. |
--runs |
str | runs |
Folder root untuk semua run. |
--device |
str | None |
Device training (diteruskan ke train.py, default: auto). |
--finalize |
flag | False |
Promosikan checkpoint terbaik ke folder out/ kanonik. |
--push |
flag | False |
Upload checkpoint terbaik ke repo HF. |
--repo |
str | adyoi/indigo |
Repo HF tujuan upload. |
--guard |
str | None |
File kamus untuk metrik rasio ejaan di manifest. |
--guard-max-new |
int | 120 |
Jumlah token generate untuk evaluasi guard. |
--guard-prefiks |
str | None |
File prefiks Indonesia. |
--guard-sufiks |
str | None |
File sufiks Indonesia. |
Hyperparameter training (diteruskan ke train.py):
| Argumen | Tipe | Default | Deskripsi |
|---|---|---|---|
--steps |
int | 2000 |
Jumlah langkah training. |
--batch-size |
int | 32 |
Batch size. |
--block-size |
int | 128 |
Panjang konteks. |
--n-layer |
int | 4 |
Jumlah layer transformer. |
--n-head |
int | 4 |
Jumlah head attention. |
--n-embd |
int | 128 |
Dimensi embedding. |
--dropout |
float | 0.1 |
Dropout rate. |
--lr |
float | 3e-4 |
Learning rate. |
--warmup |
int | 100 |
Langkah warmup. |
--weight-decay |
float | 0.1 |
Weight decay. |
--eval-interval |
int | 200 |
Evaluasi setiap N langkah. |
--eval-iters |
int | 20 |
Jumlah batch evaluasi. |
--seed |
int | 1337 |
Seed random. |
--init-from |
str | None |
Checkpoint untuk resume. |
--tokenizer |
char/bpe |
char |
Jenis tokenizer. |
--vocab-size |
int | 512 |
Vocab size untuk BPE. |
--val-fraction |
float | 0.1 |
Proporsi file validasi. |
Contoh
# Data lokal saja
python pipeline.py --tag run01 --data data/sample.txt --steps 2000
# Data dari HF + BPE tokenizer
python pipeline.py --tag run02 --data data/teks.txt --hf-dataset adyoi/indigo \
--tokenizer bpe --vocab-size 512 --steps 900 --device cpu
# Dataset Alpaca JSON dari HF
python pipeline.py --tag qa01 \
--hf-dataset rohanrdy/CS-Theory-QA-Dataset \
--format-qa --steps 3000 --n-layer 6 --n-embd 256
# Full pipeline: train + finalize + push
python pipeline.py --tag final01 --data data/ --steps 2000 --finalize --push
# Dengan guard kamus untuk metrik kualitas
python pipeline.py --tag guarded --data data/ --steps 2000 --guard data/kamus_id.txt
Output
runs/<tag>/data/β data yang digunakan (copy dari sumber)runs/<tag>/ckpt/β checkpoint trainingruns/<tag>/manifest.jsonβ statistik + metadata run (termasukkamus_ratiojika--guardaktif)
eval.py β Evaluasi Batched
Bandingkan beberapa checkpoint pada set uji tetap. Metrik:
- nats/token: loss rata-rata per token (cross-entropy). Lebih rendah = lebih baik.
- nats/karakter: loss per karakter (dikoreksi dengan compression ratio). Memungkinkan perbandingan antar tokenizer.
Argumen
| Argumen | Tipe | Default | Deskripsi |
|---|---|---|---|
--ckpt |
str (nargs+) | wajib | Path ke satu atau lebih file checkpoint (.safetensors). |
--test |
str | data/sample.txt |
Path ke file teks uji. |
--device |
cpu/cuda |
cpu |
Device untuk evaluasi. |
--guard |
str | None |
Path file kamus; generate teks β hitung rasio kata dikenal. |
--guard-max-new |
int | 120 |
Jumlah token generate untuk evaluasi guard. |
--seed |
int | 42 |
Seed untuk generate saat --guard aktif. |
--batch-size |
int | 32 |
Batch size untuk evaluasi. |
Contoh
# Evaluasi satu checkpoint
python eval.py --ckpt out/indigo_best.safetensors
# Bandingkan beberapa checkpoint
python eval.py --ckpt out/indigo_best.safetensors runs/*/ckpt/indigo.safetensors \
--test data/sample.txt
# Dengan guard kamus
python eval.py --ckpt out/indigo_best.safetensors --guard data/kampus_id.txt
Contoh output
set uji: data/sample.txt (29,123 karakter)
checkpoint nats/tok nat/kar kamus
run/csqa500/ckpt/indigo_best.safetensors 3.962 3.962 32%
run/wiki500/ckpt/indigo_best.safetensors 3.018 3.018 25%
audit_kamus.py β Audit Wordlist Kamus
Verifikasi kata-kata dalam file kamus terhadap KBBI daring (sampling acak).
Argumen
| Argumen | Tipe | Default | Deskripsi |
|---|---|---|---|
--kamus |
str | data/kamus_id.txt |
Path ke file kamus (satu kata per baris). |
--n |
int | 200 |
Jumlah kata sampel yang diambil untuk verifikasi. |
--seed |
int | 1337 |
Seed random untuk sampling. |
--delay |
float | 0.8 |
Jeda antar-permintaan web (detik). Hindari rate limiting. |
--backend |
auto/pypi/web |
auto |
Backend verifikasi. pypi = library kbbi, web = scraping kbbi.web.id. |
--apply |
flag | False |
Hapus kata TIDAK-DIKENAL dari kamus (backup otomatis ke .bak.txt). |
--out |
str | None |
Path output laporan JSON. Default: runs/kamus_audit_<timestamp>.json. |
Contoh
# Audit dasar
python audit_kamus.py --kamus data/kamus_id.txt --n 200
# Hapus kata tak-valid (backup otomatis)
python audit_kamus.py --kamus data/kamus_id.txt --apply
# Backend web saja, delay lebih lama
python audit_kamus.py --backend web --delay 1.5 --n 100
Output
Laporan JSON berisi:
ada: jumlah kata yang ditemukan di KBBItidak_dikenal: jumlah kata yang tidak ditemukangagal_ceks: jumlah verifikasi yang gagal (timeout, dll)estimasi_entri_tidak_valid: proyeksi total entri tak-valid di seluruh kamuskata_ditolak: daftar kata yang tidak dikenal (akan dihapus jika--apply)
Guard Kamus (Sistem Kualitas Ejaan)
Sistem guard membantu menjaga kualitas output model tanpa mengubah bobot:
- Wordlist:
data/kamus_id.txtβ ~70K kata Indonesia (satu kata per baris) - Morfologi:
data/prefiks.txt+data/sufiks.txtβ pendeteksi imbuhan - Asimilasi:
meny-βs,peny-βs,pem-βpβ menangani perubahan bunyi
Cara kerja:
- generate.py: generate beberapa kandidat β pilih yang rasio kata dikenal tertinggi
- pipeline.py: generate sekali β simpan
kamus_ratiodi manifest.json - eval.py: generate sekali β tampilkan rasio di tabel perbandingan
Edit data/prefiks.txt dan data/sufiks.txt untuk memperluas cakupan tanpa menyentuh kode.
Format Checkpoint
| File | Isi |
|---|---|
*.safetensors |
Bobot model (format aman, tanpa pickle) |
*_meta.json |
Metadata: config, vocab, step, val_loss, backend, tokenizer info |
*_optimizer.pt |
State optimizer AdamW (untuk resume training) |
Format .safetensors tidak mengeksekusi kode saat dimuat β lebih aman dari format .pt lama.
Tips Training
| Skenario | Rekomendasi |
|---|---|
| Data < 100 KB | --tokenizer char, 4L/4H/128E, 2000 steps |
| Data 100 KBβ1 MB | --tokenizer char atau bpe (vocab 512), 4L/8H/256E, 3000+ steps |
| Data > 1 MB | --tokenizer char (BPE training sangat lambat di CPU >1MB) |
| CPU-only | Model max ~1M params (4L/4H/128E), 5-8 detik/step |
| Resume training | --init-from runs/xxx/ckpt/indigo_best.safetensors |
Batasan
- Dilatih pada data sangat kecil β output belum koheren; cocok untuk edukasi bukan produksi.
- Gunakan checkpoint
indigo_best(terpilih berdasarkan validasi), bukan checkpoint akhir. - BPE training sangat lambat di CPU untuk data > 1 MB β gunakan
--tokenizer char.
Keamanan
Bobot disimpan sebagai .safetensors (tanpa pickle, tidak mengeksekusi kode saat dimuat). State optimizer (*_optimizer.pt) hanya untuk resume lokal β jangan dibagikan.