{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":106809,"databundleVersionId":13056355,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install --quiet h5py einops jiwer torch torchvision matplotlib tqdm\n\nimport os, sys, math, json, glob, random, time, collections, subprocess\nfrom pathlib import Path\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport h5py\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.optim import AdamW\nfrom torch.cuda.amp import GradScaler, autocast\n\nimport jiwer  # for WER/CER\n\nprint(\"Torch version:\", torch.__version__)\nprint(\"CUDA available:\", torch.cuda.is_available())\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(\"Using device:\", device)\n\nif torch.cuda.is_available():\n    try:\n        gpu_info = subprocess.check_output(\n            [\"nvidia-smi\", \"--query-gpu=name,memory.total\", \"--format=csv,noheader\"]\n        ).decode().strip()\n        print(\"GPU info:\", gpu_info)\n    except Exception as e:\n        print(\"Could not get GPU info:\", e)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:44:47.604009Z","iopub.execute_input":"2025-11-09T17:44:47.604312Z","iopub.status.idle":"2025-11-09T17:46:01.753680Z","shell.execute_reply.started":"2025-11-09T17:44:47.604282Z","shell.execute_reply":"2025-11-09T17:46:01.752791Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"INPUT_DIR = Path(\"/kaggle/input/brain-to-text-25\")\nassert INPUT_DIR.exists(), f\"Input not found: {INPUT_DIR}\"\nprint(\"Input root exists?\", INPUT_DIR.exists())\n\n# all .hdf5 file \nhdf5_files = sorted(INPUT_DIR.rglob(\"*.hdf5\"))\nprint(f\"Found {len(hdf5_files)} .hdf5 files\")\nprint(\"Top-level folders:\")\nfor d in INPUT_DIR.iterdir():\n    if d.is_dir():\n        print(\"-\", d.name)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:01.754950Z","iopub.execute_input":"2025-11-09T17:46:01.755364Z","iopub.status.idle":"2025-11-09T17:46:01.924764Z","shell.execute_reply.started":"2025-11-09T17:46:01.755344Z","shell.execute_reply":"2025-11-09T17:46:01.924142Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_file = hdf5_files[0]\nprint(\"Using sample file:\", sample_file.relative_to(INPUT_DIR))\nwith h5py.File(sample_file, \"r\") as hf:\n    print(\"Top-level keys:\", list(hf.keys())[:5], \"... (total:\", len(hf.keys()), \")\")\n    g0 = list(hf.keys())[0]\n    print(\"Example group:\", g0, \"->\", list(hf[g0].keys()))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:01.925536Z","iopub.execute_input":"2025-11-09T17:46:01.925808Z","iopub.status.idle":"2025-11-09T17:46:02.057898Z","shell.execute_reply.started":"2025-11-09T17:46:01.925784Z","shell.execute_reply":"2025-11-09T17:46:02.057272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def index_split_files(root: Path):\n    # canonical layout: .../<date>/data_{train|val|test}.hdf5\n    split_map = {\"train\": [], \"val\": [], \"test\": []}\n    for fp in root.rglob(\"data_*.hdf5\"):\n        name = fp.name\n        if \"data_train\" in name:\n            split_map[\"train\"].append(fp)\n        elif \"data_val\" in name:\n            split_map[\"val\"].append(fp)\n        elif \"data_test\" in name:\n            split_map[\"test\"].append(fp)\n    for k in split_map:\n        split_map[k] = sorted(split_map[k])\n    return split_map\n\nsplit_files = index_split_files(INPUT_DIR)\nprint({k: len(v) for k,v in split_files.items()})\n\ndef list_trials(h5_path: Path):\n    trials = []\n    with h5py.File(h5_path, \"r\") as hf:\n        for k in hf.keys():\n            g = hf[k]\n            if \"input_features\" in g and \"transcription\" in g:\n                trials.append(k)\n    return trials","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:02.059308Z","iopub.execute_input":"2025-11-09T17:46:02.059874Z","iopub.status.idle":"2025-11-09T17:46:02.106064Z","shell.execute_reply.started":"2025-11-09T17:46:02.059854Z","shell.execute_reply":"2025-11-09T17:46:02.105437Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_index(file_list):\n    rows = []\n    for fp in file_list:\n        with h5py.File(fp, \"r\") as hf:\n            for k in hf.keys():\n                g = hf[k]\n                if \"input_features\" in g and \"transcription\" in g:\n                    rows.append({\"file\": str(fp), \"trial\": k})\n    return pd.DataFrame(rows)\n\ntrain_df = build_index(split_files[\"train\"])\nval_df   = build_index(split_files[\"val\"]) if split_files[\"val\"] else build_index(split_files[\"test\"])  # fallback\nprint(\"Train trials:\", len(train_df), \"Val trials:\", len(val_df))\ndisplay(train_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:02.106725Z","iopub.execute_input":"2025-11-09T17:46:02.106913Z","iopub.status.idle":"2025-11-09T17:46:24.690088Z","shell.execute_reply.started":"2025-11-09T17:46:02.106898Z","shell.execute_reply":"2025-11-09T17:46:24.689211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BrainDataset(Dataset):\n    def __init__(self, df: pd.DataFrame):\n        self.df = df.reset_index(drop=True)\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        fp = row[\"file\"]\n        trial = row[\"trial\"]\n        with h5py.File(fp, \"r\") as hf:\n            g = hf[trial]\n            x = g[\"input_features\"][()]  # shape (T, C)\n            y = g[\"transcription\"][()]   # shape (L,) int32\n        x = torch.tensor(x, dtype=torch.float32)        # [T, C]\n        y = torch.tensor(y, dtype=torch.long)           # [L]\n    \n        return x, y","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:24.690934Z","iopub.execute_input":"2025-11-09T17:46:24.691240Z","iopub.status.idle":"2025-11-09T17:46:24.697193Z","shell.execute_reply.started":"2025-11-09T17:46:24.691221Z","shell.execute_reply":"2025-11-09T17:46:24.696270Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def collate_for_ctc(batch):\n    xs, ys = zip(*batch)\n    x_lens = [x.shape[0] for x in xs]  # T\n    t_lens = [y.shape[0] for y in ys]  # L\n    max_t = max(x_lens)\n    channels = xs[0].shape[1]\n    x_padded = torch.zeros(len(xs), channels, max_t, dtype=torch.float32)\n    for i, x in enumerate(xs):\n        T = x.shape[0]\n        x_padded[i, :, :T] = x.permute(1, 0)  # [C, T]\n    targets_concat = torch.cat([y for y in ys]) if sum(t_lens) > 0 else torch.tensor([], dtype=torch.long)\n    return x_padded, targets_concat, torch.tensor(x_lens, dtype=torch.long), torch.tensor(t_lens, dtype=torch.long)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:24.698645Z","iopub.execute_input":"2025-11-09T17:46:24.699042Z","iopub.status.idle":"2025-11-09T17:46:26.292004Z","shell.execute_reply.started":"2025-11-09T17:46:24.699015Z","shell.execute_reply":"2025-11-09T17:46:26.291264Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_loader = DataLoader(BrainDataset(train_df), batch_size=8, shuffle=True, collate_fn=collate_for_ctc, num_workers=2)\nval_loader   = DataLoader(BrainDataset(val_df),   batch_size=8, shuffle=False, collate_fn=collate_for_ctc, num_workers=2)\n\n# sanity check\nbx, bt, blx, blt = next(iter(train_loader))\nprint(\"Batch x:\", bx.shape, \"targets:\", bt.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:26.292727Z","iopub.execute_input":"2025-11-09T17:46:26.292933Z","iopub.status.idle":"2025-11-09T17:46:27.092724Z","shell.execute_reply.started":"2025-11-09T17:46:26.292916Z","shell.execute_reply":"2025-11-09T17:46:27.091938Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class PositionalEncoding(nn.Module):\n    def __init__(self, d_model, max_len=20000):\n        super().__init__()\n        pe = torch.zeros(max_len, d_model)\n        position = torch.arange(0, max_len).unsqueeze(1)\n        div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))\n        pe[:, 0::2] = torch.sin(position * div_term)\n        pe[:, 1::2] = torch.cos(position * div_term)\n        self.register_buffer(\"pe\", pe)\n\n    def forward(self, x):\n        # x: [B, T, D]\n        return x + self.pe[:x.size(1)].unsqueeze(0)\n\nclass ConvStem(nn.Module):\n    def __init__(self, in_ch, d_model):\n        super().__init__()\n        self.net = nn.Sequential(\n            nn.Conv1d(in_ch, d_model // 2, kernel_size=7, stride=2, padding=3),\n            nn.ReLU(),\n            nn.Conv1d(d_model // 2, d_model, kernel_size=5, stride=2, padding=2),\n            nn.ReLU(),\n        )\n    def forward(self, x):  # x: [B, C, T]\n        return self.net(x) # [B, D, T']\n\nclass TransformerEncoderModel(nn.Module):\n    def __init__(self, in_ch, d_model=384, nhead=8, num_layers=6, vocab_size=256):\n        super().__init__()\n        self.conv = ConvStem(in_ch, d_model)\n        enc_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=nhead,\n                                               dim_feedforward=d_model*4, dropout=0.1, activation=\"relu\", batch_first=False)\n        self.transformer = nn.TransformerEncoder(enc_layer, num_layers=num_layers)\n        self.pos_enc = PositionalEncoding(d_model)\n        self.fc = nn.Linear(d_model, vocab_size)\n\n    def forward(self, x):  # x: [B, C, T]\n        x = self.conv(x)            # [B, D, T']\n        x = x.permute(0, 2, 1)      # [B, T', D]\n        x = self.pos_enc(x)\n        x = x.permute(1, 0, 2)      # [T', B, D]\n        x = self.transformer(x)\n        x = x.permute(1, 0, 2)      # [B, T', D]\n        logits = self.fc(x)\n        return F.log_softmax(logits, dim=-1)  # [B, T', V]\n\nclass BiLSTMEncoderModel(nn.Module):\n    def __init__(self, in_ch, hidden=512, num_layers=3, vocab_size=256, proj_dim=256):\n        super().__init__()\n        self.conv = nn.Sequential(\n            nn.Conv1d(in_ch, in_ch, kernel_size=3, padding=1),\n            nn.ReLU()\n        )\n        self.rnn = nn.LSTM(input_size=in_ch, hidden_size=hidden, num_layers=num_layers,\n                           batch_first=True, bidirectional=True)\n        self.proj = nn.Linear(hidden*2, proj_dim)\n        self.fc = nn.Linear(proj_dim, vocab_size)\n\n    def forward(self, x):  # x: [B, C, T]\n        x = self.conv(x)              # [B, C, T]\n        x = x.permute(0, 2, 1)        # [B, T, C]\n        out, _ = self.rnn(x)          # [B, T, 2H]\n        proj = F.relu(self.proj(out)) # [B, T, D]\n        logits = self.fc(proj)        # [B, T, V]\n        return F.log_softmax(logits, dim=-1)\n\nclass SimpleConvTransformer(nn.Module):\n    def __init__(self, in_ch, d_model=256, nhead=4, num_layers=4, vocab_size=256):\n        super().__init__()\n        self.conv = nn.Sequential(\n            nn.Conv1d(in_ch, d_model, kernel_size=5, stride=2, padding=2),\n            nn.ReLU(),\n            nn.Conv1d(d_model, d_model, kernel_size=3, stride=2, padding=1),\n            nn.ReLU(),\n        )\n        enc_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=nhead,\n                                               dim_feedforward=d_model*4, dropout=0.1, activation=\"relu\", batch_first=False)\n        self.transformer = nn.TransformerEncoder(enc_layer, num_layers=num_layers)\n        self.pos_enc = PositionalEncoding(d_model)\n        self.fc = nn.Linear(d_model, vocab_size)\n\n    def forward(self, x):  # x: [B, C, T]\n        x = self.conv(x)            # [B, D, T']\n        x = x.permute(0, 2, 1)      # [B, T', D]\n        x = self.pos_enc(x)\n        x = x.permute(1, 0, 2)      # [T', B, D]\n        x = self.transformer(x)\n        x = x.permute(1, 0, 2)      # [B, T', D]\n        logits = self.fc(x)\n        return F.log_softmax(logits, dim=-1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:27.093759Z","iopub.execute_input":"2025-11-09T17:46:27.093988Z","iopub.status.idle":"2025-11-09T17:46:27.109223Z","shell.execute_reply.started":"2025-11-09T17:46:27.093967Z","shell.execute_reply":"2025-11-09T17:46:27.108477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"@torch.no_grad()\ndef greedy_decode_from_logprobs(log_probs, blank=0):\n    # log_probs: [B, T, V]\n    preds = log_probs.argmax(-1).cpu().numpy()  # [B, T]\n    decoded = []\n    for i in range(preds.shape[0]):\n        seq = preds[i]\n        seq_clean = [p for j, p in enumerate(seq) if (j == 0 or p != seq[j-1]) and p != blank]\n        decoded.append(seq_clean)\n    return decoded","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:27.111423Z","iopub.execute_input":"2025-11-09T17:46:27.111860Z","iopub.status.idle":"2025-11-09T17:46:27.127851Z","shell.execute_reply.started":"2025-11-09T17:46:27.111843Z","shell.execute_reply":"2025-11-09T17:46:27.127060Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def ids_to_text(id_list):\n    # এখানে 0 = CTC blank ধরে নেওয়া হলো, 1..255 = byte-like tokens\n    # সিম্পল ম্যাপ: id in [1..255] -> chr(id)\n    chars = []\n    for i in id_list:\n        if 1 <= i <= 255:\n            chars.append(chr(i))\n    return \"\".join(chars)\n\ndef evaluate(model, loader, criterion, blank_id=0, max_batches=50):\n    model.eval()\n    tot_loss, tot_T, n_batches = 0.0, 0, 0\n    hyps, refs = [], []\n    with torch.no_grad():\n        for b, (x, targets, x_lens, t_lens) in enumerate(loader):\n            x = x.to(device)  # [B, C, T]\n            B, C, T = x.shape\n            logp = model(x)   # [B, T', V]\n            Tprime = logp.size(1)\n\n            # prepare for CTC: [T', B, V]\n            logp_ctc = logp.permute(1, 0, 2)\n            input_lengths = torch.full((B,), Tprime, dtype=torch.long, device=logp.device)\n            target_lengths = t_lens.to(device)\n\n            loss = criterion(logp_ctc, targets.to(device), input_lengths, target_lengths)\n            tot_loss += loss.item()\n            n_batches += 1\n\n            # decode\n            pred_ids_batch = greedy_decode_from_logprobs(logp, blank=blank_id)\n            # split concatenated targets back to sequences\n            off = 0\n            for i in range(B):\n                L = t_lens[i].item()\n                ref_ids = targets[off:off+L].tolist()\n                off += L\n                hyp_text = ids_to_text(pred_ids_batch[i])\n                ref_text = ids_to_text(ref_ids)\n                hyps.append(hyp_text)\n                refs.append(ref_text)\n            if b + 1 >= max_batches:\n                break\n\n    # WER/CER\n    wer = jiwer.wer(refs, hyps) if refs else 0.0\n    cer = jiwer.cer(refs, hyps) if refs else 0.0\n    avg_loss = tot_loss / max(1, n_batches)\n    return avg_loss, wer, cer\n\ndef train_loop(model, train_loader, val_loader, epochs=5, lr=2e-4, blank_id=0):\n    model.to(device)\n    optimizer = AdamW(model.parameters(), lr=lr)\n    scaler = GradScaler(enabled=(device==\"cuda\"))\n    criterion = nn.CTCLoss(blank=blank_id, zero_infinity=True)\n\n    train_losses, val_losses, val_wers = [], [], []\n\n    for ep in range(1, epochs+1):\n        model.train()\n        running = 0.0\n        pbar = tqdm(train_loader, desc=f\"Epoch {ep}\")\n        for x, targets, x_lens, t_lens in pbar:\n            x = x.to(device)                    # [B, C, T]\n            B, C, T = x.shape\n            logp = model(x)                     # [B, T', V]\n            Tprime = logp.size(1)\n\n            # for CTC: [T', B, V]\n            logp_ctc = logp.permute(1, 0, 2)\n            input_lengths = torch.full((B,), Tprime, dtype=torch.long, device=logp.device)\n            target_lengths = t_lens.to(device)\n\n            loss = criterion(logp_ctc, targets.to(device), input_lengths, target_lengths)\n\n            optimizer.zero_grad(set_to_none=True)\n            scaler.scale(loss).backward()\n            scaler.step(optimizer)\n            scaler.update()\n\n            running += loss.item()\n            pbar.set_postfix(loss=f\"{loss.item():.4f}\")\n\n        train_loss = running / max(1, len(train_loader))\n        val_loss, val_wer, val_cer = evaluate(model, val_loader, criterion, blank_id=blank_id, max_batches=50)\n\n        train_losses.append(train_loss)\n        val_losses.append(val_loss)\n        val_wers.append(val_wer)\n\n        print(f\"[Epoch {ep}] train_loss={train_loss:.4f}  val_loss={val_loss:.4f}  WER={val_wer:.3f}  CER={val_cer:.3f}\")\n\n    return train_losses, val_losses, val_wers","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:27.128714Z","iopub.execute_input":"2025-11-09T17:46:27.128938Z","iopub.status.idle":"2025-11-09T17:46:27.149890Z","shell.execute_reply.started":"2025-11-09T17:46:27.128915Z","shell.execute_reply":"2025-11-09T17:46:27.149143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IN_CH = bx.shape[1]  # 512\nVOCAB_SIZE = 256     # 0=blank + 1..255 bytes","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:27.150663Z","iopub.execute_input":"2025-11-09T17:46:27.150906Z","iopub.status.idle":"2025-11-09T17:46:27.166978Z","shell.execute_reply.started":"2025-11-09T17:46:27.150884Z","shell.execute_reply":"2025-11-09T17:46:27.166175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = BiLSTMEncoderModel(IN_CH, hidden=512, num_layers=3, vocab_size=VOCAB_SIZE, proj_dim=256)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:27.167809Z","iopub.execute_input":"2025-11-09T17:46:27.168576Z","iopub.status.idle":"2025-11-09T17:46:27.332061Z","shell.execute_reply.started":"2025-11-09T17:46:27.168553Z","shell.execute_reply":"2025-11-09T17:46:27.331483Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install tqdm\n\nfrom tqdm import tqdm\n\ntrain_losses, val_losses, val_wers = train_loop(model, train_loader, val_loader, epochs=5, lr=2e-4, blank_id=0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T17:46:27.332859Z","iopub.execute_input":"2025-11-09T17:46:27.333192Z","iopub.status.idle":"2025-11-09T18:39:25.105723Z","shell.execute_reply.started":"2025-11-09T17:46:27.333145Z","shell.execute_reply":"2025-11-09T18:39:25.104647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_metrics(train_losses, val_losses, val_wers=None):\n    epochs = range(1, len(train_losses)+1)\n    plt.figure(figsize=(10,4))\n    plt.subplot(1,2,1)\n    plt.plot(epochs, train_losses, marker='o', label='train loss')\n    plt.plot(epochs, val_losses, marker='o', label='val loss')\n    plt.xlabel('epoch'); plt.ylabel('CTC loss'); plt.legend(); plt.title('Loss')\n    if val_wers is not None:\n        plt.subplot(1,2,2)\n        plt.plot(epochs, val_wers, marker='o', label='val WER')\n        plt.xlabel('epoch'); plt.ylabel('WER'); plt.legend(); plt.title('WER')\n    plt.tight_layout()\n    plt.show()\n\nplot_metrics(train_losses, val_losses, val_wers)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T18:39:25.106925Z","iopub.execute_input":"2025-11-09T18:39:25.107682Z","iopub.status.idle":"2025-11-09T18:39:25.543210Z","shell.execute_reply.started":"2025-11-09T18:39:25.107657Z","shell.execute_reply":"2025-11-09T18:39:25.542555Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"@torch.no_grad()\ndef preview_predictions(model, loader, n_batches=1, blank_id=0):\n    model.eval()\n    cnt = 0\n    for x, targets, x_lens, t_lens in loader:\n        x = x.to(device)\n        logp = model(x)\n        hyps = greedy_decode_from_logprobs(logp, blank=blank_id)\n        off = 0\n        for i in range(x.size(0)):\n            L = t_lens[i].item()\n            ref_ids = targets[off:off+L].tolist()\n            off += L\n            hyp_text = ids_to_text(hyps[i])\n            ref_text = ids_to_text(ref_ids)\n            print(f\"[Sample {i}]\")\n            print(\"REF:\", ref_text)\n            print(\"HYP:\", hyp_text)\n        cnt += 1\n        if cnt >= n_batches: break\n\npreview_predictions(model, val_loader, n_batches=1, blank_id=0)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-09T18:39:25.544439Z","iopub.execute_input":"2025-11-09T18:39:25.544897Z","iopub.status.idle":"2025-11-09T18:39:26.137562Z","shell.execute_reply.started":"2025-11-09T18:39:25.544878Z","shell.execute_reply":"2025-11-09T18:39:26.136744Z"}},"outputs":[],"execution_count":null}]}