{"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":"none","dataSources":[{"sourceId":121150,"databundleVersionId":15061024,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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-02-09T12:15:23.355075Z","iopub.execute_input":"2026-02-09T12:15:23.355308Z","iopub.status.idle":"2026-02-09T12:15:23.387426Z","shell.execute_reply.started":"2026-02-09T12:15:23.355288Z","shell.execute_reply":"2026-02-09T12:15:23.386662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport numpy as np\nimport pandas as pd\nimport torch\n\nSEED = 42\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntorch.manual_seed(SEED)\ntorch.cuda.manual_seed_all(SEED)\n\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nDEVICE","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:23.387792Z","iopub.execute_input":"2026-02-09T12:15:23.387937Z","iopub.status.idle":"2026-02-09T12:15:23.393013Z","shell.execute_reply.started":"2026-02-09T12:15:23.387923Z","shell.execute_reply":"2026-02-09T12:15:23.392367Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/deep-past-initiative-machine-translation/train.csv\")\n\ndef split_sentences(text):\n    return [s.strip() for s in text.split(\".\") if len(s.strip()) > 4]\n\npairs = []\nfor _, row in train.iterrows():\n    src = split_sentences(row.transliteration)\n    tgt = split_sentences(row.translation)\n    for s, t in zip(src, tgt):\n        pairs.append((s, t))\n\ndf = pd.DataFrame(pairs, columns=[\"src\", \"tgt\"])\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:23.393355Z","iopub.execute_input":"2026-02-09T12:15:23.393513Z","iopub.status.idle":"2026-02-09T12:15:23.648251Z","shell.execute_reply.started":"2026-02-09T12:15:23.393499Z","shell.execute_reply":"2026-02-09T12:15:23.647478Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_df, val_df = train_test_split(\n    df, test_size=0.1, random_state=SEED\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:23.648754Z","iopub.execute_input":"2026-02-09T12:15:23.648917Z","iopub.status.idle":"2026-02-09T12:15:23.654641Z","shell.execute_reply.started":"2026-02-09T12:15:23.648901Z","shell.execute_reply":"2026-02-09T12:15:23.653897Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from transformers import AutoTokenizer, AutoModelForSeq2SeqLM\nimport torch\nimport os\n\n# Force CPU usage\nDEVICE = \"cpu\"\n\nMODEL_NAME = \"google/byt5-small\"\n\n# Clear any leftover GPU memory (optional, but safe)\nif torch.cuda.is_available():\n    torch.cuda.empty_cache()\n\n# Load tokenizer\ntokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)\n\n# Load model directly on CPU\nmodel = AutoModelForSeq2SeqLM.from_pretrained(\n    MODEL_NAME,\n    device_map=None,  # No automatic GPU/CPU splitting\n    dtype=torch.float32  # CPU uses float32 by default\n)\n\nmodel.to(DEVICE)  # Move model to CPU (optional, already default)\nmodel.eval()      # Set model to evaluation mode","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:23.655101Z","iopub.execute_input":"2026-02-09T12:15:23.655266Z","iopub.status.idle":"2026-02-09T12:15:24.959553Z","shell.execute_reply.started":"2026-02-09T12:15:23.655251Z","shell.execute_reply":"2026-02-09T12:15:24.958704Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DS(torch.utils.data.Dataset):\n    def __init__(self, df):\n        self.s, self.t = df.src.tolist(), df.tgt.tolist()\n\n    def __len__(self): return len(self.s)\n\n    def __getitem__(self, i):\n        x = tokenizer(self.s[i], max_length=256, truncation=True,\n                      padding=\"max_length\", return_tensors=\"pt\")\n        y = tokenizer(self.t[i], max_length=128, truncation=True,\n                      padding=\"max_length\", return_tensors=\"pt\")\n        labels = y.input_ids.squeeze()\n        labels[labels == tokenizer.pad_token_id] = -100\n        return {\n            \"input_ids\": x.input_ids.squeeze(),\n            \"attention_mask\": x.attention_mask.squeeze(),\n            \"labels\": labels\n        }","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:24.960098Z","iopub.execute_input":"2026-02-09T12:15:24.960270Z","iopub.status.idle":"2026-02-09T12:15:24.964473Z","shell.execute_reply.started":"2026-02-09T12:15:24.960254Z","shell.execute_reply":"2026-02-09T12:15:24.963742Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\ntrain_loader = DataLoader(\n    DS(train_df),\n    batch_size=8,\n    shuffle=True,\n    num_workers=2,\n    pin_memory=True\n)\n\nval_loader = DataLoader(\n    DS(val_df),\n    batch_size=8,\n    shuffle=False,\n    num_workers=2,\n    pin_memory=True\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:24.965044Z","iopub.execute_input":"2026-02-09T12:15:24.965219Z","iopub.status.idle":"2026-02-09T12:15:24.980995Z","shell.execute_reply.started":"2026-02-09T12:15:24.965203Z","shell.execute_reply":"2026-02-09T12:15:24.980339Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import DataLoader, TensorDataset\nfrom torch.optim import AdamW\nfrom torch.amp import autocast, GradScaler\n\n# Device setup\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\n# Example data\nx = torch.randn(100, 10)\ny = torch.randint(0, 2, (100,))\n\ndataset = TensorDataset(x, y)\ntrain_loader = DataLoader(dataset, batch_size=16, shuffle=True)  # renamed to train_loader\n\n# Model\nmodel = torch.nn.Linear(10, 1).to(DEVICE)\noptimizer = AdamW(model.parameters(), lr=3e-4)\nscaler = GradScaler(device=DEVICE if DEVICE==\"cuda\" else None)  # AMP scaler only for GPU","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:24.981528Z","iopub.execute_input":"2026-02-09T12:15:24.981684Z","iopub.status.idle":"2026-02-09T12:15:24.991056Z","shell.execute_reply.started":"2026-02-09T12:15:24.981669Z","shell.execute_reply":"2026-02-09T12:15:24.990348Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def validate(model, loader):\n    model.eval()\n    total_loss = 0\n\n    with torch.no_grad():\n        for batch in loader:\n            batch = {k: v.to(DEVICE) for k, v in batch.items()}\n            loss = model(**batch).loss\n            total_loss += loss.item()\n\n    model.train()\n    return total_loss / len(loader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:24.991403Z","iopub.execute_input":"2026-02-09T12:15:24.991563Z","iopub.status.idle":"2026-02-09T12:15:25.001037Z","shell.execute_reply.started":"2026-02-09T12:15:24.991549Z","shell.execute_reply":"2026-02-09T12:15:25.000362Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCHS = 4 if DEVICE==\"cuda\" else 3\nfor epoch in range(EPOCHS):\n    train_loss = 0.0\n\n    for batch in train_loader:\n        inputs, targets = [b.to(DEVICE) for b in batch]\n        optimizer.zero_grad()\n\n        # AMP autocast (only enabled for GPU)\n        with autocast(device_type=DEVICE, enabled=(DEVICE==\"cuda\")):\n            outputs = model(inputs)\n            loss = torch.nn.functional.binary_cross_entropy_with_logits(\n                outputs.squeeze(), targets.float()\n            )\n\n        # Backprop with GradScaler\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n\n        train_loss += loss.item()\n\n    print(f\"Epoch {epoch+1}/{EPOCHS} | Train Loss: {train_loss/len(train_loader):.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:25.001554Z","iopub.execute_input":"2026-02-09T12:15:25.001715Z","iopub.status.idle":"2026-02-09T12:15:25.025433Z","shell.execute_reply.started":"2026-02-09T12:15:25.001700Z","shell.execute_reply":"2026-02-09T12:15:25.024767Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q sacrebleu","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:25.025898Z","iopub.execute_input":"2026-02-09T12:15:25.026068Z","iopub.status.idle":"2026-02-09T12:15:26.103635Z","shell.execute_reply.started":"2026-02-09T12:15:25.026053Z","shell.execute_reply":"2026-02-09T12:15:26.102777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from transformers import AutoTokenizer, AutoModelForSeq2SeqLM\nimport torch\nimport sacrebleu\n\nDEVICE = \"cpu\"  # or \"cuda\" if GPU available\nMODEL_NAME = \"google/byt5-small\"  # T5 model for translation\n\n# Load tokenizer and model\ntokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME)\nmodel.to(DEVICE)\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:26.104259Z","iopub.execute_input":"2026-02-09T12:15:26.104426Z","iopub.status.idle":"2026-02-09T12:15:27.350832Z","shell.execute_reply.started":"2026-02-09T12:15:26.104409Z","shell.execute_reply":"2026-02-09T12:15:27.350040Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def translate(text):\n    inputs = tokenizer(text, return_tensors=\"pt\", truncation=True, max_length=128).to(DEVICE)\n    with torch.no_grad():\n        outputs = model.generate(\n            **inputs,\n            max_length=64,\n            min_length=6,\n            num_beams=3,\n            no_repeat_ngram_size=3,\n            length_penalty=1.0,\n            early_stopping=True\n        )\n    return tokenizer.decode(outputs[0], skip_special_tokens=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:27.351570Z","iopub.execute_input":"2026-02-09T12:15:27.351739Z","iopub.status.idle":"2026-02-09T12:15:27.355027Z","shell.execute_reply.started":"2026-02-09T12:15:27.351724Z","shell.execute_reply":"2026-02-09T12:15:27.354301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample = val_df.sample(200, random_state=SEED)\nhyps = [translate(x) for x in sample.src.tolist()]\nrefs = sample.tgt.tolist()\n\nbleu = sacrebleu.corpus_bleu(hyps, [refs]).score\nchrf = sacrebleu.corpus_chrf(hyps, [refs]).score\ngm = (bleu * chrf) ** 0.5\n\nprint(\"BLEU:\", bleu, \"CHRF:\", chrf, \"GM:\", gm)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:15:27.355491Z","iopub.execute_input":"2026-02-09T12:15:27.355640Z","iopub.status.idle":"2026-02-09T12:18:57.483819Z","shell.execute_reply.started":"2026-02-09T12:15:27.355626Z","shell.execute_reply":"2026-02-09T12:18:57.482942Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test = pd.read_csv(\"/kaggle/input/deep-past-initiative-machine-translation/test.csv\")\n\ntranslations = []\nfor i, t in enumerate(test.transliteration):\n    out = translate(t).strip()\n    if not out.endswith(\".\"):\n        out += \".\"\n    translations.append(out)\n\n    if i % 200 == 0:\n        print(f\"Translated {i}/{len(test)} sentences\")\n\nsubmission = pd.DataFrame({\n    \"id\": test.id,\n    \"translation\": translations\n})\n\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:18:57.484522Z","iopub.execute_input":"2026-02-09T12:18:57.484693Z","iopub.status.idle":"2026-02-09T12:19:01.775622Z","shell.execute_reply.started":"2026-02-09T12:18:57.484677Z","shell.execute_reply":"2026-02-09T12:19:01.774640Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sacrebleu\nimport math\n\n# Use validation set as proxy for GM\nval_hyps = [translate(x).strip() for x in val_df.src.tolist()]\nval_refs = val_df.tgt.tolist()\n\nbleu = sacrebleu.corpus_bleu(val_hyps, [val_refs]).score\nchrf = sacrebleu.corpus_chrf(val_hyps, [val_refs]).score\ngm = math.sqrt(bleu * chrf)\n\nprint(f\"Proxy GM on validation set → BLEU: {bleu:.2f}, chrF++: {chrf:.2f}, GM: {gm:.2f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:19:01.775957Z","iopub.execute_input":"2026-02-09T12:19:01.776133Z","iopub.status.idle":"2026-02-09T12:30:07.394126Z","shell.execute_reply.started":"2026-02-09T12:19:01.776116Z","shell.execute_reply":"2026-02-09T12:30:07.392951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}