{
  "id": 684537,
  "title": "Silver Medal Solution[29th]: ByT5-XL Custom CPT with Dictionary Data + KL-Anchor",
  "url": "/competitions/deep-past-initiative-machine-translation/discussion/684537",
  "author_name": "nawta",
  "post_date": "2026-03-25T10:51:15.030000",
  "votes": 4,
  "comment_count": 0,
  "views": 0,
  "content": "<h2>Summary</h2>\n<ul>\n<li><strong>Model</strong>: ByT5-XL (3.7B) with custom Continued Pre-Training (CPT) on Akkadian domain data (eSAD/CAD dictionaries + onomasticon + published texts) followed by fine-tuning → <strong>LB = 37.6</strong></li>\n<li><strong>Key insight</strong>: CV and LB are inversely correlated — fine-tuning consistently improves CV but worsens LB, due to a fundamental distribution mismatch between train and hidden test data</li>\n<li><strong>Novel approach</strong>: KL-anchored LoRA adaptation that preserves the base model's translation ability while adapting to domain-specific patterns</li>\n<li>Over 40 experiments conducted; sharing technical findings that I hope are useful to the community</li>\n</ul>\n<p><strong>Shared notebook</strong>: <a href=\"https://www.kaggle.com/code/naotonishida/expj00-ft-infer\" target=\"_blank\">expJ00 FT Infer</a> (inference) + <a href=\"https://www.kaggle.com/code/naotonishida/expj00-ft-dl\" target=\"_blank\">expJ00 FT DL</a> (model downloader)</p>\n<h2>Model &amp; Training Pipeline</h2>\n<h3>Base Model</h3>\n<p>google/byt5-xl (3.7B parameters) — a byte-level T5 model with 36 encoder layers and 12 decoder layers.\nStarting from a publicly available CPT checkpoint that had already been pre-trained on Akkadian transliterations for 400 steps.</p>\n<h3>Stage 1: Continued Pre-Training (CPT)</h3>\n<p><strong>Task</strong>: ByT5 span corruption (noise_density=0.15, mean_noise_span_length=20 bytes)</p>\n<p><strong>CPT Corpus</strong> (79,604 texts, 7.3 MB — transliteration only, no English):</p>\n<table>\n<thead>\n<tr>\n<th>Source</th>\n<th>Entries</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>published_texts</td>\n<td>~8,000 docs</td>\n<td>Transliterations from ORACC/CDLI</td>\n</tr>\n<tr>\n<td>eSAD dictionary</td>\n<td>2,645 entries</td>\n<td>Akkadian headwords &amp; transliterations extracted from PDF</td>\n</tr>\n<tr>\n<td>CAD dictionary</td>\n<td>8,682 entries</td>\n<td>Chicago Assyrian Dictionary, all volumes, extracted from 782MB PDF</td>\n</tr>\n<tr>\n<td>onomasticon</td>\n<td>5,595 entries</td>\n<td>Proper noun transliterations</td>\n</tr>\n<tr>\n<td>Sentences_Oare</td>\n<td>~9,700 texts</td>\n<td>Sentence-level transliterations</td>\n</tr>\n<tr>\n<td>eBL_Dictionary, OA_Lexicon</td>\n<td>~50K+ entries</td>\n<td>Additional lexical resources</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Hyperparameters</strong>:</p>\n<ul>\n<li>1,600 steps, LR = 5e-5, effective batch size = 16</li>\n<li>BF16 precision (critical for ByT5 — FP16 causes NaN divergence)</li>\n<li>max_length = 512 bytes</li>\n<li>Final loss: 1.12</li>\n<li>Training time: ~27 min on RTX PRO 6000 (96GB)</li>\n</ul>\n<h3>Stage 2: Fine-Tuning (FT)</h3>\n<ul>\n<li>Data: train.csv (1,561 pairs) + synthetic translations (7,660 pairs generated by the base model on published_texts)</li>\n<li>5 epochs, LR = 1e-5, max_length = 256</li>\n<li>num_beams = 4, length_penalty = 1.3</li>\n<li>Best checkpoint selected by CV score (step 800)</li>\n</ul>\n<h3>Stage 3: Inference</h3>\n<ul>\n<li>BF16 on T4 16GB (model uses ~7.5GB VRAM)</li>\n<li>MBR decoding: 2 beam candidates + 1 sampling candidate, chrF++ consensus</li>\n<li>Minimal post-processing only (subscript normalization, gap normalization, whitespace cleanup)</li>\n<li>Utility notebook pattern: downloader (internet=ON) → inference (internet=OFF, kernel_sources)</li>\n</ul>\n<h2>Key Finding: The CV-LB Gap</h2>\n<p>This was the most important and frustrating discovery of this competition. <strong>Fine-tuning consistently improves CV but worsens LB.</strong></p>\n<table>\n<thead>\n<tr>\n<th>Experiment</th>\n<th>Description</th>\n<th>CV</th>\n<th>LB</th>\n<th>CV-LB Gap</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Base model (no FT)</td>\n<td>ByT5-XL, zero-shot</td>\n<td>12.4</td>\n<td><strong>38.0</strong></td>\n<td>-25.6</td>\n</tr>\n<tr>\n<td>+ CPT 400 + FT 5ep</td>\n<td>Published texts CPT</td>\n<td>40.5</td>\n<td>35.0</td>\n<td>5.5</td>\n</tr>\n<tr>\n<td>+ CPT 1600 + FT (eSAD+CAD, English included)</td>\n<td>expJ00</td>\n<td>43.7</td>\n<td><strong>37.6</strong></td>\n<td>6.1</td>\n</tr>\n<tr>\n<td>+ CPT 1600 + FT (translit-only)</td>\n<td>expJ01</td>\n<td><strong>44.2</strong></td>\n<td>36.7</td>\n<td>7.5</td>\n</tr>\n<tr>\n<td>+ LoRA + KL distillation</td>\n<td>expK01</td>\n<td>—</td>\n<td>37.1</td>\n<td>—</td>\n</tr>\n<tr>\n<td>ByT5-base FT (data aug)</td>\n<td>Small model, heavy FT</td>\n<td><strong>53.3</strong></td>\n<td>29.2</td>\n<td>24.1</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Root cause</strong>: The training data consists of ~1,500 Old Assyrian commercial texts (contracts, debt notes, trade correspondence), while the hidden test appears to contain sentence-level samples from diverse genres (letters, legal texts, formal documents). Fine-tuning on train data specializes the model for one narrow domain, hurting generalization.</p>\n<p><strong>The paradox</strong>: CPT-only (without FT) cannot translate at all — it outputs span corruption responses (<code>&lt;extra_id_0&gt;</code> + Akkadian text). But FT, while enabling translation, inevitably overfits to the training distribution. This structural dilemma defined my entire competition experience.</p>\n<h2>What Worked</h2>\n<h3>1. Model Scale (580M → 3.7B): +14.4 LB points</h3>\n<p>The single biggest improvement. ByT5-XL (3.7B) at LB=38.0 vs ByT5-base (580M) at LB=23.6. The larger model's broader pre-training knowledge provides much better zero-shot translation ability.</p>\n<h3>2. BF16 Precision (mandatory for ByT5)</h3>\n<p>FP16 causes NaN divergence in ByT5 due to its narrow dynamic range (max ~65,504). BF16 shares FP32's dynamic range (max ~3.4e38) while using only 2 bytes per parameter. This is not optional — FP16 gives Score=0.54 vs BF16's Score=25.95.</p>\n<h3>3. Translit-Only CPT Data (no English)</h3>\n<p>Including English dictionary definitions in CPT data hurts performance (CV 43.7 vs 44.2 for translit-only). Span corruption is a monolingual task — English text is noise. Extract only Akkadian headwords and transliterations from dictionaries.</p>\n<h3>4. Dictionary &amp; Lexicon Data for CPT</h3>\n<p>Adding eSAD, CAD, and onomasticon transliterations improved the model's Akkadian vocabulary coverage. The CPT corpus grew from ~8K to ~80K texts, and the model learned rarer cuneiform sign readings and proper noun patterns.</p>\n<h3>5. Minimal Post-Processing</h3>\n<p>Aggressive post-processing (fraction conversion, PN normalization, Roman numeral conversion, annotation removal) consistently hurt LB scores. The optimal pipeline is minimal: subscript digit conversion + gap normalization + whitespace cleanup only.</p>\n<h3>6. LoRA + KL Distillation (Anchored Adaptation)</h3>\n<p>To mitigate the FT-induced LB degradation, I developed a KL-anchored LoRA approach:</p>\n<ul>\n<li><strong>Teacher</strong>: Base model (frozen)</li>\n<li><strong>Student</strong>: Base model + LoRA (0.24% trainable params)</li>\n<li><strong>LoRA targets</strong>: Encoder self-attention (q, v) + Decoder cross-attention (q, v)</li>\n<li><strong>Frozen</strong>: Decoder self-attention + lm_head</li>\n<li><strong>Loss</strong>: <code>0.7 × denoise + 0.2 × KL_distill + 0.1 × anchor_CE</code></li>\n</ul>\n<p>This achieved LB=37.1, improving +0.4 over standard FT (36.7), confirming that preserving the base model's translation distribution helps. However, it still couldn't surpass the base model's 38.0.</p>\n<h3>7. MBR Decoding</h3>\n<p>Minimum Bayes Risk decoding with chrF++ scoring. For the 3.7B model, a lightweight config works best: 2 beam candidates + 1 sampling candidate (3 total). Larger candidate pools don't justify the compute cost at this model scale.</p>\n<h2>What Didn't Work</h2>\n<table>\n<thead>\n<tr>\n<th>Approach</th>\n<th>Result</th>\n<th>Why</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Aggressive fine-tuning</td>\n<td>CV=53.3, LB=29.2</td>\n<td>Overfits to train distribution</td>\n</tr>\n<tr>\n<td>English-mixed CPT data</td>\n<td>CV=43.7 (vs 44.2 translit-only)</td>\n<td>English is noise for span corruption</td>\n</tr>\n<tr>\n<td>Heavy post-processing</td>\n<td>LB -0.2 to -0.4</td>\n<td>GT format doesn't match assumed patterns</td>\n</tr>\n<tr>\n<td>Flan-T5 Philologist refinement</td>\n<td>LB=21.1</td>\n<td>Destroys proper nouns (karum → Krum)</td>\n</tr>\n<tr>\n<td>Inference parameter tuning</td>\n<td>LB ±0.0</td>\n<td>Already near-optimal with default settings</td>\n</tr>\n<tr>\n<td>CPT-only (no FT)</td>\n<td>Cannot translate</td>\n<td>Outputs span corruption responses only</td>\n</tr>\n<tr>\n<td>NLLB 3.3B</td>\n<td>LB=31.9</td>\n<td>No Akkadian-specific pre-training</td>\n</tr>\n<tr>\n<td>ByT5-small/base models</td>\n<td>LB=23-26</td>\n<td>Insufficient model capacity</td>\n</tr>\n<tr>\n<td>Longer sequences (max512, max1024)</td>\n<td>CV drops significantly</td>\n<td>Model trained on shorter sequences</td>\n</tr>\n</tbody>\n</table>\n<h2>Technical Details</h2>\n<h3>ByT5 Span Corruption for CPT</h3>\n<p>ByT5 operates at the byte level, so the standard T5 span corruption parameters need adjustment. Use <code>mean_noise_span_length=20</code> (bytes, not tokens — standard T5 uses 3 tokens ≈ 15 bytes). <code>noise_density=0.15</code> works well.</p>\n<h3>BF16 on T4 16GB</h3>\n<p>ByT5-XL (3.7B) in BF16 uses only ~7.5GB VRAM, fitting comfortably on T4 with room for beam search KV cache. Save models in BF16 format to avoid FP16 NaN issues during loading:</p>\n<pre><code>model = AutoModelForSeq2SeqLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)\nmodel.save_pretrained(output_path)  # Saved as BF16\n</code></pre>\n<h3>Utility Notebook Pattern</h3>\n<p>For internet-disabled competitions:</p>\n<ol>\n<li><strong>Downloader notebook</strong> (internet=ON): Download from HuggingFace, save BF16 model to <code>/kaggle/working/</code></li>\n<li><strong>Inference notebook</strong> (internet=OFF): Reference downloader output via <code>kernel_sources</code>, load model from <code>/kaggle/input/notebooks/&lt;owner&gt;/&lt;slug&gt;/</code></li>\n</ol>\n<p>Use <code>glob</code> to discover <code>config.json</code> path rather than hardcoding — Kaggle's mount paths can vary.</p>\n<h3>Synthetic Data Generation</h3>\n<p>Generated ~7,660 translation pairs by running the base ByT5-XL model on published_texts transliterations. These synthetic pairs, combined with the original train.csv, provided the FT training data. Quality is reasonable since the base model already has strong Akkadian translation ability from its original training.</p>\n<h2>Reflections</h2>\n<p>The biggest lesson: <strong>in low-resource translation with distribution mismatch, a strong pre-trained model with minimal adaptation beats heavy fine-tuning.</strong> The base ByT5-XL model (LB=38.0) outperformed every fine-tuned variant I produced. If I could do it over, I would focus more on:</p>\n<ol>\n<li>Data curation for CPT that better matches the hidden test distribution</li>\n<li>Even lighter adaptation methods (prompt tuning, adapter layers with stronger regularization)</li>\n<li>Ensemble of CPT-only models with different data subsets</li>\n</ol>\n<p>The CV-LB gap is a known challenge in NLP competitions but rarely this extreme. The key takeaway: <strong>when your CV and LB diverge, trust LB and investigate the distribution gap rather than optimizing CV.</strong></p>\n<h2>Acknowledgments</h2>\n<p>Thanks to the Deep Past Initiative organizers for this fascinating competition — working with Akkadian is a unique and intellectually rewarding challenge. Thanks also to the Kaggle community for sharing models and insights throughout the competition.</p>",
  "messages": [
    {
      "id": 3428358,
      "postDate": "2026-03-25T10:51:15.030Z",
      "content": "<h2>Summary</h2>\n<ul>\n<li><strong>Model</strong>: ByT5-XL (3.7B) with custom Continued Pre-Training (CPT) on Akkadian domain data (eSAD/CAD dictionaries + onomasticon + published texts) followed by fine-tuning → <strong>LB = 37.6</strong></li>\n<li><strong>Key insight</strong>: CV and LB are inversely correlated — fine-tuning consistently improves CV but worsens LB, due to a fundamental distribution mismatch between train and hidden test data</li>\n<li><strong>Novel approach</strong>: KL-anchored LoRA adaptation that preserves the base model's translation ability while adapting to domain-specific patterns</li>\n<li>Over 40 experiments conducted; sharing technical findings that I hope are useful to the community</li>\n</ul>\n<p><strong>Shared notebook</strong>: <a href=\"https://www.kaggle.com/code/naotonishida/expj00-ft-infer\" target=\"_blank\">expJ00 FT Infer</a> (inference) + <a href=\"https://www.kaggle.com/code/naotonishida/expj00-ft-dl\" target=\"_blank\">expJ00 FT DL</a> (model downloader)</p>\n<h2>Model &amp; Training Pipeline</h2>\n<h3>Base Model</h3>\n<p>google/byt5-xl (3.7B parameters) — a byte-level T5 model with 36 encoder layers and 12 decoder layers.\nStarting from a publicly available CPT checkpoint that had already been pre-trained on Akkadian transliterations for 400 steps.</p>\n<h3>Stage 1: Continued Pre-Training (CPT)</h3>\n<p><strong>Task</strong>: ByT5 span corruption (noise_density=0.15, mean_noise_span_length=20 bytes)</p>\n<p><strong>CPT Corpus</strong> (79,604 texts, 7.3 MB — transliteration only, no English):</p>\n<table>\n<thead>\n<tr>\n<th>Source</th>\n<th>Entries</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>published_texts</td>\n<td>~8,000 docs</td>\n<td>Transliterations from ORACC/CDLI</td>\n</tr>\n<tr>\n<td>eSAD dictionary</td>\n<td>2,645 entries</td>\n<td>Akkadian headwords &amp; transliterations extracted from PDF</td>\n</tr>\n<tr>\n<td>CAD dictionary</td>\n<td>8,682 entries</td>\n<td>Chicago Assyrian Dictionary, all volumes, extracted from 782MB PDF</td>\n</tr>\n<tr>\n<td>onomasticon</td>\n<td>5,595 entries</td>\n<td>Proper noun transliterations</td>\n</tr>\n<tr>\n<td>Sentences_Oare</td>\n<td>~9,700 texts</td>\n<td>Sentence-level transliterations</td>\n</tr>\n<tr>\n<td>eBL_Dictionary, OA_Lexicon</td>\n<td>~50K+ entries</td>\n<td>Additional lexical resources</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Hyperparameters</strong>:</p>\n<ul>\n<li>1,600 steps, LR = 5e-5, effective batch size = 16</li>\n<li>BF16 precision (critical for ByT5 — FP16 causes NaN divergence)</li>\n<li>max_length = 512 bytes</li>\n<li>Final loss: 1.12</li>\n<li>Training time: ~27 min on RTX PRO 6000 (96GB)</li>\n</ul>\n<h3>Stage 2: Fine-Tuning (FT)</h3>\n<ul>\n<li>Data: train.csv (1,561 pairs) + synthetic translations (7,660 pairs generated by the base model on published_texts)</li>\n<li>5 epochs, LR = 1e-5, max_length = 256</li>\n<li>num_beams = 4, length_penalty = 1.3</li>\n<li>Best checkpoint selected by CV score (step 800)</li>\n</ul>\n<h3>Stage 3: Inference</h3>\n<ul>\n<li>BF16 on T4 16GB (model uses ~7.5GB VRAM)</li>\n<li>MBR decoding: 2 beam candidates + 1 sampling candidate, chrF++ consensus</li>\n<li>Minimal post-processing only (subscript normalization, gap normalization, whitespace cleanup)</li>\n<li>Utility notebook pattern: downloader (internet=ON) → inference (internet=OFF, kernel_sources)</li>\n</ul>\n<h2>Key Finding: The CV-LB Gap</h2>\n<p>This was the most important and frustrating discovery of this competition. <strong>Fine-tuning consistently improves CV but worsens LB.</strong></p>\n<table>\n<thead>\n<tr>\n<th>Experiment</th>\n<th>Description</th>\n<th>CV</th>\n<th>LB</th>\n<th>CV-LB Gap</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Base model (no FT)</td>\n<td>ByT5-XL, zero-shot</td>\n<td>12.4</td>\n<td><strong>38.0</strong></td>\n<td>-25.6</td>\n</tr>\n<tr>\n<td>+ CPT 400 + FT 5ep</td>\n<td>Published texts CPT</td>\n<td>40.5</td>\n<td>35.0</td>\n<td>5.5</td>\n</tr>\n<tr>\n<td>+ CPT 1600 + FT (eSAD+CAD, English included)</td>\n<td>expJ00</td>\n<td>43.7</td>\n<td><strong>37.6</strong></td>\n<td>6.1</td>\n</tr>\n<tr>\n<td>+ CPT 1600 + FT (translit-only)</td>\n<td>expJ01</td>\n<td><strong>44.2</strong></td>\n<td>36.7</td>\n<td>7.5</td>\n</tr>\n<tr>\n<td>+ LoRA + KL distillation</td>\n<td>expK01</td>\n<td>—</td>\n<td>37.1</td>\n<td>—</td>\n</tr>\n<tr>\n<td>ByT5-base FT (data aug)</td>\n<td>Small model, heavy FT</td>\n<td><strong>53.3</strong></td>\n<td>29.2</td>\n<td>24.1</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Root cause</strong>: The training data consists of ~1,500 Old Assyrian commercial texts (contracts, debt notes, trade correspondence), while the hidden test appears to contain sentence-level samples from diverse genres (letters, legal texts, formal documents). Fine-tuning on train data specializes the model for one narrow domain, hurting generalization.</p>\n<p><strong>The paradox</strong>: CPT-only (without FT) cannot translate at all — it outputs span corruption responses (<code>&lt;extra_id_0&gt;</code> + Akkadian text). But FT, while enabling translation, inevitably overfits to the training distribution. This structural dilemma defined my entire competition experience.</p>\n<h2>What Worked</h2>\n<h3>1. Model Scale (580M → 3.7B): +14.4 LB points</h3>\n<p>The single biggest improvement. ByT5-XL (3.7B) at LB=38.0 vs ByT5-base (580M) at LB=23.6. The larger model's broader pre-training knowledge provides much better zero-shot translation ability.</p>\n<h3>2. BF16 Precision (mandatory for ByT5)</h3>\n<p>FP16 causes NaN divergence in ByT5 due to its narrow dynamic range (max ~65,504). BF16 shares FP32's dynamic range (max ~3.4e38) while using only 2 bytes per parameter. This is not optional — FP16 gives Score=0.54 vs BF16's Score=25.95.</p>\n<h3>3. Translit-Only CPT Data (no English)</h3>\n<p>Including English dictionary definitions in CPT data hurts performance (CV 43.7 vs 44.2 for translit-only). Span corruption is a monolingual task — English text is noise. Extract only Akkadian headwords and transliterations from dictionaries.</p>\n<h3>4. Dictionary &amp; Lexicon Data for CPT</h3>\n<p>Adding eSAD, CAD, and onomasticon transliterations improved the model's Akkadian vocabulary coverage. The CPT corpus grew from ~8K to ~80K texts, and the model learned rarer cuneiform sign readings and proper noun patterns.</p>\n<h3>5. Minimal Post-Processing</h3>\n<p>Aggressive post-processing (fraction conversion, PN normalization, Roman numeral conversion, annotation removal) consistently hurt LB scores. The optimal pipeline is minimal: subscript digit conversion + gap normalization + whitespace cleanup only.</p>\n<h3>6. LoRA + KL Distillation (Anchored Adaptation)</h3>\n<p>To mitigate the FT-induced LB degradation, I developed a KL-anchored LoRA approach:</p>\n<ul>\n<li><strong>Teacher</strong>: Base model (frozen)</li>\n<li><strong>Student</strong>: Base model + LoRA (0.24% trainable params)</li>\n<li><strong>LoRA targets</strong>: Encoder self-attention (q, v) + Decoder cross-attention (q, v)</li>\n<li><strong>Frozen</strong>: Decoder self-attention + lm_head</li>\n<li><strong>Loss</strong>: <code>0.7 × denoise + 0.2 × KL_distill + 0.1 × anchor_CE</code></li>\n</ul>\n<p>This achieved LB=37.1, improving +0.4 over standard FT (36.7), confirming that preserving the base model's translation distribution helps. However, it still couldn't surpass the base model's 38.0.</p>\n<h3>7. MBR Decoding</h3>\n<p>Minimum Bayes Risk decoding with chrF++ scoring. For the 3.7B model, a lightweight config works best: 2 beam candidates + 1 sampling candidate (3 total). Larger candidate pools don't justify the compute cost at this model scale.</p>\n<h2>What Didn't Work</h2>\n<table>\n<thead>\n<tr>\n<th>Approach</th>\n<th>Result</th>\n<th>Why</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Aggressive fine-tuning</td>\n<td>CV=53.3, LB=29.2</td>\n<td>Overfits to train distribution</td>\n</tr>\n<tr>\n<td>English-mixed CPT data</td>\n<td>CV=43.7 (vs 44.2 translit-only)</td>\n<td>English is noise for span corruption</td>\n</tr>\n<tr>\n<td>Heavy post-processing</td>\n<td>LB -0.2 to -0.4</td>\n<td>GT format doesn't match assumed patterns</td>\n</tr>\n<tr>\n<td>Flan-T5 Philologist refinement</td>\n<td>LB=21.1</td>\n<td>Destroys proper nouns (karum → Krum)</td>\n</tr>\n<tr>\n<td>Inference parameter tuning</td>\n<td>LB ±0.0</td>\n<td>Already near-optimal with default settings</td>\n</tr>\n<tr>\n<td>CPT-only (no FT)</td>\n<td>Cannot translate</td>\n<td>Outputs span corruption responses only</td>\n</tr>\n<tr>\n<td>NLLB 3.3B</td>\n<td>LB=31.9</td>\n<td>No Akkadian-specific pre-training</td>\n</tr>\n<tr>\n<td>ByT5-small/base models</td>\n<td>LB=23-26</td>\n<td>Insufficient model capacity</td>\n</tr>\n<tr>\n<td>Longer sequences (max512, max1024)</td>\n<td>CV drops significantly</td>\n<td>Model trained on shorter sequences</td>\n</tr>\n</tbody>\n</table>\n<h2>Technical Details</h2>\n<h3>ByT5 Span Corruption for CPT</h3>\n<p>ByT5 operates at the byte level, so the standard T5 span corruption parameters need adjustment. Use <code>mean_noise_span_length=20</code> (bytes, not tokens — standard T5 uses 3 tokens ≈ 15 bytes). <code>noise_density=0.15</code> works well.</p>\n<h3>BF16 on T4 16GB</h3>\n<p>ByT5-XL (3.7B) in BF16 uses only ~7.5GB VRAM, fitting comfortably on T4 with room for beam search KV cache. Save models in BF16 format to avoid FP16 NaN issues during loading:</p>\n<pre><code>model = AutoModelForSeq2SeqLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)\nmodel.save_pretrained(output_path)  # Saved as BF16\n</code></pre>\n<h3>Utility Notebook Pattern</h3>\n<p>For internet-disabled competitions:</p>\n<ol>\n<li><strong>Downloader notebook</strong> (internet=ON): Download from HuggingFace, save BF16 model to <code>/kaggle/working/</code></li>\n<li><strong>Inference notebook</strong> (internet=OFF): Reference downloader output via <code>kernel_sources</code>, load model from <code>/kaggle/input/notebooks/&lt;owner&gt;/&lt;slug&gt;/</code></li>\n</ol>\n<p>Use <code>glob</code> to discover <code>config.json</code> path rather than hardcoding — Kaggle's mount paths can vary.</p>\n<h3>Synthetic Data Generation</h3>\n<p>Generated ~7,660 translation pairs by running the base ByT5-XL model on published_texts transliterations. These synthetic pairs, combined with the original train.csv, provided the FT training data. Quality is reasonable since the base model already has strong Akkadian translation ability from its original training.</p>\n<h2>Reflections</h2>\n<p>The biggest lesson: <strong>in low-resource translation with distribution mismatch, a strong pre-trained model with minimal adaptation beats heavy fine-tuning.</strong> The base ByT5-XL model (LB=38.0) outperformed every fine-tuned variant I produced. If I could do it over, I would focus more on:</p>\n<ol>\n<li>Data curation for CPT that better matches the hidden test distribution</li>\n<li>Even lighter adaptation methods (prompt tuning, adapter layers with stronger regularization)</li>\n<li>Ensemble of CPT-only models with different data subsets</li>\n</ol>\n<p>The CV-LB gap is a known challenge in NLP competitions but rarely this extreme. The key takeaway: <strong>when your CV and LB diverge, trust LB and investigate the distribution gap rather than optimizing CV.</strong></p>\n<h2>Acknowledgments</h2>\n<p>Thanks to the Deep Past Initiative organizers for this fascinating competition — working with Akkadian is a unique and intellectually rewarding challenge. Thanks also to the Kaggle community for sharing models and insights throughout the competition.</p>",
      "rawMarkdown": "## Summary\n\n- **Model**: ByT5-XL (3.7B) with custom Continued Pre-Training (CPT) on Akkadian domain data (eSAD/CAD dictionaries + onomasticon + published texts) followed by fine-tuning → **LB = 37.6**\n- **Key insight**: CV and LB are inversely correlated — fine-tuning consistently improves CV but worsens LB, due to a fundamental distribution mismatch between train and hidden test data\n- **Novel approach**: KL-anchored LoRA adaptation that preserves the base model's translation ability while adapting to domain-specific patterns\n- Over 40 experiments conducted; sharing technical findings that I hope are useful to the community\n\n**Shared notebook**: [expJ00 FT Infer](https://www.kaggle.com/code/naotonishida/expj00-ft-infer) (inference) + [expJ00 FT DL](https://www.kaggle.com/code/naotonishida/expj00-ft-dl) (model downloader)\n\n## Model & Training Pipeline\n\n### Base Model\n\ngoogle/byt5-xl (3.7B parameters) — a byte-level T5 model with 36 encoder layers and 12 decoder layers.\nStarting from a publicly available CPT checkpoint that had already been pre-trained on Akkadian transliterations for 400 steps.\n\n### Stage 1: Continued Pre-Training (CPT)\n\n**Task**: ByT5 span corruption (noise_density=0.15, mean_noise_span_length=20 bytes)\n\n**CPT Corpus** (79,604 texts, 7.3 MB — transliteration only, no English):\n\n| Source | Entries | Notes |\n|--------|---------|-------|\n| published_texts | ~8,000 docs | Transliterations from ORACC/CDLI |\n| eSAD dictionary | 2,645 entries | Akkadian headwords & transliterations extracted from PDF |\n| CAD dictionary | 8,682 entries | Chicago Assyrian Dictionary, all volumes, extracted from 782MB PDF |\n| onomasticon | 5,595 entries | Proper noun transliterations |\n| Sentences_Oare | ~9,700 texts | Sentence-level transliterations |\n| eBL_Dictionary, OA_Lexicon | ~50K+ entries | Additional lexical resources |\n\n**Hyperparameters**:\n- 1,600 steps, LR = 5e-5, effective batch size = 16\n- BF16 precision (critical for ByT5 — FP16 causes NaN divergence)\n- max_length = 512 bytes\n- Final loss: 1.12\n- Training time: ~27 min on RTX PRO 6000 (96GB)\n\n### Stage 2: Fine-Tuning (FT)\n\n- Data: train.csv (1,561 pairs) + synthetic translations (7,660 pairs generated by the base model on published_texts)\n- 5 epochs, LR = 1e-5, max_length = 256\n- num_beams = 4, length_penalty = 1.3\n- Best checkpoint selected by CV score (step 800)\n\n### Stage 3: Inference\n\n- BF16 on T4 16GB (model uses ~7.5GB VRAM)\n- MBR decoding: 2 beam candidates + 1 sampling candidate, chrF++ consensus\n- Minimal post-processing only (subscript normalization, gap normalization, whitespace cleanup)\n- Utility notebook pattern: downloader (internet=ON) → inference (internet=OFF, kernel_sources)\n\n## Key Finding: The CV-LB Gap\n\nThis was the most important and frustrating discovery of this competition. **Fine-tuning consistently improves CV but worsens LB.**\n\n| Experiment | Description | CV | LB | CV-LB Gap |\n|------------|-------------|----|----|-----------|\n| Base model (no FT) | ByT5-XL, zero-shot | 12.4 | **38.0** | -25.6 |\n| + CPT 400 + FT 5ep | Published texts CPT | 40.5 | 35.0 | 5.5 |\n| + CPT 1600 + FT (eSAD+CAD, English included) | expJ00 | 43.7 | **37.6** | 6.1 |\n| + CPT 1600 + FT (translit-only) | expJ01 | **44.2** | 36.7 | 7.5 |\n| + LoRA + KL distillation | expK01 | — | 37.1 | — |\n| ByT5-base FT (data aug) | Small model, heavy FT | **53.3** | 29.2 | 24.1 |\n\n**Root cause**: The training data consists of ~1,500 Old Assyrian commercial texts (contracts, debt notes, trade correspondence), while the hidden test appears to contain sentence-level samples from diverse genres (letters, legal texts, formal documents). Fine-tuning on train data specializes the model for one narrow domain, hurting generalization.\n\n**The paradox**: CPT-only (without FT) cannot translate at all — it outputs span corruption responses (`<extra_id_0>` + Akkadian text). But FT, while enabling translation, inevitably overfits to the training distribution. This structural dilemma defined my entire competition experience.\n\n## What Worked\n\n### 1. Model Scale (580M → 3.7B): +14.4 LB points\nThe single biggest improvement. ByT5-XL (3.7B) at LB=38.0 vs ByT5-base (580M) at LB=23.6. The larger model's broader pre-training knowledge provides much better zero-shot translation ability.\n\n### 2. BF16 Precision (mandatory for ByT5)\nFP16 causes NaN divergence in ByT5 due to its narrow dynamic range (max ~65,504). BF16 shares FP32's dynamic range (max ~3.4e38) while using only 2 bytes per parameter. This is not optional — FP16 gives Score=0.54 vs BF16's Score=25.95.\n\n### 3. Translit-Only CPT Data (no English)\nIncluding English dictionary definitions in CPT data hurts performance (CV 43.7 vs 44.2 for translit-only). Span corruption is a monolingual task — English text is noise. Extract only Akkadian headwords and transliterations from dictionaries.\n\n### 4. Dictionary & Lexicon Data for CPT\nAdding eSAD, CAD, and onomasticon transliterations improved the model's Akkadian vocabulary coverage. The CPT corpus grew from ~8K to ~80K texts, and the model learned rarer cuneiform sign readings and proper noun patterns.\n\n### 5. Minimal Post-Processing\nAggressive post-processing (fraction conversion, PN normalization, Roman numeral conversion, annotation removal) consistently hurt LB scores. The optimal pipeline is minimal: subscript digit conversion + gap normalization + whitespace cleanup only.\n\n### 6. LoRA + KL Distillation (Anchored Adaptation)\nTo mitigate the FT-induced LB degradation, I developed a KL-anchored LoRA approach:\n- **Teacher**: Base model (frozen)\n- **Student**: Base model + LoRA (0.24% trainable params)\n- **LoRA targets**: Encoder self-attention (q, v) + Decoder cross-attention (q, v)\n- **Frozen**: Decoder self-attention + lm_head\n- **Loss**: `0.7 × denoise + 0.2 × KL_distill + 0.1 × anchor_CE`\n\nThis achieved LB=37.1, improving +0.4 over standard FT (36.7), confirming that preserving the base model's translation distribution helps. However, it still couldn't surpass the base model's 38.0.\n\n### 7. MBR Decoding\nMinimum Bayes Risk decoding with chrF++ scoring. For the 3.7B model, a lightweight config works best: 2 beam candidates + 1 sampling candidate (3 total). Larger candidate pools don't justify the compute cost at this model scale.\n\n## What Didn't Work\n\n| Approach | Result | Why |\n|----------|--------|-----|\n| Aggressive fine-tuning | CV=53.3, LB=29.2 | Overfits to train distribution |\n| English-mixed CPT data | CV=43.7 (vs 44.2 translit-only) | English is noise for span corruption |\n| Heavy post-processing | LB -0.2 to -0.4 | GT format doesn't match assumed patterns |\n| Flan-T5 Philologist refinement | LB=21.1 | Destroys proper nouns (karum → Krum) |\n| Inference parameter tuning | LB ±0.0 | Already near-optimal with default settings |\n| CPT-only (no FT) | Cannot translate | Outputs span corruption responses only |\n| NLLB 3.3B | LB=31.9 | No Akkadian-specific pre-training |\n| ByT5-small/base models | LB=23-26 | Insufficient model capacity |\n| Longer sequences (max512, max1024) | CV drops significantly | Model trained on shorter sequences |\n\n## Technical Details\n\n### ByT5 Span Corruption for CPT\nByT5 operates at the byte level, so the standard T5 span corruption parameters need adjustment. Use `mean_noise_span_length=20` (bytes, not tokens — standard T5 uses 3 tokens ≈ 15 bytes). `noise_density=0.15` works well.\n\n### BF16 on T4 16GB\nByT5-XL (3.7B) in BF16 uses only ~7.5GB VRAM, fitting comfortably on T4 with room for beam search KV cache. Save models in BF16 format to avoid FP16 NaN issues during loading:\n```python\nmodel = AutoModelForSeq2SeqLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)\nmodel.save_pretrained(output_path)  # Saved as BF16\n```\n\n### Utility Notebook Pattern\nFor internet-disabled competitions:\n1. **Downloader notebook** (internet=ON): Download from HuggingFace, save BF16 model to `/kaggle/working/`\n2. **Inference notebook** (internet=OFF): Reference downloader output via `kernel_sources`, load model from `/kaggle/input/notebooks/<owner>/<slug>/`\n\nUse `glob` to discover `config.json` path rather than hardcoding — Kaggle's mount paths can vary.\n\n### Synthetic Data Generation\nGenerated ~7,660 translation pairs by running the base ByT5-XL model on published_texts transliterations. These synthetic pairs, combined with the original train.csv, provided the FT training data. Quality is reasonable since the base model already has strong Akkadian translation ability from its original training.\n\n## Reflections\n\nThe biggest lesson: **in low-resource translation with distribution mismatch, a strong pre-trained model with minimal adaptation beats heavy fine-tuning.** The base ByT5-XL model (LB=38.0) outperformed every fine-tuned variant I produced. If I could do it over, I would focus more on:\n\n1. Data curation for CPT that better matches the hidden test distribution\n2. Even lighter adaptation methods (prompt tuning, adapter layers with stronger regularization)\n3. Ensemble of CPT-only models with different data subsets\n\nThe CV-LB gap is a known challenge in NLP competitions but rarely this extreme. The key takeaway: **when your CV and LB diverge, trust LB and investigate the distribution gap rather than optimizing CV.**\n\n## Acknowledgments\n\nThanks to the Deep Past Initiative organizers for this fascinating competition — working with Akkadian is a unique and intellectually rewarding challenge. Thanks also to the Kaggle community for sharing models and insights throughout the competition.\n",
      "votes": 4
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "3428358": "## Summary\n\n- **Model**: ByT5-XL (3.7B) with custom Continued Pre-Training (CPT) on Akkadian domain data (eSAD/CAD dictionaries + onomasticon + published texts) followed by fine-tuning → **LB = 37.6**\n- **Key insight**: CV and LB are inversely correlated — fine-tuning consistently improves CV but worsens LB, due to a fundamental distribution mismatch between train and hidden test data\n- **Novel approach**: KL-anchored LoRA adaptation that preserves the base model's translation ability while adapting to domain-specific patterns\n- Over 40 experiments conducted; sharing technical findings that I hope are useful to the community\n\n**Shared notebook**: [expJ00 FT Infer](https://www.kaggle.com/code/naotonishida/expj00-ft-infer) (inference) + [expJ00 FT DL](https://www.kaggle.com/code/naotonishida/expj00-ft-dl) (model downloader)\n\n## Model & Training Pipeline\n\n### Base Model\n\ngoogle/byt5-xl (3.7B parameters) — a byte-level T5 model with 36 encoder layers and 12 decoder layers.\nStarting from a publicly available CPT checkpoint that had already been pre-trained on Akkadian transliterations for 400 steps.\n\n### Stage 1: Continued Pre-Training (CPT)\n\n**Task**: ByT5 span corruption (noise_density=0.15, mean_noise_span_length=20 bytes)\n\n**CPT Corpus** (79,604 texts, 7.3 MB — transliteration only, no English):\n\n| Source | Entries | Notes |\n|--------|---------|-------|\n| published_texts | ~8,000 docs | Transliterations from ORACC/CDLI |\n| eSAD dictionary | 2,645 entries | Akkadian headwords & transliterations extracted from PDF |\n| CAD dictionary | 8,682 entries | Chicago Assyrian Dictionary, all volumes, extracted from 782MB PDF |\n| onomasticon | 5,595 entries | Proper noun transliterations |\n| Sentences_Oare | ~9,700 texts | Sentence-level transliterations |\n| eBL_Dictionary, OA_Lexicon | ~50K+ entries | Additional lexical resources |\n\n**Hyperparameters**:\n- 1,600 steps, LR = 5e-5, effective batch size = 16\n- BF16 precision (critical for ByT5 — FP16 causes NaN divergence)\n- max_length = 512 bytes\n- Final loss: 1.12\n- Training time: ~27 min on RTX PRO 6000 (96GB)\n\n### Stage 2: Fine-Tuning (FT)\n\n- Data: train.csv (1,561 pairs) + synthetic translations (7,660 pairs generated by the base model on published_texts)\n- 5 epochs, LR = 1e-5, max_length = 256\n- num_beams = 4, length_penalty = 1.3\n- Best checkpoint selected by CV score (step 800)\n\n### Stage 3: Inference\n\n- BF16 on T4 16GB (model uses ~7.5GB VRAM)\n- MBR decoding: 2 beam candidates + 1 sampling candidate, chrF++ consensus\n- Minimal post-processing only (subscript normalization, gap normalization, whitespace cleanup)\n- Utility notebook pattern: downloader (internet=ON) → inference (internet=OFF, kernel_sources)\n\n## Key Finding: The CV-LB Gap\n\nThis was the most important and frustrating discovery of this competition. **Fine-tuning consistently improves CV but worsens LB.**\n\n| Experiment | Description | CV | LB | CV-LB Gap |\n|------------|-------------|----|----|-----------|\n| Base model (no FT) | ByT5-XL, zero-shot | 12.4 | **38.0** | -25.6 |\n| + CPT 400 + FT 5ep | Published texts CPT | 40.5 | 35.0 | 5.5 |\n| + CPT 1600 + FT (eSAD+CAD, English included) | expJ00 | 43.7 | **37.6** | 6.1 |\n| + CPT 1600 + FT (translit-only) | expJ01 | **44.2** | 36.7 | 7.5 |\n| + LoRA + KL distillation | expK01 | — | 37.1 | — |\n| ByT5-base FT (data aug) | Small model, heavy FT | **53.3** | 29.2 | 24.1 |\n\n**Root cause**: The training data consists of ~1,500 Old Assyrian commercial texts (contracts, debt notes, trade correspondence), while the hidden test appears to contain sentence-level samples from diverse genres (letters, legal texts, formal documents). Fine-tuning on train data specializes the model for one narrow domain, hurting generalization.\n\n**The paradox**: CPT-only (without FT) cannot translate at all — it outputs span corruption responses (`<extra_id_0>` + Akkadian text). But FT, while enabling translation, inevitably overfits to the training distribution. This structural dilemma defined my entire competition experience.\n\n## What Worked\n\n### 1. Model Scale (580M → 3.7B): +14.4 LB points\nThe single biggest improvement. ByT5-XL (3.7B) at LB=38.0 vs ByT5-base (580M) at LB=23.6. The larger model's broader pre-training knowledge provides much better zero-shot translation ability.\n\n### 2. BF16 Precision (mandatory for ByT5)\nFP16 causes NaN divergence in ByT5 due to its narrow dynamic range (max ~65,504). BF16 shares FP32's dynamic range (max ~3.4e38) while using only 2 bytes per parameter. This is not optional — FP16 gives Score=0.54 vs BF16's Score=25.95.\n\n### 3. Translit-Only CPT Data (no English)\nIncluding English dictionary definitions in CPT data hurts performance (CV 43.7 vs 44.2 for translit-only). Span corruption is a monolingual task — English text is noise. Extract only Akkadian headwords and transliterations from dictionaries.\n\n### 4. Dictionary & Lexicon Data for CPT\nAdding eSAD, CAD, and onomasticon transliterations improved the model's Akkadian vocabulary coverage. The CPT corpus grew from ~8K to ~80K texts, and the model learned rarer cuneiform sign readings and proper noun patterns.\n\n### 5. Minimal Post-Processing\nAggressive post-processing (fraction conversion, PN normalization, Roman numeral conversion, annotation removal) consistently hurt LB scores. The optimal pipeline is minimal: subscript digit conversion + gap normalization + whitespace cleanup only.\n\n### 6. LoRA + KL Distillation (Anchored Adaptation)\nTo mitigate the FT-induced LB degradation, I developed a KL-anchored LoRA approach:\n- **Teacher**: Base model (frozen)\n- **Student**: Base model + LoRA (0.24% trainable params)\n- **LoRA targets**: Encoder self-attention (q, v) + Decoder cross-attention (q, v)\n- **Frozen**: Decoder self-attention + lm_head\n- **Loss**: `0.7 × denoise + 0.2 × KL_distill + 0.1 × anchor_CE`\n\nThis achieved LB=37.1, improving +0.4 over standard FT (36.7), confirming that preserving the base model's translation distribution helps. However, it still couldn't surpass the base model's 38.0.\n\n### 7. MBR Decoding\nMinimum Bayes Risk decoding with chrF++ scoring. For the 3.7B model, a lightweight config works best: 2 beam candidates + 1 sampling candidate (3 total). Larger candidate pools don't justify the compute cost at this model scale.\n\n## What Didn't Work\n\n| Approach | Result | Why |\n|----------|--------|-----|\n| Aggressive fine-tuning | CV=53.3, LB=29.2 | Overfits to train distribution |\n| English-mixed CPT data | CV=43.7 (vs 44.2 translit-only) | English is noise for span corruption |\n| Heavy post-processing | LB -0.2 to -0.4 | GT format doesn't match assumed patterns |\n| Flan-T5 Philologist refinement | LB=21.1 | Destroys proper nouns (karum → Krum) |\n| Inference parameter tuning | LB ±0.0 | Already near-optimal with default settings |\n| CPT-only (no FT) | Cannot translate | Outputs span corruption responses only |\n| NLLB 3.3B | LB=31.9 | No Akkadian-specific pre-training |\n| ByT5-small/base models | LB=23-26 | Insufficient model capacity |\n| Longer sequences (max512, max1024) | CV drops significantly | Model trained on shorter sequences |\n\n## Technical Details\n\n### ByT5 Span Corruption for CPT\nByT5 operates at the byte level, so the standard T5 span corruption parameters need adjustment. Use `mean_noise_span_length=20` (bytes, not tokens — standard T5 uses 3 tokens ≈ 15 bytes). `noise_density=0.15` works well.\n\n### BF16 on T4 16GB\nByT5-XL (3.7B) in BF16 uses only ~7.5GB VRAM, fitting comfortably on T4 with room for beam search KV cache. Save models in BF16 format to avoid FP16 NaN issues during loading:\n```python\nmodel = AutoModelForSeq2SeqLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)\nmodel.save_pretrained(output_path)  # Saved as BF16\n```\n\n### Utility Notebook Pattern\nFor internet-disabled competitions:\n1. **Downloader notebook** (internet=ON): Download from HuggingFace, save BF16 model to `/kaggle/working/`\n2. **Inference notebook** (internet=OFF): Reference downloader output via `kernel_sources`, load model from `/kaggle/input/notebooks/<owner>/<slug>/`\n\nUse `glob` to discover `config.json` path rather than hardcoding — Kaggle's mount paths can vary.\n\n### Synthetic Data Generation\nGenerated ~7,660 translation pairs by running the base ByT5-XL model on published_texts transliterations. These synthetic pairs, combined with the original train.csv, provided the FT training data. Quality is reasonable since the base model already has strong Akkadian translation ability from its original training.\n\n## Reflections\n\nThe biggest lesson: **in low-resource translation with distribution mismatch, a strong pre-trained model with minimal adaptation beats heavy fine-tuning.** The base ByT5-XL model (LB=38.0) outperformed every fine-tuned variant I produced. If I could do it over, I would focus more on:\n\n1. Data curation for CPT that better matches the hidden test distribution\n2. Even lighter adaptation methods (prompt tuning, adapter layers with stronger regularization)\n3. Ensemble of CPT-only models with different data subsets\n\nThe CV-LB gap is a known challenge in NLP competitions but rarely this extreme. The key takeaway: **when your CV and LB diverge, trust LB and investigate the distribution gap rather than optimizing CV.**\n\n## Acknowledgments\n\nThanks to the Deep Past Initiative organizers for this fascinating competition — working with Akkadian is a unique and intellectually rewarding challenge. Thanks also to the Kaggle community for sharing models and insights throughout the competition.\n"
  },
  "complete": true,
  "source": "existing_discussion",
  "competition_id": 121150,
  "competition_slug": "deep-past-initiative-machine-translation",
  "team_id": 15229523,
  "solution_url": "/competitions/deep-past-initiative-machine-translation/writeups/silver-medal-solution29th-byt5-xl-custom-cpt-wi"
}