{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":118765,"databundleVersionId":15231210,"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,"jupyter":{"source_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import KFold\nfrom torch.cuda.amp import GradScaler, autocast\n\n# 1. High-Performance Configuration\nCFG = {\n    'seed': 42,\n    'n_folds': 5,            # Essential for leaderboard stability\n    'batch_size': 64,        # Optimized for T4 x2 / P100\n    'lr': 1e-4,\n    'epochs': 40,            \n    'hidden_dim': 512,       # Large dimension to capture complex 3D patterns\n    'n_layers': 12,          # Deep architecture for high capacity\n    'n_heads': 8,\n    'max_len': 512,\n    # Kaggle Paths\n    'train_path': '/kaggle/input/stanford-rna-3d-folding-part-2/train.csv',\n    'test_path': '/kaggle/input/stanford-rna-3d-folding-part-2/test.csv',\n    'sample_sub': '/kaggle/input/stanford-rna-3d-folding-part-2/sample_submission.csv'\n}\n\n# 2. Reproducibility & Device Setup\ndef seed_everything(seed):\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n\nseed_everything(CFG['seed'])\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# 3. Dataset Class\nclass RNADataset(Dataset):\n    def __init__(self, df, mode='train'):\n        self.seqs = df['sequence'].values\n        self.mode = mode\n        self.vocab = {'A': 0, 'C': 1, 'G': 2, 'U': 3, 'N': 4}\n        if mode == 'train':\n            # Dynamically select coordinate columns (x, y, z)\n            self.targets = df.filter(regex='coord').values \n\n    def __len__(self):\n        return len(self.seqs)\n\n    def __getitem__(self, idx):\n        seq = self.seqs[idx]\n        tokens = [self.vocab.get(s, 4) for s in seq]\n        \n        # Padding/Truncating to max_len\n        if len(tokens) < CFG['max_len']:\n            tokens += [4] * (CFG['max_len'] - len(tokens))\n        else:\n            tokens = tokens[:CFG['max_len']]\n            \n        x = torch.tensor(tokens, dtype=torch.long)\n        if self.mode == 'train':\n            return x, torch.tensor(self.targets[idx], dtype=torch.float)\n        return x\n\n# 4. Multi-GPU Optimized Transformer Model\nclass RNAModel(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.embedding = nn.Embedding(5, CFG['hidden_dim'])\n        self.pos_encoder = nn.Parameter(torch.randn(1, CFG['max_len'], CFG['hidden_dim']))\n        \n        encoder_layers = nn.TransformerEncoderLayer(\n            d_model=CFG['hidden_dim'], \n            nhead=CFG['n_heads'], \n            batch_first=True\n        )\n        self.transformer = nn.TransformerEncoder(encoder_layers, num_layers=CFG['n_layers'])\n        self.fc = nn.Linear(CFG['hidden_dim'], 3) # Predicts x, y, z\n\n    def forward(self, x):\n        x = self.embedding(x) + self.pos_encoder\n        x = self.transformer(x)\n        # Pooling to get global molecule representation\n        return self.fc(x.mean(dim=1))\n\n# 5. Training and Inference Pipeline\ndef run_championship_pipeline():\n    if not os.path.exists(CFG['train_path']):\n        print(\"Data files not found! Please ensure the dataset is added to the notebook.\")\n        return\n\n    train_df = pd.read_csv(CFG['train_path'])\n    test_df = pd.read_csv(CFG['test_path'])\n    \n    kf = KFold(n_splits=CFG['n_folds'], shuffle=True, random_state=CFG['seed'])\n    test_ds = RNADataset(test_df, mode='test')\n    test_loader = DataLoader(test_ds, batch_size=CFG['batch_size'], shuffle=False)\n    \n    all_fold_preds = []\n\n    for fold, (train_idx, val_idx) in enumerate(kf.split(train_df)):\n        print(f\"\\n--- Training Fold {fold+1}/{CFG['n_folds']} ---\")\n        train_ds = RNADataset(train_df.iloc[train_idx])\n        train_loader = DataLoader(train_ds, batch_size=CFG['batch_size'], shuffle=True)\n        \n        # Load Model to Multi-GPU if available\n        model = RNAModel().to(device)\n        if torch.cuda.device_count() > 1:\n            print(f\"Using {torch.cuda.device_count()} GPUs!\")\n            model = nn.DataParallel(model)\n            \n        optimizer = optim.AdamW(model.parameters(), lr=CFG['lr'], weight_decay=0.01)\n        scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=CFG['epochs'])\n        criterion = nn.HuberLoss() # Robust against outliers in 3D data\n        scaler = GradScaler()\n\n        for epoch in range(CFG['epochs']):\n            model.train()\n            epoch_loss = 0\n            for x, y in train_loader:\n                x, y = x.to(device), y.to(device)\n                optimizer.zero_grad()\n                with autocast():\n                    pred = model(x)\n                    loss = criterion(pred, y)\n                scaler.scale(loss).backward()\n                scaler.step(optimizer)\n                scaler.update()\n                epoch_loss += loss.item()\n            \n            scheduler.step()\n            if (epoch+1) % 10 == 0:\n                print(f\"Epoch {epoch+1} | Loss: {epoch_loss/len(train_loader):.6f}\")\n\n        # Prediction for this fold\n        model.eval()\n        fold_preds = []\n        with torch.no_grad():\n            for x in test_loader:\n                pred = model(x.to(device))\n                fold_preds.append(pred.cpu().numpy())\n        all_fold_preds.append(np.concatenate(fold_preds))\n\n    # Averaging predictions (Ensemble)\n    final_preds = np.mean(all_fold_preds, axis=0)\n    \n    # Create Submission\n    sub = pd.read_csv(CFG['sample_sub'])\n    coord_cols = [col for col in sub.columns if col != 'id']\n    sub[coord_cols] = final_preds\n    sub.to_csv('submission.csv', index=False)\n    print(\"\\nSUCCESS: submission.csv is ready for the first prize!\")\n\nif __name__ == \"__main__\":\n    run_championship_pipeline()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}