File size: 7,806 Bytes
d007d5a
 
 
 
 
 
 
 
 
 
 
 
 
 
27bbbd7
 
d007d5a
27bbbd7
d007d5a
27bbbd7
 
 
 
 
 
 
 
 
 
 
d007d5a
 
 
 
 
27bbbd7
d007d5a
 
27bbbd7
d007d5a
27bbbd7
 
d007d5a
27bbbd7
d007d5a
27bbbd7
 
 
 
 
 
 
 
 
 
 
d007d5a
 
 
 
 
 
 
 
 
 
 
27bbbd7
d007d5a
 
 
 
 
 
 
 
 
 
 
 
 
 
27bbbd7
d007d5a
27bbbd7
d007d5a
27bbbd7
d007d5a
27bbbd7
d007d5a
27bbbd7
d007d5a
 
 
 
 
 
 
 
 
 
 
27bbbd7
d007d5a
 
 
27bbbd7
 
 
 
 
d007d5a
27bbbd7
d007d5a
27bbbd7
d007d5a
 
 
27bbbd7
d007d5a
27bbbd7
d007d5a
 
 
27bbbd7
d007d5a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27bbbd7
d007d5a
 
 
 
 
27bbbd7
 
 
 
d007d5a
 
27bbbd7
d007d5a
 
 
 
 
27bbbd7
 
 
d007d5a
27bbbd7
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
---
language:
- id
license: apache-2.0
tags:
- causal-lm
- indonesian
- moe
- custom-architecture
- from-scratch
datasets:
- Lyon28/Corpus-Indonesia
---

<div align="center">
  <img src="https://huggingface.co/Veenn/photon-3m/resolve/main/1000326189.png" alt="Photon Mascot" width="300"/>

  # Photon-3M

  Model bahasa Indonesia skala kecil dengan arsitektur *Dual Sparse*, dibangun dan dilatih dari nol di Google Colab Free T4.

  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
  [![HuggingFace](https://img.shields.io/badge/πŸ€—%20HuggingFace-Veenn%2Fphoton--3m-yellow)](https://huggingface.co/Veenn/photon-3m)
  [![Dataset](https://img.shields.io/badge/Dataset-Lyon28%2FCorpus--Indonesia-green)](https://huggingface.co/datasets/Lyon28/Corpus-Indonesia)
  [![Colab](https://img.shields.io/badge/Trained%20on-Google%20Colab%20Free%20T4-orange)](https://colab.research.google.com)
</div>

---

Nama "3M" merujuk pada jumlah parameter **aktif per forward pass**, bukan total parameter. Total parameter sebenarnya **10.47M** karena MoE.

## Arsitektur

Konsep utamanya adalah **Dual Sparse** β€” dua level sparsity yang bekerja bersamaan supaya model kecil bisa berkapasitas lebih dari ukuran parameternya.

### MoE (Mixture of Experts)
Satu shared expert yang selalu aktif ditambah empat specialist expert yang dipilih router per token. Efeknya: kapasitas representasi ~5x lebih tinggi dari parameter aktif per forward pass, tanpa nambah biaya komputasi secara proporsional.

> Referensi konsep: [Mixtral of Experts (Mistral AI)](https://arxiv.org/abs/2401.04088)

### Adaptive Layer Skipping
Router kecil di tiap layer memutuskan apakah layer perlu diproses atau dilewati. Token sederhana bisa melewati beberapa layer, token kompleks dapat perhatian penuh. Diaktifkan di versi ini dengan skip probability **0.3**.

> Referensi konsep: [Confident Adaptive Language Modeling (CALM)](https://arxiv.org/abs/2207.07061)

### Komponen Lain

| Komponen | Keterangan | Referensi |
|---|---|---|
| GQA | 4 query heads, 2 KV heads | [GQA Paper](https://arxiv.org/abs/2305.13245) |
| RoPE | Rotary Position Embedding | [RoFormer](https://arxiv.org/abs/2104.09864) |
| SwiGLU | Aktivasi di FFN | [GLU Variants](https://arxiv.org/abs/2002.05202) |
| RMSNorm | Normalisasi per layer | [RMSNorm Paper](https://arxiv.org/abs/1910.07467) |
| Weight Tying | Embedding dan output head berbagi bobot | [Press & Wolf, 2017](https://arxiv.org/abs/1608.05859) |

### Konfigurasi

```
VOCAB_SIZE  = 8.000
HIDDEN      = 128
LAYERS      = 12
HEADS       = 4
KV_HEADS    = 2
FF_MULT     = 3
NUM_EXPERTS = 4 + 1 shared
MAX_SEQ     = 256
Total params: 10.472.076
Active params per forward: ~3.000.000
```

## Tokenizer

BPE tokenizer yang dilatih dari scratch dari dataset yang sama, bukan hasil adopt dari model lain.

```
Tipe    : Byte Pair Encoding (ByteLevel)
Vocab   : 8.000
Special : [UNK] [BOS] [EOS] [PAD]
```

## Training

### Dataset

Sumber: [`Lyon28/Corpus-Indonesia`](https://huggingface.co/datasets/Lyon28/Corpus-Indonesia) β€” 100.000 baris pertama dipakai untuk training tokenizer, 500.000 baris untuk training model. Setelah filter teks terlalu pendek: **449.909 valid**.

### Packing Dataset

Mayoritas kalimat di dataset panjangnya di bawah 50 token. Dengan padding biasa, sekitar 96% slot per batch terisi token padding yang tidak berkontribusi ke loss. Solusinya: semua token digabung jadi satu stream panjang lalu dipotong jadi chunk 256 token. Hasilnya 21.237.953 token terpacking jadi **82.960 chunks**, tidak ada padding sama sekali.

### Proses Training

```
Hardware         : Tesla T4 15.6GB (Google Colab Free)
Durasi           : ~84 menit (sampai step 2000)
Batch size       : 128
Grad accumulation: 2 (effective batch 256)
Optimizer        : AdamW (lr=1e-4, weight_decay=0.01)
Scheduler        : Cosine Annealing Warm Restarts
Warmup           : 500 steps
```

### Kurva Loss

| Step | Loss | PPL |
|------|------|-----|
| 50   | 8.97 | 7836 |
| 500  | 7.39 | 1618 |
| 1000 | 6.50 | 662  |
| 1500 | 6.19 | 486  |
| 2000 | 5.89 | 360  |

Baseline acak untuk vocab 8.000: `log(8000) = 8.987`

### Bug yang Ditemui

Dua bug utama ditemukan dan diperbaiki selama proses ini:

**Masalah padding 96%.** Terdeteksi lewat print debug manual pada sample batch yang menunjukkan hampir seluruh slot terisi token `-100`. Solusinya beralih ke packing dataset.

**Posisi akumulasi loss yang salah.** `running_loss` diakumulasi di luar blok gradient accumulation tapi dibagi per step, menghasilkan angka loss yang tampak ~8x lebih besar dari nilai sebenarnya. Solusinya memindahkan akumulasi ke dalam blok yang benar.

## Cara Load

Model ini menggunakan arsitektur custom, jadi perlu menyertakan definisi kelas-kelasnya sebelum bisa diload. Salin file [`modeling_photon.py`](https://huggingface.co/Veenn/photon-3m/blob/main/modeling_photon.py) dari repo ini, lalu:

```python
import torch
import torch.nn.functional as F
from modeling_photon import PhotonModel
from transformers import PreTrainedTokenizerFast

device = torch.device("cuda")  # atau "cpu"
ckpt   = "Veenn/photon-3m"     # atau path lokal

cfg       = torch.load("config.pt", map_location=device)
tokenizer = PreTrainedTokenizerFast.from_pretrained(ckpt)
model     = PhotonModel(**cfg).to(device)
model.load_state_dict(torch.load("model.pt", map_location=device))
model.eval()
```

**Generate teks**

```python
def generate(prompt, max_new=80, temp=0.8):
    ids = tokenizer(prompt, return_tensors="pt").input_ids.to(device)
    with torch.no_grad():
        for _ in range(max_new):
            _, logits = model(ids)
            next_tok  = torch.multinomial(
                F.softmax(logits[:, -1] / temp, dim=-1), 1
            )
            ids = torch.cat([ids, next_tok], dim=-1)
            if next_tok.item() == tokenizer.eos_token_id:
                break
    return tokenizer.decode(ids[0], skip_special_tokens=True)

print(generate("Indonesia adalah"))
```

## Contoh Output

```
Input  : "Indonesia adalah"
Output : "Indonesia adalah Jropoce di kota Lantik saat ini di itu,
          di Indonesia, Kabupaten Mubel..."

Input  : "Teknologi semakin"
Output : "Teknologi semakin menggunakan dunia untuk dapat mulai
          dipakat yangpun akan sangat banyak."
```

Output belum koheren. Kata-katanya sudah valid Bahasa Indonesia dan tidak ada lagi token sampah seperti di checkpoint awal, tapi struktur kalimatnya masih belum terbentuk dengan baik. Ini wajar untuk loss di kisaran 5.8 dengan model 10M parameter dan vocab 8.000.

## Limitasi

Model ini adalah **proof of concept arsitektur**, bukan model siap pakai. Vocab 8.000 terlalu kecil untuk menghasilkan teks yang baik, hidden 128 membatasi kapasitas representasi, dan training baru sampai step 2000 dari 3.240 yang direncanakan. Untuk hasil yang lebih baik perlu scale up ke vocab yang lebih besar dan hidden yang lebih lebar.

## Isi Repo

```
Veenn/photon-3m
β”œβ”€β”€ model.pt              <- state dict model
β”œβ”€β”€ config.pt             <- konfigurasi arsitektur
β”œβ”€β”€ modeling_photon.py    <- definisi arsitektur (wajib disertakan)
β”œβ”€β”€ training_state.pt     <- state training untuk resume
β”œβ”€β”€ tokenizer.json
β”œβ”€β”€ tokenizer_config.json
β”œβ”€β”€ 1000326189.png        <- maskot Photon
└── README.md
```

## Rencana Selanjutnya

Iterasi berikutnya kemungkinan akan menaikkan vocab ke **16.000–32.000** dan hidden ke **256**, dengan target parameter di kisaran **50–100M**. Adaptive Layer Skipping juga akan dievaluasi lebih lanjut apakah benar memberikan efek positif atau tidak setelah training lebih panjang.

---

<div align="center">
  <em>Dikembangkan oleh <a href="https://huggingface.co/Veenn">Velyn</a></em><br>
  <em>Dilatih di Google Colab Free T4</em>
</div>