TL;DR
nanochat adalah kerangka kerja pelatihan LLM sumber terbuka milik Andrej Karpathy yang memungkinkan Anda melatih chatbot setara GPT-2 dengan biaya kurang dari $50 dalam waktu sekitar 2 jam. Proyek ini menggunakan satu node GPU 8xH100, kode minimal (sekitar 500 baris untuk model inti), dan satu tombol konfigurasi (--depth) untuk mengoptimalkan semua hyperparameter secara otomatis. Catatan saat ini menunjukkan penyelesaian pelatihan dalam 1,65 jam dengan skor CORE 0,2626, mengalahkan GPT-2 OpenAI tahun 2019 yang menelan biaya $43.000 dan membutuhkan waktu 168 jam.
Pendahuluan
Melatih model bahasa besar dulunya membutuhkan jutaan dolar dan tim peneliti PhD. Masa-masa itu sudah berlalu.
Andrej Karpathy baru saja merilis nanochat, sebuah proyek sumber terbuka yang melatih AI percakapan yang mumpuni dengan biaya kurang dari harga makan malam yang enak. Seluruh pipeline berjalan pada satu node GPU 8xH100 dan selesai dalam waktu kurang dari 2 jam.
Mengapa Ini Penting Sekarang
Lanskap AI bergeser secara dramatis pada awal 2026. Apa yang membutuhkan waktu 168 jam dan $43.000 bagi OpenAI pada tahun 2019 kini membutuhkan 1,65 jam dan $48. Itu adalah peningkatan kecepatan 100x yang didorong oleh peningkatan algoritma, perangkat keras yang lebih baik, dan optimasi komunitas.
Bagi pengembang API dan tim yang membangun aplikasi bertenaga AI, ini mengubah segalanya. Anda kini dapat bereksperimen dengan pelatihan model kustom, menguji perubahan arsitektur, dan memahami internal LLM tanpa anggaran infrastruktur yang besar.
tombol
Apa yang Akan Anda Pelajari
Di akhir artikel ini, Anda akan memahami:
- Bagaimana nanochat mencapai pengurangan biaya 100x dibandingkan pelatihan LLM tradisional
- Arsitektur lengkap (model GPT, pengoptimal Muon, pemuatan data)
- Instruksi langkah demi langkah untuk melatih model Anda sendiri
- Cara menggunakan nanochat untuk penelitian dan eksperimen LLM yang cepat
- Keterbatasan sebenarnya dan apa arti kemampuan GPT-2
Apa Itu nanochat?
nanochat adalah kerangka kerja pelatihan LLM minimal yang mencakup seluruh pipeline pengembangan: tokenisasi, pra-pelatihan, fine-tuning, evaluasi, inferensi, dan UI web mirip ChatGPT.

Basis kode ini terdapat dalam satu repositori tanpa monster konfigurasi atau kompleksitas kerangka kerja. Karpathy merancangnya sebagai "baseline yang kuat" yang mudah dibaca, diubah, dan di-fork.
Klaim Utama
Melatih model berkemampuan GPT-2 (1,6B parameter) dengan:
- $48 sesuai permintaan (2 jam dengan ~$24/jam untuk 8xH100)
- ~$15 pada instans spot
Sebagai konteks, pelatihan GPT-2 asli OpenAI pada tahun 2019 menelan biaya sekitar $43.000 dan memakan waktu 7 hari pada 32 chip TPU v3.
Apa yang Dicakup nanochat
| Tahap | Skrip | Deskripsi |
|---|---|---|
| Tokenisasi | scripts.tok_train |
Melatih tokenizer BPE (kosakata 32.768) |
| Pra-pelatihan | scripts.base_train |
Melatih model dasar GPT |
| Fine-tuning | scripts.chat_sft |
Fine-tuning terarah untuk obrolan |
| Evaluasi | scripts.base_eval |
Metrik CORE, bit-per-byte |
| Inferensi | scripts.chat_cli |
Antarmuka obrolan CLI |
| UI Web | scripts.chat_web |
Antarmuka web mirip ChatGPT |
Filosofi: Satu Tombol untuk Mengontrol Segalanya
Sebagian besar kerangka kerja LLM membanjiri Anda dengan file konfigurasi. nanochat mengambil pendekatan yang berlawanan.
Seluruh sistem berputar di sekitar satu parameter: --depth (jumlah lapisan transformer).
# GPT-1 size model
torchrun --standalone --nproc_per_node=8 -m scripts.base_train -- --depth=12
# GPT-2 capability model
torchrun --standalone --nproc_per_node=8 -m scripts.base_train -- --depth=24
# Pushing the boundaries
torchrun --standalone --nproc_per_node=8 -m scripts.base_train -- --depth=26
Atur kedalaman, dan nanochat akan menghitung segalanya secara otomatis:
- Lebar Transformer (dimensi embedding)
- Jumlah attention head
- Learning rate untuk setiap grup parameter
- Horizon pelatihan (total langkah)
- Jadwal peluruhan bobot (weight decay)
- Ukuran batch
Filosofi "satu tombol" ini memungkinkan apa yang disebut Karpathy sebagai miniseri nanochat: keluarga model optimal komputasi dengan ukuran berbeda, semuanya dilatih dengan pendekatan berprinsip yang sama.
Mengapa Ini Berhasil
Tim mengukur hukum penskalaan di puluhan sesi pelatihan. Mereka menemukan hubungan yang dapat diprediksi antara kedalaman, lebar, ukuran batch, dan durasi pelatihan. Alih-alih mengekspos semua pengaturan ini, nanochat mengkodekan hubungan ini langsung ke dalam skrip pelatihan.

Anda mendapatkan pelatihan optimal komputasi tanpa perlu gelar PhD dalam pembelajaran mendalam.
Papan Peringkat: Berpacu Mengalahkan GPT-2
nanochat memelihara papan peringkat publik yang melacak kemampuan "waktu ke GPT-2". Targetnya adalah mengalahkan skor CORE asli OpenAI sebesar 0.256525 pada 22 tugas evaluasi (ARC, MMLU, dan lainnya dari rangkaian benchmark DCLM).
Rekor Saat Ini
| Jalankan | Model | Waktu | Skor CORE | Inovasi Utama |
|---|---|---|---|---|
| GPT-2 Asli | 1.6B | 168 jam | 0.2565 | Baseline OpenAI 2019 |
| Jalankan 1 | d24 | 3.04 jam | 0.2585 | Baseline awal |
| Jalankan 2 | d26 | 2.91 jam | 0.2578 | Pelatihan FP8 |
| Jalankan 3 | d26 | 2.76 jam | 0.2602 | Ukuran batch 1M token |
| Jalankan 4 | d24 | 2.02 jam | 0.2571 | Dataset ClimbMix |
| Jalankan 5 | d24 | 1.80 jam | 0.2690 | Optimisasi yang ditemukan AI |
| Jalankan 6 | d24 | 1.65 jam | 0.2626 | Peningkatan smear/backout |
Bagaimana AI Menemukan Optimasi
Eksekusi 5 dan 6 menggabungkan perubahan dari sistem "autoresearch" Karpathy. Sebuah agen AI menjelajahi modifikasi arsitektural pada model d12 kecil (sesi pelatihan 5 menit), lalu menerjemahkan perubahan yang berhasil ke pengaturan d24 penuh.
Sistem menemukan peningkatan pada:
- Mekanisme Backout: Pengurangan residual lapisan tengah yang lebih baik
- Implementasi Smear: Pencampuran bigram yang lebih efisien dari token sebelumnya
Perubahan ini mengurangi waktu pelatihan dari 2,02 jam menjadi 1,65 jam, peningkatan 19% yang ditemukan melalui eksperimen otonom.
Bagaimana nanochat Bekerja
Basis kode berisi sekitar 3.000 baris di seluruh modul inti. Mari kita periksa setiap komponen.
1. Model GPT (nanochat/gpt.py)
Transformer ini mengikuti praktik terbaik modern dengan beberapa optimasi:
Fitur Arsitektur:
- Rotary embeddings (RoPE): Encoding posisi relatif tanpa learned position embeddings
- Normalisasi QK: Menstabilkan pelatihan pada skala besar
- Bobot tidak terikat: Lapisan token embedding dan proyeksi output terpisah
- Aktivasi ReLU²: ReLU kuadrat di MLP alih-alih GeLU
- Grouped Query Attention (GQA): Jumlah KV head lebih sedikit dari query head untuk inferensi yang lebih cepat
- Sliding window attention: Pola yang dapat dikonfigurasi (misalnya, “SSSL” mengganti konteks pendek/panjang)
- Flash Attention 3: Optimasi GPU Hopper dengan fallback SDPA
Value Embeddings (ResFormer):Lapisan bergantian mencakup learnable value embeddings yang dicampur melalui gating yang bergantung pada input:
# Value residual: mix in value embedding with per-head gate
if ve is not None:
ve = ve.view(B, T, self.n_kv_head, self.head_dim)
gate = 3 * torch.sigmoid(self.ve_gate(x[..., :self.ve_gate_channels]))
v = v + gate.unsqueeze(-1) * ve
Ini menambah kapasitas tanpa overhead komputasi yang signifikan.
Trik Efisiensi:
Model ini mencakup tiga mekanisme yang dipelajari yang meningkatkan dinamika pelatihan:
# 1. Per-layer residual scaling
x = self.resid_lambdas[i] * x + self.x0_lambdas[i] * x0
# 2. Smear: mix previous token embedding for bigram info
gate = self.smear_lambda * torch.sigmoid(self.smear_gate(x[:, :, :24]))
x = x + gate * x_pre_smear
# 3. Backout: subtract mid-layer residual
x = x - self.backout_lambda * x_backout
2. Pengoptimal Muon (nanochat/optim.py)
nanochat menggunakan strategi pengoptimal campuran:
| Jenis Parameter | Pengoptimal | Tujuan |
|---|---|---|
| Embeddings, lm_head | AdamW | Optimasi adaptif standar |
| Parameter skalar | AdamW | Faktor penskalaan yang dipelajari |
| Matriks 2D | Muon | Pembaruan ortogonal |
Muon (MomentUm Orthogonalized by Newton-Schulz):
Pengoptimal Muon mengortogonalisasi pembaruan bobot menggunakan iterasi Newton-Schulz kuintik yang disebut “Polar Express”:
# Polar Express coefficients (5 iterations)
polar_express_coeffs = [
(8.156, -22.483, 15.879),
(4.043, -2.809, 0.500),
# ... more coefficients
]
# Orthogonalization loop
for a, b, c in polar_express_coeffs[:ns_steps]:
A = X.mT @ X
B = b * A + c * (A @ A)
X = a * X + X @ B
Reduksi Varians NorMuon:
Setelah ortogonalisasi, pembaruan dinormalisasi per-neuron untuk mencegah kolapsnya skala:
v_mean = g.float().square().mean(dim=red_dim, keepdim=True)
v_norm = v_mean.sum(dim=(-2, -1), keepdim=True).sqrt()
final_scale = step_size * (v_norm / v_norm_new.clamp_min(1e-10))
g = g * final_scale.to(g.dtype)
Pelatihan Terdistribusi:
Untuk pengaturan multi-GPU, pengoptimal mengimplementasikan sharding gaya ZeRO-2 dengan komunikasi asinkron tiga fase:
Phase 1: Launch all async reduce_scatter operations
Phase 2: Wait for reduces, compute updates, launch all_gathers
Phase 3: Wait for gathers, copy back updated params
Ini menumpuk komunikasi dengan komputasi, memaksimalkan pemanfaatan GPU.
3. Manajemen Presisi (nanochat/common.py)
nanochat mengelola presisi secara eksplisit alih-alih menggunakan torch.amp.autocast:
| Perangkat Keras | Default dtype | Alasan |
|---|---|---|
| CUDA SM 80+ (A100, H100) | bfloat16 | Core tensor BF16 asli |
| CUDA SM < 80 (V100, T4) | float32 | Tidak ada dukungan BF16 |
| CPU / MPS | float32 | Tidak ada core presisi yang dikurangi |
Lapisan Linear kustom melemparkan bobot agar sesuai dengan tipe data komputasi selama forward pass:
class Linear(nn.Linear):
def forward(self, x):
return F.linear(x, self.weight.to(dtype=x.dtype))
Bobot master tetap dalam FP32 untuk presisi pengoptimal. Untuk GPU H100 dan Blackwell, pelatihan FP8 tersedia melalui --fp8, mengubah sebagian besar lapisan menjadi Float8Linear dengan penskalaan tensorwise.
4. Pemuatan Data (nanochat/dataloader.py)
Dataloader menggunakan pengemasan best-fit yang sejajar dengan BOS:
- Setiap baris dimulai dengan token BOS (Beginning of Sequence)
- Dokumen dikemas menggunakan algoritma best-fit untuk meminimalkan pemborosan
- Ketika tidak ada dokumen yang muat, satu dokumen dipotong untuk mengisi tepat
- Pemanfaatan 100% dengan pemotongan token ~35% pada panjang urutan 2048
Ini memastikan setiap token dapat kembali ke BOS dan melihat konteks dokumen penuh.
# Find largest document that fits entirely
best_idx = -1
best_len = 0
for i, doc in enumerate(doc_buffer):
doc_len = len(doc)
if doc_len <= remaining and doc_len > best_len:
best_idx = i
best_len = doc_len
if best_idx >= 0:
doc = doc_buffer.pop(best_idx)
# Add full document
else:
# Crop shortest doc to fill remaining space
5. Penyatuan Flash Attention (nanochat/flash_attention.py)
Proyek ini menyediakan antarmuka terpadu yang secara otomatis beralih antara FA3 dan PyTorch SDPA:
from nanochat.flash_attention import flash_attn
# Works on any hardware - auto-selects best backend
y = flash_attn.flash_attn_func(q, k, v, causal=True, window_size=window_size)
Pada GPU Hopper dengan bfloat16, ia menggunakan Flash Attention 3. Di tempat lain, ia kembali ke scaled dot-product attention dari PyTorch.
6. Mesin Inferensi (nanochat/engine.py)
Kelas Engine menangani generasi yang efisien dengan:
- KV Cache: Cache prompt yang telah diisi sebelumnya dengan
flash_attn_with_kvcachedari FA3 - Penggunaan Alat: Token khusus memicu kalkulator Python melalui
eval() - Generasi Batch: Mengkloning KV cache untuk sampling paralel
Mesin ini mengoordinasikan alur percakapan, termasuk memaksa token keluaran alat saat model memanggil kalkulator.
Langkah demi Langkah: Latih Model Anda Sendiri
Seluruh pipeline berada di runs/speedrun.sh. Berikut cara menjalankannya.
Prasyarat
- Node GPU 8xH100 (atau yang serupa)
- Ruang disk ~20 GB untuk dataset
- Python 3.10+
- Manajer paket uv
Langkah 1: Pengaturan Lingkungan
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create and activate virtual environment
uv venv
source .venv/bin/activate
# Install dependencies
uv sync --extra gpu
Langkah 2: Unduh Data Pelatihan
# Download ~2B characters from ClimbMix dataset
python -m nanochat.dataset -n 170
# This downloads ~170 shards at ~100MB each
# Total: ~17 GB compressed
Ini mengunduh ~170 shard masing-masing ~100MB
Total: ~17 GB terkompresi
Skrip mengunduh shard data pra-pelatihan dengan penguncian file untuk menangani koordinasi multi-peringkat.
Langkah 3: Latih Tokenizer
# Train BPE tokenizer with 32,768 vocab
python -m scripts.tok_train
# Evaluate compression ratio
python -m scripts.tok_eval
Tokenizer menggunakan pola pemisahan gaya GPT-4 dengan BPE byte-fallback. Pelatihan selesai dalam ~10 menit pada 2B karakter.
Langkah 4: Pra-pelatihan Model Dasar
# Train d24 model (GPT-2 capability)
torchrun --standalone --nproc_per_node=8 -m scripts.base_train -- \
--depth=24 \
--target-param-data-ratio=8 \
--device-batch-size=16 \
--fp8 \
--run=my-first-model
Parameter kunci:
--depth=24: Model ukuran GPT-2--target-param-data-ratio=8: Sedikit kurang terlatih untuk kecepatan--device-batch-size=16: Ukuran batch per-GPU--fp8: Mengaktifkan pelatihan FP8 (khusus H100+)
Perkiraan waktu eksekusi: ~2 jam.
Langkah 5: Fine-tuning Terarah
# Download identity conversations
curl -L -o ~/.cache/nanochat/identity_conversations.jsonl \
https://karpathy-public.s3.us-west-2.amazonaws.com/identity_conversations.jsonl
# Run SFT for chat capability
torchrun --standalone --nproc_per_node=8 -m scripts.chat_sft -- \
--device-batch-size=16 \
--run=my-sft
Ini mengajarkan format percakapan model, token khusus, dan penggunaan alat.
Langkah 6: Obrolan dengan Model Anda
# CLI chat
python -m scripts.chat_cli -p "Why is the sky blue?"
# Or launch web UI
python -m scripts.chat_web
UI web berjalan di port 8000 dan menyediakan antarmuka mirip ChatGPT.
Alur Kerja Penelitian: Eksperimen Cepat
Untuk menguji ide-ide baru, gunakan model yang lebih kecil untuk iterasi yang lebih cepat.
Eksperimen Cepat (sekitar 5 menit)
OMP_NUM_THREADS=1 torchrun --standalone --nproc_per_node=8 -m scripts.base_train -- \
--depth=12 \
--run="d12-test" \
--core-metric-every=999999 \
--sample-every=-1 \
--save-every=-1
Ini melatih model d12 (ukuran GPT-1) dengan pencatatan minimal. Sempurna untuk menguji perubahan arsitektur.
Metrik yang Harus Dipantau
Lacak ini di Weights & Biases:
- val_bpb: Validasi bits-per-byte (kehilangan yang tidak tergantung pada ukuran kosakata)
- core_metric: Skor evaluasi DCLM CORE
- train/mfu: Pemanfaatan FLOPS Model (efisiensi perangkat keras)
- train/tok_per_sec: Throughput pelatihan
Persyaratan Pengujian
Setiap peningkatan harus bekerja di semua kedalaman (d12 hingga d26). Ini mencegah overfitting ke satu ukuran model dan memastikan kemajuan berprinsip.
Mengapa nanochat Penting
Aksesibilitas Biaya
| Pendekatan | Biaya | Waktu | Perangkat Keras |
|---|---|---|---|
| OpenAI GPT-2 (2019) | $43.000 | 168 jam | 32 TPU v3 |
| nanochat (2026) | $48 | 2 jam | 8xH100 |
| nanochat spot | ~$15 | 2 jam | Spot 8xH100 |
Ini menjadikan pelatihan LLM dapat dijangkau oleh:
- Peneliti individu
- Startup kecil
- Mata kuliah universitas
- Para penghobi
Nilai Edukasional
Basis kode ini berfungsi sebagai sumber belajar:
- ~500 baris untuk model GPT
- ~530 baris untuk pengoptimal
- Komentar yang jelas pada setiap keputusan desain
- Tidak ada konfigurasi tersembunyi
Kecepatan Penelitian
Mengurangi pelatihan dari hitungan hari menjadi jam memungkinkan:
- Pengujian hipotesis lebih cepat
- Lebih banyak eksperimen per minggu
- Biaya kegagalan yang lebih rendah
- Kolaborasi komunitas melalui papan peringkat
Transparansi
Setiap pilihan desain didokumentasikan:
- Hukum penskalaan di
dev/LOG.md - Studi ablasi di Diskusi GitHub
- Detail reproduksi lengkap untuk entri papan peringkat
- Pengungkapan kontribusi AI yang jelas
Keterbatasan dan Cek Realitas
nanochat memang mengesankan tetapi memiliki batasan yang jelas.
Persyaratan Perangkat Keras
Angka $48 mengasumsikan akses ke node 8xH100. Biaya sewa cloud bervariasi:
- Lambda Labs: ~$25/jam untuk 8xH100
- RunPod: ~$15/jam harga spot
- Total waktu berjalan: ~2 jam pra-pelatihan + SFT
Anda akan membutuhkan ~$50-100 untuk sekali jalan penuh tergantung pada penyedia.
Batas Kemampuan
nanochat mencapai kinerja setingkat GPT-2 (teknologi 2019). Ini berarti:
Apa yang bisa dilakukannya:
- Percakapan dasar
- Penalaran sederhana
- Matematika dasar
- Mengingat fakta (terbatas)
Apa yang tidak bisa dilakukannya:
- Penalaran multi-langkah yang kompleks
- Generasi kode di luar fungsi sederhana
- Mengikuti instruksi yang nuansanya halus
- Bersaing dengan GPT-4, Claude, atau Gemini
Bayangkan seperti anak TK: mampu melakukan percakapan dasar tetapi bukan pekerjaan tingkat ahli.
Persyaratan Data
Speedrun lengkap mengunduh:
- ~170 shard data
- ~17 GB terkompresi
- ~2B karakter total
Anda akan membutuhkan penyimpanan dan bandwidth yang memadai.
Keterbatasan Metrik
Skor CORE mengukur 22 tugas tetapi tidak menangkap:
- Kualitas percakapan dunia nyata
- Pengetahuan spesifik domain
- Nuansa mengikuti instruksi
- Keamanan dan keselarasan
Seed acak yang berbeda menghasilkan varians CORE ~0,016. Hasil Anda mungkin bervariasi.
FAQ
Berapa biaya untuk melatih model dengan nanochat?
Sekitar $48 sesuai permintaan ($24/jam × 2 jam) atau ~$15 pada instans spot. Ini hanya mencakup pra-pelatihan. Tambahkan ~30 menit untuk SFT.
GPU apa yang saya butuhkan?
Minimum: Satu GPU (GPU pusat data modern apa pun). Optimal: 8xH100 atau 8xA100 untuk pelatihan tercepat. Kode ini dapat diskalakan dari 1 GPU hingga 8 GPU dengan akumulasi gradien otomatis.
Berapa lama waktu pelatihan?
1,65 hingga 3 jam tergantung pada konfigurasi dan perangkat keras. Rekor papan peringkat saat ini adalah 1,65 jam untuk model d24.
Apa itu metrik CORE?
Skor DCLM CORE mengevaluasi model pada 22 tugas termasuk ARC (pertanyaan sains), MMLU (pemahaman bahasa multi-tugas), dan benchmark lainnya. GPT-2 mencetak 0,256525. nanochat secara teratur melampaui 0,26.
Bisakah saya melatih pada satu GPU?
Ya. Hilangkan torchrun dan kode secara otomatis menggunakan akumulasi gradien. Pelatihan akan memakan waktu 8× lebih lama tetapi menghasilkan hasil yang hampir identik.
Dataset apa yang digunakan nanochat?
Versi terbaik saat ini menggunakan ClimbMix (dataset web yang dikurasi NVIDIA). Versi sebelumnya menggunakan FineWeb-EDU. Tokenizer dilatih pada ~2B karakter dari ~8 shard pertama.
Apakah nanochat berfungsi di Apple Silicon?
Ya. Kode berjalan pada MPS (Metal Performance Shaders) dengan presisi float32. Pelatihan lebih lambat dari CUDA tetapi fungsional untuk eksperimen.
Bisakah saya melanjutkan pelatihan dari checkpoint?
Ya. Gunakan --resume-from-step=<step> untuk melanjutkan dari checkpoint yang disimpan. Status dataloader juga disimpan untuk kelanjutan yang tepat.
Apa perbedaan antara nanochat dan nanoGPT?
nanoGPT hanya mencakup pra-pelatihan. nanochat meluas ke seluruh pipeline: tokenisasi, pra-pelatihan, SFT, RLHF, evaluasi, inferensi, dan UI web.
Kesimpulan
nanochat membuktikan bahwa pelatihan LLM tidak lagi memerlukan anggaran besar atau infrastruktur khusus. Apa yang berharga $43.000 pada tahun 2019 kini berharga kurang dari $50.
Dampak proyek ini melampaui pengurangan biaya mentah. Dengan menyediakan basis kode minimal yang mudah dibaca dengan antarmuka "satu tombol", Karpathy telah menciptakan alat penelitian dan sumber daya edukasi.
Poin-Poin Penting
- Pengurangan biaya 100x: Dari $43.000 menjadi $48 untuk kemampuan GPT-2
- Peningkatan kecepatan 100x: Dari 168 jam menjadi 1,65 jam
- Satu tombol konfigurasi:
--depthmengontrol segalanya - Pipeline lengkap: Tokenisasi hingga UI web
- Didorong komunitas: Papan peringkat publik dengan peningkatan berkelanjutan
Langkah Selanjutnya
Siap melatih model Anda sendiri? Mulai dengan repositori nanochat dan skrip runs/speedrun.sh.
Bagi pengembang API yang membangun aplikasi bertenaga AI, memahami internal pelatihan LLM tidak pernah semudah ini. Batasan untuk masuk telah turun dari "startup yang didanai ventura" menjadi "proyek akhir pekan."
tombol
