{"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":121150,"databundleVersionId":15833391,"isSourceIdPinned":false},{"sourceType":"modelInstanceVersion","sourceId":779904,"databundleVersionId":15995617,"modelInstanceId":595093,"modelId":607339,"isSourceIdPinned":false}],"dockerImageVersionId":31287,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"%%writefile infer_qwen25_coder_7b_it.py\nimport os\nimport re\nimport pandas as pd\nimport sacrebleu\nfrom tqdm import tqdm\nfrom lmdeploy import pipeline, GenerationConfig, TurbomindEngineConfig\n\nMODEL_PATH = \"/kaggle/input/models/daylighth/dpc-qwen25-coder-7b-bf16/pytorch/default/1\"\nTEST_CSV_PATH = \"/kaggle/input/competitions/deep-past-initiative-machine-translation/test.csv\"\nOUTPUT_CSV_PATH = \"submission.csv\"\n\nNUM_HYPOTHESES = 8\n\nSYSTEM_PROMPT = \"\"\"You are an expert Assyriologist. Translate the Old Assyrian transliteration into English.\nStrict Rules:\n1. Maintain all <gap> tokens exactly where they appear.\n2. Output ONLY the English translation without any explanations or notes.\n3. Use unicode fractions (e.g., ½, ⅓) instead of decimals where appropriate.\n4. Replace illegible personal names (PN) with <gap>.\"\"\"\n\nclass InferenceProcessor:\n    def __init__(self):\n        self.char_map = str.maketrans(\"ḫḪ\", \"hH\")\n        self.gap_patterns = re.compile(r'(\\.{3,}|…+|……|\\(\\s*(large\\s*)?break\\s*\\)|\\[\\s*\\d*\\s*broken\\s*lines?\\s*\\]|\\b(x\\s*)+x?\\b|\\[x\\]|\\bx\\b|<big_gap>)', re.IGNORECASE)\n\n    def apply_clean_akkadian_logic(self, text):\n        if pd.isna(text): return \"\"\n        text = str(text).translate(self.char_map).translate(str.maketrans(\"₀₁₂₃₄₅₆₇₈₉ₓ\", \"0123456789x\"))\n        text = re.sub(r'\\(\\s*d\\s*\\)', '{d}', text, flags=re.IGNORECASE)\n        text = re.sub(r'\\(\\s*ki\\s*\\)', '{ki}', text, flags=re.IGNORECASE)\n        text = re.sub(r'\\(\\s*TÚG\\s*\\)', 'TÚG', text, flags=re.IGNORECASE)\n        text = text.replace('KÙ.B.', 'KÙ.BABBAR')\n        text = re.sub(r'[\\[\\]]', '', text)\n        text = re.sub(r'<(big_)?gap>', ' __GAP__ ', text, flags=re.IGNORECASE)\n        text = self.gap_patterns.sub(' __GAP__ ', text)\n        words = text.split()\n        res = []\n        for w in words:\n            if w == \"__GAP__\":\n                if not res or res[-1] != \"<gap>\": res.append(\"<gap>\")\n            else: res.append(w)\n        return \" \".join(res)\n\ndef select_best_candidate(candidates):\n    if not candidates: return \"\"\n    if len(candidates) == 1: return candidates[0]\n        \n    metric = sacrebleu.metrics.CHRF(word_order=2)\n    best_idx = 0\n    best_score = -1.0\n    \n    n = len(candidates)\n    for i in range(n):\n        score = sum(metric.sentence_score(candidates[i], [candidates[j]]).score for j in range(n) if j != i)\n        if score > best_score:\n            best_score = score\n            best_idx = i\n            \n    return candidates[best_idx].strip()\n\ndef main():\n    print(f\"🚀 Initializing LMDeploy pipeline for {MODEL_PATH}...\")\n    \n    engine_config = TurbomindEngineConfig(\n        tp=2,                     \n        session_len=2048,         \n        max_batch_size=64,        \n        cache_max_entry_count=0.4 \n    )\n    \n    pipe = pipeline(MODEL_PATH, backend_config=engine_config)\n    \n    print(\"📄 Loading test data...\")\n    df = pd.read_csv(TEST_CSV_PATH)\n    processor = InferenceProcessor()\n    \n    base_prompts = []\n    for text in df['transliteration']:\n        clean_text = processor.apply_clean_akkadian_logic(text)\n        messages = [\n            {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n            {\"role\": \"user\", \"content\": clean_text}\n        ]\n        base_prompts.append(messages)\n    \n    flattened_prompts = []\n    gen_configs = []\n    \n    for prompt in base_prompts:\n        for hyp_idx in range(NUM_HYPOTHESES):\n            flattened_prompts.append(prompt)\n            gen_configs.append(GenerationConfig(\n                max_new_tokens=256,\n                temperature=0.4,     # 较低的温度，保持翻译稳定性，但允许足够的多样性\n                top_p=0.9,\n                do_sample=True,\n                random_seed=42 + hyp_idx  # 显式换种子！\n            ))\n            \n    print(f\"⚡ Batch inferencing {len(flattened_prompts)} sequences (Best-of-{NUM_HYPOTHESES})...\")\n    responses = pipe(flattened_prompts, gen_config=gen_configs)\n    \n    print(\"🧩 Performing Local MBR reranking...\")\n    final_predictions = []\n    \n    for i in tqdm(range(len(base_prompts)), desc=\"MBR Selection\"):\n        start_idx = i * NUM_HYPOTHESES\n        end_idx = start_idx + NUM_HYPOTHESES\n        \n        candidates = [resp.text for resp in responses[start_idx:end_idx]]\n        \n        best_translation = select_best_candidate(candidates)\n        final_predictions.append(best_translation)\n    \n    submission_df = pd.DataFrame({\n        \"id\": df[\"id\"] if \"id\" in df.columns else range(len(final_predictions)),\n        \"translation\": final_predictions\n    })\n    submission_df.to_csv(OUTPUT_CSV_PATH, index=False)\n    print(f\"✅ Inference complete! Saved to {OUTPUT_CSV_PATH}\")\n\nif __name__ == \"__main__\":\n    main()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-09T17:26:26.645521Z","iopub.execute_input":"2026-03-09T17:26:26.646210Z","iopub.status.idle":"2026-03-09T17:26:26.654439Z","shell.execute_reply.started":"2026-03-09T17:26:26.646175Z","shell.execute_reply":"2026-03-09T17:26:26.653794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!python infer_qwen25_coder_7b_it.py","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-09T17:26:28.437525Z","iopub.execute_input":"2026-03-09T17:26:28.438036Z","iopub.status.idle":"2026-03-09T17:26:57.432705Z","shell.execute_reply.started":"2026-03-09T17:26:28.437977Z","shell.execute_reply":"2026-03-09T17:26:57.432020Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!head submission.csv","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-09T17:27:41.370899Z","iopub.execute_input":"2026-03-09T17:27:41.371610Z","iopub.status.idle":"2026-03-09T17:27:41.491553Z","shell.execute_reply.started":"2026-03-09T17:27:41.371575Z","shell.execute_reply":"2026-03-09T17:27:41.490840Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}