{"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":"none","dataSources":[{"sourceType":"competition","sourceId":121150,"databundleVersionId":15833391,"isSourceIdPinned":false}],"dockerImageVersionId":31286,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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":"code","source":"import pandas as pd\n\ntrain = pd.read_csv(\"/kaggle/input/competitions/deep-past-initiative-machine-translation/train.csv\")\ntest = pd.read_csv(\"/kaggle/input/competitions/deep-past-initiative-machine-translation/test.csv\")\n\ntrain.head()\n\nimport re\nimport pandas as pd\n\ndef normalize_akkadian(text):\n\n    if pd.isna(text):\n        return \"\"\n\n    # normalize h characters\n    text = text.replace(\"Ḫ\", \"H\").replace(\"ḫ\", \"h\")\n\n    # normalize ellipsis\n    text = text.replace(\"…\", \" <big_gap> \")\n\n    # normalize [x] gaps\n    text = re.sub(r\"\\[x\\]\", \" <gap> \", text)\n\n    # remove half brackets\n    text = re.sub(r\"[˹˺]\", \"\", text)\n\n    # remove square brackets but keep text\n    text = re.sub(r\"\\[|\\]\", \"\", text)\n\n    # remove certainty markers\n    text = re.sub(r\"[!?/]\", \"\", text)\n\n    # normalize whitespace around hyphens\n    text = re.sub(r\"\\s*-\\s*\", \"-\", text)\n\n    # preserve determinatives\n    text = re.sub(r\"\\{([^}]*)\\}\", r\"{\\1}\", text)\n\n    # normalize subscripts (optional)\n    text = text.replace(\"₀\",\"0\").replace(\"₁\",\"1\").replace(\"₂\",\"2\")\n    text = text.replace(\"₃\",\"3\").replace(\"₄\",\"4\").replace(\"₅\",\"5\")\n    text = text.replace(\"₆\",\"6\").replace(\"₇\",\"7\").replace(\"₈\",\"8\").replace(\"₉\",\"9\")\n\n    # normalize whitespace\n    text = re.sub(r\"\\s+\", \" \", text).strip()\n\n    return text\n\n\ntrain[\"akk_norm\"] = train[\"transliteration\"].apply(normalize_transliteration)\ntest[\"akk_norm\"] = test[\"transliteration\"].apply(normalize_transliteration)\n\ntrain[[\"transliteration\",\"akk_norm\"]].head(10)\n\nfor i in range(5):\n    print(\"RAW :\", train.transliteration.iloc[i])\n    print(\"CLEAN:\", train.akk_norm.iloc[i])\n    print()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-02T13:26:57.208627Z","iopub.execute_input":"2026-03-02T13:26:57.209101Z","iopub.status.idle":"2026-03-02T13:26:57.35958Z","shell.execute_reply.started":"2026-03-02T13:26:57.209062Z","shell.execute_reply":"2026-03-02T13:26:57.358709Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install sentencepiece -q\nimport pandas as pd\nimport numpy as np\nimport re\nimport sentencepiece as spm\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom tqdm import tqdm\ntrain = pd.read_csv(\"//kaggle/input/competitions/deep-past-initiative-machine-translation/train.csv\")\ntest = pd.read_csv(\"/kaggle/input/competitions/deep-past-initiative-machine-translation/test.csv\")\n\nprint(train.head())\ndef normalize_text(text):\n    \n    text = str(text)\n    \n    # normalize h variants\n    text = text.replace(\"ḫ\",\"h\").replace(\"Ḫ\",\"H\")\n    \n    # normalize subscripts\n    text = re.sub(r\"[₀₁₂₃₄₅₆₇₈₉]\", \"\", text)\n    \n    # preserve <gap>\n    text = re.sub(r\"<gap>\", \" GAPTOKEN \", text)\n    \n    # remove strange punctuation\n    text = re.sub(r\"[^\\w\\s\\-\\.\\{\\}]\", \" \", text)\n    \n    # restore gap\n    text = text.replace(\"GAPTOKEN\", \"<gap>\")\n    \n    # normalize spaces\n    text = re.sub(r\"\\s+\", \" \", text)\n    \n    return text.strip()\ntrain[\"transliteration\"] = train[\"transliteration\"].apply(normalize_text)\ntrain[\"translation\"] = train[\"translation\"].apply(normalize_text)\n\ntest[\"transliteration\"] = test[\"transliteration\"].apply(normalize_text)\nwith open(\"akk_corpus.txt\",\"w\",encoding=\"utf8\") as f:\n    for t in train[\"transliteration\"]:\n        f.write(t+\"\\n\")\n\nwith open(\"eng_corpus.txt\",\"w\",encoding=\"utf8\") as f:\n    for t in train[\"translation\"]:\n        f.write(t+\"\\n\")\nspm.SentencePieceTrainer.train(\n    input=\"akk_corpus.txt\",\n    model_prefix=\"akk_sp\",\n    vocab_size=8000,\n    model_type=\"unigram\",\n    character_coverage=1.0\n)\n\nspm.SentencePieceTrainer.train(\n    input=\"eng_corpus.txt\",\n    model_prefix=\"eng_sp\",\n    vocab_size=8000,\n    model_type=\"unigram\",\n    character_coverage=1.0\n)\nakk_sp = spm.SentencePieceProcessor()\nakk_sp.load(\"akk_sp.model\")\n\neng_sp = spm.SentencePieceProcessor()\neng_sp.load(\"eng_sp.model\")\nclass TranslationDataset(Dataset):\n    \n    def __init__(self, src, tgt):\n        self.src = src\n        self.tgt = tgt\n        \n    def __len__(self):\n        return len(self.src)\n    \n    def __getitem__(self, idx):\n        \n        src_ids = akk_sp.encode(self.src[idx])\n        tgt_ids = eng_sp.encode(self.tgt[idx])\n        \n        return torch.tensor(src_ids), torch.tensor(tgt_ids)\ndef collate_fn(batch):\n    \n    src_batch = []\n    tgt_batch = []\n    \n    for src,tgt in batch:\n        src_batch.append(src)\n        tgt_batch.append(tgt)\n        \n    src_batch = nn.utils.rnn.pad_sequence(src_batch, batch_first=True)\n    tgt_batch = nn.utils.rnn.pad_sequence(tgt_batch, batch_first=True)\n    \n    return src_batch, tgt_batch\ndataset = TranslationDataset(\n    train[\"akkadian\"].values,\n    train[\"english\"].values\n)\n\nloader = DataLoader(\n    dataset,\n    batch_size=32,\n    shuffle=True,\n    collate_fn=collate_fn\n)\nclass TransformerModel(nn.Module):\n    \n    def __init__(self, src_vocab, tgt_vocab):\n        \n        super().__init__()\n        \n        self.src_embed = nn.Embedding(src_vocab,256)\n        self.tgt_embed = nn.Embedding(tgt_vocab,256)\n        \n        self.transformer = nn.Transformer(\n            d_model=256,\n            nhead=8,\n            num_encoder_layers=4,\n            num_decoder_layers=4\n        )\n        \n        self.fc = nn.Linear(256,tgt_vocab)\n        \n    def forward(self, src, tgt):\n        \n        src = self.src_embed(src)\n        tgt = self.tgt_embed(tgt)\n        \n        out = self.transformer(\n            src.transpose(0,1),\n            tgt.transpose(0,1)\n        )\n        \n        out = self.fc(out)\n        \n        return out\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = TransformerModel(\n    akk_sp.get_piece_size(),\n    eng_sp.get_piece_size()\n).to(device)\n\noptimizer = torch.optim.Adam(model.parameters(),lr=3e-4)\n\nloss_fn = nn.CrossEntropyLoss()\nEPOCHS = 5\n\nfor epoch in range(EPOCHS):\n    \n    model.train()\n    total_loss = 0\n    \n    for src,tgt in tqdm(loader):\n        \n        src = src.to(device)\n        tgt = tgt.to(device)\n        \n        tgt_input = tgt[:,:-1]\n        tgt_output = tgt[:,1:]\n        \n        pred = model(src,tgt_input)\n        \n        pred = pred.reshape(-1,pred.shape[-1])\n        tgt_output = tgt_output.reshape(-1)\n        \n        loss = loss_fn(pred,tgt_output)\n        \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        total_loss += loss.item()\n    \n    print(\"Epoch\",epoch,\"Loss\",total_loss/len(loader))\ndef translate(text,max_len=50):\n    \n    model.eval()\n    \n    src = torch.tensor(\n        akk_sp.encode(text)\n    ).unsqueeze(0).to(device)\n    \n    tgt = torch.tensor([[eng_sp.bos_id()]]).to(device)\n    \n    for _ in range(max_len):\n        \n        out = model(src,tgt)\n        \n        next_token = out[-1].argmax(-1)[-1]\n        \n        tgt = torch.cat(\n            [tgt,next_token.unsqueeze(0).unsqueeze(0)],\n            dim=1\n        )\n        \n        if next_token == eng_sp.eos_id():\n            break\n    \n    return eng_sp.decode(tgt.squeeze().tolist())\npredictions = []\n\nfor text in tqdm(test[\"akkadian\"]):\n    \n    pred = translate(text)\n    \n    predictions.append(pred)\nsubmission = pd.DataFrame({\n    \n    \"oare_id\":test[\"oare_id\"],\n    \"translation\":predictions\n    \n})\n\nsubmission.to_csv(\"submission.csv\",index=False)\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-13T18:56:02.379151Z","iopub.execute_input":"2026-03-13T18:56:02.379518Z","iopub.status.idle":"2026-03-13T18:56:12.429497Z","shell.execute_reply.started":"2026-03-13T18:56:02.379489Z","shell.execute_reply":"2026-03-13T18:56:12.427898Z"}},"outputs":[],"execution_count":null}]}