{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":121150,"databundleVersionId":15833391},{"sourceType":"datasetVersion","sourceId":14410665,"datasetId":9203761,"databundleVersionId":15226414},{"sourceType":"datasetVersion","sourceId":14376272,"datasetId":9181082,"databundleVersionId":15188111},{"sourceType":"datasetVersion","sourceId":14899351,"datasetId":9366631,"databundleVersionId":15763950},{"sourceType":"datasetVersion","sourceId":14523528,"datasetId":9275882,"databundleVersionId":15351527},{"sourceType":"datasetVersion","sourceId":14374989,"datasetId":9147887,"databundleVersionId":15186684},{"sourceType":"modelInstanceVersion","sourceId":282751,"databundleVersionId":11375937,"modelInstanceId":239470,"modelId":222398}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:47:47.463072Z","iopub.execute_input":"2026-03-26T19:47:47.463780Z","iopub.status.idle":"2026-03-26T19:47:47.870412Z","shell.execute_reply.started":"2026-03-26T19:47:47.463750Z","shell.execute_reply":"2026-03-26T19:47:47.869593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# This code is from the original notebook AllCaps: https://www.kaggle.com/code/akkmit/allcaps/notebook\nimport os\nimport re\nimport gc\nimport pandas as pd\nimport torch\nfrom torch.utils.data import DataLoader, Dataset\nfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM, Seq2SeqTrainer, Seq2SeqTrainingArguments, DataCollatorForSeq2Seq\nfrom tqdm.auto import tqdm\n\nDATA_DIR = \"/kaggle/input/deep-past-initiative-machine-translation\"\nBASE_MODEL = \"/kaggle/input/final-byt5/byt5-akkadian-optimized-34x\"\n\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(\"Checking model path:\", BASE_MODEL)\nimport os\nprint(\"Exists?\", os.path.isdir(BASE_MODEL))\nprint(\"Files:\", os.listdir(BASE_MODEL))\nMAX_LENGTH = 512  \nMAX_PAIRS = 5000\nprint(f\"Device: {DEVICE}, Model: {BASE_MODEL}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:47:47.871975Z","iopub.execute_input":"2026-03-26T19:47:47.872933Z","iopub.status.idle":"2026-03-26T19:48:20.443716Z","shell.execute_reply.started":"2026-03-26T19:47:47.872904Z","shell.execute_reply":"2026-03-26T19:48:20.442895Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Normalize transliteration for test\n#Some ideas taken from https://www.kaggle.com/code/ngyzly/better-candidate-diversity-on-public-model\n#And https://www.kaggle.com/code/manwithacat/chunky-v1-3-0\nimport unicodedata\nimport re\n\ndef normalize_text(text):\n    if pd.isna(text) or not isinstance(text, str):\n        return \"\"\n\n    text = unicodedata.normalize(\"NFC\", str(text))\n\n    # Canonicalize H/Ḫ\n    text = text.replace(\"Ḫ\", \"H\").replace(\"ḫ\", \"h\")\n\n    # CDLI ASCII → Unicode canonical forms\n    text = re.sub(r\"sz\", \"š\", text)\n    text = re.sub(r\"SZ\", \"Š\", text)\n    text = re.sub(r\"s,\", \"ṣ\", text)\n    text = re.sub(r\"S,\", \"Ṣ\", text)\n    text = re.sub(r\"t,\", \"ṭ\", text)\n    text = re.sub(r\"T,\", \"Ṭ\", text)\n    text = re.sub(r\"j,\", \"ŋ\", text)\n    text = re.sub(r\"J,\", \"Ŋ\", text)\n\n    # Normalize big gaps\n    text = re.sub(r\"\\[[^\\]]*?\\.{2,}[^\\]]*?\\]\", \"<gap>\", text)\n    text = re.sub(r\"…+\", \"<gap>\", text)\n    text = re.sub(r\"\\.{2,}\", \"<gap>\", text)\n\n    # Single missing sign [x] → <gap>\n    text = re.sub(r\"\\[x\\]\", \"<gap>\", text)\n\n    # merge adjacent gap markers\n    text = re.sub(r\"<gap>\\s*<gap>\", \"<gap>\", text)\n    text = re.sub(r\"<big_gap>\\s*<big_gap>\", \"<gap>\", text)\n\n    # Replace subscript numbers to regular numbers\n    subscript_to_normal = str.maketrans(\"₀₁₂₃₄₅₆₇₈₉ₓ\", \"0123456789x\")\n    text = text.translate(subscript_to_normal)\n\n    # normalize sign indices \n    text = re.sub(r\"-(\\d+)\", r\"\\1\", text)\n\n    # Remove double angle brackets but keep content\n    text = re.sub(r\"<<(.*?)>>\", r\"\\1\", text)\n\n    # Normalize multiple hyphens\n    text = re.sub(r\"-{2,}\", \"-\", text)\n\n    # Remove modern editorial marks\n    text = re.sub(r\"[!?/]\", \"\", text)\n    text = text.replace(\"˹\", \"\").replace(\"˺\", \"\")\n\n    # Remove square brackets literally (after gap handling)\n    text = text.replace(\"[\", \"\").replace(\"]\", \"\")\n\n    # Remove word dividers \":\" or \"·\"\n    text = re.sub(r\"\\s*[:·]\\s*\", \" \", text)\n\n    # Determinatives (d, ki, ...) sometimes appear in parentheses\n    determinative_pattern = r\"\\((d|ki|mi|lu2|e2|mul|kur|uru|m|dub|geš|ĝeš|tug2|id2|mušen|na4|kuš|u2)\\)\"\n    text = re.sub(determinative_pattern, r\"{\\1}\", text)\n\n    # Collapse whitespace\n    text = re.sub(r\"\\s+\", \" \", text).strip()\n\n    return text","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:48:20.444804Z","iopub.execute_input":"2026-03-26T19:48:20.445599Z","iopub.status.idle":"2026-03-26T19:48:20.454490Z","shell.execute_reply.started":"2026-03-26T19:48:20.445548Z","shell.execute_reply":"2026-03-26T19:48:20.453494Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load and extract data\n# This code is inspired by the original codebook AllCaps: https://www.kaggle.com/code/akkmit/allcaps\ntrain_df = pd.read_csv(f\"{DATA_DIR}/train.csv\")\nall_pairs = []\n\nfor _, row in train_df.iterrows():\n    t, e = row.get('transliteration', ''), row.get('translation', '')\n    if pd.notna(t) and pd.notna(e) and len(str(t)) > 5 and len(str(e)) > 5:\n        all_pairs.append({\n            'transliteration': normalize_text(t),\n            'translation': normalize_text(e),\n            'source': 'train'\n        })\n\nprint(f\"From pairs_df: {len(all_pairs)}\")\n\ndf_all = pd.DataFrame(all_pairs[:MAX_PAIRS])\ndf_all = df_all.drop_duplicates(subset=['transliteration'])\ndf_all.to_csv(\"sentence_aligned_pairs.csv\", index=False)\nprint(f\"TOTAL: {len(df_all)} pairs\")\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:48:20.456443Z","iopub.execute_input":"2026-03-26T19:48:20.457239Z","iopub.status.idle":"2026-03-26T19:48:21.272283Z","shell.execute_reply.started":"2026-03-26T19:48:20.457191Z","shell.execute_reply":"2026-03-26T19:48:21.271395Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Dataset\n# This code is from the original notebook AllCaps: https://www.kaggle.com/code/akkmit/allcaps\nclass AkkadianDataset(Dataset):\n    def __init__(self, df, tokenizer):\n        self.df = df.reset_index(drop=True)\n        self.tokenizer = tokenizer\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        source = \"translate Akkadian to English: \" + str(row['transliteration'])\n        target = str(row['translation'])\n        \n        src = self.tokenizer(source, max_length=MAX_LENGTH, padding='max_length', truncation=True, return_tensors='pt')\n        with self.tokenizer.as_target_tokenizer():\n            tgt = self.tokenizer(target, max_length=MAX_LENGTH, padding='max_length', truncation=True, return_tensors='pt')\n        \n        labels = tgt['input_ids'].squeeze()\n        labels[labels == self.tokenizer.pad_token_id] = -100\n        \n        return {'input_ids': src['input_ids'].squeeze(), 'attention_mask': src['attention_mask'].squeeze(), 'labels': labels}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:48:21.273292Z","iopub.execute_input":"2026-03-26T19:48:21.273634Z","iopub.status.idle":"2026-03-26T19:48:21.280587Z","shell.execute_reply.started":"2026-03-26T19:48:21.273602Z","shell.execute_reply":"2026-03-26T19:48:21.279846Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Test and validation set for experiment setup\n# This is our own code \nprint(\"Loading pretrained model...\")\nfrom torch.optim import AdamW\nfrom torch.utils.data import DataLoader\n\ntokenizer = AutoTokenizer.from_pretrained(\n    BASE_MODEL,\n    local_files_only=True\n)\n\nmodel = AutoModelForSeq2SeqLM.from_pretrained(\n    BASE_MODEL,\n    local_files_only=True\n).to(DEVICE)\n\noptimizer = AdamW(model.parameters(), lr=5e-5)\ndf_exp = df_all.sample(n=500, random_state=42).reset_index(drop=True)\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:48:21.281521Z","iopub.execute_input":"2026-03-26T19:48:21.281859Z","iopub.status.idle":"2026-03-26T19:48:39.860277Z","shell.execute_reply.started":"2026-03-26T19:48:21.281825Z","shell.execute_reply":"2026-03-26T19:48:39.859641Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Split the data into a train, validation and test set.\n# This is our own code\nfrom sklearn.model_selection import train_test_split\n\ntrain_df, temp_df = train_test_split(\n    df_exp, test_size=0.2, random_state=42\n)\n\nval_df, test_df = train_test_split(\n    temp_df, test_size=0.5, random_state=42\n)\n\nprint(len(train_df), len(val_df), len(test_df))\n\ntrain_dataset = AkkadianDataset(train_df, tokenizer)\nval_dataset = AkkadianDataset(val_df, tokenizer)\n\ntrain_loader = DataLoader(train_dataset, batch_size=2, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=2)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:48:39.861259Z","iopub.execute_input":"2026-03-26T19:48:39.861483Z","iopub.status.idle":"2026-03-26T19:48:39.889273Z","shell.execute_reply.started":"2026-03-26T19:48:39.861459Z","shell.execute_reply":"2026-03-26T19:48:39.888647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Training model\n#This is our own code inspired by a PyTorch tutorial: https://docs.pytorch.org/tutorials/beginner/introyt/trainingyt.html.\nimport torch\nfrom tqdm import tqdm\n\nEPOCHS = 3 \neval_every = 50  \n\nglobal_step = 0\n\nfor epoch in range(EPOCHS):\n    model.train()\n    total_train_loss = 0\n    \n    for batch in tqdm(train_loader):\n        optimizer.zero_grad()\n        \n        input_ids = batch[\"input_ids\"].to(DEVICE)\n        attention_mask = batch[\"attention_mask\"].to(DEVICE)\n        labels = batch[\"labels\"].to(DEVICE)\n        \n        outputs = model(\n            input_ids=input_ids,\n            attention_mask=attention_mask,\n            labels=labels\n        )\n        \n        loss = outputs.loss\n        loss.backward()\n        optimizer.step()\n        \n        total_train_loss += loss.item()\n        global_step += 1\n        \n        # Frequent evaluation\n        if global_step % eval_every == 0:\n            model.eval()\n            total_val_loss = 0\n            \n            with torch.no_grad():\n                for val_batch in val_loader:\n                    val_input_ids = val_batch[\"input_ids\"].to(DEVICE)\n                    val_attention_mask = val_batch[\"attention_mask\"].to(DEVICE)\n                    val_labels = val_batch[\"labels\"].to(DEVICE)\n                    \n                    val_outputs = model(\n                        input_ids=val_input_ids,\n                        attention_mask=val_attention_mask,\n                        labels=val_labels\n                    )\n                    \n                    total_val_loss += val_outputs.loss.item()\n            \n            avg_val_loss = total_val_loss / len(val_loader)\n            print(f\"Step {global_step} | Val Loss: {avg_val_loss:.4f}\")\n            \n            model.train()\n    \n    avg_train_loss = total_train_loss / len(train_loader)\nprint(f\"Epoch {epoch+1} | Train Loss: {avg_train_loss:.4f}\")\nprint(\"Model loaded successfully. No training.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T19:48:39.890037Z","iopub.execute_input":"2026-03-26T19:48:39.890647Z","iopub.status.idle":"2026-03-26T20:06:27.858383Z","shell.execute_reply.started":"2026-03-26T19:48:39.890620Z","shell.execute_reply":"2026-03-26T20:06:27.857407Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Inspecting the translations\n#This was our own code\nmodel.eval()\n\nprint(\"\\nInspecting translations:\\n\")\nwith torch.no_grad():\n    for i in range(10): \n        row = val_df.iloc[i]\n        \n        source_text = \"translate Akkadian to English: \" + str(row['transliteration'])\n        reference = row['translation']\n        \n        inputs = tokenizer(\n            source_text,\n            return_tensors='pt',\n            max_length=MAX_LENGTH,\n            truncation=True\n        ).to(DEVICE)\n        \n        outputs = model.generate(\n            **inputs,\n            max_length=MAX_LENGTH,\n            num_beams=4,\n            early_stopping=True\n        )\n        \n        prediction = tokenizer.decode(\n            outputs[0],\n            skip_special_tokens=True\n        ).strip()\n        \nprint(\"SOURCE:     \", row['transliteration'])\nprint(\"REFERENCE:  \", reference)\nprint(\"PREDICTED:  \", prediction)\nprint(\"-\" * 60)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T20:06:27.859534Z","iopub.execute_input":"2026-03-26T20:06:27.859835Z","iopub.status.idle":"2026-03-26T20:07:10.503951Z","shell.execute_reply.started":"2026-03-26T20:06:27.859810Z","shell.execute_reply":"2026-03-26T20:07:10.503125Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Install if neseccasry\n!pip install sacrebleu\n#Calculate the score before submission\n# This code was copied from the notebook in the Kaggle Overview Evaluation section: https://www.kaggle.com/code/metric/dpi-bleu-chrf\nimport math\nimport pandas as pd\nimport pandas.api.types\nimport sacrebleu\n\nclass ParticipantVisibleError(Exception):\n    pass\n\ndef score(\n    solution: pd.DataFrame,\n    submission: pd.DataFrame,\n    row_id_column_name: str,\n    text_column_name: str,\n) -> float:\n    if row_id_column_name in solution.columns:\n        del solution[row_id_column_name]\n    if row_id_column_name in submission.columns:\n        del submission[row_id_column_name]\n\n    # Validate submission column type\n    if not (\n        pandas.api.types.is_string_dtype(submission[text_column_name])\n        or pandas.api.types.is_object_dtype(submission[text_column_name])\n    ):\n        raise ParticipantVisibleError(\n            f\"Submission column '{text_column_name}' must be of string type.\"\n        )\n\n    # Extract lists of strings\n    references = solution[text_column_name].astype(str).tolist()\n    hypotheses = submission[text_column_name].astype(str).tolist()\n\n    # Calculate BLEU\n    bleu = sacrebleu.corpus_bleu(hypotheses, [references])\n\n    # Calculate CHRF++ (word_order=2)\n    chrf = sacrebleu.corpus_chrf(hypotheses, [references], word_order=2)\n\n    return math.sqrt(bleu.score * chrf.score)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T20:07:10.506039Z","iopub.execute_input":"2026-03-26T20:07:10.506275Z","iopub.status.idle":"2026-03-26T20:07:15.768165Z","shell.execute_reply.started":"2026-03-26T20:07:10.506253Z","shell.execute_reply":"2026-03-26T20:07:15.767376Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Some of this is taken from different notebooks but it is a mix between own stuff aswell\n#one notebook: https://www.kaggle.com/code/manwithacat/chunky-v1-3-0 however this notebook\n# Used classes while we wanted to work in a functional programming manner. \n#This one was also used: https://www.kaggle.com/code/ngyzly/better-candidate-diversity-on-public-model\n#Suggestion from discussion post: https://www.kaggle.com/competitions/deep-past-initiative-machine-translation/discussion/678899\ndef postprocess(\n    translations,\n    special_chars_trans,\n    subscript_trans,\n    patterns,\n    aggressive=False,\n    forbidden_trans=None,\n):\n    # Convert to Series\n    s = pd.Series(translations)\n\n    # Validate entries -> boolean mask\n    valid_mask = s.apply(lambda x: isinstance(x, str) and (len(x.strip()) > 0))\n    if not bool(valid_mask.all()):\n        s.loc[~valid_mask] = \"\"\n\n    # Basic cleaning\n    s = s.fillna(\"\").astype(str)\n    s = s.str.translate(special_chars_trans)\n    s = s.str.translate(subscript_trans)\n    s = s.str.replace(patterns[\"whitespace\"], \" \", regex=True)\n    s = s.str.strip()\n\n    # Aggressive postprocessing\n    if aggressive:\n        # Normalize gaps\n        s = s.str.replace(patterns[\"gap\"], \"<gap>\", regex=True)\n        s = s.str.replace(patterns[\"big_gap\"], \"<gap>\", regex=True)\n\n        # Merge adjacent gaps\n        s = s.str.replace(\"<gap> <gap>\", \"<gap>\", regex=False)\n        s = s.str.replace(\"<big_gap> <big_gap>\", \"<gap>\", regex=False)\n\n        # Remove annotations\n        s = s.str.replace(patterns[\"annotations\"], \"\", regex=True)\n\n        # Protect gaps during forbidden-character removal\n        s = s.str.replace(\"<gap>\", \"\\x00GAP\\x00\", regex=False)\n\n        # Remove forbidden characters\n        if forbidden_trans is not None:\n            s = s.str.translate(forbidden_trans)\n\n        # Restore gaps\n        s = s.str.replace(\"\\x00GAP\\x00\", \" <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(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(patterns[\"punct_space\"], r\"\\1\", regex=True)\n        s = s.str.replace(patterns[\"repeated_punct\"], r\"\\1\", regex=True)\n\n        # Final whitespace cleanup\n        s = s.str.replace(patterns[\"whitespace\"], \" \", regex=True)\n        s = s.str.strip().str.strip(\"-\").str.strip()\n\n    return s.tolist()\n\n\npatterns = {\n    \"gap\": re.compile(r\"(\\[x\\]|\\(x\\)|\\bx\\b)\", re.I),\n    \"big_gap\": re.compile(r\"(\\.{3,}|…|\\[\\.+\\])\"),\n    \"annotations\": re.compile(\n        r\"\\((fem|plur|pl|sing|singular|plural|\\?|!)\\..\\s*\\w*\\)\", re.I\n    ),\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# Subscript digits to normal digits\nsubscript_trans = str.maketrans(\n    \"₀₁₂₃₄₅₆₇₈₉\",\n    \"0123456789\"\n)\n\n# Special Akkadian characters\nspecial_chars_trans = str.maketrans(\n    \"ḫḪ\",\n    \"hH\"\n)\n\n\nforbidden_chars = '!?()\"——<>⌈⌋⌊[]+ʾ/;'\n\nforbidden_trans = str.maketrans(\n    \"\",\n    \"\",\n    forbidden_chars\n)\n\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T20:07:15.769342Z","iopub.execute_input":"2026-03-26T20:07:15.770293Z","iopub.status.idle":"2026-03-26T20:07:15.783515Z","shell.execute_reply.started":"2026-03-26T20:07:15.770170Z","shell.execute_reply":"2026-03-26T20:07:15.782789Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = []\n\nmodel.eval()\nwith torch.no_grad():\n    for i in range(len(val_df)):\n        row = val_df.iloc[i]\n        text = \"translate Akkadian to English: \" + str(row['transliteration'])\n        inputs = tokenizer(text, return_tensors='pt', max_length=MAX_LENGTH, truncation=True).to(DEVICE)\n        outputs = model.generate(**inputs, max_length=MAX_LENGTH, num_beams=4)\n        pred = tokenizer.decode(outputs[0], skip_special_tokens=True).strip()\n        predictions.append(pred)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T20:42:35.824266Z","iopub.execute_input":"2026-03-26T20:42:35.824594Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\ntest_df = pd.read_csv(f\"{DATA_DIR}/test.csv\")\ntest_df['transliteration_norm'] = test_df['transliteration'].apply(normalize_text)\n\nmodel.eval()\npredictions = []\n\nwith torch.no_grad():\n    for _, row in tqdm(test_df.iterrows(), total=len(test_df)):\n        text = \"translate Akkadian to English: \" + str(row['transliteration_norm'])\n        inputs = tokenizer(text, return_tensors='pt', max_length=MAX_LENGTH, truncation=True).to(DEVICE)\n        outputs = model.generate(**inputs, max_length=MAX_LENGTH, num_beams=4, early_stopping=True)\n        predictions.append(tokenizer.decode(outputs[0], skip_special_tokens=True).strip())\n\npredictions = postprocess(\n    predictions,\n    special_chars_trans=special_chars_trans,\n    subscript_trans=subscript_trans,\n    patterns=patterns,\n    aggressive=True,\n    forbidden_trans=forbidden_trans,\n)\n'''\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T20:31:37.675985Z","iopub.execute_input":"2026-03-26T20:31:37.676777Z","iopub.status.idle":"2026-03-26T20:31:45.557035Z","shell.execute_reply.started":"2026-03-26T20:31:37.676747Z","shell.execute_reply":"2026-03-26T20:31:45.556374Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Prepare submission DataFrame for scoring compute the geometric mean score\n#This is our own code\nimport pandas as pd\nsubmission_df = pd.DataFrame({\n    'transliteration': test_df['transliteration'],\n    'translation': predictions\n})\n\ngeom_score = score(\n    solution=val_df.copy(),\n    submission=submission_df.copy(),\n    row_id_column_name='transliteration',\n    text_column_name='translation'\n)\n\nprint(f\"Geometric BLEU x CHRF++ score: {geom_score:.2f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-26T20:32:11.464471Z","iopub.execute_input":"2026-03-26T20:32:11.464797Z","iopub.status.idle":"2026-03-26T20:32:11.537045Z","shell.execute_reply.started":"2026-03-26T20:32:11.464772Z","shell.execute_reply":"2026-03-26T20:32:11.536388Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save the new model \n# This is our own code. \nsave_path = \"/kaggle/working/mymodel_base_byt5\"\n\nmodel.save_pretrained(save_path)\ntokenizer.save_pretrained(save_path)\n\nprint(\"Model saved to:\", save_path)\nprint(os.listdir(save_path))\nprint(\"Model saved to:\", save_path)\nprint(os.listdir(save_path))","metadata":{"trusted":true,"execution":{"execution_failed":"2026-03-26T16:31:16.286Z"}},"outputs":[],"execution_count":null}]}