{"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,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":692580,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":525132,"modelId":539167}],"dockerImageVersionId":31236,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport warnings\nimport pandas as pd\nimport torch\nfrom torch.utils.data import DataLoader, Dataset\nfrom transformers import AutoTokenizer, AutoModelForSeq2SeqLM\nfrom tqdm.auto import tqdm\nfrom tabulate import tabulate\nimport matplotlib.pyplot as plt\nimport matplotlib\nimport seaborn as sns\nfrom IPython.display import Image, display\n\n# Suppress warnings & setup backend\nwarnings.filterwarnings('ignore')\nmatplotlib.use('Agg')\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'\nos.environ['CUDA_LAUNCH_BLOCKING'] = '1'\n\nprint(\"=\"*80)\nprint(\"🚀 DEEP PAST CHALLENGE - OFFLINE SUBMISSION\")\nprint(\"=\"*80)\n\n# ===============================================================================\n# SECTION 1: AUTO-DETECT MODEL PATH\n# ===============================================================================\n\n# We will try these paths in order. The first one that exists is the winner.\nPOTENTIAL_PATHS = [\n    # 1. Most likely for Kaggle Models (Transformers)\n    \"/kaggle/input/akkadian-byt5-small-translator/transformers/default/1\",\n    # 2. Alternative for Kaggle Models (PyTorch)\n    \"/kaggle/input/akkadian-byt5-translator/pytorch/default/1/akkadian_byt5_trained/\",\n    # 3. If uploaded as a standard Dataset\n    \"/kaggle/input/akkadian-byt5-small-translator\",\n    # 4. If inside a folder in a Dataset\n    \"/kaggle/input/akkadian-byt5-small-translator/akkadian_byt5_trained\"\n]\n\nMODEL_PATH = None\nprint(\"\\n🔍 Auto-detecting Model Path...\")\n\nfor path in POTENTIAL_PATHS:\n    if os.path.exists(path) and \"config.json\" in os.listdir(path):\n        MODEL_PATH = path\n        print(f\"✅ FOUND MODEL AT: {MODEL_PATH}\")\n        break\n\nif MODEL_PATH is None:\n    print(\"\\n❌ ERROR: Could not find 'config.json' in any standard path.\")\n    print(\"Listing all input directories to help you debug:\")\n    for root, dirs, files in os.walk(\"/kaggle/input\"):\n        print(f\"  {root}\")\n    raise FileNotFoundError(\"Model not found. Please check the Input section sidebar.\")\n\nTEST_DATA_PATH = \"/kaggle/input/deep-past-initiative-machine-translation/test.csv\"\n\nBATCH_SIZE = 4\nMAX_LENGTH = 512\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nconfig_table = [\n    [\"Model\", \"byt5-base\"],\n    [\"Device\", DEVICE.upper()],\n    [\"Batch Size\", BATCH_SIZE],\n    [\"Max Length\", MAX_LENGTH],\n    [\"Model Path\", MODEL_PATH]\n]\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"⚙️  CONFIGURATION\")\nprint(\"=\"*80)\nprint(tabulate(config_table, headers=[\"Parameter\", \"Value\"], tablefmt=\"fancy_grid\"))\n\n# ===============================================================================\n# SECTION 2: MODEL & TOKENIZER LOADING\n# ===============================================================================\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"🤖 LOADING MODEL & TOKENIZER\")\nprint(\"=\"*80)\n\nprint(\"\\n📥 Loading tokenizer...\")\ntry:\n    tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)\n    print(\"✅ Tokenizer loaded successfully\")\nexcept Exception as e:\n    print(f\"❌ Error loading tokenizer: {e}\")\n    raise\n\nprint(\"📥 Loading model to\", DEVICE.upper())\ntry:\n    model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_PATH).to(DEVICE)\n    model.eval()\n    print(\"✅ Model loaded successfully\")\nexcept Exception as e:\n    print(f\"❌ Error loading model: {e}\")\n    raise\n\nmodel_info = [\n    [\"Model Type\", \"AutoModelForSeq2SeqLM\"],\n    [\"Parameters\", f\"{sum(p.numel() for p in model.parameters()):,}\"],\n    [\"Device\", DEVICE.upper()],\n    [\"Mode\", \"Evaluation (eval)\"]\n]\n\nprint(\"\\n\" + tabulate(model_info, headers=[\"Property\", \"Value\"], tablefmt=\"fancy_grid\"))\n\n# ===============================================================================\n# SECTION 3: DATA LOADING\n# ===============================================================================\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"📂 LOADING TEST DATA\")\nprint(\"=\"*80)\n\nif os.path.exists(TEST_DATA_PATH):\n    test_df = pd.read_csv(TEST_DATA_PATH)\n    print(f\"\\n✅ Loaded {len(test_df):,} test samples\")\nelse:\n    raise FileNotFoundError(f\"Test data not found at {TEST_DATA_PATH}\")\n\ndata_info = [\n    [\"Total Samples\", f\"{len(test_df):,}\"],\n    [\"Columns\", \", \".join(test_df.columns.tolist())],\n    [\"Memory Usage\", f\"{test_df.memory_usage(deep=True).sum() / 1024 / 1024:.2f} MB\"]\n]\n\nprint(tabulate(data_info, headers=[\"Metric\", \"Value\"], tablefmt=\"fancy_grid\"))\n\n# ===============================================================================\n# SECTION 4: INFERENCE DATASET & DATALOADER\n# ===============================================================================\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"🔧 SETTING UP INFERENCE PIPELINE\")\nprint(\"=\"*80)\n\nPREFIX = \"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\npipeline_info = [\n    [\"Dataset Size\", f\"{len(test_dataset):,}\"],\n    [\"Batch Size\", BATCH_SIZE],\n    [\"Number of Batches\", f\"{len(test_loader)}\"],\n    [\"Task Prefix\", PREFIX]\n]\n\nprint(\"\\n\" + tabulate(pipeline_info, headers=[\"Component\", \"Value\"], tablefmt=\"fancy_grid\"))\n\n# ===============================================================================\n# SECTION 5: INFERENCE EXECUTION\n# ===============================================================================\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"🔮 GENERATING PREDICTIONS\")\nprint(\"=\"*80)\n\nall_predictions = []\n\nprint(\"\\n⏱️  Starting inference loop...\\n\")\n\nwith torch.no_grad():\n    for batch in tqdm(test_loader, desc=\"Inference Progress\"):\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        \n        decoded = tokenizer.batch_decode(outputs, skip_special_tokens=True)\n        all_predictions.extend([d.strip() for d in decoded])\n\nprint(\"\\n✅ Inference complete!\")\n\ninference_stats = [\n    [\"Total Predictions\", f\"{len(all_predictions):,}\"],\n    [\"Device Used\", DEVICE.upper()],\n    [\"Generation Method\", \"Beam Search (num_beams=4)\"]\n]\n\nprint(\"\\n\" + tabulate(inference_stats, headers=[\"Statistic\", \"Value\"], tablefmt=\"fancy_grid\"))\n\n# ===============================================================================\n# SECTION 6: SUBMISSION PREPARATION\n# ===============================================================================\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"📝 CREATING SUBMISSION FILE\")\nprint(\"=\"*80)\n\nsubmission = pd.DataFrame({\n    \"id\": test_df[\"id\"],\n    \"translation\": all_predictions\n})\n\n# Fill any empty predictions\nsubmission[\"translation\"] = submission[\"translation\"].apply(\n    lambda x: x if len(str(x)) > 0 else \"broken text\"\n)\n\n# Translation statistics\ntrans_lengths = submission['translation'].str.len()\n\nsubmission_stats = [\n    [\"Total Entries\", f\"{len(submission):,}\"],\n    [\"Empty Translations\", f\"{(trans_lengths == 0).sum()}\"],\n    [\"Avg Translation Length\", f\"{trans_lengths.mean():.1f} chars\"],\n    [\"Min Length\", f\"{trans_lengths.min()} chars\"],\n    [\"Max Length\", f\"{trans_lengths.max()} chars\"],\n    [\"Median Length\", f\"{trans_lengths.median():.0f} chars\"]\n]\n\nprint(\"\\n\" + tabulate(submission_stats, headers=[\"Metric\", \"Value\"], tablefmt=\"fancy_grid\"))\n\nsubmission.to_csv(\"submission.csv\", index=False)\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"✅ SUBMISSION FILE SAVED\")\nprint(\"=\"*80)\n\nsave_info = [\n    [\"Filename\", \"submission.csv\"],\n    [\"Location\", \"/kaggle/working/submission.csv\"],\n    [\"File Size\", f\"{os.path.getsize('submission.csv') / 1024:.2f} KB\"],\n    [\"Rows\", f\"{len(submission):,}\"],\n    [\"Columns\", \", \".join(submission.columns.tolist())]\n]\n\nprint(\"\\n\" + tabulate(save_info, headers=[\"Property\", \"Value\"], tablefmt=\"fancy_grid\"))\n\n# ===============================================================================\n# SECTION 7: SAMPLE PREDICTIONS\n# ===============================================================================\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"📊 SAMPLE PREDICTIONS\")\nprint(\"=\"*80)\n\nsample_table = []\nfor i in range(min(5, len(submission))):\n    sample_table.append([\n        submission.iloc[i]['id'],\n        str(submission.iloc[i]['translation'])[:70] + \"...\"\n    ])\n\nprint(\"\\n\" + tabulate(sample_table, headers=[\"ID\", \"Translation (Preview)\"], tablefmt=\"fancy_grid\"))\n\n# ===============================================================================\n# SECTION 8: VISUALIZATIONS\n# ===============================================================================\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"📈 GENERATING VISUALIZATIONS\")\nprint(\"=\"*80)\n\nfig = plt.figure(figsize=(16, 10))\ngs = fig.add_gridspec(3, 3, hspace=0.35, wspace=0.3)\nfig.patch.set_facecolor('#0f1419')\n\n# 1. Translation Length Distribution\nax1 = fig.add_subplot(gs[0, :2])\nax1.hist(trans_lengths, bins=40, color='#00D9FF', edgecolor='#FFD60A', linewidth=2, alpha=0.8)\nax1.axvline(trans_lengths.mean(), color='#FF006E', linestyle='--', linewidth=3, label=f'Mean: {trans_lengths.mean():.0f}')\nax1.set_xlabel('Translation Length (characters)', fontsize=12, color='white', fontweight='bold')\nax1.set_ylabel('Frequency', fontsize=12, color='white', fontweight='bold')\nax1.set_title('Translation Length Distribution', fontsize=13, color='white', fontweight='bold', pad=15)\nax1.legend(fontsize=11, facecolor='#1a1f2e', edgecolor='#00D9FF')\nax1.grid(alpha=0.2, color='white')\nax1.set_facecolor('#1a1f2e')\nax1.tick_params(colors='white')\n\n# 2. Data Quality Pie Chart\nax2 = fig.add_subplot(gs[0, 2])\nquality_values = [(trans_lengths > 0).sum(), (trans_lengths == 0).sum()]\nif quality_values[1] == 0:\n    quality_values = [100, 0]\ncolors_pie = ['#00D9FF', '#FF006E']\nax2.pie(quality_values, labels=['Valid', 'Empty'], autopct='%1.1f%%', \n        colors=colors_pie, startangle=90, textprops={'color': 'white', 'fontweight': 'bold'})\nax2.set_title('Data Quality', fontsize=13, color='white', fontweight='bold', pad=15)\nax2.set_facecolor('#1a1f2e')\n\n# 3. Box Plot\nax3 = fig.add_subplot(gs[1, 0])\nbp = ax3.boxplot(trans_lengths, vert=True, patch_artist=True, widths=0.5)\nfor patch in bp['boxes']:\n    patch.set_facecolor('#00D9FF')\n    patch.set_alpha(0.7)\nfor element in ['whiskers', 'fliers', 'means', 'medians', 'caps']:\n    plt.setp(bp[element], color='#FFD60A', linewidth=2)\nax3.set_ylabel('Length (characters)', fontsize=11, color='white', fontweight='bold')\nax3.set_title('Length Box Plot', fontsize=12, color='white', fontweight='bold')\nax3.set_facecolor('#1a1f2e')\nax3.tick_params(colors='white')\nax3.grid(alpha=0.2, axis='y', color='white')\n\n# 4. Statistics Bar Chart\nax4 = fig.add_subplot(gs[1, 1])\nstats_labels = ['Min', 'Mean', 'Median', 'Max']\nstats_values = [trans_lengths.min(), trans_lengths.mean(), trans_lengths.median(), trans_lengths.max()]\nbars = ax4.bar(stats_labels, stats_values, color=['#FF006E', '#00D9FF', '#FFBE0B', '#00D9FF'], edgecolor='white', linewidth=2)\nax4.set_title('Statistics Summary', fontsize=12, color='white', fontweight='bold')\nax4.set_facecolor('#1a1f2e')\nax4.tick_params(colors='white')\nfor bar in bars:\n    height = bar.get_height()\n    ax4.text(bar.get_x() + bar.get_width()/2., height, f'{int(height)}', \n             ha='center', va='bottom', color='white', fontweight='bold')\n\n# 5. Sample Counts\nax5 = fig.add_subplot(gs[1, 2])\nsample_info = [\n    ['Total', len(submission)],\n    ['Valid', (trans_lengths > 0).sum()],\n    ['Empty', (trans_lengths == 0).sum()]\n]\nax5.axis('off')\ntable_data = ax5.table(cellText=sample_info, colLabels=['Metric', 'Count'], \n                       cellLoc='center', loc='center', colWidths=[0.5, 0.5])\ntable_data.auto_set_font_size(False)\ntable_data.set_fontsize(11)\ntable_data.scale(1, 2.5)\nfor i in range(len(sample_info) + 1):\n    table_data[(i, 0)].set_facecolor('#00D9FF')\n    table_data[(i, 1)].set_facecolor('#FFBE0B')\n\n# 6. KDE Plot\nax6 = fig.add_subplot(gs[2, :2])\ntrans_lengths.plot(kind='density', ax=ax6, color='#00D9FF', linewidth=3)\nax6.set_xlabel('Translation Length', fontsize=12, color='white', fontweight='bold')\nax6.set_ylabel('Density', fontsize=12, color='white', fontweight='bold')\nax6.set_title('Length Density', fontsize=13, color='white', fontweight='bold', pad=15)\nax6.set_facecolor('#1a1f2e')\nax6.tick_params(colors='white')\nax6.grid(alpha=0.2, color='white')\n\n# 7. Submission Info Panel\nax7 = fig.add_subplot(gs[2, 2])\nax7.axis('off')\ninfo_text = f\"\"\"\nSUBMISSION INFO\n═══════════════════\nTotal: {len(submission):,}\nModel: byt5-base\nDevice: {DEVICE.upper()}\nBeams: 4\nStatus: ✓ READY\n\"\"\"\nax7.text(0.5, 0.5, info_text, fontsize=11, family='monospace', color='white', fontweight='bold',\n        verticalalignment='center', horizontalalignment='center',\n        bbox=dict(boxstyle='round', facecolor='#00D9FF', alpha=0.2, edgecolor='#00D9FF', linewidth=2))\n\nplt.savefig('submission_metrics.png', dpi=300, bbox_inches='tight', facecolor='#0f1419')\nprint(\"\\n✅ Visualization saved: submission_metrics.png\")\n\n# Try to display if in notebook\ntry:\n    display(Image('submission_metrics.png'))\nexcept:\n    pass\n\nplt.close()\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"🎉 SUBMISSION COMPLETE\")\nprint(\"=\"*80)\nprint(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-01T16:09:51.767843Z","iopub.execute_input":"2026-01-01T16:09:51.768435Z","iopub.status.idle":"2026-01-01T16:10:44.514209Z","shell.execute_reply.started":"2026-01-01T16:09:51.768408Z","shell.execute_reply":"2026-01-01T16:10:44.513401Z"}},"outputs":[],"execution_count":null}]}