{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceType":"competition","sourceId":118765,"databundleVersionId":15231210}],"dockerImageVersionId":31260,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.status.busy":"2026-02-19T10:47:47.681306Z","iopub.execute_input":"2026-02-19T10:47:47.68156Z","iopub.status.idle":"2026-02-19T10:47:48.706287Z","shell.execute_reply.started":"2026-02-19T10:47:47.681532Z","shell.execute_reply":"2026-02-19T10:47:48.705528Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_labels = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv')\ntrain_labels['chain'] = train_labels['chain'].map(str)\n\nval_labels = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/validation_labels.csv')\nval_labels['chain'] = val_labels['chain'].map(str)","metadata":{"execution":{"iopub.status.busy":"2026-02-19T10:47:48.707847Z","iopub.execute_input":"2026-02-19T10:47:48.708193Z","iopub.status.idle":"2026-02-19T10:47:58.620112Z","shell.execute_reply.started":"2026-02-19T10:47:48.70817Z","shell.execute_reply":"2026-02-19T10:47:58.619308Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T10:48:08.889466Z","iopub.execute_input":"2026-02-19T10:48:08.889754Z","iopub.status.idle":"2026-02-19T10:48:08.924038Z","shell.execute_reply.started":"2026-02-19T10:48:08.889729Z","shell.execute_reply":"2026-02-19T10:48:08.923396Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T10:48:21.189642Z","iopub.execute_input":"2026-02-19T10:48:21.190222Z","iopub.status.idle":"2026-02-19T10:48:21.222074Z","shell.execute_reply.started":"2026-02-19T10:48:21.190195Z","shell.execute_reply":"2026-02-19T10:48:21.221473Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cols = ['x_1', 'y_1', 'z_1']\n\nthr = 1e17\nfor c in cols:\n    train_labels.loc[train_labels[c].abs() > thr, c] = np.nan\n\nfor c in cols:\n    val_labels.loc[val_labels[c].abs() > thr, c] = np.nan\n","metadata":{"execution":{"iopub.status.busy":"2026-02-19T10:48:29.252976Z","iopub.execute_input":"2026-02-19T10:48:29.253622Z","iopub.status.idle":"2026-02-19T10:48:29.432102Z","shell.execute_reply.started":"2026-02-19T10:48:29.253595Z","shell.execute_reply":"2026-02-19T10:48:29.431543Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_sequences = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv')\nval_sequences = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/validation_sequences.csv')\n\ntrain_sequences = train_sequences[train_sequences['sequence'].str.len() <= 4000].reset_index(drop=True)\nval_sequences = val_sequences[val_sequences['sequence'].str.len() <= 4000].reset_index(drop=True)\n\ntrain_sequences","metadata":{"execution":{"iopub.status.busy":"2026-02-19T10:48:38.488387Z","iopub.execute_input":"2026-02-19T10:48:38.488966Z","iopub.status.idle":"2026-02-19T10:48:39.038593Z","shell.execute_reply.started":"2026-02-19T10:48:38.48894Z","shell.execute_reply":"2026-02-19T10:48:39.037952Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_sequences","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T10:48:51.79942Z","iopub.execute_input":"2026-02-19T10:48:51.799677Z","iopub.status.idle":"2026-02-19T10:48:51.811715Z","shell.execute_reply.started":"2026-02-19T10:48:51.799657Z","shell.execute_reply":"2026-02-19T10:48:51.811102Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch import nn\nfrom torch.nn.utils.rnn import pad_sequence\n\nvocab = {\"A\":1, \"C\":2, \"G\":3, \"U\":4}","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:51:37.701646Z","iopub.execute_input":"2026-02-13T16:51:37.701937Z","iopub.status.idle":"2026-02-13T16:51:41.054922Z","shell.execute_reply.started":"2026-02-13T16:51:37.701914Z","shell.execute_reply":"2026-02-13T16:51:41.054378Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SequenceDataset(torch.utils.data.Dataset):\n    def __init__(self, seqs, targets, vocab):\n        self.seqs = seqs\n        self.targets = targets.copy()\n        self.targets['clean_id'] = self.targets['ID'].apply(lambda s: s.rsplit(\"_\", 1)[0])\n        self.vocab = vocab\n        self.target_map = {}\n        for cid, df in self.targets.groupby('clean_id'):\n            self.target_map[cid] = df.sort_values('resid')[['resid', 'x_1', 'y_1', 'z_1']].reset_index(drop=True)\n\n    def __len__(self):\n        return len(self.seqs)\n\n    def __getitem__(self, idx):\n        seq_id = self.seqs.iloc[idx]['target_id']\n        seq = self.seqs.iloc[idx]['sequence']\n        L = len(seq)\n        df = self.target_map[seq_id]\n        full_targets = torch.full((L, 3), float('nan'), dtype=torch.float32)\n        resid = torch.LongTensor(df['resid'].values) - 1\n        coords = torch.FloatTensor(df[['x_1', 'y_1', 'z_1']].values)\n        ok = (resid >= 0) & (resid < L)\n        full_targets[resid[ok]] = coords[ok]\n        seq_idx = [self.vocab[letter] for letter in seq]\n        return torch.LongTensor(seq_idx), full_targets\n        # (последовательность_в_числах, координаты_с_пропусками)","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:51:49.601829Z","iopub.execute_input":"2026-02-13T16:51:49.602449Z","iopub.status.idle":"2026-02-13T16:51:49.609515Z","shell.execute_reply.started":"2026-02-13T16:51:49.602421Z","shell.execute_reply":"2026-02-13T16:51:49.608828Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def collate_fn(batch):\n    tensors, targets = zip(*batch)\n    lengths = torch.LongTensor([t.size(0) for t in tensors])\n    features = pad_sequence(tensors, batch_first=True, padding_value=0)\n    targets = pad_sequence(targets, batch_first=True, padding_value=float('nan'))\n\n    T = features.size(1)\n    seq_mask = (torch.arange(T).unsqueeze(0) < lengths.unsqueeze(1))\n    finite_targets = torch.isfinite(targets).all(dim=-1)\n    mask = seq_mask & finite_targets\n\n    return features, targets, mask","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:51:54.67902Z","iopub.execute_input":"2026-02-13T16:51:54.679688Z","iopub.status.idle":"2026-02-13T16:51:54.684289Z","shell.execute_reply.started":"2026-02-13T16:51:54.679639Z","shell.execute_reply":"2026-02-13T16:51:54.683633Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_ds = SequenceDataset(train_sequences, train_labels, vocab)\ntrain_dl = torch.utils.data.DataLoader(\n    train_ds, batch_size=256, collate_fn=collate_fn,\n    num_workers=2, pin_memory=True, shuffle=True\n)\n\nval_ds = SequenceDataset(val_sequences, val_labels, vocab)\nval_dl = torch.utils.data.DataLoader(\n    val_ds, batch_size=256, collate_fn=collate_fn,\n    num_workers=2, pin_memory=True\n)","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:51:56.694979Z","iopub.execute_input":"2026-02-13T16:51:56.695576Z","iopub.status.idle":"2026-02-13T16:52:06.804678Z","shell.execute_reply.started":"2026-02-13T16:51:56.695548Z","shell.execute_reply":"2026-02-13T16:52:06.804016Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SequenceRegressor(nn.Module):\n    def __init__(self, input_dim, hidden_dim, n_out, n_layers_rnn=1, emb_dim=16):\n        super(SequenceRegressor, self).__init__()\n\n        self.input_dim = input_dim\n        self.hidden_dim = hidden_dim\n        self.n_out = n_out\n        self.n_layers_rnn = n_layers_rnn\n        self.emb_dim = emb_dim\n\n        self.embedding = nn.Embedding(self.input_dim, self.emb_dim, padding_idx=0)\n\n        self.rnn = nn.GRU(\n            input_size=self.emb_dim,\n            hidden_size=self.hidden_dim,\n            num_layers=self.n_layers_rnn,\n            batch_first=True,\n            bidirectional=True\n        )\n\n        self.classifier = nn.Sequential(\n            nn.Linear(self.hidden_dim * 2, self.hidden_dim),\n            nn.Tanh(),\n            nn.Linear(self.hidden_dim, self.hidden_dim),\n            nn.Tanh(),\n            nn.Linear(self.hidden_dim, self.n_out)\n        )\n\n    def forward(self, input_sentence):\n        x = self.embedding(input_sentence)\n        output, hn = self.rnn(x)\n        return self.classifier(output)","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:52:06.806044Z","iopub.execute_input":"2026-02-13T16:52:06.806484Z","iopub.status.idle":"2026-02-13T16:52:06.813659Z","shell.execute_reply.started":"2026-02-13T16:52:06.806448Z","shell.execute_reply":"2026-02-13T16:52:06.812946Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def masked_mse(pred, target, mask):\n    if mask.sum() == 0:\n        return torch.zeros((), device=pred.device)\n\n    target2 = torch.nan_to_num(target, nan=0.0, posinf=0.0, neginf=0.0)\n    m = mask.unsqueeze(-1).float()\n\n    diff = (pred - target2) * m\n    diff2 = diff.pow(2).sum(dim=-1)\n\n    return diff2.sum() / mask.sum().clamp(min=1)\n","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:52:12.138932Z","iopub.execute_input":"2026-02-13T16:52:12.139305Z","iopub.status.idle":"2026-02-13T16:52:12.144211Z","shell.execute_reply.started":"2026-02-13T16:52:12.139278Z","shell.execute_reply":"2026-02-13T16:52:12.143322Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.manual_seed(42)\nnp.random.seed(42)\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = SequenceRegressor(input_dim=len(vocab) + 1, hidden_dim=20, n_out=3).to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:52:12.557267Z","iopub.execute_input":"2026-02-13T16:52:12.557838Z","iopub.status.idle":"2026-02-13T16:52:15.614081Z","shell.execute_reply.started":"2026-02-13T16:52:12.557809Z","shell.execute_reply":"2026-02-13T16:52:15.613313Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:52:15.615342Z","iopub.execute_input":"2026-02-13T16:52:15.616017Z","iopub.status.idle":"2026-02-13T16:52:15.620597Z","shell.execute_reply.started":"2026-02-13T16:52:15.615992Z","shell.execute_reply":"2026-02-13T16:52:15.61994Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tqdm.notebook import tqdm","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:52:16.148817Z","iopub.execute_input":"2026-02-13T16:52:16.149419Z","iopub.status.idle":"2026-02-13T16:52:16.276219Z","shell.execute_reply.started":"2026-02-13T16:52:16.149392Z","shell.execute_reply":"2026-02-13T16:52:16.275662Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"n_epochs = 101\n\nt_losses = []\nv_losses = []\n\nfor i in range(n_epochs):\n    train_loss = 0\n    val_loss = 0\n    model.train()\n\n    for x_batch, y_batch, mask_batch in train_dl:\n        x_batch = x_batch.to(device, non_blocking=True)\n        y_batch = y_batch.to(device, non_blocking=True)\n        mask_batch = mask_batch.to(device, non_blocking=True)\n\n        optimizer.zero_grad()\n\n        pred = model(x_batch)\n        loss = masked_mse(pred, y_batch, mask_batch)\n\n        train_loss += loss.item() / len(train_dl)\n\n        loss.backward()\n        optimizer.step()\n\n    t_losses.append(train_loss)\n            \n    if i%20 == 0:\n        model.eval()\n        with torch.no_grad():\n            for x_batch, y_batch, mask_batch in val_dl:\n                x_batch = x_batch.to(device, non_blocking=True)\n                y_batch = y_batch.to(device, non_blocking=True)\n                mask_batch = mask_batch.to(device, non_blocking=True)\n    \n                pred = model(x_batch)\n                loss = masked_mse(pred, y_batch, mask_batch)\n    \n                val_loss += loss.item() / len(val_dl)\n                v_losses.append(val_loss)\n                print('epoch:', i, 'loss:', train_loss, 'val_loss:', val_loss)\n    else:\n        v_losses.append(v_losses[-1])","metadata":{"execution":{"iopub.status.busy":"2026-02-13T16:52:16.800385Z","iopub.execute_input":"2026-02-13T16:52:16.801085Z","iopub.status.idle":"2026-02-13T16:57:38.941506Z","shell.execute_reply.started":"2026-02-13T16:52:16.801058Z","shell.execute_reply":"2026-02-13T16:57:38.940655Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2026-02-13T17:14:30.09233Z","iopub.execute_input":"2026-02-13T17:14:30.093461Z","iopub.status.idle":"2026-02-13T17:14:30.097732Z","shell.execute_reply.started":"2026-02-13T17:14:30.093403Z","shell.execute_reply":"2026-02-13T17:14:30.096989Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.plot(range(101), t_losses)\nplt.plot(range(0, 101, 20), v_losses[::20])","metadata":{"execution":{"iopub.status.busy":"2026-02-13T17:14:30.447776Z","iopub.execute_input":"2026-02-13T17:14:30.44861Z","iopub.status.idle":"2026-02-13T17:14:30.618871Z","shell.execute_reply.started":"2026-02-13T17:14:30.448568Z","shell.execute_reply":"2026-02-13T17:14:30.618267Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nclass TestDataset(torch.utils.data.Dataset):\n    def __init__(self, seqs, vocab):\n        self.seqs = seqs\n        self.vocab = vocab\n\n    def __len__(self):\n        return len(self.seqs)\n\n    def __getitem__(self, idx):\n        seq_id = self.seqs.iloc[idx]['target_id']\n        seq = self.seqs.iloc[idx]['sequence']\n        seq_idx = [self.vocab[letter] for letter in seq]\n        return seq_id, torch.LongTensor(seq_idx)\n\ndef collate_fn_test(batch):\n    ids, tensors = zip(*batch)\n    lengths = torch.LongTensor([t.size(0) for t in tensors])\n    features = pad_sequence(tensors, batch_first=True, padding_value=0)\n    return ids, features, lengths\n    #ID структуры + последовательность\n","metadata":{"execution":{"iopub.status.busy":"2026-02-13T17:14:31.206942Z","iopub.execute_input":"2026-02-13T17:14:31.207594Z","iopub.status.idle":"2026-02-13T17:14:31.213366Z","shell.execute_reply.started":"2026-02-13T17:14:31.207566Z","shell.execute_reply":"2026-02-13T17:14:31.212635Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_sequences = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/test_sequences.csv')\n\ntest_ds = TestDataset(test_sequences, vocab)\ntest_dl = torch.utils.data.DataLoader(\n    test_ds, batch_size=32, collate_fn=collate_fn_test,\n    num_workers=2, pin_memory=True\n)\n\nmodel.eval()\npred_map = {}\n\nwith torch.no_grad():\n    for ids, x_batch, lengths in tqdm(test_dl):\n        x_batch = x_batch.to(device, non_blocking=True)\n        pred = model(x_batch).detach().cpu().numpy()\n        for j, tid in enumerate(ids):\n            L = int(lengths[j].item())\n            xyz = pred[j, :L, :]\n            pred_map[tid] = xyz","metadata":{"execution":{"iopub.status.busy":"2026-02-13T17:14:31.968575Z","iopub.execute_input":"2026-02-13T17:14:31.968883Z","iopub.status.idle":"2026-02-13T17:14:32.20524Z","shell.execute_reply.started":"2026-02-13T17:14:31.968858Z","shell.execute_reply":"2026-02-13T17:14:32.204197Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/sample_submission.csv')\n\nsub['target_id'] = sub['ID'].apply(lambda s: s.rsplit('_', 1)[0])\nsub['resid_int'] = sub['ID'].apply(lambda s: int(s.rsplit('_', 1)[1]))\n\ncoord_cols = []\nfor k in range(1, 6):\n    coord_cols += [f'x_{k}', f'y_{k}', f'z_{k}']\n\nfor tid, grp in sub.groupby('target_id'):\n    xyz = pred_map[tid]\n    resid = grp['resid_int'].values\n    out = xyz[resid - 1]\n    out5 = np.tile(out, (1, 5))\n    sub.loc[grp.index, coord_cols] = out5\n\nsub = sub.drop(columns=['target_id', 'resid_int'])\nsub.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2026-02-13T17:14:34.811635Z","iopub.execute_input":"2026-02-13T17:14:34.811958Z","iopub.status.idle":"2026-02-13T17:14:35.321913Z","shell.execute_reply.started":"2026-02-13T17:14:34.811924Z","shell.execute_reply":"2026-02-13T17:14:35.32131Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub","metadata":{"execution":{"iopub.status.busy":"2026-02-13T17:14:40.455218Z","iopub.execute_input":"2026-02-13T17:14:40.455519Z","iopub.status.idle":"2026-02-13T17:14:40.475679Z","shell.execute_reply.started":"2026-02-13T17:14:40.455495Z","shell.execute_reply":"2026-02-13T17:14:40.47509Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nsub.to_csv('submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-13T17:14:42.30878Z","iopub.execute_input":"2026-02-13T17:14:42.309323Z","iopub.status.idle":"2026-02-13T17:14:42.520658Z","shell.execute_reply.started":"2026-02-13T17:14:42.309293Z","shell.execute_reply":"2026-02-13T17:14:42.519826Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}