Download code/src/seq2seq/train_text_only.py from savastakan/hitit-cuneiform-ocr: direct link, hf CLI and curl.
- Browser
- Download file 4.05 kB
-
https://huggingface.co/savastakan/hitit-cuneiform-ocr/resolve/main/code/src/seq2seq/train_text_only.py
- Command line
-
hf download hf://savastakan/hitit-cuneiform-ocr/code/src/seq2seq/train_text_only.py
-
curl -L -o train_text_only.py https://huggingface.co/savastakan/hitit-cuneiform-ocr/resolve/main/code/src/seq2seq/train_text_only.py
4.05 kB
| #!/usr/bin/env python3 | |
| """ByT5 text-only pretrain on Hittite parallel corpus. | |
| Cuneiform Unicode → Transliteration, 280K pairs. | |
| Reference: SumTablets ACL ML4AL 2024. | |
| """ | |
| import os, sys, json, argparse, time | |
| from pathlib import Path | |
| import yaml | |
| ROOT = Path("/arf/scratch/stakan/hitit-proje") | |
| def log(msg): print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument('--config', default=str(ROOT / 'hitit_ocr/configs/seq2seq_hitit.yaml')) | |
| ap.add_argument('--phase', default='pretrain') | |
| ap.add_argument('--data', default=str(ROOT / 'datasets/processed/tlhdig_corpora/hittite_parallel.jsonl')) | |
| ap.add_argument('--output', default=str(ROOT / 'hitit_ocr/runs/seq2seq_text_pretrain/')) | |
| args = ap.parse_args() | |
| cfg = yaml.safe_load(open(args.config)) | |
| output = Path(args.output) | |
| output.mkdir(parents=True, exist_ok=True) | |
| try: | |
| import torch | |
| from transformers import (AutoTokenizer, T5ForConditionalGeneration, | |
| Seq2SeqTrainer, Seq2SeqTrainingArguments, | |
| DataCollatorForSeq2Seq) | |
| from datasets import Dataset | |
| except ImportError as e: | |
| log(f"Missing library: {e}"); sys.exit(1) | |
| model_name = cfg.get('model', {}).get('decoder', {}).get('pretrained', 'google/byt5-small') | |
| log(f"Phase: {args.phase}, Model: {model_name}") | |
| tokenizer = AutoTokenizer.from_pretrained(model_name) | |
| model = T5ForConditionalGeneration.from_pretrained(model_name) | |
| # Data | |
| log(f"Loading {args.data}") | |
| examples = [] | |
| with open(args.data) as f: | |
| for line in f: | |
| r = json.loads(line) | |
| cune = r.get('cuneiform') or '' | |
| translit = r.get('transliteration') or '' | |
| if cune and translit and len(cune) < 200 and len(translit) < 400: | |
| examples.append({'input_text': cune, 'target_text': translit}) | |
| log(f"Total: {len(examples)} pairs") | |
| n_val = int(len(examples) * 0.05) | |
| val_examples = examples[:n_val] | |
| train_examples = examples[n_val:] | |
| def preprocess(batch): | |
| inputs = tokenizer(batch['input_text'], max_length=512, truncation=True) | |
| targets = tokenizer(batch['target_text'], max_length=512, truncation=True) | |
| inputs['labels'] = targets['input_ids'] | |
| return inputs | |
| train_ds = Dataset.from_list(train_examples).map(preprocess, batched=True, | |
| remove_columns=['input_text', 'target_text']) | |
| val_ds = Dataset.from_list(val_examples).map(preprocess, batched=True, | |
| remove_columns=['input_text', 'target_text']) | |
| training = cfg.get('training', {}) | |
| targs = Seq2SeqTrainingArguments( | |
| output_dir=str(output), | |
| num_train_epochs=3, # pretrain epochs (shortened for 1-day target) | |
| per_device_train_batch_size=training.get('batch_size', 8), | |
| per_device_eval_batch_size=16, | |
| learning_rate=1e-4, | |
| weight_decay=0.01, | |
| warmup_steps=2000, | |
| bf16=True, | |
| fp16=False, | |
| logging_steps=200, | |
| eval_strategy='epoch', | |
| save_strategy='epoch', | |
| save_total_limit=2, | |
| load_best_model_at_end=True, | |
| metric_for_best_model='eval_loss', | |
| greater_is_better=False, | |
| dataloader_num_workers=4, | |
| report_to='none', | |
| ) | |
| trainer = Seq2SeqTrainer( | |
| model=model, args=targs, | |
| train_dataset=train_ds, eval_dataset=val_ds, | |
| data_collator=DataCollatorForSeq2Seq(tokenizer, model=model), | |
| tokenizer=tokenizer, | |
| ) | |
| log("Training text-only pretrain...") | |
| trainer.train() | |
| trainer.save_model(str(output / 'checkpoint')) | |
| tokenizer.save_pretrained(str(output / 'checkpoint')) | |
| # Also save symlink/copy as checkpoint.pt for seq2seq_ft | |
| import shutil | |
| # Save in trainer format; train_image loads via HF from_pretrained | |
| log(f"DONE: {output}/checkpoint") | |
| if __name__ == '__main__': | |
| main() | |