{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":121150,"databundleVersionId":15061024,"sourceType":"competition"},{"sourceId":753803,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":575614,"modelId":587917}],"dockerImageVersionId":31260,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\nos.environ[\"OMP_NUM_THREADS\"] = \"4\"\nos.environ[\"MKL_NUM_THREADS\"] = \"4\"\nos.environ[\"CUDA_LAUNCH_BLOCKING\"] = \"0\"\nos.environ[\"TORCH_CUDNN_V8_API_ENABLED\"] = \"1\"\nos.environ[\"TOKENIZERS_PARALLELISM\"] = \"true\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:00.767363Z","iopub.execute_input":"2026-02-17T08:01:00.767886Z","iopub.status.idle":"2026-02-17T08:01:00.776499Z","shell.execute_reply.started":"2026-02-17T08:01:00.767852Z","shell.execute_reply":"2026-02-17T08:01:00.775698Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd \nfrom datasets import Dataset\nfrom transformers import (\n    AutoTokenizer,\n    AutoModelForSeq2SeqLM,\n    DataCollatorForSeq2Seq,\n    Trainer,\n    Seq2SeqTrainingArguments\n)\nimport numpy as np\nfrom tqdm import tqdm\nimport torch\nimport re\nfrom torch.amp import autocast","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:00.777938Z","iopub.execute_input":"2026-02-17T08:01:00.778194Z","iopub.status.idle":"2026-02-17T08:01:31.463779Z","shell.execute_reply.started":"2026-02-17T08:01:00.778169Z","shell.execute_reply":"2026-02-17T08:01:31.463202Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_path = \"/kaggle/input/models/swayamsinghal/byt5-small-akkadian-finetuned-model/pytorch/v1/1/byt5-small_best_model\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:31.464601Z","iopub.execute_input":"2026-02-17T08:01:31.465277Z","iopub.status.idle":"2026-02-17T08:01:31.469054Z","shell.execute_reply.started":"2026-02-17T08:01:31.465248Z","shell.execute_reply":"2026-02-17T08:01:31.468178Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv(\"/kaggle/input/deep-past-initiative-machine-translation/test.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:31.470880Z","iopub.execute_input":"2026-02-17T08:01:31.471171Z","iopub.status.idle":"2026-02-17T08:01:31.495696Z","shell.execute_reply.started":"2026-02-17T08:01:31.471150Z","shell.execute_reply":"2026-02-17T08:01:31.495006Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def clean_transliteration(text):\n    \"\"\"\n    Clean Akkadian transliteration according to competition guidelines.\n    Removes modern scribal notations and standardizes formatting.\n    \"\"\"\n    if pd.isna(text):\n        return text\n    \n    # Remove modern scribal notations\n    text = text.replace('!', '')  # certain reading\n    text = text.replace('?', '')  # questionable reading\n    text = text.replace('/', ' ')  # line divider → space\n    text = text.replace(':', ' ')  # word divider → space\n    text = text.replace('.', ' ')  # word divider → space\n    \n    # Remove scribal insertions brackets but keep content\n    text = re.sub(r'[<>]', '', text)\n    \n    # Remove partially broken sign indicators\n    text = text.replace('˹', '')\n    text = text.replace('˺', '')\n    \n    # Remove square brackets (restore broken text)\n    text = re.sub(r'[\\[\\]]', '', text)\n    \n    # Replace gaps with standardized tokens\n    text = re.sub(r'\\[x\\]', '<gap>', text)\n    text = re.sub(r'…', '<big_gap>', text)\n    text = re.sub(r'\\[… …\\]', '<big_gap>', text)\n    \n    # Normalize subscript numbers (e.g., il₅ → il5)\n    subscript_map = {\n        '₀': '0', '₁': '1', '₂': '2', '₃': '3', '₄': '4',\n        '₅': '5', '₆': '6', '₇': '7', '₈': '8', '₉': '9', 'ₓ': 'x'\n    }\n    for sub, normal in subscript_map.items():\n        text = text.replace(sub, normal)\n    \n    # Normalize special characters to ASCII equivalents\n    char_map = {\n        'á': 'a2', 'à': 'a3',\n        'é': 'e2', 'è': 'e3',\n        'í': 'i2', 'ì': 'i3',\n        'ú': 'u2', 'ù': 'u3',\n        'š': 'sz', 'Š': 'SZ',\n        'ṣ': 's,', 'Ṣ': 'S,',\n        'ṭ': 't,', 'Ṭ': 'T,',\n        'ḫ': 'h', 'Ḫ': 'H',\n        'ʾ': \"'\"\n    }\n    for special, normal in char_map.items():\n        text = text.replace(special, normal)\n    \n    # Clean up multiple spaces\n    text = re.sub(r'\\s+', ' ', text)\n    text = text.strip()\n    \n    return text","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:31.496510Z","iopub.execute_input":"2026-02-17T08:01:31.496759Z","iopub.status.idle":"2026-02-17T08:01:31.505450Z","shell.execute_reply.started":"2026-02-17T08:01:31.496724Z","shell.execute_reply":"2026-02-17T08:01:31.504540Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df[\"transliteration\"] = test_df[\"transliteration\"].apply(clean_transliteration)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:31.506481Z","iopub.execute_input":"2026-02-17T08:01:31.506885Z","iopub.status.idle":"2026-02-17T08:01:31.522671Z","shell.execute_reply.started":"2026-02-17T08:01:31.506849Z","shell.execute_reply":"2026-02-17T08:01:31.522008Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset=Dataset.from_pandas(test_df[[\"transliteration\"]])\n\ntokenizer=AutoTokenizer.from_pretrained(model_path, device_map=\"cuda\")\n\ndef preprocess(batch):\n    src=[f\"Translate Akkadian to English: {x}\" for x in batch[\"transliteration\"]]\n    model_inputs=tokenizer(src,max_length=512,truncation=True, padding=False)\n    return model_inputs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:31.523546Z","iopub.execute_input":"2026-02-17T08:01:31.523902Z","iopub.status.idle":"2026-02-17T08:01:31.566874Z","shell.execute_reply.started":"2026-02-17T08:01:31.523871Z","shell.execute_reply":"2026-02-17T08:01:31.566122Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model=AutoModelForSeq2SeqLM.from_pretrained(model_path, device_map=\"cuda\")\ntry:\n    from optimum.bettertransformer import BetterTransformer\n    print(\"Applying BetterTransformer...\")\n    self.model = BetterTransformer.transform(self.model)\n    logger.info(\"BetterTransformer applied\")\nexcept ImportError:\n    print(\"optimum not installed, skipping BetterTransformer\")\nexcept Exception as e:\n    print(f\"BetterTransformer failed: {e}\")\n    \ndata_collator=DataCollatorForSeq2Seq(\n    tokenizer,\n    model=model,\n    padding=True,           \n    label_pad_token_id=-100\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:31.567925Z","iopub.execute_input":"2026-02-17T08:01:31.568218Z","iopub.status.idle":"2026-02-17T08:01:38.756002Z","shell.execute_reply.started":"2026-02-17T08:01:31.568186Z","shell.execute_reply":"2026-02-17T08:01:38.755304Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = dataset.map(preprocess, batched=True, remove_columns=[\"transliteration\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:38.756861Z","iopub.execute_input":"2026-02-17T08:01:38.757144Z","iopub.status.idle":"2026-02-17T08:01:38.807036Z","shell.execute_reply.started":"2026-02-17T08:01:38.757121Z","shell.execute_reply":"2026-02-17T08:01:38.806145Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class VectorizedPostprocessor:\n    # Initialize postprocessor patterns and translation tables\n    def __init__(self, aggressive: bool = True):\n        # Store mode\n        self.aggressive = aggressive\n\n        # Pre-compile patterns\n        self.patterns = {\n            \"gap\": re.compile(r\"(\\[x\\]|\\(x\\)|\\bx\\b)\", re.I),\n            \"big_gap\": re.compile(r\"(\\.{3,}|…|\\[\\.+\\])\"),\n            \"annotations\": re.compile(r\"\\((fem|plur|pl|sing|singular|plural|\\?|!)\\..\\s*\\w*\\)\", re.I),\n            \"repeated_words\": re.compile(r\"\\b(\\w+)(?:\\s+\\1\\b)+\"),\n            \"whitespace\": re.compile(r\"\\s+\"),\n            \"punct_space\": re.compile(r\"\\s+([.,:])\"),\n            \"repeated_punct\": re.compile(r\"([.,])\\1+\"),\n        }\n\n        # Create character translation tables\n        self.subscript_trans = str.maketrans(\"₀₁₂₃₄₅₆₇₈₉\", \"0123456789\")\n        self.special_chars_trans = str.maketrans(\"ḫḪ\", \"hH\")\n\n        # Define forbidden characters\n        self.forbidden_chars = '!?()\"——<>⌈⌋⌊[]+ʾ/;'\n\n        # Create forbidden translate table\n        self.forbidden_trans = str.maketrans(\"\", \"\", self.forbidden_chars)\n\n    # Vectorized postprocessing\n    def postprocess_batch(self, translations: list[str]) -> list[str]:\n        # Convert to Series\n        s = pd.Series(translations)\n\n        # Validate entries\n        valid_mask = s.apply(lambda x: isinstance(x, str) and x.strip())\n        if not valid_mask.all():\n            s[~valid_mask] = \"\"\n\n        # Basic cleaning\n        s = s.str.translate(self.special_chars_trans)\n        s = s.str.translate(self.subscript_trans)\n        s = s.str.replace(self.patterns[\"whitespace\"], \" \", regex=True)\n        s = s.str.strip()\n\n        # Aggressive postprocessing\n        if self.aggressive:\n            # Normalize gaps\n            s = s.str.replace(self.patterns[\"gap\"], \"<gap>\", regex=True)\n            s = s.str.replace(self.patterns[\"big_gap\"], \"<big_gap>\", regex=True)\n\n            # Merge adjacent gaps\n            s = s.str.replace(\"<gap> <gap>\", \"<big_gap>\", regex=False)\n            s = s.str.replace(\"<big_gap> <big_gap>\", \"<big_gap>\", regex=False)\n\n            # Remove annotations\n            s = s.str.replace(self.patterns[\"annotations\"], \"\", regex=True)\n\n            # Protect gaps during forbidden-character removal\n            s = s.str.replace(\"<gap>\", \"\\x00GAP\\x00\", regex=False)\n            s = s.str.replace(\"<big_gap>\", \"\\x00BIG\\x00\", regex=False)\n\n            # Remove forbidden characters\n            s = s.str.translate(self.forbidden_trans)\n\n            # Restore gaps\n            s = s.str.replace(\"\\x00GAP\\x00\", \" <gap> \", regex=False)\n            s = s.str.replace(\"\\x00BIG\\x00\", \" <big_gap> \", regex=False)\n\n            # Fractions\n            s = s.str.replace(r\"(\\d+)\\.5\\b\", r\"\\1½\", regex=True)\n            s = s.str.replace(r\"\\b0\\.5\\b\", \"½\", regex=True)\n            s = s.str.replace(r\"(\\d+)\\.25\\b\", r\"\\1¼\", regex=True)\n            s = s.str.replace(r\"\\b0\\.25\\b\", \"¼\", regex=True)\n            s = s.str.replace(r\"(\\d+)\\.75\\b\", r\"\\1¾\", regex=True)\n            s = s.str.replace(r\"\\b0\\.75\\b\", \"¾\", regex=True)\n\n            # Remove repeated words\n            s = s.str.replace(self.patterns[\"repeated_words\"], r\"\\1\", regex=True)\n\n            # Remove repeated n-grams (4 -> 2)\n            for n in range(4, 1, -1):\n                pattern = r\"\\b((?:\\w+\\s+){\" + str(n - 1) + r\"}\\w+)(?:\\s+\\1\\b)+\"\n                s = s.str.replace(pattern, r\"\\1\", regex=True)\n\n            # Fix punctuation spacing and repeats\n            s = s.str.replace(self.patterns[\"punct_space\"], r\"\\1\", regex=True)\n            s = s.str.replace(self.patterns[\"repeated_punct\"], r\"\\1\", regex=True)\n\n            # Final whitespace cleanup\n            s = s.str.replace(self.patterns[\"whitespace\"], \" \", regex=True)\n            s = s.str.strip().str.strip(\"-\").str.strip()\n\n        return s.tolist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:38.809159Z","iopub.execute_input":"2026-02-17T08:01:38.809462Z","iopub.status.idle":"2026-02-17T08:01:38.822545Z","shell.execute_reply.started":"2026-02-17T08:01:38.809424Z","shell.execute_reply":"2026-02-17T08:01:38.822053Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"postprocessor = VectorizedPostprocessor()\n\ndef run_inference(model, tokenizer, dataset, data_collator, batch_size=32, max_len=512):\n    loader = torch.utils.data.DataLoader(\n        dataset,\n        batch_size=batch_size,\n        shuffle=False,\n        collate_fn=data_collator\n    )\n\n    model.eval()\n    device = model.device\n    all_preds=[]\n\n    with torch.no_grad():\n        for batch in tqdm(loader):\n            input_ids=batch[\"input_ids\"].to(device)\n            attention_mask=batch[\"attention_mask\"].to(device)\n            num_beams = 4\n            # with autocast(\"cuda\"):\n            outputs=model.generate(\n                input_ids=input_ids,\n                attention_mask=attention_mask,\n                max_new_tokens=max_len,\n                num_beams=4,\n                length_penalty=1.5,\n                repetition_penalty=1.2,\n                no_repeat_ngram_size=3,\n                early_stopping=True\n            )\n\n            preds=tokenizer.batch_decode(outputs, skip_special_tokens=True)\n            preds=[p.strip().replace(\" ,\",\",\").replace(\" .\",\".\") for p in preds]\n            preds=postprocessor.postprocess_batch(preds)\n            all_preds.extend(preds)\n\n    return all_preds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:38.823508Z","iopub.execute_input":"2026-02-17T08:01:38.823921Z","iopub.status.idle":"2026-02-17T08:01:38.840227Z","shell.execute_reply.started":"2026-02-17T08:01:38.823898Z","shell.execute_reply":"2026-02-17T08:01:38.839682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ids = test_df[\"id\"].tolist()\n\ntranslations = run_inference(model, tokenizer, dataset, data_collator)\n\nsubmission = pd.DataFrame({\n    \"id\": ids,\n    \"translation\": translations\n})\n\nsubmission[\"translation\"] = submission[\"translation\"].apply(lambda x: x if len(x) > 0 else \"broken text\")\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:38.841116Z","iopub.execute_input":"2026-02-17T08:01:38.841529Z","iopub.status.idle":"2026-02-17T08:01:43.915569Z","shell.execute_reply.started":"2026-02-17T08:01:38.841501Z","shell.execute_reply":"2026-02-17T08:01:43.914955Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for idx, row in submission.head(5).iterrows(): \n    print(test_df.loc[idx, \"transliteration\"])\n    print(\"---\")\n    print(row[\"translation\"])\n    print(\"-*-\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T08:01:43.916545Z","iopub.execute_input":"2026-02-17T08:01:43.916865Z","iopub.status.idle":"2026-02-17T08:01:43.921950Z","shell.execute_reply.started":"2026-02-17T08:01:43.916841Z","shell.execute_reply":"2026-02-17T08:01:43.921270Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}