{"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},{"sourceType":"datasetVersion","sourceId":14899351,"datasetId":9366631,"databundleVersionId":15763950}],"dockerImageVersionId":31328,"isInternetEnabled":false,"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,"execution":{"iopub.status.busy":"2026-03-23T21:11:33.539991Z","iopub.execute_input":"2026-03-23T21:11:33.540326Z","iopub.status.idle":"2026-03-23T21:11:34.754061Z","shell.execute_reply.started":"2026-03-23T21:11:33.540288Z","shell.execute_reply":"2026-03-23T21:11:34.753105Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\"\"\"\nAkkadian to English Translation - ByT5 Optimized 34x Inference\nFork of assiaben's optimized model with enhanced postprocessing.\n\"\"\"\nimport os\nimport re\nimport pandas as pd\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM\nfrom tqdm.auto import tqdm\n\n# === Configuration ===\nINPUT_DIR = None\nfor candidate in [\n    \"/kaggle/input/deep-past-initiative-machine-translation\",\n    \"/kaggle/input/competitions/deep-past-initiative-machine-translation\",\n]:\n    if os.path.exists(candidate):\n        INPUT_DIR = candidate\n        break\nif INPUT_DIR is None:\n    for root, dirs, files in os.walk(\"/kaggle/input\"):\n        if \"test.csv\" in files:\n            INPUT_DIR = root\n            break\nif INPUT_DIR is None:\n    raise FileNotFoundError(\"Cannot find competition data!\")\n\nTEST_DATA_PATH = f\"{INPUT_DIR}/test.csv\"\n\n# Debug: list /kaggle/input to find model\nprint(\"=== Listing /kaggle/input ===\")\nfor item in sorted(os.listdir(\"/kaggle/input\")):\n    full = os.path.join(\"/kaggle/input\", item)\n    if os.path.isdir(full):\n        print(f\"  DIR: {item}/\")\n        try:\n            for sub in sorted(os.listdir(full))[:10]:\n                subfull = os.path.join(full, sub)\n                if os.path.isdir(subfull):\n                    print(f\"    DIR: {sub}/\")\n                    for subsub in sorted(os.listdir(subfull))[:5]:\n                        print(f\"      {subsub}\")\n                else:\n                    print(f\"    FILE: {sub} ({os.path.getsize(subfull)} bytes)\")\n        except Exception as e:\n            print(f\"    Error listing: {e}\")\n    else:\n        print(f\"  FILE: {item}\")\n\n# Find model path\nMODEL_PATH = None\nfor candidate in [\n    \"/kaggle/input/final-byt5/byt5-akkadian-optimized-34x\",\n    \"/kaggle/input/final-byt5\",\n    \"/kaggle/input/datasets/assiaben/final-byt5/byt5-akkadian-optimized-34x\",\n    \"/kaggle/input/datasets/assiaben/final-byt5\",\n]:\n    if os.path.isdir(candidate) and os.path.exists(os.path.join(candidate, \"config.json\")):\n        MODEL_PATH = candidate\n        break\n\nif MODEL_PATH is None:\n    # Walk all of /kaggle/input to find config.json\n    for root, dirs, files in os.walk(\"/kaggle/input\"):\n        if \"config.json\" in files and \"model.safetensors\" in files:\n            MODEL_PATH = root\n            break\n\nif MODEL_PATH is None:\n    raise FileNotFoundError(\"Cannot find model! Check /kaggle/input listing above.\")\nBATCH_SIZE = 8\nMAX_LENGTH = 512\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nprint(f\"Using data from: {INPUT_DIR}\")\nprint(f\"Device: {DEVICE}\")\n\n# === Preprocessing ===\n_big_gap_re = re.compile(r'(\\.{3,}|…+|……)')\n_small_gap_re = re.compile(r'(xx+|\\s+x\\s+)')\n\ndef preprocess_input(text):\n    if pd.isna(text):\n        return \"\"\n    text = str(text)\n    text = _big_gap_re.sub('<big_gap>', text)\n    text = _small_gap_re.sub('<gap>', text)\n    return text\n\n# === Postprocessing ===\n_subscript_trans = str.maketrans(\"₀₁₂₃₄₅₆₇₈₉\", \"0123456789\")\n_special_trans = str.maketrans(\"ḫḪ\", \"hH\")\n_forbidden = '!?()\"—–<>⌈⌋⌊[]+ʾ/;'\n_forbidden_trans = str.maketrans(\"\", \"\", _forbidden)\n\ndef postprocess_output(text):\n    if not isinstance(text, str) or not text.strip():\n        return \"\"\n    t = text\n    t = t.translate(_special_trans)\n    t = t.translate(_subscript_trans)\n    # Normalize gaps\n    t = re.sub(r'(\\[x\\]|\\(x\\)|\\bx\\b)', '<gap>', t, flags=re.I)\n    t = re.sub(r'(\\.{3,}|…|\\[\\.+\\])', '<big_gap>', t)\n    t = t.replace('<gap> <gap>', '<big_gap>')\n    t = t.replace('<big_gap> <big_gap>', '<big_gap>')\n    # Remove annotations\n    t = re.sub(r'\\((fem|plur|pl|sing|singular|plural|\\?|!)\\.?\\s*\\w*\\)', '', t, flags=re.I)\n    # Protect gaps, remove forbidden chars\n    t = t.replace('<gap>', '\\x00GAP\\x00').replace('<big_gap>', '\\x00BIG\\x00')\n    t = t.translate(_forbidden_trans)\n    t = t.replace('\\x00GAP\\x00', ' <gap> ').replace('\\x00BIG\\x00', ' <big_gap> ')\n    # Fractions\n    t = re.sub(r'(\\d+)\\.5\\b', r'\\1 ½', t)\n    t = re.sub(r'\\b0\\.5\\b', '½', t)\n    t = re.sub(r'(\\d+)\\.25\\b', r'\\1 ¼', t)\n    t = re.sub(r'\\b0\\.25\\b', '¼', t)\n    t = re.sub(r'(\\d+)\\.75\\b', r'\\1 ¾', t)\n    t = re.sub(r'\\b0\\.75\\b', '¾', t)\n    # Remove repeated words and n-grams\n    t = re.sub(r'\\b(\\w+)(?:\\s+\\1\\b)+', r'\\1', t)\n    for n in range(4, 1, -1):\n        pat = r'\\b((?:\\w+\\s+){' + str(n-1) + r'}\\w+)(?:\\s+\\1\\b)+'\n        t = re.sub(pat, r'\\1', t)\n    # Fix spacing\n    t = re.sub(r'\\s+([.,:])', r'\\1', t)\n    t = re.sub(r'([.,])\\1+', r'\\1', t)\n    t = re.sub(r'\\s+', ' ', t).strip().strip('-').strip()\n    return t\n\n# === Dataset ===\nclass InferenceDataset(Dataset):\n    def __init__(self, df):\n        self.ids = df['id'].tolist()\n        self.texts = [\"translate Akkadian to English: \" + preprocess_input(t) for t in df['transliteration']]\n    def __len__(self):\n        return len(self.ids)\n    def __getitem__(self, idx):\n        return self.ids[idx], self.texts[idx]\n\n# === Load data and model ===\nprint(\"Loading test data...\")\ntest_df = pd.read_csv(TEST_DATA_PATH)\nprint(f\"Test samples: {len(test_df)}\")\n\nprint(\"Loading model...\")\nprint(f\"Model path: {MODEL_PATH}\")\nprint(f\"Model files: {os.listdir(MODEL_PATH)}\")\ntokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, local_files_only=True)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(MODEL_PATH, local_files_only=True).to(DEVICE).eval()\nprint(f\"Model loaded on {DEVICE}\")\n\n# Try BetterTransformer\ntry:\n    from optimum.bettertransformer import BetterTransformer\n    model = BetterTransformer.transform(model)\n    print(\"BetterTransformer applied\")\nexcept Exception:\n    print(\"BetterTransformer not available, using standard model\")\n\n# === Collate function ===\ndef collate_fn(batch):\n    ids = [b[0] for b in batch]\n    texts = [b[1] for b in batch]\n    tokens = tokenizer(texts, max_length=MAX_LENGTH, padding=True, truncation=True, return_tensors=\"pt\")\n    return ids, tokens\n\n# === Inference ===\ndataset = InferenceDataset(test_df)\nloader = DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2, collate_fn=collate_fn, pin_memory=True)\n\nprint(f\"Running inference ({len(loader)} batches)...\")\nresults = []\n\nwith torch.inference_mode():\n    for batch_ids, tokens in tqdm(loader, desc=\"Translating\"):\n        input_ids = tokens.input_ids.to(DEVICE)\n        attention_mask = tokens.attention_mask.to(DEVICE)\n\n        # Adaptive beam size\n        seq_len = attention_mask.sum(dim=1).float().mean().item()\n        num_beams = 4 if seq_len < 100 else 8\n\n        outputs = model.generate(\n            input_ids=input_ids,\n            attention_mask=attention_mask,\n            num_beams=num_beams,\n            max_new_tokens=512,\n            length_penalty=1.09,\n            early_stopping=True,\n            use_cache=True,\n        )\n\n        decoded = tokenizer.batch_decode(outputs, skip_special_tokens=True)\n        cleaned = [postprocess_output(d) for d in decoded]\n        results.extend(zip(batch_ids, cleaned))\n\n        if torch.cuda.is_available() and len(results) % 100 == 0:\n            torch.cuda.empty_cache()\n\n\n# === Save submission ===\nsubmission = pd.DataFrame(results, columns=['id', 'translation'])\nsubmission['translation'] = submission['translation'].apply(lambda x: x if len(str(x)) > 0 else \"broken text\")\nsubmission.to_csv('submission.csv', index=False)\nprint(f\"Submission saved: {len(submission)} rows\")\nprint(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-23T21:11:34.756217Z","iopub.execute_input":"2026-03-23T21:11:34.756726Z","iopub.status.idle":"2026-03-23T21:13:32.222050Z","shell.execute_reply.started":"2026-03-23T21:11:34.756684Z","shell.execute_reply":"2026-03-23T21:13:32.220914Z"}},"outputs":[],"execution_count":null}]}