{"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":14846681,"sourceType":"datasetVersion","datasetId":9495869}],"dockerImageVersionId":31260,"isInternetEnabled":false,"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":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# ⚱️ Ancient Akkadian → English Translator\n\nThis notebook builds a high-quality translation system for Old Assyrian cuneiform transliterations using a pretrained multilingual sequence-to-sequence model.\n\n### 🚀 Features\n- byt5-base multilingual model\n- Beam-search optimized decoding\n- Length-controlled generation\n- Smart post-processing\n- GPU-optimized inference\n- Kaggle submission ready\n\n### 🧠 Strategy\nLow-resource languages perform best when:\n- Using pretrained multilingual models\n- Avoiding overfitting small datasets\n- Optimizing decoding rather than training from scratch\n\nThis notebook focuses on **inference optimization**, which consistently outperforms naive training in low-data MT tasks.\n\n---\n\n⭐ If you find this helpful, please upvote!\n","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport torch\nimport re\nfrom tqdm.auto import tqdm\nfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM\n\nDATA_PATH = \"/kaggle/input/deep-past-initiative-machine-translation/\"\nMODEL_PATH = \"/kaggle/input/datasets/rhythmghai/byt5-base-local/byt5-base-local\"\n\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nBATCH_SIZE = 8\nMAX_LEN = 256\n\nprint(\"Device:\", DEVICE)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test = pd.read_csv(DATA_PATH + \"test.csv\")\ndef clean_text(t):\n    t = str(t)\n    t = re.sub(r\"[!?/]\", \"\", t)\n    t = re.sub(r\"[<>\\[\\]˹˺]\", \"\", t)\n    t = re.sub(r\"\\.\\.\\.|…\", \" <gap> \", t)\n    t = re.sub(r\"\\bx\\b\", \" <gap> \", t)\n    t = re.sub(r\"[₀-₉]\", \"\", t)\n    t = t.replace(\"Ḫ\",\"H\").replace(\"ḫ\",\"h\")\n    t = re.sub(r\"\\s+\", \" \", t).strip()\n    return t\n\ntest[\"src\"] = test.transliteration.map(clean_text)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"lexicon = {\n    \"šarrum\":\"king\",\n    \"awīlum\":\"man\",\n    \"bītum\":\"house\",\n    \"wardum\":\"servant\",\n    \"iltum\":\"goddess\",\n    \"ilum\":\"god\",\n    \"dumu\":\"son\",\n    \"aššur\":\"Assur\",\n    \"kaspum\":\"silver\",\n    \"annum\":\"this\",\n    \"umma\":\"thus says\",\n    \"ana\":\"to\",\n    \"itti\":\"with\",\n    \"ina\":\"in\",\n    \"ištu\":\"from\",\n    \"lā\":\"not\",\n    \"šum\":\"name\",\n    \"mār\":\"son\",\n    \"šamaš\":\"Shamash\",\n    \"bēlum\":\"lord\",\n    \"ēkallum\":\"palace\",\n    \"ṣibtum\":\"interest\",\n    \"ṭuppum\":\"tablet\",\n}\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tokenizer = AutoTokenizer.from_pretrained(\n    MODEL_PATH,\n    local_files_only=True,\n    use_fast=False\n)\n\nmodel = AutoModelForSeq2SeqLM.from_pretrained(\n    MODEL_PATH,\n    local_files_only=True\n)\n\nmodel = model.to(DEVICE).half().eval()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def dictionary_translate(text):\n    words = text.split()\n    return \" \".join([lexicon.get(w.lower(), w) for w in words])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def model_translate(texts):\n\n    prompts = [\"translate to English: \" + t for t in texts]\n\n    inputs = tokenizer(\n        prompts,\n        return_tensors=\"pt\",\n        padding=True,\n        truncation=True,\n        max_length=MAX_LEN\n    ).to(DEVICE)\n\n    with torch.no_grad():\n        outputs = model.generate(\n            **inputs,\n            num_beams=4,\n            max_new_tokens=128,\n            length_penalty=0.9,\n            repetition_penalty=1.05,\n            early_stopping=True\n        )\n\n    return tokenizer.batch_decode(outputs, skip_special_tokens=True)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def hybrid_translate(text):\n\n    dict_out = dictionary_translate(text)\n\n    # if dictionary already translated many words → use it\n    if sum(w in lexicon.values() for w in dict_out.split()) >= 2:\n        return dict_out\n\n    # otherwise fallback to neural\n    return model_translate([text])[0]\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preds = []\n\nfor i in tqdm(range(0, len(test), BATCH_SIZE)):\n    batch = test.src.iloc[i:i+BATCH_SIZE].tolist()\n    for text in batch:\n        preds.append(hybrid_translate(text))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def clean_output(t):\n    t = re.sub(r\"\\s+\", \" \", t).strip()\n    t = re.sub(r\"\\b(\\w+)( \\1\\b)+\", r\"\\1\", t)\n    return t\n\npreds = [clean_output(x) for x in preds]\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"id\": test.id,\n    \"translation\": preds\n})\n\nsubmission.to_csv(\"submission.csv\", index=False)\n\nprint(\"Submission ready!\")\nsubmission.head()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}