{"cells": [{"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "\"\"\"\nModel Soup Inference - Fixed for Deep Past\nUses deep-past-byt5-models dataset\n\"\"\"\nimport pandas as pd\nimport torch\nfrom pathlib import Path\nfrom transformers import T5ForConditionalGeneration, ByT5Tokenizer\nimport os\nimport glob\n\ndef find_model_path():\n    \"\"\"Find model files in the Kaggle input directory\"\"\"\n    # Search for config.json to identify model directory\n    search_paths = [\n        \"/kaggle/input/deep-past-byt5-models/**/config.json\",\n        \"/kaggle/input/byt5-combined-akkadian/**/config.json\",\n    ]\n\n    for pattern in search_paths:\n        matches = glob.glob(pattern, recursive=True)\n        if matches:\n            return os.path.dirname(matches[0])\n\n    # List what's actually in the input directory\n    print(\"Contents of /kaggle/input/:\")\n    if os.path.exists(\"/kaggle/input/\"):\n        for item in os.listdir(\"/kaggle/input/\"):\n            print(f\"  {item}\")\n            item_path = os.path.join(\"/kaggle/input/\", item)\n            if os.path.isdir(item_path):\n                try:\n                    subitems = os.listdir(item_path)\n                    for sub in subitems[:5]:\n                        print(f\"    {sub}\")\n                except:\n                    pass\n\n    return None\n\ndef load_models():\n    \"\"\"Load all models for soup\"\"\"\n    models = {}\n    tokenizer = None\n\n    print(\"Searching for model...\")\n    model_path = find_model_path()\n\n    if model_path is None:\n        print(\"ERROR: Could not find model path\")\n        return {}, None\n\n    print(f\"Found model at: {model_path}\")\n\n    try:\n        print(\"Loading model...\")\n        model = T5ForConditionalGeneration.from_pretrained(model_path)\n        tokenizer = ByT5Tokenizer.from_pretrained(model_path)\n\n        model.eval()\n        if torch.cuda.is_available():\n            model = model.cuda()\n\n        models[\"byt5\"] = {\n            \"model\": model,\n            \"weight\": 1.0\n        }\n        print(\"  Loaded successfully\")\n    except Exception as e:\n        print(f\"  ERROR loading model: {e}\")\n        import traceback\n        traceback.print_exc()\n\n    return models, tokenizer\n\ndef preprocess_akkadian(text):\n    \"\"\"Normalize Akkadian input before translation\"\"\"\n    # Normalize gap markers (from top notebook)\n    text = text.replace('...', '<gap>')\n    text = text.replace('xx', '<gap>')\n    text = text.replace('[...]', '<gap>')\n\n    # Add task prefix (some models expect this)\n    # text = \"translate Akkadian to English: \" + text\n\n    return text\n\ndef generate_with_model(model, tokenizer, text, **gen_kwargs):\n    \"\"\"Generate using a single model\"\"\"\n    inputs = tokenizer(text, return_tensors=\"pt\", padding=True, truncation=True, max_length=512)\n\n    if torch.cuda.is_available():\n        inputs = {k: v.cuda() for k, v in inputs.items()}\n\n    with torch.no_grad():\n        outputs = model.generate(\n            **inputs,\n            **gen_kwargs\n        )\n\n    decoded = tokenizer.decode(outputs[0], skip_special_tokens=True)\n    return decoded\n\ndef main():\n    # Optimized generation parameters for chrF++\n    GEN_CONFIG = {\n        \"max_length\": 256,\n        \"num_beams\": 10,\n        \"repetition_penalty\": 1.5,\n        \"length_penalty\": 1.2,\n        \"no_repeat_ngram_size\": 3,\n        \"early_stopping\": True,\n        \"do_sample\": False,\n    }\n\n    print(\"Loading model...\")\n    models, tokenizer = load_models()\n\n    if len(models) == 0:\n        print(\"ERROR: No models loaded!\")\n        test_df = pd.read_csv(\"/kaggle/input/deep-past-initiative-machine-translation/test.csv\")\n        submission = pd.DataFrame({\n            \"id\": test_df[\"id\"],\n            \"translation\": [\"ERROR: No models loaded\"] * len(test_df)\n        })\n        submission.to_csv(\"submission.csv\", index=False)\n        return\n\n    if tokenizer is None:\n        print(\"ERROR: Tokenizer not loaded!\")\n        return\n\n    print(f\"Loaded {len(models)} models\")\n\n    # Load test data\n    test_df = pd.read_csv(\"/kaggle/input/deep-past-initiative-machine-translation/test.csv\")\n    print(f\"Test columns: {list(test_df.columns)}\")\n    print(f\"Test rows: {len(test_df)}\")\n\n    # Generate translations\n    translations = []\n    for idx, row in test_df.iterrows():\n        # Use 'transliteration' column\n        akkadian = row[\"transliteration\"]\n\n        # Preprocess\n        akkadian = preprocess_akkadian(akkadian)\n\n        # Generate with first available model\n        model_data = list(models.values())[0]\n        translation = generate_with_model(\n            model_data[\"model\"],\n            tokenizer,\n            akkadian,\n            **GEN_CONFIG\n        )\n\n        translations.append(translation)\n\n        if (idx + 1) % 10 == 0:\n            print(f\"Processed {idx + 1}/{len(test_df)}\")\n\n    # CRITICAL FIX: Use \"translation\" column, not \"target\"\n    submission = pd.DataFrame({\n        \"id\": test_df[\"id\"],\n        \"translation\": translations\n    })\n\n    submission.to_csv(\"submission.csv\", index=False)\n    print(f\"Saved submission.csv with {len(submission)} rows\")\n    print(f\"Columns: {list(submission.columns)}\")\n    print(\"\\nSample outputs:\")\n    for i in range(min(3, len(submission))):\n        print(f\"  {submission.iloc[i]['id']}: {submission.iloc[i]['translation'][:100]}...\")\n\nif __name__ == \"__main__\":\n    main()\n"}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"name": "python", "version": "3.10.0"}}, "nbformat": 4, "nbformat_minor": 4}