{"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":14374989,"sourceType":"datasetVersion","datasetId":9147887},{"sourceId":14376272,"sourceType":"datasetVersion","datasetId":9181082},{"sourceId":14410665,"sourceType":"datasetVersion","datasetId":9203761}],"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\nimport joblib","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2026-01-10T10:25:43.579146Z","iopub.execute_input":"2026-01-10T10:25:43.579485Z","iopub.status.idle":"2026-01-10T10:25:55.236744Z","shell.execute_reply.started":"2026-01-10T10:25:43.579458Z","shell.execute_reply":"2026-01-10T10:25:55.236077Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def replace_gaps(text):\n    if pd.isna(text): \n        return text\n    \n    text = re.sub(r'\\.3(?:\\s+\\.3)+\\.{3}(?:\\s+\\.{3})+\\s+\\.{3}(?:\\s+\\.{3})+', '<big_gap>', text)\n    text = re.sub(r'\\.3(?:\\s+\\.3)+\\.{3}(?:\\s+\\.{3})+', '<big_gap>', text)\n    text = re.sub(r'\\.{3}(?:\\s+\\.{3})+', '<big_gap>', text)\n\n    text = re.sub(r'xx', '<gap>', text)\n    text = re.sub(r' x ', ' <gap> ', text)\n    text = re.sub(r'……', '<big_gap>', text)\n    text = re.sub(r'\\.\\.\\.\\.\\.\\.', '<big_gap>', text)\n    text = re.sub(r'…', '<big_gap>', text)\n    text = re.sub(r'\\.\\.\\.', '<big_gap>', text)\n\n    return text\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-10T10:25:55.238059Z","iopub.execute_input":"2026-01-10T10:25:55.238551Z","iopub.status.idle":"2026-01-10T10:25:55.243655Z","shell.execute_reply.started":"2026-01-10T10:25:55.238524Z","shell.execute_reply":"2026-01-10T10:25:55.242962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def replace_gaps_back(text):\n    if pd.isna(text):  \n        return text\n    \n    text = re.sub(r'<gap>', 'x', text)\n    text = re.sub(r'<big_gap>', '...', text)\n\n    return text","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-10T10:25:55.244473Z","iopub.execute_input":"2026-01-10T10:25:55.244796Z","iopub.status.idle":"2026-01-10T10:25:55.262097Z","shell.execute_reply.started":"2026-01-10T10:25:55.244773Z","shell.execute_reply":"2026-01-10T10:25:55.261472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# MODEL_PATH = \"/kaggle/input/dcp-train/byt5-base-akkadian-gap/\" its\nMODEL1_PATH = \"/kaggle/input/byt5-base-big-data2\"\nMODEL2_PATH = \"/kaggle/input/byt5-akkadian-model\"\nMODEL3_PATH = \"/kaggle/input/train-gap-all-2/byt5-base-akkadian_gap_setence2\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-10T10:25:55.263619Z","iopub.execute_input":"2026-01-10T10:25:55.263854Z","iopub.status.idle":"2026-01-10T10:25:55.277063Z","shell.execute_reply.started":"2026-01-10T10:25:55.263834Z","shell.execute_reply":"2026-01-10T10:25:55.276327Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport pandas as pd\nfrom transformers import AutoModelForSeq2SeqLM, AutoTokenizer\nimport re  # 如果 replace_gaps 使用正则的话\n\n# ================================================\n# 配置参数\n# ================================================\nTEST_DATA_PATH = \"/kaggle/input/deep-past-initiative-machine-translation/test.csv\"\nBATCH_SIZE = 8\nMAX_LENGTH = 512\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\n# 模型路径（请替换成你实际的路径）\nMODEL1_PATH = \"/kaggle/input/byt5-base-big-data2\"\nMODEL2_PATH = \"/kaggle/input/byt5-akkadian-model\"\nMODEL3_PATH = \"/kaggle/input/train-gap-all-2/byt5-base-akkadian_gap_setence2\"\n\n# 性能比例（相对于 Model 2）\nperf1 = 0.98   # Model 1 有 Model 2 的 0.98x 性能\nperf2 = 1.00   # Model 2 为基准\nperf3 = 0.90   # Model 3 的性能\n\n# 计算权重（简单线性比例 + 归一化）\ntotal = perf1 + perf2 + perf3\nw1 = perf1 / total\nw2 = perf2 / total\nw3 = perf3 / total\n\nprint(f\"权重分配:\")\nprint(f\"  w1 (Model1): {w1:.4f}\")\nprint(f\"  w2 (Model2): {w2:.4f}\")\nprint(f\"  w3 (Model3): {w3:.4f}\")\nprint(f\"  总和: {w1 + w2 + w3:.4f}\\n\")\n\n# ================================================\n# 加载模型\n# ================================================\nprint(\"Loading Model 1...\")\nmodel1 = AutoModelForSeq2SeqLM.from_pretrained(MODEL1_PATH)\nsd1 = model1.state_dict()\n\nprint(\"Loading Model 2...\")\nmodel2 = AutoModelForSeq2SeqLM.from_pretrained(MODEL2_PATH)\nsd2 = model2.state_dict()\n\nprint(\"Loading Model 3...\")\nmodel3 = AutoModelForSeq2SeqLM.from_pretrained(MODEL3_PATH)\nsd3 = model3.state_dict()\n\n# ================================================\n# 加权平均权重\n# ================================================\nprint(\"Averaging weights (weighted ensemble)...\")\nfinal_sd = sd2.copy()  # 以 model2 为基础（权重最高时最稳定）\n\nfor key in final_sd:\n    if key in sd1 and key in sd3:\n        final_sd[key] = (\n            w1 * sd1[key] +\n            w2 * sd2[key] +\n            w3 * sd3[key]\n        )\n    elif key in sd1:\n        final_sd[key] = w1 * sd1[key] + (w2 + w3) * sd2[key]  # fallback\n    elif key in sd3:\n        final_sd[key] = w3 * sd3[key] + (w1 + w2) * sd2[key]\n    # else: 保持 model2 原值\n\n# 加载融合后的权重到 model2（或新建一个模型实例）\nmodel = AutoModelForSeq2SeqLM.from_pretrained(MODEL2_PATH)  # 结构以 model2 为准\nmodel.load_state_dict(final_sd)\nmodel = model.to(DEVICE)\nmodel.eval()\n\nprint(\"Ensemble model loaded successfully!\")\n\n# ================================================\n# Tokenizer（使用 Model 2 的 tokenizer，通常三个模型共享同一 tokenizer）\n# ================================================\ntokenizer = AutoTokenizer.from_pretrained(MODEL2_PATH)\n\n# ================================================\n# 读取测试集并应用 gap 替换\n# ================================================\ntest_df = pd.read_csv(TEST_DATA_PATH)\n\n# 你的 gap 替换函数（请确保已定义）\ndef replace_gaps(text):\n    # 示例实现（根据你的实际需求修改）\n    text = re.sub(r'\\.{3,}|\\.{2,}|x+x+|\\bx\\b|\\s+x\\s+', '<big_gap>', text)\n    text = re.sub(r'\\bx\\b', '<gap>', text)\n    return text\n\ntest_df['transliteration'] = test_df['transliteration'].apply(replace_gaps)\n\nprint(\"Data preparation completed.\")\nprint(f\"Test set size: {len(test_df)} rows\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-10T10:25:55.278028Z","iopub.execute_input":"2026-01-10T10:25:55.278435Z","iopub.status.idle":"2026-01-10T10:26:47.582944Z","shell.execute_reply.started":"2026-01-10T10:25:55.278371Z","shell.execute_reply":"2026-01-10T10:26:47.58223Z"}},"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            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":"2026-01-10T10:26:47.58393Z","iopub.execute_input":"2026-01-10T10:26:47.584177Z","iopub.status.idle":"2026-01-10T10:26:47.591848Z","shell.execute_reply.started":"2026-01-10T10:26:47.584154Z","shell.execute_reply":"2026-01-10T10:26:47.590965Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom tqdm import tqdm\n\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = model.to(DEVICE)\nmodel.eval()\nmodel.float()\n\nall_predictions = []\n\ntorch.set_grad_enabled(False)\n\nwith torch.inference_mode():\n    for batch in tqdm(test_loader):\n        input_ids = batch[\"input_ids\"].to(DEVICE)              # int64, normal\n        attention_mask = batch[\"attention_mask\"].to(DEVICE)    # int64/bool, normal\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\n        decoded = tokenizer.batch_decode(outputs, skip_special_tokens=True)\n        all_predictions.extend([d.strip() for d in decoded])\n        \n        predictions = []\n        for txt in all_predictions:\n            predictions.append(txt)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-10T10:26:47.592858Z","iopub.execute_input":"2026-01-10T10:26:47.593214Z","iopub.status.idle":"2026-01-10T10:26:52.358477Z","shell.execute_reply.started":"2026-01-10T10:26:47.593171Z","shell.execute_reply":"2026-01-10T10:26:52.35782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(next(model.parameters()).dtype)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-10T10:26:52.359226Z","iopub.execute_input":"2026-01-10T10:26:52.359463Z","iopub.status.idle":"2026-01-10T10:26:52.363967Z","shell.execute_reply.started":"2026-01-10T10:26:52.359441Z","shell.execute_reply":"2026-01-10T10:26:52.363382Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"id\": test_df[\"id\"],\n    \"translation\": predictions\n})\n\nsubmission[\"translation\"] = submission[\"translation\"].apply(lambda x: x if len(x) > 0 else \"broken text\")\n\n    \nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\"Submission file saved successfully!\")\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-10T10:26:52.364774Z","iopub.execute_input":"2026-01-10T10:26:52.365016Z","iopub.status.idle":"2026-01-10T10:26:52.39928Z","shell.execute_reply.started":"2026-01-10T10:26:52.364995Z","shell.execute_reply":"2026-01-10T10:26:52.398526Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}