{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","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":14976537,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":287306416,"sourceType":"kernelVersion"}],"dockerImageVersionId":31236,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport torch\nfrom torch.utils.data import DataLoader, Dataset\nfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM\nfrom tqdm.auto import tqdm\nimport re","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-18T02:33:44.877889Z","iopub.execute_input":"2025-12-18T02:33:44.878106Z","iopub.status.idle":"2025-12-18T02:33:56.608122Z","shell.execute_reply.started":"2025-12-18T02:33:44.878082Z","shell.execute_reply":"2025-12-18T02:33:56.607486Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"MODEL_PATH = \"/kaggle/input/deep-past-challenge-byt5-base-training/byt5-base-akkadian/\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-18T02:33:56.609922Z","iopub.execute_input":"2025-12-18T02:33:56.61062Z","iopub.status.idle":"2025-12-18T02:33:56.614217Z","shell.execute_reply.started":"2025-12-18T02:33:56.610597Z","shell.execute_reply":"2025-12-18T02:33:56.613525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TEST_DATA_PATH = \"/kaggle/input/deep-past-initiative-machine-translation/test.csv\"\nBATCH_SIZE = 4\nMAX_LENGTH = 512\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(MODEL_PATH).to(DEVICE)\nmodel.eval()\n\ntest_df = pd.read_csv(TEST_DATA_PATH)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-18T02:33:56.61507Z","iopub.execute_input":"2025-12-18T02:33:56.615354Z","iopub.status.idle":"2025-12-18T02:34:24.076844Z","shell.execute_reply.started":"2025-12-18T02:33:56.615328Z","shell.execute_reply":"2025-12-18T02:34:24.076056Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def clean_akkadian_text(text):\n    # 移除现代学者的注记符号，但保留文本本身\n    # 1. 移除表示不确定或确定的 ! 和 ?\n    text = re.sub(r'[!?]', '', text)\n    \n    # 2. 移除行内分割符和词分割符（如果它们干扰了语义，视情况而定，官方提到 / 和 :）\n    # 注意：ByT5 对空格敏感，不要误删单词间的空格\n    text = re.sub(r'[/:]', ' ', text)\n    \n    # 3. 处理断裂标记，官方建议将 [x], <gap> 等统一处理\n    # 或者是直接移除它们让句子连贯（对于翻译任务通常移除更好，除非模型专门训练过预测缺失）\n    text = re.sub(r'\\[x\\]', '', text)\n    text = re.sub(r'<gap>', '', text)\n    text = re.sub(r'<big_gap>', '', text)\n    text = re.sub(r'\\[… …\\]', '', text)\n    \n    # 4. 移除行号注记（如 \"1.\", \"10'\" 等），避免模型翻译数字\n    # 这是一个比较激进的正则，匹配行首或句中的数字加点/撇\n    text = re.sub(r'\\b\\d+\\'*[\\.:]', '', text)\n    \n    # 5. 清理多余的空格\n    text = re.sub(r'\\s+', ' ', text).strip()\n    \n    return text","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PREFIX = \"translate Akkadian to English: \"\n\nclass InferenceDataset(Dataset):\n    def __init__(self, df, tokenizer):\n        self.texts = df['transliteration'].astype(str).tolist()\n        self.texts = [PREFIX + i for i in self.texts]\n        self.tokenizer = tokenizer\n        \n    def __len__(self):\n        return len(self.texts)\n    \n    def __getitem__(self, idx):\n        text = self.texts[idx]\n        inputs = self.tokenizer(\n            clean_akkadian_text(text), \n            max_length=MAX_LENGTH, \n            padding=\"max_length\", \n            truncation=True, \n            return_tensors=\"pt\"\n        )\n        return {\n            \"input_ids\": inputs[\"input_ids\"].squeeze(0),\n            \"attention_mask\": inputs[\"attention_mask\"].squeeze(0)\n        }\n\ntest_dataset = InferenceDataset(test_df, tokenizer)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)\n\nprint(\"Starting Inference...\")\nall_predictions = []","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-18T02:34:24.077673Z","iopub.execute_input":"2025-12-18T02:34:24.077979Z","iopub.status.idle":"2025-12-18T02:34:24.08771Z","shell.execute_reply.started":"2025-12-18T02:34:24.07795Z","shell.execute_reply":"2025-12-18T02:34:24.086952Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with torch.no_grad():\n    for batch in tqdm(test_loader):\n        input_ids = batch[\"input_ids\"].to(DEVICE)\n        attention_mask = batch[\"attention_mask\"].to(DEVICE)\n  \n        # outputs = model.generate(\n        #     input_ids=input_ids,\n        #     attention_mask=attention_mask,\n        #     max_length=MAX_LENGTH,\n        #     num_beams=4,\n        #     early_stopping=True\n        # )\n        outputs = model.generate(\n            input_ids,\n            attention_mask=attention_mask,\n            max_length=MAX_LENGTH,          # 根据目标英文长度适当调整\n            num_beams=4,             # 开启 Beam Search，通常 4 或 5 是性价比最高的\n            length_penalty=0.6,      # 长度惩罚。>1.0 鼓励生成长句，<1.0 鼓励短句。可以试着调到 0.8 或 1.2 看看效果  # 防止它重复生成相同的短语（如 \"the king the king\"）\n            early_stopping=True\n        )\n        \n        decoded = tokenizer.batch_decode(outputs, skip_special_tokens=True)\n        all_predictions.extend([d.strip() for d in decoded])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-18T02:34:24.08837Z","iopub.execute_input":"2025-12-18T02:34:24.088533Z","iopub.status.idle":"2025-12-18T02:34:29.956084Z","shell.execute_reply.started":"2025-12-18T02:34:24.088519Z","shell.execute_reply":"2025-12-18T02:34:29.955214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"id\": test_df[\"id\"],\n    \"translation\": all_predictions\n})\n\nsubmission[\"translation\"] = submission[\"translation\"].apply(lambda x: x if len(x) > 0 else \"broken text\")\n\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\"Submission file saved successfully!\")\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-18T02:34:29.956945Z","iopub.execute_input":"2025-12-18T02:34:29.957255Z","iopub.status.idle":"2025-12-18T02:34:29.979145Z","shell.execute_reply.started":"2025-12-18T02:34:29.957235Z","shell.execute_reply":"2025-12-18T02:34:29.978588Z"}},"outputs":[],"execution_count":null}]}