{"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":[{"sourceId":121150,"databundleVersionId":15061024,"sourceType":"competition"},{"sourceId":704725,"sourceType":"modelInstanceVersion","modelInstanceId":534933,"modelId":548549}],"dockerImageVersionId":31236,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:28.594147Z","iopub.execute_input":"2026-01-04T09:47:28.594766Z","iopub.status.idle":"2026-01-04T09:47:28.878720Z","shell.execute_reply.started":"2026-01-04T09:47:28.594734Z","shell.execute_reply":"2026-01-04T09:47:28.878035Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport re\nimport os\nfrom pathlib import Path\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Deep Learning\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom transformers import (\n    T5ForConditionalGeneration,\n    ByT5Tokenizer,\n    Seq2SeqTrainingArguments,\n    Seq2SeqTrainer,\n    DataCollatorForSeq2Seq\n)\nfrom sklearn.model_selection import train_test_split\nfrom tqdm. auto import tqdm\n\n# Check GPU availability\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f\"Using device:  {device}\")\nif torch.cuda.is_available():\n    print(f\"GPU:  {torch.cuda.get_device_name(0)}\")\n    print(f\"GPU Memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.2f} GB\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:28.880086Z","iopub.execute_input":"2026-01-04T09:47:28.880464Z","iopub.status.idle":"2026-01-04T09:47:37.935129Z","shell.execute_reply.started":"2026-01-04T09:47:28.880439Z","shell.execute_reply":"2026-01-04T09:47:37.934401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load datasets\ntrain_df = pd.read_csv('/kaggle/input/deep-past-initiative-machine-translation/train.csv')\ntest_df = pd.read_csv('/kaggle/input/deep-past-initiative-machine-translation/test.csv')\nsample_sub = pd.read_csv('/kaggle/input/deep-past-initiative-machine-translation/sample_submission.csv')\nprint(\"DATASETS LOADING SUCCESSFUL\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:37.936050Z","iopub.execute_input":"2026-01-04T09:47:37.936586Z","iopub.status.idle":"2026-01-04T09:47:37.974415Z","shell.execute_reply.started":"2026-01-04T09:47:37.936559Z","shell.execute_reply":"2026-01-04T09:47:37.973883Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Check for missing values\nprint(\"Missing values in training data:\")\nprint(train_df.isnull().sum())\n\n# Check data statistics\nif 'transliteration' in train_df.columns and 'translation' in train_df.columns:\n    train_df['translit_len'] = train_df['transliteration'].astype(str).str.len()\n    train_df['translation_len'] = train_df['translation'].astype(str).str.len()\n    \n    print(\"\\nText length statistics:\")\n    print(train_df[['translit_len', 'translation_len']].describe())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:37.975125Z","iopub.execute_input":"2026-01-04T09:47:37.975406Z","iopub.status.idle":"2026-01-04T09:47:37.991862Z","shell.execute_reply.started":"2026-01-04T09:47:37.975380Z","shell.execute_reply":"2026-01-04T09:47:37.991127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def clean_transliteration(text):\n    \"\"\"\n    Clean transliteration text according to competition guidelines.\n    \"\"\"\n    if pd.isna(text):\n        return \"\"\n    \n    text = str(text)\n    \n    # Remove certain punctuation and markers\n    text = re.sub(r'[! ? /]', '', text)\n    \n    # Replace word dividers (:  and .) with space\n    text = re.sub(r'[: .]', ' ', text)\n    \n    # Remove half brackets for partially broken signs\n    text = text.replace('˹', '').replace('˺', '')\n    \n    # Replace gap markers\n    text = re.sub(r'\\[\\.\\.\\.\\s+\\.\\.\\.\\]', '<big_gap>', text)  # [… …]\n    text = re. sub(r'\\. \\.\\.', '<big_gap>', text)  # …\n    text = re.sub(r'\\[x\\]', '<gap>', text)  # [x]\n    text = re.sub(r'\\[\\s*x+\\s*\\]', '<gap>', text)  # [x], [xx], etc.\n    \n    # Remove angle brackets but keep content (scribal insertions)\n    text = re.sub(r'<<([^>]+)>>', r'\\1', text)  # << >>\n    text = re.sub(r'<([^>]+)>', r'\\1', text)  # < >\n    \n    # Remove square brackets but keep content (broken signs)\n    text = re.sub(r'\\[([^\\]]+)\\]', r'\\1', text)\n    \n    # Remove parentheses (comments)\n    text = re.sub(r'\\([^)]*\\)', '', text)\n    \n    # Normalize whitespace\n    text = re.sub(r'\\s+', ' ', text)\n    text = text.strip()\n    \n    return text\n\n\ndef clean_translation(text):\n    \"\"\"\n    Clean translation text. \n    \"\"\"\n    if pd. isna(text):\n        return \"\"\n    \n    text = str(text)\n    \n    # Remove brackets but keep content\n    text = re. sub(r'\\[([^\\]]+)\\]', r'\\1', text)\n    text = re.sub(r'\\(([^)]+)\\)', r'\\1', text)\n    \n    # Normalize whitespace\n    text = re.sub(r'\\s+', ' ', text)\n    text = text.strip()\n    \n    return text\n\n\n# Test preprocessing\ntest_translit = \"a-lim{ki} [x] A-mur-{d}UTU ...  [broken text] <insertion> !\"\nprint(\"Original:\", test_translit)\nprint(\"Cleaned:\", clean_transliteration(test_translit))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:37.993825Z","iopub.execute_input":"2026-01-04T09:47:37.994410Z","iopub.status.idle":"2026-01-04T09:47:38.003610Z","shell.execute_reply.started":"2026-01-04T09:47:37.994378Z","shell.execute_reply":"2026-01-04T09:47:38.002659Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Apply preprocessing to training data\nprint(\"Available columns:\", train_df.columns. tolist())\n\n# Adjust these column names based on actual data\nsource_col = 'transliteration' if 'transliteration' in train_df.columns else train_df.columns[1]\ntarget_col = 'translation' if 'translation' in train_df.columns else train_df.columns[2]\n\nprint(f\"\\nUsing source column: {source_col}\")\nprint(f\"Using target column: {target_col}\")\n\n# Clean the data\ntrain_df['source_clean'] = train_df[source_col].apply(clean_transliteration)\ntrain_df['target_clean'] = train_df[target_col].apply(clean_translation)\n\n# Remove empty pairs\ntrain_df = train_df[(train_df['source_clean']. str.len() > 0) & \n                    (train_df['target_clean'].str.len() > 0)]. reset_index(drop=True)\n\nprint(f\"\\nCleaned dataset size: {len(train_df)}\")\nprint(\"\\nExample pairs after cleaning:\")\nfor i in range(min(3, len(train_df))):\n    print(f\"\\n--- Example {i+1} ---\")\n    print(f\"Source:  {train_df.iloc[i]['source_clean'][: 200]}\")\n    print(f\"Target: {train_df.iloc[i]['target_clean'][:200]}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:38.004434Z","iopub.execute_input":"2026-01-04T09:47:38.004643Z","iopub.status.idle":"2026-01-04T09:47:38.150306Z","shell.execute_reply.started":"2026-01-04T09:47:38.004622Z","shell.execute_reply":"2026-01-04T09:47:38.149700Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load ByT5-small model and tokenizer\nMODEL_PATH = '/kaggle/input/byt5-small/transformers/default/1/byt5-small'\n\nprint(\"Loading ByT5-small tokenizer...\")\ntokenizer = ByT5Tokenizer.from_pretrained(MODEL_PATH)\n\nprint(\"Loading ByT5-small model...\")\nmodel = T5ForConditionalGeneration.from_pretrained(MODEL_PATH)\nmodel.to(device)\n\nprint(f\"✅ Model loaded successfully!\")\nprint(f\"Model parameters: {model.num_parameters():,}\")\nprint(f\"Tokenizer vocab size: {tokenizer.vocab_size}\")\nprint(f\"Pad token ID: {tokenizer.pad_token_id}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:38.151190Z","iopub.execute_input":"2026-01-04T09:47:38.151523Z","iopub.status.idle":"2026-01-04T09:47:38.737356Z","shell.execute_reply.started":"2026-01-04T09:47:38.151496Z","shell.execute_reply":"2026-01-04T09:47:38.736666Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TranslationDataset(Dataset):\n    \"\"\"\n    Dataset for Old Assyrian to English translation.\n    Simplified version - let DataCollator handle padding and label masking.\n    \"\"\"\n    def __init__(self, sources, targets, tokenizer, max_source_length=300, max_target_length=300):\n        self.sources = sources\n        self.targets = targets\n        self.tokenizer = tokenizer\n        self.max_source_length = max_source_length\n        self.max_target_length = max_target_length\n    \n    def __len__(self):\n        return len(self.sources)\n    \n    def __getitem__(self, idx):\n        source = str(self.sources[idx])\n        target = str(self.targets[idx])\n        \n        # Tokenize source - NO padding here\n        source_encoding = self. tokenizer(\n            source,\n            max_length=self.max_source_length,\n            truncation=True,\n        )\n        \n        # Tokenize target - NO padding here\n        target_encoding = self.tokenizer(\n            target,\n            max_length=self.max_target_length,\n            truncation=True,\n        )\n        \n        return {\n            'input_ids': source_encoding['input_ids'],\n            'attention_mask': source_encoding['attention_mask'],\n            'labels': target_encoding['input_ids'],  # DataCollator will handle -100\n        }\n\nprint(\"✅ Dataset class created!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:38.738229Z","iopub.execute_input":"2026-01-04T09:47:38.738536Z","iopub.status.idle":"2026-01-04T09:47:38.744989Z","shell.execute_reply.started":"2026-01-04T09:47:38.738510Z","shell.execute_reply":"2026-01-04T09:47:38.744275Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Clear any cached memory\nimport gc\ntorch.cuda.empty_cache()\ngc.collect()\n\nprint(\"GPU memory cleared!\")\nprint(f\"GPU memory allocated: {torch.cuda.memory_allocated(0) / 1e9:.2f} GB\")\nprint(f\"GPU memory reserved: {torch.cuda.memory_reserved(0) / 1e9:.2f} GB\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:38.746107Z","iopub.execute_input":"2026-01-04T09:47:38.746433Z","iopub.status.idle":"2026-01-04T09:47:39.083680Z","shell.execute_reply.started":"2026-01-04T09:47:38.746412Z","shell.execute_reply":"2026-01-04T09:47:39.082873Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Split data into train and validation\ntrain_data, val_data = train_test_split(\n    train_df, \n    test_size=0.1, \n    random_state=42\n)\n\n# Filter out very short or very long sequences\ndef filter_length(df, min_len=20, max_len=700):\n    df_filtered = df[\n        (df['source_clean']. str.len() >= min_len) & \n        (df['source_clean'].str.len() <= max_len) &\n        (df['target_clean'].str.len() >= min_len) &\n        (df['target_clean'].str.len() <= max_len)\n    ].copy()\n    return df_filtered. reset_index(drop=True)\n\ntrain_data = filter_length(train_data)\nval_data = filter_length(val_data)\n\nprint(f\"Training samples (after filtering): {len(train_data)}\")\nprint(f\"Validation samples (after filtering): {len(val_data)}\")\n\n# Verify data quality\nprint(\"\\n✅ Sample training pair:\")\nprint(f\"Source: {train_data.iloc[0]['source_clean'][:150]}\")\nprint(f\"Target: {train_data.iloc[0]['target_clean'][:150]}\")\n\n# Create datasets\nMAX_LENGTH = 300\n\ntrain_dataset = TranslationDataset(\n    train_data['source_clean'].tolist(),\n    train_data['target_clean'].tolist(),\n    tokenizer,\n    max_source_length=MAX_LENGTH,\n    max_target_length=MAX_LENGTH\n)\n\nval_dataset = TranslationDataset(\n    val_data['source_clean'].tolist(),\n    val_data['target_clean']. tolist(),\n    tokenizer,\n    max_source_length=MAX_LENGTH,\n    max_target_length=MAX_LENGTH\n)\n\nprint(f\"\\n✅ Datasets created!\")\nprint(f\"Train dataset size: {len(train_dataset)}\")\nprint(f\"Val dataset size: {len(val_dataset)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:39.084683Z","iopub.execute_input":"2026-01-04T09:47:39.085108Z","iopub.status.idle":"2026-01-04T09:47:39.109080Z","shell.execute_reply.started":"2026-01-04T09:47:39.085073Z","shell.execute_reply":"2026-01-04T09:47:39.108365Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Clear GPU cache\nimport gc\ntorch.cuda.empty_cache()\ngc.collect()\n\nprint(\"Reloading model to ensure clean state...\")\n# Reload model fresh\nmodel = T5ForConditionalGeneration.from_pretrained(MODEL_PATH)\nmodel.to(device)\n\n# Training arguments - FIXED LOGGING\ntraining_args = Seq2SeqTrainingArguments(\n    output_dir='./results',\n    eval_strategy='no',\n    save_strategy='epoch',\n    learning_rate=5e-4,\n    per_device_train_batch_size=8,\n    num_train_epochs=5,\n    weight_decay=0.01,\n    save_total_limit=1,\n    predict_with_generate=False,\n    fp16=True,\n    logging_steps=50,\n    logging_first_step=False,  # CHANGED:  Don't log first step\n    report_to='none',\n    gradient_accumulation_steps=1,\n    gradient_checkpointing=True,\n    warmup_steps=100,\n    max_grad_norm=1.0,\n    lr_scheduler_type='cosine',\n    dataloader_num_workers=0,\n)\n\nprint(\"=\"*80)\nprint(\"TRAINING CONFIGURATION\")\nprint(\"=\"*80)\nprint(f\"  Batch size: 8\")\nprint(f\"  Epochs: 5\")\nprint(f\"  Learning rate: 5e-4\")\nprint(f\"  Warmup steps: 100\")\nprint(f\"  Evaluation:  DISABLED\")\nprint(f\"  Total training samples: {len(train_dataset)}\")\nsteps_per_epoch = len(train_dataset) // 8\nprint(f\"  Steps per epoch: {steps_per_epoch}\")\nprint(f\"  Total steps: {steps_per_epoch * 5}\")\nprint(\"=\"*80)\n\n# Data collator\ndata_collator = DataCollatorForSeq2Seq(\n    tokenizer=tokenizer,\n    model=model,\n    label_pad_token_id=-100,\n    padding=True,\n    max_length=MAX_LENGTH,\n)\n\n# Enable gradient checkpointing\nif hasattr(model, 'gradient_checkpointing_enable'):\n    model.gradient_checkpointing_enable()\n    print(\"✅ Gradient checkpointing enabled\")\n\n# Initialize trainer\ntrainer = Seq2SeqTrainer(\n    model=model,\n    args=training_args,\n    train_dataset=train_dataset,\n    data_collator=data_collator,\n    tokenizer=tokenizer,\n)\n\nprint(\"✅ Trainer initialized!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:39.110133Z","iopub.execute_input":"2026-01-04T09:47:39.110541Z","iopub.status.idle":"2026-01-04T09:47:39.916231Z","shell.execute_reply.started":"2026-01-04T09:47:39.110508Z","shell.execute_reply":"2026-01-04T09:47:39.915401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# MANUAL TRAINING LOOP - MEMORY EFFICIENT VERSION\nprint(\"=\"*80)\nprint(\"MANUAL TRAINING (Memory Efficient)\")\nprint(\"=\"*80)\n\n# Clear all GPU memory first\nimport gc\ntorch.cuda.empty_cache()\ngc.collect()\n\n# Reload model fresh\nmodel = T5ForConditionalGeneration.from_pretrained(MODEL_PATH)\nmodel.to(device)\nmodel.train()\n\n# Enable gradient checkpointing\nif hasattr(model, 'gradient_checkpointing_enable'):\n    model.gradient_checkpointing_enable()\n    print(\"✅ Gradient checkpointing enabled\")\n\n# Setup optimizer\nfrom torch.optim import AdamW\noptimizer = AdamW(model.parameters(), lr=5e-4, weight_decay=0.01)\n\n# Create dataloader with SMALLER batch size\nfrom torch.utils.data import DataLoader\ntrain_loader = DataLoader(\n    train_dataset,\n    batch_size=2,  # REDUCED from 8 to 2\n    shuffle=True,\n    collate_fn=data_collator,\n)\n\n# Training parameters\nnum_epochs = 2\naccumulation_steps = 4  # Effective batch size = 2 * 4 = 8\ntotal_steps = 0\nlosses = []\n\nprint(f\"Batch size: 2\")\nprint(f\"Gradient accumulation:  {accumulation_steps}\")\nprint(f\"Effective batch size: {2 * accumulation_steps}\")\nprint(\"=\"*80)\n\nfor epoch in range(num_epochs):\n    print(f\"\\nEpoch {epoch+1}/{num_epochs}\")\n    print(\"-\" * 80)\n    \n    epoch_losses = []\n    optimizer.zero_grad()\n    \n    for step, batch in enumerate(train_loader):\n        # Move batch to device\n        batch = {k: v.to(device) if isinstance(v, torch.Tensor) else v \n                 for k, v in batch.items()}\n        \n        # Forward pass\n        outputs = model(**batch)\n        loss = outputs.loss\n        \n        # Scale loss for gradient accumulation\n        loss = loss / accumulation_steps\n        \n        # Backward pass\n        loss.backward()\n        \n        # Optimizer step every accumulation_steps\n        if (step + 1) % accumulation_steps == 0:\n            optimizer.step()\n            optimizer.zero_grad()\n            \n            # Clear cache periodically\n            if (step + 1) % (accumulation_steps * 10) == 0:\n                torch. cuda.empty_cache()\n        \n        # Log (unscaled loss)\n        actual_loss = loss.item() * accumulation_steps\n        epoch_losses.append(actual_loss)\n        total_steps += 1\n        \n        if (step + 1) % 40 == 0:\n            avg_loss = sum(epoch_losses[-40:]) / len(epoch_losses[-40:])\n            print(f\"  Step {total_steps: 4d} | Loss: {avg_loss:.4f}\")\n        \n        losses.append(actual_loss)\n        \n        # Clear batch from memory\n        del batch, outputs, loss\n    \n    # Final optimizer step for remaining gradients\n    optimizer.step()\n    optimizer.zero_grad()\n    \n    avg_epoch_loss = sum(epoch_losses) / len(epoch_losses)\n    print(f\"\\nEpoch {epoch+1} Average Loss: {avg_epoch_loss:.4f}\")\n    \n    # Clear cache after each epoch\n    torch.cuda.empty_cache()\n    gc.collect()\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"MANUAL TRAINING COMPLETED!\")\nprint(\"=\"*80)\nprint(f\"Final loss: {losses[-1]:.4f}\")\nif len(losses) >= 50:\n    print(f\"Average last 50 steps: {sum(losses[-50:])/50:.4f}\")\nelse:\n    print(f\"Average all losses: {sum(losses)/len(losses):.4f}\")\n\n# Save model\nmodel.save_pretrained('./manual_trained_byt5')\ntokenizer.save_pretrained('./manual_trained_byt5')\nprint(\"✅ Model saved to './manual_trained_byt5'\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:47:39.917991Z","iopub.execute_input":"2026-01-04T09:47:39.918308Z","iopub.status.idle":"2026-01-04T09:58:47.339469Z","shell.execute_reply.started":"2026-01-04T09:47:39.918284Z","shell.execute_reply":"2026-01-04T09:58:47.338630Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load the manually trained model\nprint(\"=\"*80)\nprint(\"LOADING MANUALLY TRAINED MODEL\")\nprint(\"=\"*80)\n\nmodel = T5ForConditionalGeneration.from_pretrained('./manual_trained_byt5')\nmodel.to(device)\nmodel.eval()\n\nprint(\"✅ Model loaded successfully!\")\n\n# Test on a training example\ntest_input = train_data. iloc[0]['source_clean']\ntest_target = train_data.iloc[0]['target_clean']\n\nprint(f\"\\nTest Input: {test_input[: 200]}\")\nprint(f\"Expected Output: {test_target[:200]}\\n\")\n\ninputs = tokenizer(test_input, return_tensors='pt', max_length=MAX_LENGTH, truncation=True).to(device)\n\nprint(f\"Input shape: {inputs['input_ids'].shape}\")\n\nwith torch.no_grad():\n    outputs = model.generate(\n        **inputs,\n        max_length=MAX_LENGTH,\n        num_beams=4,\n        early_stopping=True,\n        min_length=10,\n        no_repeat_ngram_size=3,\n    )\n\nprint(f\"Output shape: {outputs.shape}\")\n\ngenerated = tokenizer.decode(outputs[0], skip_special_tokens=True)\nprint(f\"\\nModel Generated: {generated[:300]}\")\nprint(f\"Generation length: {len(generated)} characters\")\n\nif len(generated) > 10:\n    print(\"\\n✅ Model is generating text!\")\n    \n    # Check if it's English-like\n    if any(word in generated.lower() for word in ['the', 'to', 'of', 'and', 'by', 'son', 'silver', 'witnessed']):\n        print(\"✅ Output appears to be ENGLISH!  Training successful!\")\n    else:\n        print(\"⚠️  Output is text but may not be proper English translation\")\nelse:\n    print(\"\\n❌ Model generated very short output\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:58:47.340386Z","iopub.execute_input":"2026-01-04T09:58:47.340650Z","iopub.status.idle":"2026-01-04T09:58:50.838915Z","shell.execute_reply.started":"2026-01-04T09:58:47.340627Z","shell.execute_reply":"2026-01-04T09:58:50.838218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"=\"*80)\nprint(\"PREPROCESSING TEST DATA\")\nprint(\"=\"*80)\n\n# Find the source column in test data\ntest_source_col = 'transliteration' if 'transliteration' in test_df.columns else test_df.columns[1]\nprint(f\"Test source column: {test_source_col}\")\n\n# Apply preprocessing\ntest_df['source_clean'] = test_df[test_source_col].apply(clean_transliteration)\n\nprint(f\"\\n✅ Test samples:  {len(test_df)}\")\nprint(\"\\nFirst few test examples:\")\nfor i in range(min(5, len(test_df))):\n    print(f\"  {i}:  {test_df.iloc[i]['source_clean'][:100]}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:58:50.841059Z","iopub.execute_input":"2026-01-04T09:58:50.841408Z","iopub.status.idle":"2026-01-04T09:58:50.848673Z","shell.execute_reply.started":"2026-01-04T09:58:50.841378Z","shell.execute_reply":"2026-01-04T09:58:50.848006Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"\\n\" + \"=\"*80)\nprint(\"GENERATING PREDICTIONS FOR TEST SET\")\nprint(\"=\"*80)\n\npredictions = []\nbatch_size = 4  # Small batch for memory safety\n\nmodel.eval()\n\nfor i in tqdm(range(0, len(test_df), batch_size), desc=\"Translating\"):\n    batch = test_df.iloc[i:i+batch_size]\n    sources = batch['source_clean'].tolist()\n    \n    # Handle empty sources\n    sources = [s if len(s) > 0 else \"empty text\" for s in sources]\n    \n    # Tokenize batch\n    inputs = tokenizer(\n        sources,\n        max_length=MAX_LENGTH,\n        truncation=True,\n        padding=True,\n        return_tensors='pt'\n    ).to(device)\n    \n    # Generate translations\n    with torch.no_grad():\n        outputs = model.generate(\n            **inputs,\n            max_length=MAX_LENGTH,\n            num_beams=4,\n            early_stopping=True,\n            no_repeat_ngram_size=3,\n            min_length=10,\n        )\n    \n    # Decode outputs\n    batch_predictions = tokenizer.batch_decode(outputs, skip_special_tokens=True)\n    predictions.extend(batch_predictions)\n    \n    # Clear cache periodically\n    if (i // batch_size) % 10 == 0:\n        torch. cuda.empty_cache()\n\nprint(f\"\\n✅ Generated {len(predictions)} predictions\")\n\n# Check prediction quality\nempty_count = sum(1 for p in predictions if len(p. strip()) == 0)\nshort_count = sum(1 for p in predictions if 0 < len(p.strip()) < 10)\ngood_count = len(predictions) - empty_count - short_count\n\nprint(f\"\\nPrediction Statistics:\")\nprint(f\"  Empty predictions: {empty_count}\")\nprint(f\"  Very short (<10 chars): {short_count}\")\nprint(f\"  Good predictions (≥10 chars): {good_count}\")\n\nif good_count > 0:\n    print(\"\\n✅ Model is generating translations!\")\n    print(f\"\\nSample predictions:\")\n    for i in range(min(10, len(predictions))):\n        if len(predictions[i]) >= 10:\n            print(f\"  {i}: {predictions[i][:120]}\")\nelse:\n    print(\"\\n⚠️  WARNING: Most predictions are empty or very short!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:58:50.849513Z","iopub.execute_input":"2026-01-04T09:58:50.849764Z","iopub.status.idle":"2026-01-04T09:58:54.772317Z","shell.execute_reply.started":"2026-01-04T09:58:50.849744Z","shell.execute_reply":"2026-01-04T09:58:54.771593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"=\"*80)\nprint(\"CREATING SUBMISSION FILE\")\nprint(\"=\"*80)\n\n# Create submission dataframe\nsubmission = pd.DataFrame({\n    'id': test_df['id'],\n    'translation': predictions\n})\n\n# Clean translations\nsubmission['translation'] = submission['translation'].str.strip()\n\n# Replace empty translations with placeholder\nempty_mask = submission['translation'] == ''\nif empty_mask.sum() > 0:\n    print(f\"\\n⚠️  Found {empty_mask.sum()} empty translations - filling with placeholder\")\n    submission.loc[empty_mask, 'translation'] = 'Translation not available'\n\nprint(\"\\n\" + \"=\"*80)\nprint(\"SUBMISSION PREVIEW\")\nprint(\"=\"*80)\nprint(submission.head(15))\n\nprint(f\"\\nSubmission shape: {submission.shape}\")\nprint(f\"Missing values: {submission.isnull().sum().sum()}\")\nprint(f\"Empty translations: {(submission['translation'] == 'Translation not available').sum()}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:58:54.773279Z","iopub.execute_input":"2026-01-04T09:58:54.773586Z","iopub.status.idle":"2026-01-04T09:58:54.783428Z","shell.execute_reply.started":"2026-01-04T09:58:54.773552Z","shell.execute_reply":"2026-01-04T09:58:54.782523Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Debug file creation issue\nimport os\n\nprint(\"Current working directory:\")\nprint(os.getcwd())\n\nprint(\"\\nFiles in current directory:\")\nfor file in os.listdir('.'):\n    print(f\"  - {file}\")\n\nprint(\"\\nAttempting to save submission.csv again...\")\n\n# Save with explicit path\nsubmission. to_csv('./submission.csv', index=False)\n\nprint(\"\\nChecking if file exists:\")\nprint(f\"  submission.csv exists: {os.path.exists('./submission.csv')}\")\nprint(f\"  /kaggle/working/submission.csv exists: {os.path.exists('/kaggle/working/submission.csv')}\")\n\n# Try absolute path\nsubmission.to_csv('/kaggle/working/submission.csv', index=False)\n\nprint(\"\\nFiles in /kaggle/working:\")\nfor file in os.listdir('/kaggle/working'):\n    print(f\"  - {file}\")\n\n# Verify the file\nif os.path.exists('/kaggle/working/submission.csv'):\n    print(\"\\n✅ SUCCESS!  File created at /kaggle/working/submission.csv\")\n    \n    # Read it back to verify\n    verify = pd.read_csv('/kaggle/working/submission.csv')\n    print(f\"\\nVerification:\")\n    print(f\"  Rows: {len(verify)}\")\n    print(f\"  Columns: {verify.columns.tolist()}\")\n    print(f\"\\nFirst 10 rows:\")\n    print(verify.head(10))\nelse:\n    print(\"\\n❌ Still failed to create file\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:58:54.784561Z","iopub.execute_input":"2026-01-04T09:58:54.785280Z","iopub.status.idle":"2026-01-04T09:58:54.808850Z","shell.execute_reply.started":"2026-01-04T09:58:54.785241Z","shell.execute_reply":"2026-01-04T09:58:54.808129Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save submission file - MUST be named 'submission.csv'\nimport os\n\n# Use absolute path for Kaggle\noutput_path = '/kaggle/working/submission.csv'\n\nprint(\"=\"*80)\nprint(\"SAVING SUBMISSION FILE\")\nprint(\"=\"*80)\n\ntry:\n    submission.to_csv(output_path, index=False)\n    print(f\"✅ File saved to: {output_path}\")\nexcept Exception as e:\n    print(f\"❌ Error saving file: {e}\")\n    # Try current directory as fallback\n    output_path = 'submission.csv'\n    submission.to_csv(output_path, index=False)\n    print(f\"✅ File saved to: {os.path.abspath(output_path)}\")\n\n# Verify file exists\nif os.path.exists(output_path):\n    file_size = os.path.getsize(output_path)\n    \n    print(\"\\n\" + \"=\"*80)\n    print(\"✅ SUBMISSION FILE CREATED SUCCESSFULLY!\")\n    #print(\"=\"*80)\n    #print(f\"📁 File path: {os.path.abspath(output_path)}\")\n    #print(f\"📊 File size: {file_size: ,} bytes ({file_size/1024:. 2f} KB)\")\n    #print(f\"📝 Number of predictions: {len(submission)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:58:54.809774Z","iopub.execute_input":"2026-01-04T09:58:54.810091Z","iopub.status.idle":"2026-01-04T09:58:54.817168Z","shell.execute_reply.started":"2026-01-04T09:58:54.810063Z","shell.execute_reply":"2026-01-04T09:58:54.816536Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Print in a more readable table format with truncation\nfrom IPython.display import display\n\nprint(\"=\"*80)\nprint(\"SUBMISSION TRANSLATIONS - INTERACTIVE TABLE\")\nprint(\"=\"*80)\n\n# Read the submission file\nverify_sub = pd.read_csv('/kaggle/working/submission.csv')\n# Display as nice table\ndisplay(verify_sub[['id', 'translation']].head(20))\n# Style the dataframe\nstyled_df = verify_sub. head(50).style.set_properties(**{\n    'text-align': 'left',\n    'white-space': 'pre-wrap',\n    'word-wrap': 'break-word'\n})\ndisplay(styled_df)\n\nprint(f\"\\n✅ Total:  {len(verify_sub)} translations\")\nprint(f\"✅ File:  /kaggle/working/submission. csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-04T09:58:54.817938Z","iopub.execute_input":"2026-01-04T09:58:54.818120Z","iopub.status.idle":"2026-01-04T09:58:54.904898Z","shell.execute_reply.started":"2026-01-04T09:58:54.818102Z","shell.execute_reply":"2026-01-04T09:58:54.904213Z"}},"outputs":[],"execution_count":null}]}