{"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":41875,"databundleVersionId":5521661},{"sourceType":"datasetVersion","sourceId":15979955,"datasetId":10247888,"databundleVersionId":16941309},{"sourceType":"datasetVersion","sourceId":15950910,"datasetId":10229225,"databundleVersionId":16909808},{"sourceType":"kernelVersion","sourceId":314644060}],"dockerImageVersionId":31329,"isInternetEnabled":true,"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\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub\n# kagglehub.dataset_download('<owner>/<dataset-slug>')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-05-21T17:27:08.965572Z","iopub.execute_input":"2026-05-21T17:27:08.966081Z","iopub.status.idle":"2026-05-21T17:27:10.902036Z","shell.execute_reply.started":"2026-05-21T17:27:08.966048Z","shell.execute_reply":"2026-05-21T17:27:10.901018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import subprocess, sys\n \ndef install_if_missing(package, pip_name=None):\n    try:\n        __import__(package)\n    except ImportError:\n        subprocess.run([sys.executable, \"-m\", \"pip\", \"install\", \"-q\",\n                        pip_name or package], check=True)\n \n# FIX 1: تثبيت pyg-lib للـ accelerated sampling\nprint(\"Installing pyg-lib for accelerated NeighborSampler...\")\ntry:\n    subprocess.run([\n        sys.executable, \"-m\", \"pip\", \"install\", \"-q\",\n        \"pyg-lib\", \"-f\",\n        \"https://data.pyg.org/whl/torch-2.10.0+cu128.html\"\n    ], check=True, capture_output=True)\n    print(\"  ✓ pyg-lib installed\")\nexcept Exception as e:\n    print(f\"  ⚠ pyg-lib install failed (non-critical): {e}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T17:27:14.168894Z","iopub.execute_input":"2026-05-21T17:27:14.169626Z","iopub.status.idle":"2026-05-21T17:27:20.875359Z","shell.execute_reply.started":"2026-05-21T17:27:14.169589Z","shell.execute_reply":"2026-05-21T17:27:20.874534Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q transformers accelerate biopython\n \nimport torch, transformers\nprint(f\"torch        : {torch.__version__}\")\nprint(f\"transformers : {transformers.__version__}\")\nprint(f\"CUDA         : {torch.cuda.is_available()}\")\nif torch.cuda.is_available():\n    print(f\"GPU          : {torch.cuda.get_device_name(0)}\")\n    print(f\"VRAM         : \"\n          f\"{torch.cuda.get_device_properties(0).total_memory/1e9:.1f} GB\")\nprint(\"✓ Ready\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T17:27:24.59274Z","iopub.execute_input":"2026-05-21T17:27:24.593438Z","iopub.status.idle":"2026-05-21T17:27:47.043845Z","shell.execute_reply.started":"2026-05-21T17:27:24.593406Z","shell.execute_reply":"2026-05-21T17:27:47.04305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q torch-geometric\n!pip install -q torch-scatter torch-sparse \\\n    -f https://data.pyg.org/whl/torch-2.0.0+cu118.html\n!pip install -q transformers accelerate faiss-cpu\n\nimport torch, torch_geometric, transformers\nprint(f\"torch          : {torch.__version__}\")\nprint(f\"torch_geometric: {torch_geometric.__version__}\")\nprint(f\"transformers   : {transformers.__version__}\")\nprint(f\"CUDA           : {torch.cuda.is_available()}\")\nif torch.cuda.is_available():\n    print(f\"GPU            : {torch.cuda.get_device_name(0)}\")\n    print(f\"VRAM           : \"\n          f\"{torch.cuda.get_device_properties(0).total_memory/1e9:.1f} GB\")\nprint(\"✓ Ready\")","metadata":{"trusted":true,"execution":{"iopub.status.idle":"2026-05-21T18:02:22.51539Z","shell.execute_reply.started":"2026-05-21T17:28:08.217628Z","shell.execute_reply":"2026-05-21T18:02:22.51439Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os, json\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.optim import AdamW\nfrom torch.optim.lr_scheduler import OneCycleLR   # FIX 6: warm-up included\nfrom torch_geometric.loader import NeighborLoader\nfrom torch_geometric.nn import SAGEConv, JumpingKnowledge\n \ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Device: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T18:02:52.48874Z","iopub.execute_input":"2026-05-21T18:02:52.489629Z","iopub.status.idle":"2026-05-21T18:02:52.49571Z","shell.execute_reply.started":"2026-05-21T18:02:52.489579Z","shell.execute_reply":"2026-05-21T18:02:52.494642Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PREP_DIR   = \"/kaggle/input/datasets/mazroa/cafa-5-2/preprocessed\"\nGRAPH_PATH = \"/kaggle/input/datasets/mazroa/cafa-5-2/protein_graph.pt\"\nOUTPUT_DIR = \"/kaggle/working\"\nCKPT_PATH  = f\"{OUTPUT_DIR}/best_model_v2.pt\"\n \nESM2_DIM       = 1280\nHIDDEN_DIM     = 1024      # FIX 8: زيادة من 512 → 1024\nNUM_GNN_LAYERS = 3\nDROPOUT        = 0.2       # FIX 9: تقليل من 0.3 → 0.2 (أقل aggression)\nBATCH_SIZE     = 512\nEPOCHS         = 120       # زيادة بما إن early stopping هيوقف لو لازم\nLR             = 5e-4      # زيادة طفيفة مع warm-up\nWEIGHT_DECAY   = 1e-4\nPATIENCE       = 20        # FIX 3: زيادة patience مع combined criterion\nLABEL_SMOOTH   = 0.05      # FIX 10: Label smoothing\nFOCAL_GAMMA    = 2.0       # FIX 10: Focal loss gamma\nACCUM_STEPS    = 2         # FIX: Gradient accumulation\nNUM_NEIGHBORS  = [15, 10, 10]  # FIX ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T18:04:34.549742Z","iopub.execute_input":"2026-05-21T18:04:34.55065Z","iopub.status.idle":"2026-05-21T18:04:34.556557Z","shell.execute_reply.started":"2026-05-21T18:04:34.550612Z","shell.execute_reply":"2026-05-21T18:04:34.555839Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"\\nLoading data...\")\ncheckpoint   = torch.load(GRAPH_PATH, weights_only=False)\ndata         = checkpoint['data']\nlabel_matrix = np.load(f\"{PREP_DIR}/label_matrix.npy\")\ntrain_idx    = np.load(f\"{PREP_DIR}/train_indices.npy\")\nval_idx      = np.load(f\"{PREP_DIR}/val_indices.npy\")\nia_weights   = np.load(f\"{PREP_DIR}/ia_weights.npy\")\n \ngo_terms = []\nwith open(f\"{PREP_DIR}/go_terms_list.txt\") as f:\n    for line in f:\n        parts = line.strip().split(\"\\t\")\n        if parts:\n            go_terms.append(parts[0])\n \nN, M = data.num_nodes, len(go_terms)\nprint(f\"  Nodes: {N:,} | GO terms: {M:,}\")\nprint(f\"  Train: {len(train_idx):,} | Val: {len(val_idx):,}\")\n \n# Set masks\ndata.train_mask = torch.zeros(N, dtype=torch.bool)\ndata.val_mask   = torch.zeros(N, dtype=torch.bool)\ndata.train_mask[train_idx] = True\ndata.val_mask[val_idx]     = True\ndata.y = torch.tensor(label_matrix, dtype=torch.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T18:04:37.532193Z","iopub.execute_input":"2026-05-21T18:04:37.53249Z","iopub.status.idle":"2026-05-21T18:04:56.626261Z","shell.execute_reply.started":"2026-05-21T18:04:37.532459Z","shell.execute_reply":"2026-05-21T18:04:56.625544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ProteinGNN(nn.Module):\n    \"\"\"\n    GraphSAGE + Jumping Knowledge\n    FIX 8: hidden_dim زادت لـ 1024\n    \"\"\"\n    def __init__(self, in_dim=ESM2_DIM, hidden_dim=HIDDEN_DIM,\n                 out_dim=M, num_layers=NUM_GNN_LAYERS, dropout=DROPOUT):\n        super().__init__()\n        self.convs   = nn.ModuleList()\n        self.norms   = nn.ModuleList()\n        self.dropout = dropout\n \n        for i in range(num_layers):\n            in_c = in_dim if i == 0 else hidden_dim\n            self.convs.append(SAGEConv(in_c, hidden_dim))\n            self.norms.append(nn.LayerNorm(hidden_dim))\n \n        self.jk         = JumpingKnowledge(\"cat\")\n        jk_dim          = hidden_dim * num_layers  # 1024 * 3 = 3072\n \n        # FIX 8: Deeper classifier head\n        self.classifier = nn.Sequential(\n            nn.Linear(jk_dim, hidden_dim * 2),\n            nn.GELU(),                              # GELU أفضل من ReLU\n            nn.Dropout(dropout),\n            nn.Linear(hidden_dim * 2, hidden_dim),\n            nn.GELU(),\n            nn.Dropout(dropout / 2),\n            nn.Linear(hidden_dim, out_dim)\n        )\n \n    def forward(self, x, edge_index):\n        layer_outs = []\n        for conv, norm in zip(self.convs, self.norms):\n            x = conv(x, edge_index)\n            x = norm(x)\n            x = F.gelu(x)\n            x = F.dropout(x, p=self.dropout, training=self.training)\n            layer_outs.append(x)\n        x = self.jk(layer_outs)\n        return self.classifier(x)\n \nmodel = ProteinGNN().to(device)\ntotal_params = sum(p.numel() for p in model.parameters())\nprint(f\"\\nModel params: {total_params:,}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T18:05:26.505166Z","iopub.execute_input":"2026-05-21T18:05:26.506092Z","iopub.status.idle":"2026-05-21T18:05:26.823014Z","shell.execute_reply.started":"2026-05-21T18:05:26.506051Z","shell.execute_reply":"2026-05-21T18:05:26.822041Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ia_tensor  = torch.tensor(ia_weights, dtype=torch.float32).to(device)\npos_weight = torch.tensor(\n    [(label_matrix[:, i] == 0).sum() / max(label_matrix[:, i].sum(), 1)\n     for i in range(M)],\n    dtype=torch.float32).to(device)\n \n \ndef focal_ia_bce(logits, targets, pos_weight, ia_tensor,\n                 gamma=FOCAL_GAMMA, smooth=LABEL_SMOOTH):\n    \"\"\"\n    FIX 10: Combined Focal + IA-weighted BCE + Label Smoothing\n    \n    Label Smoothing: targets → [smooth/2 .. 1 - smooth/2]\n    Focal Loss: حل مشكلة class imbalance بتركيز على الـ hard examples\n    IA Weights: حل مشكلة GO term importance\n    \"\"\"\n    # Label smoothing\n    targets_smooth = targets * (1.0 - smooth) + smooth * 0.5\n \n    # Standard BCE\n    bce = F.binary_cross_entropy_with_logits(\n        logits, targets_smooth,\n        pos_weight=pos_weight,\n        reduction='none'\n    )\n \n    # Focal weight: (1 - p_t)^gamma\n    probs   = torch.sigmoid(logits)\n    p_t     = probs * targets + (1 - probs) * (1 - targets)\n    focal_w = (1 - p_t) ** gamma\n \n    # IA weight\n    ia_w = 1.0 + ia_tensor.unsqueeze(0)\n \n    weighted = bce * focal_w * ia_w\n    return weighted.mean()\n \n \n# FIX 5: تحسين compute_fmax — threshold sweep أدق + metric averaging options\ndef compute_fmax(y_true_np, y_pred_np, step=0.01):\n    \"\"\"\n    Fmax بـ fine-grained threshold sweep (step=0.01 بدل 0.05)\n    يرجع (fmax, best_threshold)\n    \"\"\"\n    best_f1, best_thr = 0.0, 0.5\n    for thr in np.arange(0.01, 0.99, step):\n        pred = (y_pred_np > thr).astype(float)\n        tp   = (y_true_np * pred).sum(1)\n        prec = (tp / (pred.sum(1) + 1e-8)).mean()\n        rec  = (tp / (y_true_np.sum(1) + 1e-8)).mean()\n        f1   = 2 * prec * rec / (prec + rec + 1e-8)\n        if float(f1) > best_f1:\n            best_f1  = float(f1)\n            best_thr = thr\n    return best_f1, best_thr\n \n ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T18:05:59.786696Z","iopub.execute_input":"2026-05-21T18:05:59.78745Z","iopub.status.idle":"2026-05-21T18:06:03.211808Z","shell.execute_reply.started":"2026-05-21T18:05:59.787411Z","shell.execute_reply":"2026-05-21T18:06:03.211125Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_loader = NeighborLoader(\n    data,\n    num_neighbors=NUM_NEIGHBORS,   # FIX 7: زيادة الجيران\n    batch_size=BATCH_SIZE,\n    input_nodes=data.train_mask,\n    shuffle=True,\n    num_workers=2,\n    persistent_workers=True,\n)\n \nval_loader = NeighborLoader(\n    data,\n    num_neighbors=NUM_NEIGHBORS,\n    batch_size=BATCH_SIZE,\n    input_nodes=data.val_mask,\n    shuffle=False,\n    num_workers=2,\n    persistent_workers=True,\n)\n \nprint(f\"\\nTrain batches: {len(train_loader):,}\")\nprint(f\"Val batches  : {len(val_loader):,}\")\n \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T18:06:06.585434Z","iopub.execute_input":"2026-05-21T18:06:06.586225Z","iopub.status.idle":"2026-05-21T18:06:07.730333Z","shell.execute_reply.started":"2026-05-21T18:06:06.586183Z","shell.execute_reply":"2026-05-21T18:06:07.729547Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"optimizer = AdamW(model.parameters(), lr=LR, weight_decay=WEIGHT_DECAY)\n \n# FIX 6: OneCycleLR = warm-up ثم cosine decay — أفضل بكتير من CosineAnnealingLR\ntotal_steps = len(train_loader) * EPOCHS // ACCUM_STEPS\nscheduler   = OneCycleLR(\n    optimizer,\n    max_lr=LR,\n    total_steps=total_steps,\n    pct_start=0.1,          # 10% warm-up\n    anneal_strategy='cos',\n    div_factor=10.0,        # initial_lr = max_lr / 10\n    final_div_factor=1e4,   # min_lr = max_lr / 10000\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-21T18:06:15.256095Z","iopub.execute_input":"2026-05-21T18:06:15.256557Z","iopub.status.idle":"2026-05-21T18:06:15.262294Z","shell.execute_reply.started":"2026-05-21T18:06:15.25652Z","shell.execute_reply":"2026-05-21T18:06:15.26133Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"\\nTraining — {EPOCHS} epochs | patience={PATIENCE} | accum={ACCUM_STEPS}\\n\")\n \nbest_fmax   = 0.0\nbest_loss   = float('inf')\nno_improve  = 0\nhistory     = []\n \nfor epoch in range(1, EPOCHS + 1):\n \n    # ── Train ────────────────────────────────────────────────────────────────\n    model.train()\n    total_loss = 0\n    n_batches  = 0\n    optimizer.zero_grad()\n \n    for i, batch in enumerate(train_loader):\n        batch     = batch.to(device)\n        seed_n    = batch.batch_size\n \n        # FIX: Mixup augmentation (10% of time)\n        if torch.rand(1).item() < 0.1:\n            lam   = np.random.beta(0.4, 0.4)\n            idx   = torch.randperm(seed_n, device=device)\n            batch.x[:seed_n] = lam * batch.x[:seed_n] + (1 - lam) * batch.x[idx]\n            # نعمل blended targets\n            targets = lam * batch.y[:seed_n] + (1 - lam) * batch.y[idx]\n        else:\n            targets = batch.y[:seed_n]\n \n        logits = model(batch.x, batch.edge_index)\n        loss   = focal_ia_bce(\n            logits[:seed_n], targets, pos_weight, ia_tensor\n        )\n \n        # FIX: Gradient accumulation\n        loss = loss / ACCUM_STEPS\n        loss.backward()\n \n        if (i + 1) % ACCUM_STEPS == 0 or (i + 1) == len(train_loader):\n            torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)\n            optimizer.step()\n            scheduler.step()\n            optimizer.zero_grad()\n \n        total_loss += loss.item() * ACCUM_STEPS\n        n_batches  += 1\n \n    avg_train_loss = total_loss / n_batches\n ","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\n    val_preds, val_labels, val_losses = [], [], []\n \n    with torch.no_grad():\n        for batch in val_loader:\n            batch  = batch.to(device)\n            seed_n = batch.batch_size\n            logits = model(batch.x, batch.edge_index)\n \n            v_loss = focal_ia_bce(\n                logits[:seed_n], batch.y[:seed_n], pos_weight, ia_tensor\n            )\n            val_losses.append(v_loss.item())\n            val_preds.append(torch.sigmoid(logits[:seed_n]).cpu().numpy())\n            val_labels.append(batch.y[:seed_n].cpu().numpy())\n \n    val_preds      = np.vstack(val_preds)\n    val_labels     = np.vstack(val_labels)\n    avg_val_loss   = np.mean(val_losses)\n    val_fmax, best_thr = compute_fmax(val_labels, val_preds)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"is_fmax_better = val_fmax > best_fmax\n    is_loss_better = avg_val_loss < best_loss and val_fmax >= best_fmax * 0.98\n \n    is_best = is_fmax_better or is_loss_better\n \n    if is_best:\n        if is_fmax_better:\n            best_fmax = val_fmax\n        best_loss  = min(best_loss, avg_val_loss)\n        no_improve = 0\n        torch.save({\n            'epoch'       : epoch,\n            'model_state' : model.state_dict(),\n            'val_fmax'    : best_fmax,\n            'val_loss'    : avg_val_loss,\n            'best_thr'    : best_thr,\n            'go_terms'    : go_terms,\n        }, CKPT_PATH)\n    else:\n        no_improve += 1\n \n    history.append({\n        'epoch'      : epoch,\n        'train_loss' : avg_train_loss,\n        'val_loss'   : avg_val_loss,\n        'val_fmax'   : val_fmax,\n        'best_thr'   : best_thr,\n    })\n \n    if epoch % 5 == 0 or epoch == 1:\n        lr_now = scheduler.get_last_lr()[0] if hasattr(scheduler, 'get_last_lr') else LR\n        print(f\"Epoch {epoch:3d} | \"\n              f\"train_loss={avg_train_loss:.4f} | \"\n              f\"val_loss={avg_val_loss:.4f} | \"\n              f\"val_Fmax={val_fmax:.4f} | \"\n              f\"thr={best_thr:.2f} | \"\n              f\"lr={lr_now:.2e}\"\n              f\"{'  ★ best' if is_best else ''}\")\n \n    if no_improve >= PATIENCE:\n        print(f\"\\nEarly stop at epoch {epoch} (no improve for {PATIENCE} epochs)\")\n        break\n \nprint(f\"\\n✓ Best val Fmax : {best_fmax:.4f}\")\nprint(f\"✓ Best val Loss : {best_loss:.4f}\")\nprint(f\"✓ Checkpoint    : {CKPT_PATH}\")\n ","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import json\nwith open(f\"{OUTPUT_DIR}/training_history_v2.json\", \"w\") as f:\n    json.dump(history, f, indent=2)\nprint(f\"✓ History saved : {OUTPUT_DIR}/training_history_v2.json\")\n ","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"\\n\" + \"=\"*60)\nprint(\"DIAGNOSIS REPORT\")\nprint(\"=\"*60)\n \nif len(history) >= 10:\n    mid   = len(history) // 2\n    early = history[:5]\n    late  = history[mid:]\n \n    early_gap = np.mean([h['val_loss'] - h['train_loss'] for h in early])\n    late_gap  = np.mean([h['val_loss'] - h['train_loss'] for h in late])\n \n    print(f\"\\nOverfitting Check (val_loss - train_loss):\")\n    print(f\"  Early epochs gap : {early_gap:.4f}\")\n    print(f\"  Late  epochs gap : {late_gap:.4f}\")\n \n    if late_gap > early_gap * 2:\n        print(\"  ⚠  Significant overfitting detected!\")\n        print(\"     → Consider: higher dropout, more weight_decay, less hidden_dim\")\n    else:\n        print(\"  ✓  Overfitting controlled\")\n \n    fmax_trend = [h['val_fmax'] for h in history[-10:]]\n    fmax_delta = fmax_trend[-1] - fmax_trend[0]\n    print(f\"\\nFmax trend (last 10 epochs): {fmax_delta:+.4f}\")\n    if fmax_delta < 0.005:\n        print(\"  → Model converged — try more epochs or different LR\")\n    else:\n        print(\"  → Model still improving — consider more epochs\")\n \nprint(\"=\"*60)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}