|
Download README.md from ZappY-AI/anlp-a2: direct link, hf CLI and curl.
- Browser
- Download file 7.09 kB
-
https://huggingface.co/ZappY-AI/anlp-a2/resolve/main/README.md
- Command line
-
hf download hf://ZappY-AI/anlp-a2/README.md
-
curl -L -o README.md https://huggingface.co/ZappY-AI/anlp-a2/resolve/main/README.md
7.09 kB
| tags: | |
| - pytorch | |
| - mixture-of-experts | |
| - machine-translation | |
| - optimizers | |
| - language-modeling | |
| # anlp-a2 | |
| Model checkpoints and result files for **Tasks 1 and 2** of Assignment 2 (Advanced NLP, Monsoon 2026). Every model here was trained from scratch with PyTorch on one RTX 5060 Ti (16 GB). Task 3 (decoding strategies) uses the pretrained `EleutherAI/pythia-160m`, so it has no checkpoints in this repository. The code is in the course repository on `code.iiit.ac.in`. | |
| ## Layout | |
| ``` | |
| task1/ Mixture-of-Experts translation models (Vietnamese/Japanese -> English) | |
| model.py model definition (needed to load the checkpoints) | |
| tokenizer.json shared byte-level BPE tokenizer | |
| test_metrics.csv/.png test perplexity and BLEU of the five variants | |
| val_loss.png validation loss vs. training tokens | |
| v1/ ... v5/ one folder per FFN variant | |
| task2/ one dense model trained with four optimizers | |
| model.py, optimizers.py model definition and the four optimizer implementations | |
| tokenizer.json English byte-level BPE tokenizer | |
| final_metrics.json final metrics of all runs | |
| training_dynamics.png validation loss and test BLEU vs. fraction of the dataset seen | |
| adamw/ nadamw/ lion/ muon/ | |
| ``` | |
| Every `final.pt` is `{"config": <TransformerConfig fields>, "model": <state_dict>}`. It holds the weights only, with no optimizer state. | |
| ```python | |
| import torch | |
| from model import Transformer, TransformerConfig # model.py from the task folder | |
| ckpt = torch.load("v2/final.pt", map_location="cpu") # e.g. task1/v2/final.pt | |
| model = Transformer(TransformerConfig(**ckpt["config"])) | |
| model.load_state_dict(ckpt["model"]) | |
| model.eval() | |
| logits, aux_loss, expert_counts = model(input_ids, attention_mask, "cpu") # input_ids, attention_mask: (B, N) | |
| ``` | |
| --- | |
| ## Task 1: Mixture of Experts | |
| Decoder-only transformer (d_model 512, 8 heads, 6 layers, RMSNorm, sinusoidal positions, tied input/output embeddings, vocabulary 16,384). Attention, embeddings, data and training are identical across the five models; **only the feed-forward block differs**: | |
| | variant | FFN | params total / active per token | | |
| |---|---|---| | |
| | v1 | dense 2-layer MLP (hidden 2048) | 27.30M / 27.30M | | |
| | v2 | 4 experts, top-1 | 27.32M / 17.86M | | |
| | v3 | 4 experts, top-2 | 27.32M / 21.02M | | |
| | v4 | 1 shared expert + 3 routed experts, top-1 routed | 27.32M / 21.01M | | |
| | v5 | 4 experts (twice the width), top-2, active parameters matched to v1 | 39.91M / 27.31M | | |
| **Data and tokenizer.** `belumind/en-vi-ja-curated-500k-triplets`: 446,252 training rows, each used twice (vi->en and ja->en), giving 892,504 samples; 24,792 validation and 24,792 test rows. Each sample is `<BOS> source <SEP> English <EOS>` (no language tags) and the loss covers only the English tokens. The tokenizer is a byte-level BPE (16,384 tokens, NFC normalisation) trained on the three language columns of the training split. Special ids: `<PAD>`=0, `<BOS>`=1, `<EOS>`=2, `<SEP>`=3. | |
| **Training.** One epoch (13,946 steps, 64 sequences per step, about 39.1M tokens), AdamW (betas 0.9 / 0.95, weight decay 0.1), constant learning rate 3e-4, bf16 autocast, gradient clipping at 1.0, seed 0 (identical data order for every variant). The MoE variants add a Switch-style load-balancing loss with weight 0.01. Notes: v3 crashed with a CUDA out-of-memory error at step 4692 and was resumed from its step-4000 checkpoint. Batches above 12,288 padded tokens are split into chunks with gradient accumulation; this was used by v3 from step 4001 on and by v4 and v5, but not by v1 and v2 (the cross-entropy is unchanged by the split; only the load-balancing term is computed per chunk). | |
| **Results** (test set, 24,792 sentences per direction; perplexity is exp of the mean cross-entropy on the English target tokens given the source; BLEU is sacreBLEU corpus BLEU of greedy decodes, "overall" pools both directions): | |
| | variant | final val loss | ppl vi->en | ppl ja->en | ppl overall | BLEU vi->en | BLEU ja->en | BLEU overall | | |
| |---|---|---|---|---|---|---|---| | |
| | v1 | 3.174 | 17.96 | 33.37 | 24.48 | 18.60 | 10.77 | 14.70 | | |
| | v2 | 2.866 | 13.59 | 24.52 | 18.26 | 22.53 | 13.51 | 18.00 | | |
| | v3 | 2.961 | 14.69 | 26.96 | 19.90 | 20.71 | 12.09 | 16.35 | | |
| | v4 | 2.928 | 14.27 | 25.70 | 19.15 | 21.52 | 12.32 | 16.84 | | |
| | v5 | 2.860 | 13.23 | 24.36 | 17.95 | 22.62 | 13.56 | 18.11 | | |
| **Files in each `task1/vN/`:** `final.pt`, `history.json` (validation loss vs. tokens seen), `test_metrics.json`, `samples.json` (50 test translations per source language). For the MoE variants (v2 to v5) also `expert_heatmap.png` (expert usage per layer and source language, all tokens), `expert_heatmap_source.png` (source tokens only) and `expert_counts.json` / `expert_counts_source.json` (the raw routing counts behind the heatmaps). | |
| --- | |
| ## Task 2: Optimizers | |
| The dense architecture of Task 1 variant v1 (27.30M parameters, context 256, vocabulary 16,384), trained from scratch for next-token prediction on `browndw/human-ai-parallel-corpus` (66,320 texts). The texts are split 90 / 5 / 5 into train / validation / test **by source document**, so no version of a document appears in two splits (39,068,808 / 2,167,168 / 2,162,705 tokens). The English byte-level BPE tokenizer (16,384 tokens, `<PAD>`=0, `<BOS>`=1, `<EOS>`=2) is trained on the training split; documents are concatenated with `<EOS>` and cut into 256-token blocks. | |
| **Optimizers** (`optimizers.py`, each subclasses `torch.optim.Optimizer` directly): | |
| | run | category | settings | | |
| |---|---|---| | |
| | `adamw` | baseline | betas (0.9, 0.95), eps 1e-8 | | |
| | `nadamw` | variance-reduced AdamW variants | Nesterov momentum, same settings as AdamW | | |
| | `lion` | memory-efficient | betas (0.9, 0.99) | | |
| | `muon` | matrix-based | momentum 0.95 (Nesterov), 5 Newton-Schulz steps, update scaled by sqrt(max(1, rows/cols)); used for the hidden 2-D weight matrices, while the embedding, norm gains and biases use an AdamW update | | |
| **Training (identical for all four).** One epoch (39.07M tokens), 16 sequences of 256 tokens per step, learning rate **3e-4 for every optimizer** (Muon: 3e-4 for the matrices and 3e-4 for its AdamW path; no per-optimizer tuning), weight decay 0.1, linear warmup over the first 2% of steps and then linear decay to 10% of the peak, gradient clipping at 1.0, bf16 autocast, seed 0. Validation loss and test BLEU are recorded every 0.1x of the dataset. | |
| **Test BLEU** is defined as follows: 500 fixed test documents; the model gets the first 128 tokens and greedily generates the next 64, which are scored with sacreBLEU against the true tokens 129 to 192. | |
| **Final results:** | |
| | run | val loss | test loss | test BLEU | | |
| |---|---|---|---| | |
| | adamw | 5.245 | 5.230 | 1.05 | | |
| | nadamw | 5.084 | 5.068 | 1.17 | | |
| | lion | 6.433 | 6.429 | 0.14 | | |
| | muon | 4.675 | 4.653 | 1.95 | | |
| **Files in each `task2/<run>/`:** `final.pt`, `history.json` (validation loss and test BLEU at each 0.1x of the epoch), `final_metrics.json`, `bleu_examples.json` (generated and reference continuations). | |