{"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":[{"sourceType":"competition","sourceId":118765,"databundleVersionId":15231210}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":" import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport pandas as pd\nimport numpy as np\n\nfrom torch.utils.data import Dataset, DataLoader\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:50:46.63095Z","iopub.execute_input":"2026-02-17T19:50:46.631344Z","iopub.status.idle":"2026-02-17T19:50:46.635428Z","shell.execute_reply.started":"2026-02-17T19:50:46.631315Z","shell.execute_reply":"2026-02-17T19:50:46.63483Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(seq.columns)\nprint(labels.columns)\n\n\nseq[\"length\"] = seq[\"sequence\"].apply(len)\n\nprint(\"Min length:\", seq[\"length\"].min())\nprint(\"Max length:\", seq[\"length\"].max())\nprint(\"Mean length:\", seq[\"length\"].mean())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:50:53.831988Z","iopub.execute_input":"2026-02-17T19:50:53.832262Z","iopub.status.idle":"2026-02-17T19:50:53.836679Z","shell.execute_reply.started":"2026-02-17T19:50:53.832232Z","shell.execute_reply":"2026-02-17T19:50:53.835996Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"seq.sort_values(\"length\", ascending=False).head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:50:53.85733Z","iopub.execute_input":"2026-02-17T19:50:53.857609Z","iopub.status.idle":"2026-02-17T19:50:53.877447Z","shell.execute_reply.started":"2026-02-17T19:50:53.85758Z","shell.execute_reply":"2026-02-17T19:50:53.876931Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"seq_small = seq[seq[\"length\"] < 5000]\n\nprint(\"Small RNA count:\", seq_small.shape[0])\nprint(\"Max small length:\", seq_small[\"length\"].max())\nprint(\"Mean small length:\", seq_small[\"length\"].mean())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:50:53.878134Z","iopub.execute_input":"2026-02-17T19:50:53.878418Z","iopub.status.idle":"2026-02-17T19:50:53.885394Z","shell.execute_reply.started":"2026-02-17T19:50:53.878395Z","shell.execute_reply":"2026-02-17T19:50:53.8846Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\nprint(\"Top 10 longest (filtered):\")\nprint(seq_small.sort_values(\"length\", ascending=False)[[\"target_id\",\"length\"]].head(10))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:50:53.886396Z","iopub.execute_input":"2026-02-17T19:50:53.886673Z","iopub.status.idle":"2026-02-17T19:50:53.899379Z","shell.execute_reply.started":"2026-02-17T19:50:53.886651Z","shell.execute_reply":"2026-02-17T19:50:53.898782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"seq_2k = seq[seq[\"length\"] < 2000]\n\nprint(\"Count <2000:\", seq_2k.shape[0])\nprint(\"Max length:\", seq_2k[\"length\"].max())\nprint(\"Mean length:\", seq_2k[\"length\"].mean())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:50:53.900323Z","iopub.execute_input":"2026-02-17T19:50:53.900618Z","iopub.status.idle":"2026-02-17T19:50:53.90704Z","shell.execute_reply.started":"2026-02-17T19:50:53.900585Z","shell.execute_reply":"2026-02-17T19:50:53.9064Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"small_ids = set(seq_2k[\"target_id\"])\n\nlabels_small = labels[labels[\"ID\"].str.split(\"_\").str[0].isin(small_ids)]\n\nprint(\"Filtered labels shape:\", labels_small.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:50:53.907873Z","iopub.execute_input":"2026-02-17T19:50:53.908113Z","iopub.status.idle":"2026-02-17T19:51:03.242765Z","shell.execute_reply.started":"2026-02-17T19:50:53.908092Z","shell.execute_reply":"2026-02-17T19:51:03.242061Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Target ID'yi ID kolonundan çıkar (bir kere yapıyoruz)\nlabels_small[\"target_id\"] = labels_small[\"ID\"].str.split(\"_\").str[0]\n\n# Groupby yapıyoruz (tek seferlik)\ngrouped = labels_small.groupby(\"target_id\")\n\ndataset = []\n\nfor _, row in seq_2k.iterrows():\n    tid = row[\"target_id\"]\n    sequence = row[\"sequence\"]\n    \n    if tid in grouped.groups:\n        df_target = grouped.get_group(tid).sort_values(\"resid\")\n        coords = df_target[[\"x_1\", \"y_1\", \"z_1\"]].values\n        \n        if len(sequence) == len(coords):\n            dataset.append({\n                \"target_id\": tid,\n                \"sequence\": sequence,\n                \"coords\": coords\n            })\n\nprint(\"Final usable dataset size:\", len(dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:03.243647Z","iopub.execute_input":"2026-02-17T19:51:03.243922Z","iopub.status.idle":"2026-02-17T19:51:08.348549Z","shell.execute_reply.started":"2026-02-17T19:51:03.243897Z","shell.execute_reply":"2026-02-17T19:51:08.347796Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\nall_coords = np.concatenate([d[\"coords\"] for d in dataset])\n\nprint(\"Min coord:\", all_coords.min())\nprint(\"Max coord:\", all_coords.max())\nprint(\"Mean coord:\", all_coords.mean())\nprint(\"Std coord:\", all_coords.std())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.349389Z","iopub.execute_input":"2026-02-17T19:51:08.349661Z","iopub.status.idle":"2026-02-17T19:51:08.382455Z","shell.execute_reply.started":"2026-02-17T19:51:08.349636Z","shell.execute_reply":"2026-02-17T19:51:08.381693Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\nnan_count = np.isnan(all_coords).sum()\ntotal_values = all_coords.size\n\nprint(\"Total values:\", total_values)\nprint(\"NaN count:\", nan_count)\nprint(\"NaN ratio:\", nan_count / total_values)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.38345Z","iopub.execute_input":"2026-02-17T19:51:08.383713Z","iopub.status.idle":"2026-02-17T19:51:08.393347Z","shell.execute_reply.started":"2026-02-17T19:51:08.38369Z","shell.execute_reply":"2026-02-17T19:51:08.392593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"clean_dataset = []\n\nfor d in dataset:\n    if not np.isnan(d[\"coords\"]).any():\n        clean_dataset.append(d)\n\nprint(\"Original dataset size:\", len(dataset))\nprint(\"Clean dataset size:\", len(clean_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.396396Z","iopub.execute_input":"2026-02-17T19:51:08.397222Z","iopub.status.idle":"2026-02-17T19:51:08.417736Z","shell.execute_reply.started":"2026-02-17T19:51:08.397167Z","shell.execute_reply":"2026-02-17T19:51:08.41716Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Bir örnek RNA alalım\nsample = clean_dataset[0]\ncoords = sample[\"coords\"]\n\n# Pairwise distance matrix\ndiff = coords[:, None, :] - coords[None, :, :]\ndist_matrix = np.sqrt((diff ** 2).sum(-1))\n\nprint(\"Sequence length:\", len(sample[\"sequence\"]))\nprint(\"Distance matrix shape:\", dist_matrix.shape)\nprint(\"Min distance:\", dist_matrix.min())\nprint(\"Max distance:\", dist_matrix.max())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.418467Z","iopub.execute_input":"2026-02-17T19:51:08.418726Z","iopub.status.idle":"2026-02-17T19:51:08.42456Z","shell.execute_reply.started":"2026-02-17T19:51:08.418701Z","shell.execute_reply":"2026-02-17T19:51:08.424002Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"lengths = [len(d[\"sequence\"]) for d in clean_dataset]\n\nprint(\"Min length:\", min(lengths))\nprint(\"Max length:\", max(lengths))\nprint(\"Mean length:\", sum(lengths)/len(lengths))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.425374Z","iopub.execute_input":"2026-02-17T19:51:08.425636Z","iopub.status.idle":"2026-02-17T19:51:08.437604Z","shell.execute_reply.started":"2026-02-17T19:51:08.425614Z","shell.execute_reply":"2026-02-17T19:51:08.436967Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Nucleotide mapping\nnt_map = {'A':0, 'C':1, 'G':2, 'U':3}\n\ndef encode_sequence(seq):\n    return [nt_map[s] for s in seq]\n\n# test\nsample_seq = clean_dataset[0][\"sequence\"]\nencoded = encode_sequence(sample_seq)\n\nprint(\"Original:\", sample_seq[:20])\nprint(\"Encoded:\", encoded[:20])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.43843Z","iopub.execute_input":"2026-02-17T19:51:08.438758Z","iopub.status.idle":"2026-02-17T19:51:08.449095Z","shell.execute_reply.started":"2026-02-17T19:51:08.438721Z","shell.execute_reply":"2026-02-17T19:51:08.448386Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" class RNADataset(torch.utils.data.Dataset):\n    \n    MAX_LEN = 256\n\n    def __init__(self, data):\n        self.data = data\n\n    def __len__(self):\n        return len(self.data)\n\n    def encode_sequence(self, seq):\n        mapping = {\"A\":0, \"C\":1, \"G\":2, \"U\":3}\n        return torch.tensor([mapping[s] for s in seq], dtype=torch.long)\n\n    def compute_distance(self, coords):\n        coords = torch.tensor(coords, dtype=torch.float32)\n        diff = coords.unsqueeze(0) - coords.unsqueeze(1)\n        dist = torch.sqrt((diff ** 2).sum(-1))\n        return dist\n\n    def __getitem__(self, idx):\n        sample = self.data[idx]\n        \n        seq_encoded = self.encode_sequence(sample[\"sequence\"])\n        dist_matrix = self.compute_distance(sample[\"coords\"])\n        \n        # truncate\n        seq_encoded = seq_encoded[:self.MAX_LEN]\n        dist_matrix = dist_matrix[:self.MAX_LEN, :self.MAX_LEN]\n        \n        dist_matrix = dist_matrix / 100.0\n        \n        return seq_encoded, dist_matrix\n\n    # PyTorch 2.x için güvenli\n    def __getitems__(self, indices):\n        return [self.__getitem__(i) for i in indices]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.449914Z","iopub.execute_input":"2026-02-17T19:51:08.45027Z","iopub.status.idle":"2026-02-17T19:51:08.462735Z","shell.execute_reply.started":"2026-02-17T19:51:08.450247Z","shell.execute_reply":"2026-02-17T19:51:08.4621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass RNATransformer(nn.Module):\n    def __init__(self, embed_dim=128, num_heads=4, num_layers=2):\n        super().__init__()\n        \n        self.embedding = nn.Embedding(4, embed_dim)\n        \n        encoder_layer = nn.TransformerEncoderLayer(\n            d_model=embed_dim,\n            nhead=num_heads,\n            dim_feedforward=256,\n            batch_first=True\n        )\n        \n        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)\n        \n        # pairwise projection\n        self.output_head = nn.Linear(embed_dim * 2, 1)\n        \n    def forward(self, x):\n        # x: (1, N)\n        x = self.embedding(x)            # (1, N, D)\n        x = self.transformer(x)          # (1, N, D)\n        \n        # pairwise combine\n        N = x.size(1)\n        x_i = x.unsqueeze(2).expand(-1, N, N, -1)\n        x_j = x.unsqueeze(1).expand(-1, N, N, -1)\n        \n        pair = torch.cat([x_i, x_j], dim=-1)  # (1, N, N, 2D)\n        \n        dist_pred = self.output_head(pair).squeeze(-1)  # (1, N, N)\n        \n        return dist_pred\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.463673Z","iopub.execute_input":"2026-02-17T19:51:08.464355Z","iopub.status.idle":"2026-02-17T19:51:08.474327Z","shell.execute_reply.started":"2026-02-17T19:51:08.464325Z","shell.execute_reply":"2026-02-17T19:51:08.473631Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"small_clean = [d for d in clean_dataset if len(d[\"sequence\"]) < 200]\n\nprint(\"Small dataset size:\", len(small_clean))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.475231Z","iopub.execute_input":"2026-02-17T19:51:08.475585Z","iopub.status.idle":"2026-02-17T19:51:08.490864Z","shell.execute_reply.started":"2026-02-17T19:51:08.475552Z","shell.execute_reply":"2026-02-17T19:51:08.490333Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data = RNADataset(small_clean[:200])\nprint(\"Dataset size:\", len(train_data))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.491653Z","iopub.execute_input":"2026-02-17T19:51:08.491905Z","iopub.status.idle":"2026-02-17T19:51:08.502001Z","shell.execute_reply.started":"2026-02-17T19:51:08.491884Z","shell.execute_reply":"2026-02-17T19:51:08.501448Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = RNATransformer().to(device)\n\nseq_tensor, dist_tensor = train_data[0]\n\nseq_tensor = seq_tensor.unsqueeze(0).to(device)\ndist_tensor = dist_tensor.unsqueeze(0).to(device)\n\npred = model(seq_tensor)\n\nprint(\"Prediction shape:\", pred.shape)\nprint(\"Target shape:\", dist_tensor.shape)\nprint(\"Model device:\", next(model.parameters()).device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.502723Z","iopub.execute_input":"2026-02-17T19:51:08.502985Z","iopub.status.idle":"2026-02-17T19:51:08.525871Z","shell.execute_reply.started":"2026-02-17T19:51:08.502963Z","shell.execute_reply":"2026-02-17T19:51:08.525323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(clean_dataset)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.526552Z","iopub.execute_input":"2026-02-17T19:51:08.526757Z","iopub.status.idle":"2026-02-17T19:51:08.531577Z","shell.execute_reply.started":"2026-02-17T19:51:08.526735Z","shell.execute_reply":"2026-02-17T19:51:08.53096Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(model)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.532355Z","iopub.execute_input":"2026-02-17T19:51:08.5326Z","iopub.status.idle":"2026-02-17T19:51:08.542844Z","shell.execute_reply.started":"2026-02-17T19:51:08.532576Z","shell.execute_reply":"2026-02-17T19:51:08.542149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sum(p.numel() for p in model.parameters() if p.requires_grad)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.543736Z","iopub.execute_input":"2026-02-17T19:51:08.544015Z","iopub.status.idle":"2026-02-17T19:51:08.553552Z","shell.execute_reply.started":"2026-02-17T19:51:08.543984Z","shell.execute_reply":"2026-02-17T19:51:08.552904Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(next(model.parameters()).device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.554423Z","iopub.execute_input":"2026-02-17T19:51:08.554792Z","iopub.status.idle":"2026-02-17T19:51:08.563983Z","shell.execute_reply.started":"2026-02-17T19:51:08.554751Z","shell.execute_reply":"2026-02-17T19:51:08.563242Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nprint(\"CUDA available:\", torch.cuda.is_available())\nprint(\"Device count:\", torch.cuda.device_count())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.564849Z","iopub.execute_input":"2026-02-17T19:51:08.565198Z","iopub.status.idle":"2026-02-17T19:51:08.575605Z","shell.execute_reply.started":"2026-02-17T19:51:08.565151Z","shell.execute_reply":"2026-02-17T19:51:08.574876Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(next(model.parameters()).device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.576463Z","iopub.execute_input":"2026-02-17T19:51:08.576771Z","iopub.status.idle":"2026-02-17T19:51:08.586953Z","shell.execute_reply.started":"2026-02-17T19:51:08.576749Z","shell.execute_reply":"2026-02-17T19:51:08.586258Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.optim as optim\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = RNATransformer().to(device)\n\ncriterion = nn.MSELoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\n\nmodel.train()\n\nepochs = 3  # şimdilik küçük tutuyoruz\n\nfor epoch in range(epochs):\n    total_loss = 0\n    \n    for i in range(len(train_data)):\n        \n        seq_tensor, dist_tensor = train_data[i]\n        \n        seq_tensor = seq_tensor.unsqueeze(0).to(device)\n        dist_tensor = dist_tensor.unsqueeze(0).to(device)\n        \n        optimizer.zero_grad()\n        \n        pred = model(seq_tensor)\n        \n        loss = criterion(pred, dist_tensor)\n        \n        loss.backward()\n        optimizer.step()\n        \n        total_loss += loss.item()\n    \n    print(f\"Epoch {epoch+1}/{epochs}, Loss: {total_loss/len(train_data):.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:08.58788Z","iopub.execute_input":"2026-02-17T19:51:08.588145Z","iopub.status.idle":"2026-02-17T19:51:11.78343Z","shell.execute_reply.started":"2026-02-17T19:51:08.588123Z","shell.execute_reply":"2026-02-17T19:51:11.782585Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import random_split\n\ntrain_size = int(0.9 * len(train_data))\nval_size = len(train_data) - train_size\n\ntrain_dataset, val_dataset = random_split(train_data, [train_size, val_size])\n\nprint(\"Train size:\", len(train_dataset))\nprint(\"Val size:\", len(val_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:11.784572Z","iopub.execute_input":"2026-02-17T19:51:11.785529Z","iopub.status.idle":"2026-02-17T19:51:11.790827Z","shell.execute_reply.started":"2026-02-17T19:51:11.785504Z","shell.execute_reply":"2026-02-17T19:51:11.790241Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn.functional as F\n\ndef collate_fn(batch):\n    sequences, distances = zip(*batch)\n    \n    max_len = max(seq.shape[0] for seq in sequences)\n    \n    padded_seqs = []\n    padded_dists = []\n    \n    for seq, dist in zip(sequences, distances):\n        pad_len = max_len - seq.shape[0]\n        \n        # sequence padding\n        seq_padded = F.pad(seq, (0, pad_len), value=0)\n        padded_seqs.append(seq_padded)\n        \n        # distance matrix padding\n        dist_padded = F.pad(dist, (0, pad_len, 0, pad_len), value=0)\n        padded_dists.append(dist_padded)\n    \n    return torch.stack(padded_seqs), torch.stack(padded_dists)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:11.79164Z","iopub.execute_input":"2026-02-17T19:51:11.791866Z","iopub.status.idle":"2026-02-17T19:51:11.802844Z","shell.execute_reply.started":"2026-02-17T19:51:11.791844Z","shell.execute_reply":"2026-02-17T19:51:11.802165Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True, collate_fn=collate_fn)\nval_loader = DataLoader(val_dataset, batch_size=16, shuffle=False, collate_fn=collate_fn)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:11.803743Z","iopub.execute_input":"2026-02-17T19:51:11.803967Z","iopub.status.idle":"2026-02-17T19:51:11.8146Z","shell.execute_reply.started":"2026-02-17T19:51:11.803947Z","shell.execute_reply":"2026-02-17T19:51:11.8139Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.optim as optim\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = RNATransformer().to(device)\n\ncriterion = nn.MSELoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\n\nepochs = 10\nbest_val_loss = float(\"inf\")\n\nfor epoch in range(epochs):\n    \n    # TRAIN\n    model.train()\n    train_loss = 0\n    \n    for seq, dist in train_loader:\n        seq = seq.to(device)\n        dist = dist.to(device)\n        \n        optimizer.zero_grad()\n        pred = model(seq)\n        loss = criterion(pred, dist)\n        loss.backward()\n        optimizer.step()\n        \n        train_loss += loss.item()\n    \n    train_loss /= len(train_loader)\n    \n    # VALIDATION\n    model.eval()\n    val_loss = 0\n    \n    with torch.no_grad():\n        for seq, dist in val_loader:\n            seq = seq.to(device)\n            dist = dist.to(device)\n            \n            pred = model(seq)\n            loss = criterion(pred, dist)\n            val_loss += loss.item()\n    \n    val_loss /= len(val_loader)\n    \n    print(f\"Epoch {epoch+1}/{epochs} | Train: {train_loss:.4f} | Val: {val_loss:.4f}\")\n    \n    # Model kaydet\n    if val_loss < best_val_loss:\n        best_val_loss = val_loss\n        torch.save(model.state_dict(), \"best_model.pth\")\n        print(\"✓ Model saved\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:11.815431Z","iopub.execute_input":"2026-02-17T19:51:11.815625Z","iopub.status.idle":"2026-02-17T19:51:13.249512Z","shell.execute_reply.started":"2026-02-17T19:51:11.815607Z","shell.execute_reply":"2026-02-17T19:51:13.248758Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(len(clean_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.250507Z","iopub.execute_input":"2026-02-17T19:51:13.250951Z","iopub.status.idle":"2026-02-17T19:51:13.255043Z","shell.execute_reply.started":"2026-02-17T19:51:13.250917Z","shell.execute_reply":"2026-02-17T19:51:13.254258Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_dataset = RNADataset(clean_dataset)\nprint(\"Full dataset:\", len(full_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.255945Z","iopub.execute_input":"2026-02-17T19:51:13.256528Z","iopub.status.idle":"2026-02-17T19:51:13.267639Z","shell.execute_reply.started":"2026-02-17T19:51:13.256503Z","shell.execute_reply":"2026-02-17T19:51:13.266896Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import random_split\n\ntrain_size = int(0.9 * len(full_dataset))\nval_size = len(full_dataset) - train_size\n\ntrain_dataset, val_dataset = random_split(full_dataset, [train_size, val_size])\n\nprint(\"Train:\", len(train_dataset))\nprint(\"Val:\", len(val_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.268698Z","iopub.execute_input":"2026-02-17T19:51:13.269251Z","iopub.status.idle":"2026-02-17T19:51:13.282762Z","shell.execute_reply.started":"2026-02-17T19:51:13.269171Z","shell.execute_reply":"2026-02-17T19:51:13.282076Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True, collate_fn=collate_fn)\nval_loader = DataLoader(val_dataset, batch_size=16, shuffle=False, collate_fn=collate_fn)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.283437Z","iopub.execute_input":"2026-02-17T19:51:13.283739Z","iopub.status.idle":"2026-02-17T19:51:13.293225Z","shell.execute_reply.started":"2026-02-17T19:51:13.28369Z","shell.execute_reply":"2026-02-17T19:51:13.292685Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = RNATransformer().to(device)\n\ncriterion = torch.nn.MSELoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n\nprint(\"Model device:\", next(model.parameters()).device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.297124Z","iopub.execute_input":"2026-02-17T19:51:13.297443Z","iopub.status.idle":"2026-02-17T19:51:13.31427Z","shell.execute_reply.started":"2026-02-17T19:51:13.297421Z","shell.execute_reply":"2026-02-17T19:51:13.31365Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(type(train_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.315011Z","iopub.execute_input":"2026-02-17T19:51:13.315298Z","iopub.status.idle":"2026-02-17T19:51:13.318711Z","shell.execute_reply.started":"2026-02-17T19:51:13.315268Z","shell.execute_reply":"2026-02-17T19:51:13.318007Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_dataset = RNADataset(clean_dataset)\nprint(type(full_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.319747Z","iopub.execute_input":"2026-02-17T19:51:13.32003Z","iopub.status.idle":"2026-02-17T19:51:13.331794Z","shell.execute_reply.started":"2026-02-17T19:51:13.319998Z","shell.execute_reply":"2026-02-17T19:51:13.331249Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import random_split\n\ntrain_size = int(0.9 * len(full_dataset))\nval_size = len(full_dataset) - train_size\n\ntrain_dataset, val_dataset = random_split(full_dataset, [train_size, val_size])\n\nprint(\"Train:\", len(train_dataset))\nprint(\"Val:\", len(val_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.332545Z","iopub.execute_input":"2026-02-17T19:51:13.332811Z","iopub.status.idle":"2026-02-17T19:51:13.342651Z","shell.execute_reply.started":"2026-02-17T19:51:13.33279Z","shell.execute_reply":"2026-02-17T19:51:13.342077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\ntrain_loader = DataLoader(train_dataset, batch_size=8, shuffle=True, collate_fn=collate_fn)\nval_loader = DataLoader(val_dataset, batch_size=8, shuffle=False, collate_fn=collate_fn)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.343418Z","iopub.execute_input":"2026-02-17T19:51:13.343671Z","iopub.status.idle":"2026-02-17T19:51:13.355609Z","shell.execute_reply.started":"2026-02-17T19:51:13.343651Z","shell.execute_reply":"2026-02-17T19:51:13.355077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"type(full_dataset)\ntype(train_dataset)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.356341Z","iopub.execute_input":"2026-02-17T19:51:13.357014Z","iopub.status.idle":"2026-02-17T19:51:13.368559Z","shell.execute_reply.started":"2026-02-17T19:51:13.356992Z","shell.execute_reply":"2026-02-17T19:51:13.367963Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(type(full_dataset))\nprint(type(train_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.369506Z","iopub.execute_input":"2026-02-17T19:51:13.369704Z","iopub.status.idle":"2026-02-17T19:51:13.380706Z","shell.execute_reply.started":"2026-02-17T19:51:13.369676Z","shell.execute_reply":"2026-02-17T19:51:13.380133Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import Subset\nimport numpy as np\n\nfull_dataset = RNADataset(clean_dataset)\n\nindices = np.arange(len(full_dataset))\nnp.random.shuffle(indices)\n\nsplit = int(0.9 * len(indices))\n\ntrain_indices = indices[:split]\nval_indices = indices[split:]\n\ntrain_dataset = Subset(full_dataset, train_indices)\nval_dataset = Subset(full_dataset, val_indices)\n\nprint(\"Train:\", len(train_dataset))\nprint(\"Val:\", len(val_dataset))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.381639Z","iopub.execute_input":"2026-02-17T19:51:13.382076Z","iopub.status.idle":"2026-02-17T19:51:13.392413Z","shell.execute_reply.started":"2026-02-17T19:51:13.382043Z","shell.execute_reply":"2026-02-17T19:51:13.391848Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\ntrain_loader = DataLoader(train_dataset, batch_size=8, shuffle=True, collate_fn=collate_fn)\nval_loader = DataLoader(val_dataset, batch_size=8, shuffle=False, collate_fn=collate_fn)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.393267Z","iopub.execute_input":"2026-02-17T19:51:13.39355Z","iopub.status.idle":"2026-02-17T19:51:13.404576Z","shell.execute_reply.started":"2026-02-17T19:51:13.393529Z","shell.execute_reply":"2026-02-17T19:51:13.404034Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 3\nbest_val_loss = float(\"inf\")\n\nfor epoch in range(epochs):\n    \n    # ===== TRAIN =====\n    model.train()\n    train_loss = 0.0\n    \n    for seq, dist in train_loader:\n        seq = seq.to(device)\n        dist = dist.to(device)\n        \n        optimizer.zero_grad()\n        \n        pred = model(seq)\n        loss = criterion(pred, dist)\n        \n        loss.backward()\n        optimizer.step()\n        \n        train_loss += loss.item()\n    \n    train_loss /= len(train_loader)\n    \n    \n    # ===== VALIDATION =====\n    model.eval()\n    val_loss = 0.0\n    \n    with torch.no_grad():\n        for seq, dist in val_loader:\n            seq = seq.to(device)\n            dist = dist.to(device)\n            \n            pred = model(seq)\n            loss = criterion(pred, dist)\n            \n            val_loss += loss.item()\n    \n    val_loss /= len(val_loader)\n    \n    \n    print(f\"Epoch {epoch+1}/{epochs} | Train: {train_loss:.4f} | Val: {val_loss:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:13.405471Z","iopub.execute_input":"2026-02-17T19:51:13.405765Z","iopub.status.idle":"2026-02-17T19:51:28.334096Z","shell.execute_reply.started":"2026-02-17T19:51:13.405735Z","shell.execute_reply":"2026-02-17T19:51:28.333274Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nfor file in os.listdir(\"/kaggle/input/stanford-rna-3d-folding-2\"):\n    print(file)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:28.33513Z","iopub.execute_input":"2026-02-17T19:51:28.335549Z","iopub.status.idle":"2026-02-17T19:51:28.34147Z","shell.execute_reply.started":"2026-02-17T19:51:28.335504Z","shell.execute_reply":"2026-02-17T19:51:28.340871Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\nlabels = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv\")\nlabels.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:28.342267Z","iopub.execute_input":"2026-02-17T19:51:28.34248Z","iopub.status.idle":"2026-02-17T19:51:35.007863Z","shell.execute_reply.started":"2026-02-17T19:51:28.34246Z","shell.execute_reply":"2026-02-17T19:51:35.007157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels.columns\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:51:35.00869Z","iopub.execute_input":"2026-02-17T19:51:35.008962Z","iopub.status.idle":"2026-02-17T19:51:35.013793Z","shell.execute_reply.started":"2026-02-17T19:51:35.00894Z","shell.execute_reply":"2026-02-17T19:51:35.013086Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def collate_fn(batch):\n    \"\"\"\n    batch: list of (seq_encoded, coords)\n    \"\"\"\n\n    seqs, coords = zip(*batch)\n\n    lengths = [len(s) for s in seqs]\n    max_len = max(lengths)\n\n    padded_seqs = []\n    padded_coords = []\n    masks = []\n\n    for seq, coord in zip(seqs, coords):\n        pad_len = max_len - len(seq)\n\n        # sequence padding (pad token = 0)\n        padded_seq = torch.cat([\n            seq,\n            torch.zeros(pad_len, dtype=torch.long)\n        ])\n\n        # coordinate padding\n        padded_coord = torch.cat([\n            coord,\n            torch.zeros(pad_len, 3)\n        ])\n\n        # mask (1 = real token, 0 = padding)\n        mask = torch.cat([\n            torch.ones(len(seq)),\n            torch.zeros(pad_len)\n        ])\n\n        padded_seqs.append(padded_seq)\n        padded_coords.append(padded_coord)\n        masks.append(mask)\n\n    return (\n        torch.stack(padded_seqs),\n        torch.stack(padded_coords),\n        torch.stack(masks)\n    )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:53:09.687436Z","iopub.execute_input":"2026-02-17T19:53:09.688047Z","iopub.status.idle":"2026-02-17T19:53:09.694335Z","shell.execute_reply.started":"2026-02-17T19:53:09.688015Z","shell.execute_reply":"2026-02-17T19:53:09.693507Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_loader = DataLoader(\n    train_dataset,\n    batch_size=16,\n    shuffle=True,\n    collate_fn=collate_fn\n)\n\nval_loader = DataLoader(\n    val_dataset,\n    batch_size=16,\n    shuffle=False,\n    collate_fn=collate_fn\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T19:53:44.926395Z","iopub.execute_input":"2026-02-17T19:53:44.926723Z","iopub.status.idle":"2026-02-17T19:53:44.931054Z","shell.execute_reply.started":"2026-02-17T19:53:44.926696Z","shell.execute_reply":"2026-02-17T19:53:44.930337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" import torch\nimport pandas as pd\nfrom torch.utils.data import Dataset, DataLoader\n\n# -------------------------\n# 1) CSV yükleme\n# -------------------------\n\ntrain_seq = pd.read_csv(\n    \"/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv\"\n)\n\ntrain_labels = pd.read_csv(\n    \"/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv\",\n    low_memory=False\n)\n\n# -------------------------\n# 2) Labels içinden base target id çıkar\n#    (157D_1 -> 157D)\n# -------------------------\n\ntrain_labels[\"base_id\"] = train_labels[\"ID\"].str.split(\"_\").str[0]\n\n# -------------------------\n# 3) Sadece label'ı olan targetları tut\n# -------------------------\n\nvalid_ids = set(train_labels[\"base_id\"].unique())\n\ntrain_seq_filtered = train_seq[\n    train_seq[\"target_id\"].isin(valid_ids)\n].reset_index(drop=True)\n\nprint(\"Toplam sequence:\", len(train_seq))\nprint(\"Label olan sequence:\", len(train_seq_filtered))\n\n# -------------------------\n# 4) Groupby base_id\n# -------------------------\n\ngrouped_labels = train_labels.groupby(\"base_id\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:15:02.173026Z","iopub.execute_input":"2026-02-17T20:15:02.173677Z","iopub.status.idle":"2026-02-17T20:15:29.230816Z","shell.execute_reply.started":"2026-02-17T20:15:02.173643Z","shell.execute_reply":"2026-02-17T20:15:29.230077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_seq = pd.read_csv(\n    \"/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv\"\n)\n\ntrain_labels = pd.read_csv(\n    \"/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv\",\n    low_memory=False\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:09:57.704877Z","iopub.execute_input":"2026-02-17T20:09:57.705495Z","iopub.status.idle":"2026-02-17T20:10:07.816432Z","shell.execute_reply.started":"2026-02-17T20:09:57.705464Z","shell.execute_reply":"2026-02-17T20:10:07.815623Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"valid_ids = set(train_labels[\"ID\"].unique())\n\ntrain_seq_filtered = train_seq[\n    train_seq[\"target_id\"].isin(valid_ids)\n].reset_index(drop=True)\n\nprint(\"Toplam sequence:\", len(train_seq))\nprint(\"Label olan sequence:\", len(train_seq_filtered))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:10:16.12891Z","iopub.execute_input":"2026-02-17T20:10:16.129534Z","iopub.status.idle":"2026-02-17T20:10:29.093Z","shell.execute_reply.started":"2026-02-17T20:10:16.129503Z","shell.execute_reply":"2026-02-17T20:10:29.092331Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"grouped_labels = train_labels.groupby(\"ID\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:10:33.108519Z","iopub.execute_input":"2026-02-17T20:10:33.109127Z","iopub.status.idle":"2026-02-17T20:10:33.112763Z","shell.execute_reply.started":"2026-02-17T20:10:33.109099Z","shell.execute_reply":"2026-02-17T20:10:33.11196Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" class RNADataset(Dataset):\n    def __init__(self, seq_df, grouped_labels):\n        self.seq_df = seq_df\n        self.grouped_labels = grouped_labels\n        self.vocab = {\"A\":0, \"C\":1, \"G\":2, \"U\":3}\n\n    def __len__(self):\n        return len(self.seq_df)\n\n    def __getitem__(self, idx):\n        row = self.seq_df.iloc[idx]\n        seq_id = row[\"target_id\"]\n        sequence = row[\"sequence\"]\n\n        seq_encoded = torch.tensor(\n            [self.vocab[s] for s in sequence],\n            dtype=torch.long\n        )\n\n        coords_np = self.grouped_labels.get_group(seq_id)[[\"x_1\",\"y_1\",\"z_1\"]].values\n        coords = torch.tensor(coords_np, dtype=torch.float32)\n\n        return seq_encoded, coords\n\n\ndef collate_fn(batch):\n    seqs, coords = zip(*batch)\n\n    max_len = max(len(s) for s in seqs)\n\n    padded_seqs = []\n    padded_coords = []\n\n    for s, c in zip(seqs, coords):\n        pad_len = max_len - len(s)\n\n        s_padded = torch.cat([s, torch.zeros(pad_len, dtype=torch.long)])\n        c_padded = torch.cat([c, torch.zeros(pad_len, 3)])\n\n        padded_seqs.append(s_padded)\n        padded_coords.append(c_padded)\n\n    return torch.stack(padded_seqs), torch.stack(padded_coords)\n\n\ntrain_dataset = RNADataset(train_seq_filtered, grouped_labels)\n\ntrain_loader = DataLoader(\n    train_dataset,\n    batch_size=8,\n    shuffle=True,\n    collate_fn=collate_fn\n)\n\nfor s, c in train_loader:\n    print(\"seq:\", s.shape)\n    print(\"coords:\", c.shape)\n    break\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:16:01.379178Z","iopub.execute_input":"2026-02-17T20:16:01.379925Z","iopub.status.idle":"2026-02-17T20:16:02.901285Z","shell.execute_reply.started":"2026-02-17T20:16:01.379896Z","shell.execute_reply":"2026-02-17T20:16:02.900572Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def collate_fn(batch):\n    seqs, coords = zip(*batch)\n\n    max_len = max(len(s) for s in seqs)\n\n    padded_seqs = []\n    padded_coords = []\n\n    for s, c in zip(seqs, coords):\n        pad_len = max_len - len(s)\n\n        s_padded = torch.cat([s, torch.zeros(pad_len, dtype=torch.long)])\n        c_padded = torch.cat([c, torch.zeros(pad_len, 3)])\n\n        padded_seqs.append(s_padded)\n        padded_coords.append(c_padded)\n\n    return torch.stack(padded_seqs), torch.stack(padded_coords)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:11:05.821557Z","iopub.execute_input":"2026-02-17T20:11:05.821862Z","iopub.status.idle":"2026-02-17T20:11:05.826912Z","shell.execute_reply.started":"2026-02-17T20:11:05.821833Z","shell.execute_reply":"2026-02-17T20:11:05.82625Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train_labels[\"ID\"].head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:17:52.944492Z","iopub.execute_input":"2026-02-17T20:17:52.945174Z","iopub.status.idle":"2026-02-17T20:17:52.949882Z","shell.execute_reply.started":"2026-02-17T20:17:52.945142Z","shell.execute_reply":"2026-02-17T20:17:52.94916Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train_seq[\"target_id\"].head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:18:11.936759Z","iopub.execute_input":"2026-02-17T20:18:11.937343Z","iopub.status.idle":"2026-02-17T20:18:11.941754Z","shell.execute_reply.started":"2026-02-17T20:18:11.93731Z","shell.execute_reply":"2026-02-17T20:18:11.94097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir(\"/kaggle/input\"))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:20:01.14526Z","iopub.execute_input":"2026-02-17T20:20:01.145604Z","iopub.status.idle":"2026-02-17T20:20:01.150036Z","shell.execute_reply.started":"2026-02-17T20:20:01.145575Z","shell.execute_reply":"2026-02-17T20:20:01.149253Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train_labels[\"ID\"].str.split(\"_\").str[0].unique()[:10])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:21:28.499994Z","iopub.execute_input":"2026-02-17T20:21:28.500375Z","iopub.status.idle":"2026-02-17T20:21:37.529529Z","shell.execute_reply.started":"2026-02-17T20:21:28.500343Z","shell.execute_reply":"2026-02-17T20:21:37.528811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train_seq[\"target_id\"].unique()[:10])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-17T20:21:47.989047Z","iopub.execute_input":"2026-02-17T20:21:47.989617Z","iopub.status.idle":"2026-02-17T20:21:48.423432Z","shell.execute_reply.started":"2026-02-17T20:21:47.989584Z","shell.execute_reply":"2026-02-17T20:21:48.422734Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport pandas as pd\n\nfrom torch.utils.data import Dataset, DataLoader\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Sadece ilk 50 target ile çalışalım\ntrain_seq = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv\")\ntrain_labels = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv\", low_memory=False)\n\ntrain_labels = train_labels.dropna(subset=[\"x_1\",\"y_1\",\"z_1\"])\n\ntrain_labels[\"base_id\"] = train_labels[\"ID\"].str.split(\"_\").str[0]\n\nsubset_ids = train_labels[\"base_id\"].unique()[:50]\n\ntrain_seq = train_seq[train_seq[\"target_id\"].isin(subset_ids)].reset_index(drop=True)\ntrain_labels = train_labels[train_labels[\"base_id\"].isin(subset_ids)]\n\ngrouped_labels = train_labels.groupby(\"base_id\")\n\nprint(\"Sequence sayısı:\", len(train_seq))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:17:37.309933Z","iopub.execute_input":"2026-02-20T19:17:37.310233Z","iopub.status.idle":"2026-02-20T19:18:05.653015Z","shell.execute_reply.started":"2026-02-20T19:17:37.310201Z","shell.execute_reply":"2026-02-20T19:18:05.652154Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class RNADataset(Dataset):\n    def __init__(self, seq_df, grouped_labels):\n        self.seq_df = seq_df\n        self.grouped_labels = grouped_labels\n        self.vocab = {\"A\":0, \"C\":1, \"G\":2, \"U\":3}\n\n    def __len__(self):\n        return len(self.seq_df)\n\n    def __getitem__(self, idx):\n        row = self.seq_df.iloc[idx]\n        seq_id = row[\"target_id\"]\n        sequence = row[\"sequence\"]\n\n        seq_encoded = torch.tensor(\n            [self.vocab.get(s,0) for s in sequence],\n            dtype=torch.long\n        )\n\n        coords_np = self.grouped_labels.get_group(seq_id)[[\"x_1\",\"y_1\",\"z_1\"]].values\n        coords = torch.tensor(coords_np, dtype=torch.float32)\n\n        min_len = min(len(seq_encoded), len(coords))\n\n        return seq_encoded[:min_len], coords[:min_len]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:18:12.271137Z","iopub.execute_input":"2026-02-20T19:18:12.271473Z","iopub.status.idle":"2026-02-20T19:18:12.277748Z","shell.execute_reply.started":"2026-02-20T19:18:12.271445Z","shell.execute_reply":"2026-02-20T19:18:12.276903Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" def collate_fn(batch):\n    seqs, coords = zip(*batch)\n\n    max_len = max(len(s) for s in seqs)\n\n    padded_seqs = []\n    padded_coords = []\n\n    for s, c in zip(seqs, coords):\n        pad_len = max_len - len(s)\n\n        s_padded = torch.cat([s, torch.zeros(pad_len, dtype=torch.long)])\n        c_padded = torch.cat([c, torch.zeros(pad_len, 3)])\n\n        padded_seqs.append(s_padded)\n        padded_coords.append(c_padded)\n\n    return torch.stack(padded_seqs), torch.stack(padded_coords)\n\n\n# Dataset oluştur\ndataset = RNADataset(train_seq, grouped_labels)\n\n# 🔥 Train / Validation split\nfrom torch.utils.data import random_split\n\ntrain_size = int(0.8 * len(dataset))\nval_size = len(dataset) - train_size\n\ntrain_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n\n# 🔥 İki ayrı loader\ntrain_loader = DataLoader(\n    train_dataset,\n    batch_size=8,\n    shuffle=True,\n    collate_fn=collate_fn\n)\n\nval_loader = DataLoader(\n    val_dataset,\n    batch_size=8,\n    shuffle=False,\n    collate_fn=collate_fn\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:31:28.941142Z","iopub.execute_input":"2026-02-20T19:31:28.941507Z","iopub.status.idle":"2026-02-20T19:31:28.950005Z","shell.execute_reply.started":"2026-02-20T19:31:28.941477Z","shell.execute_reply":"2026-02-20T19:31:28.949182Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" class SimpleModel(nn.Module):\n    def __init__(self):\n        super().__init__()\n        \n        self.embedding = nn.Embedding(4, 32)\n        \n        self.lstm = nn.LSTM(\n            input_size=32,\n            hidden_size=256,\n            num_layers=2,\n            batch_first=True,\n            bidirectional=True,\n            dropout=0.3\n        )\n        \n        self.norm = nn.LayerNorm(512)   # <-- BUNU EKLE\n        \n        self.fc = nn.Linear(512, 3)\n\n    def forward(self, x):\n        x = self.embedding(x)\n        x, _ = self.lstm(x)\n        x = self.norm(x)                # <-- BUNU EKLE\n        x = self.fc(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:41:34.788706Z","iopub.execute_input":"2026-02-20T19:41:34.789499Z","iopub.status.idle":"2026-02-20T19:41:34.795039Z","shell.execute_reply.started":"2026-02-20T19:41:34.789467Z","shell.execute_reply":"2026-02-20T19:41:34.79436Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" model.train()\n\nmean = train_labels[[\"x_1\",\"y_1\",\"z_1\"]].mean().values\nstd = train_labels[[\"x_1\",\"y_1\",\"z_1\"]].std().values\n\nmean = torch.tensor(mean, dtype=torch.float32).to(device)\nstd = torch.tensor(std, dtype=torch.float32).to(device)\n\nEPOCHS = 20\n\nfor epoch in range(EPOCHS):\n\n    # ===== TRAIN =====\n    model.train()\n    train_loss = 0\n\n    for seq, coords in train_loader:\n        seq = seq.to(device)\n        coords = coords.to(device)\n\n        coords = (coords - mean) / std\n\n        optimizer.zero_grad()\n        output = model(seq)\n\n        loss = criterion(output, coords)\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item()\n\n    train_loss /= len(train_loader)\n\n\n    # ===== VALIDATION =====\n    model.eval()\n    val_loss = 0\n\n    with torch.no_grad():\n        for seq, coords in val_loader:\n            seq = seq.to(device)\n            coords = coords.to(device)\n\n            coords = (coords - mean) / std\n            output = model(seq)\n\n            loss = criterion(output, coords)\n            val_loss += loss.item()\n\n    val_loss /= len(val_loader)\n    optimizer = optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5)\n    scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau\n     \n\n    print(f\"Epoch {epoch+1}/{EPOCHS} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:44:59.534245Z","iopub.execute_input":"2026-02-20T19:44:59.53483Z","iopub.status.idle":"2026-02-20T19:45:14.151223Z","shell.execute_reply.started":"2026-02-20T19:44:59.534802Z","shell.execute_reply":"2026-02-20T19:45:14.150437Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" model.train()\n\nfor seq, coords in loader:\n    seq = seq.to(device)\n    coords = coords.to(device)\n\n    coords = (coords - mean) / std\n\n    optimizer.zero_grad()\n\n    output = model(seq)\n    loss = criterion(output, coords)\n\n    loss.backward()\n    torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)\n    optimizer.step()\n     ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:48:25.385468Z","iopub.execute_input":"2026-02-20T19:48:25.385812Z","iopub.status.idle":"2026-02-20T19:48:26.43168Z","shell.execute_reply.started":"2026-02-20T19:48:25.385783Z","shell.execute_reply":"2026-02-20T19:48:26.43101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\n\nseq, coords = next(iter(loader))\nseq = seq.to(device)\ncoords = coords.to(device)\n\ncoords_norm = (coords - mean) / std\n\nwith torch.no_grad():\n    pred = model(seq)\n\n# Denormalize\npred_denorm = pred * std + mean\n\ntrue = coords[0].cpu().numpy()\npredicted = pred_denorm[0].cpu().numpy()\n\nprint(true[:5])\nprint(predicted[:5])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:48:32.703404Z","iopub.execute_input":"2026-02-20T19:48:32.704366Z","iopub.status.idle":"2026-02-20T19:48:32.731694Z","shell.execute_reply.started":"2026-02-20T19:48:32.704328Z","shell.execute_reply":"2026-02-20T19:48:32.731017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.plot(true[:,0], label=\"True X\")\nplt.plot(predicted[:,0], label=\"Pred X\")\nplt.legend()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:19:13.704255Z","iopub.execute_input":"2026-02-20T19:19:13.705078Z","iopub.status.idle":"2026-02-20T19:19:13.890215Z","shell.execute_reply.started":"2026-02-20T19:19:13.705046Z","shell.execute_reply":"2026-02-20T19:19:13.889545Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(coords_norm[0][:10])\nprint(coords_norm.mean())\nprint(coords_norm.std())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:19:15.838398Z","iopub.execute_input":"2026-02-20T19:19:15.839218Z","iopub.status.idle":"2026-02-20T19:19:16.024248Z","shell.execute_reply.started":"2026-02-20T19:19:15.839184Z","shell.execute_reply":"2026-02-20T19:19:16.023614Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(pred.std())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:19:21.412712Z","iopub.execute_input":"2026-02-20T19:19:21.413537Z","iopub.status.idle":"2026-02-20T19:19:21.419025Z","shell.execute_reply.started":"2026-02-20T19:19:21.413503Z","shell.execute_reply":"2026-02-20T19:19:21.418378Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\n\nfig = plt.figure()\nax = fig.add_subplot(111, projection='3d')\n\n# Gerçek RNA\nax.plot(true[:,0], true[:,1], true[:,2], label=\"True\", linewidth=2)\n\n# Tahmin RNA\nax.plot(predicted[:,0], predicted[:,1], predicted[:,2], label=\"Pred\", linewidth=2)\n\nax.legend()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T19:49:16.052646Z","iopub.execute_input":"2026-02-20T19:49:16.053289Z","iopub.status.idle":"2026-02-20T19:49:16.190014Z","shell.execute_reply.started":"2026-02-20T19:49:16.053257Z","shell.execute_reply":"2026-02-20T19:49:16.18934Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom torch.utils.data import Dataset, DataLoader\nfrom mpl_toolkits.mplot3d import Axes3D\n\n# 1. VERİ YÜKLEME VE DELTA HESAPLAMA\nprint(\"Veriler yükleniyor (500 örnek)...\")\ntrain_seq = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv\")\ntrain_labels = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv\", low_memory=False)\n\ntrain_labels = train_labels.dropna(subset=[\"x_1\",\"y_1\",\"z_1\"])\ntrain_labels[\"base_id\"] = train_labels[\"ID\"].str.split(\"_\").str[0]\n\n# Veri setini büyütüyoruz (Daha sağlam öğrenme için)\nsubset_ids = train_labels[\"base_id\"].unique()[:500] \ntrain_seq = train_seq[train_seq[\"target_id\"].isin(subset_ids)].reset_index(drop=True)\ntrain_labels = train_labels[train_labels[\"base_id\"].isin(subset_ids)]\ngrouped_labels = train_labels.groupby(\"base_id\")\n\nclass RNADataset(Dataset):\n    def __init__(self, seq_df, grouped_labels):\n        self.seq_df = seq_df\n        self.grouped_labels = grouped_labels\n        self.vocab = {\"A\":0, \"C\":1, \"G\":2, \"U\":3}\n\n    def __len__(self):\n        return len(self.seq_df)\n\n    def __getitem__(self, idx):\n        row = self.seq_df.iloc[idx]\n        seq_id = row[\"target_id\"]\n        sequence = row[\"sequence\"]\n        seq_encoded = torch.tensor([self.vocab.get(s, 0) for s in sequence], dtype=torch.long)\n        \n        coords = self.grouped_labels.get_group(seq_id)[[\"x_1\",\"y_1\",\"z_1\"]].values\n        coords = torch.tensor(coords, dtype=torch.float32)\n        \n        # --- KRİTİK DEĞİŞİKLİK: DELTA (FARK) HESAPLAMA ---\n        # Her nükleotidin bir önceki nükleotide göre farkını alıyoruz\n        deltas = torch.zeros_like(coords)\n        deltas[1:] = coords[1:] - coords[:-1] \n        # İlk nükleotit başlangıç noktası olarak kalsın veya 0 olsun\n        \n        min_len = min(len(seq_encoded), len(deltas))\n        return seq_encoded[:min_len], deltas[:min_len], coords[:min_len]\n\ndef collate_fn(batch):\n    seqs, deltas, coords = zip(*batch)\n    max_len = max(len(s) for s in seqs)\n    padded_seqs = torch.stack([torch.cat([s, torch.zeros(max_len - len(s), dtype=torch.long)]) for s in seqs])\n    padded_deltas = torch.stack([torch.cat([d, torch.zeros(max_len - len(d), 3)]) for d in deltas])\n    return padded_seqs, padded_deltas, coords[0] # Test için ham koordinatları da sakla\n\ndataset = RNADataset(train_seq, grouped_labels)\ntrain_loader = DataLoader(dataset, batch_size=16, shuffle=True, collate_fn=collate_fn)\n\n# 2. GELİŞMİŞ MODEL (Bi-LSTM + Residual mantığı)\nclass RNAModel(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.embedding = nn.Embedding(4, 128)\n        self.lstm = nn.LSTM(128, 512, num_layers=3, batch_first=True, bidirectional=True, dropout=0.3)\n        self.fc = nn.Sequential(\n            nn.Linear(1024, 256),\n            nn.ReLU(),\n            nn.Dropout(0.2),\n            nn.Linear(256, 3) # Tahmin edilen şey: Delta (x,y,z)\n        )\n\n    def forward(self, x):\n        x = self.embedding(x)\n        x, _ = self.lstm(x)\n        return self.fc(x)\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = RNAModel().to(device)\n\n# 3. EĞİTİM (Optimizer dışarıda, Scheduler eklendi)\ncriterion = nn.MSELoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-3)\nscheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)\n\nprint(f\"Eğitim başlıyor ({device})...\")\nmodel.train()\nfor epoch in range(25):\n    epoch_loss = 0\n    for seq, deltas, _ in train_loader:\n        seq, deltas = seq.to(device), deltas.to(device)\n        \n        optimizer.zero_grad()\n        output_deltas = model(seq)\n        loss = criterion(output_deltas, deltas)\n        loss.backward()\n        optimizer.step()\n        epoch_loss += loss.item()\n    \n    scheduler.step()\n    if (epoch+1) % 5 == 0:\n        print(f\"Epoch {epoch+1}/25 | Loss: {epoch_loss/len(train_loader):.6f}\")\n\n# 4. REKONSTRÜKSİYON VE GÖRSELLEŞTİRME\nprint(\"Görselleştirme hazırlanıyor...\")\nmodel.eval()\nwith torch.no_grad():\n    # Rastgele bir örnek al\n    test_seq, test_deltas, true_coords = dataset[10] # 10. örneği inceleyelim\n    pred_deltas = model(test_seq.unsqueeze(0).to(device)).cpu().squeeze(0).numpy()\n    \n    # Deltalardan koordinatlara geri dön (Cumulative Sum)\n    # p_i = p_0 + sum(deltas)\n    true_coords_np = true_coords.numpy()\n    pred_coords = np.cumsum(pred_deltas, axis=0) \n    \n    # Başlangıç noktasını gerçek koordinatla eşitle (Karşılaştırma için)\n    pred_coords = pred_coords - pred_coords[0] + true_coords_np[0]\n\nfig = plt.figure(figsize=(12, 8))\nax = fig.add_subplot(111, projection='3d')\nax.plot(true_coords_np[:,0], true_coords_np[:,1], true_coords_np[:,2], label=\"Gerçek Yapı\", color='blue', alpha=0.8)\nax.plot(pred_coords[:,0], pred_coords[:,1], pred_coords[:,2], label=\"Delta Tahmini (Gelişmiş)\", color='red', linestyle='--', alpha=0.8)\nax.set_title(\"RNA 3D Katlanma (Relatif Adım Tahmini)\")\nax.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-25T21:03:39.017614Z","iopub.execute_input":"2026-02-25T21:03:39.01801Z","iopub.status.idle":"2026-02-25T21:30:08.546642Z","shell.execute_reply.started":"2026-02-25T21:03:39.01798Z","shell.execute_reply":"2026-02-25T21:30:08.545863Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}