{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":87793,"databundleVersionId":12024591,"sourceType":"competition"},{"sourceId":11571891,"sourceType":"datasetVersion","datasetId":7254911}],"dockerImageVersionId":31012,"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":"2025-05-03T06:23:11.807660Z","iopub.execute_input":"2025-05-03T06:23:11.807920Z","iopub.status.idle":"2025-05-03T06:23:13.313030Z","shell.execute_reply.started":"2025-05-03T06:23:11.807901Z","shell.execute_reply":"2025-05-03T06:23:13.312245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.nn as nn\nimport torch.optim as optim\n\n# === 1) Load & Combine Training + Validation for Training ===\ndftrain_seq   = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/train_sequences.v2.csv\")\ndftrain_lab   = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/train_labels.v2.csv\")\ndfvalid_seq   = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/validation_sequences.csv\")\ndfvalid_lab   = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/validation_labels.csv\")\n\ncombined_seqs_df  = pd.concat([dftrain_seq, dfvalid_seq], ignore_index=True)\ncombined_labs_df  = pd.concat([dftrain_lab, dfvalid_lab], ignore_index=True)\n\n# === 2) Helper Functions ===\ndef encode_sequence(seq):\n    mapping = {'A':[1,0,0,0], 'C':[0,1,0,0], 'G':[0,0,1,0], 'U':[0,0,0,1]}\n    return [mapping.get(b,[0,0,0,0]) for b in seq]\n\ndef clean_coords(c):\n    c = c.copy()\n    c[~np.isfinite(c)] = np.nan\n    for j in range(c.shape[1]):\n        col = c[:, j]\n        if np.isnan(col).all():\n            c[:, j] = 0.0\n        else:\n            m = np.nanmean(col)\n            col[np.isnan(col)] = m if np.isfinite(m) else 0.0\n            c[:, j] = col\n    return np.clip(c, -100, 100)\n\ndef merge_labels(seqs_df, labs_df):\n    S, C = [], []\n    for _, row in seqs_df.iterrows():\n        tid = row['target_id']\n        enc = encode_sequence(row['sequence'])\n        L   = len(enc)\n\n        lab = labs_df[labs_df['ID'].str.startswith(tid + '_')]\n        if lab.empty: continue\n        lab = lab.sort_values('resid')\n\n        coord = np.full((L, 15), np.nan, dtype=np.float32)\n        for i, (x,y,z) in enumerate(zip(\n            ['x_1','x_2','x_3','x_4','x_5'],\n            ['y_1','y_2','y_3','y_4','y_5'],\n            ['z_1','z_2','z_3','z_4','z_5']\n        )):\n            if x in lab.columns:\n                vals = lab[[x,y,z]].to_numpy(dtype=np.float32)\n                m = min(vals.shape[0], L)\n                coord[:m, i*3:(i+1)*3] = vals[:m]\n\n        coord = clean_coords(coord)\n        S.append(torch.tensor(enc,  dtype=torch.float32))\n        C.append(torch.tensor(coord, dtype=torch.float32))\n    return S, C\n\n# === 3) Prepare Training Data ===\nseq_tensors, coord_tensors = merge_labels(combined_seqs_df, combined_labs_df)\nmaxL = max(s.shape[0] for s in seq_tensors)\nfor i in range(len(seq_tensors)):\n    pad = maxL - seq_tensors[i].shape[0]\n    if pad>0:\n        seq_tensors[i] = torch.cat([seq_tensors[i],   torch.zeros(pad,4)])\n        coord_tensors[i] = torch.cat([coord_tensors[i], torch.zeros(pad,15)])\n\nclass RNADataset(Dataset):\n    def __init__(self, seqs, coords):\n        self.seqs, self.coords = seqs, coords\n    def __len__(self):\n        return len(self.seqs)\n    def __getitem__(self, i):\n        return self.seqs[i], self.coords[i]\n\ntrain_loader = DataLoader(RNADataset(seq_tensors, coord_tensors),\n                          batch_size=1, shuffle=True)\n\n# === 4) Define Model ===\nclass SimpleRNA3DModel(nn.Module):\n    def __init__(self, feat_dim=4, hid=128, out=15):\n        super().__init__()\n        self.fc1 = nn.Linear(feat_dim, hid)\n        self.fc2 = nn.Linear(hid, out)\n    def forward(self,x):\n        return self.fc2(torch.relu(self.fc1(x)))\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel = SimpleRNA3DModel().to(device)\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\nlossf     = nn.MSELoss()\n\n# === 5) Training Loop ===\nfor epoch in range(10):\n    model.train()\n    total_loss = 0.0\n    for seq_batch, coord_batch in train_loader:\n        sb = seq_batch.squeeze(0).to(device)  # [L,4]\n        cb = coord_batch.squeeze(0).to(device)  # [L,15]\n\n        optimizer.zero_grad()\n        pred = model(sb)\n        loss = lossf(pred, cb)\n        loss.backward()\n        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)\n        optimizer.step()\n        total_loss += loss.item()\n    print(f\"Epoch {epoch+1}/10 — Avg Loss: {total_loss/len(train_loader):.4f}\")\n\n# === 6) Robust Inference & Submission ===\n# 6a) Load sample_submission\nsample = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/sample_submission.csv\")\ntest_ids = sample['ID'].str.extract(r'(^.+)_\\d+$')[0].unique()\n\n# 6b) Pick correct sequences file\nbase = \"/kaggle/input/stanford-rna-3d-folding\"\nif   os.path.exists(f\"{base}/test_sequences.csv\"):\n    test_df = pd.read_csv(f\"{base}/test_sequences.csv\")\nelif os.path.exists(f\"{base}/validation_sequences.csv\"):\n    test_df = pd.read_csv(f\"{base}/validation_sequences.csv\")\nelse:\n    raise FileNotFoundError(\"No test_sequences.csv or validation_sequences.csv found\")\n\ntest_df = test_df[test_df['target_id'].isin(test_ids)].reset_index(drop=True)\n\n# 6c) Encode & pad\nseqs_test = [encode_sequence(s) for s in test_df['sequence']]\nfor i,s in enumerate(seqs_test):\n    pad = maxL - len(s)\n    if pad>0:\n        seqs_test[i] = s + [[0,0,0,0]]*pad\n\n# 6d) Predict one by one\nmodel.eval()\npreds = []\nwith torch.no_grad():\n    for s in seqs_test:\n        x = torch.tensor(s, dtype=torch.float32).to(device)\n        out = model(x).cpu().numpy()  # [L,15]\n        preds.append(out)\n\n# 6e) Build submission rows\nrows = []\nfor i, tid in enumerate(test_df['target_id']):\n    L = len(encode_sequence(test_df.loc[i,'sequence']))\n    for j in range(L):\n        row = {'ID': f\"{tid}_{j+1}\"}\n        for k in range(5):\n            row[f\"x_{k+1}\"] = float(preds[i][j, 3*k+0])\n            row[f\"y_{k+1}\"] = float(preds[i][j, 3*k+1])\n            row[f\"z_{k+1}\"] = float(preds[i][j, 3*k+2])\n        rows.append(row)\n\nsub = pd.DataFrame(rows)\nsub = pd.merge(sample[['ID']], sub, on='ID', how='left').fillna(0.0)\nsub.to_csv(\"submission.csv\", index=False)\nprint(\"✅ submission.csv written\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-03T06:23:13.314592Z","iopub.execute_input":"2025-05-03T06:23:13.314963Z","execution_failed":"2025-05-03T06:45:12.846Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}