{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "---\n",
    "execute:\n",
    "  enabled: false\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=hosted-notebooks-md-1 fw=all -->\n",
    "\n",
    "# Colab and Kaggle\n",
    "\n",
    "The fastest way to run this book's code is to not install anything at all.\n",
    "[Google Colab](https://colab.research.google.com/) and\n",
    "[Kaggle](https://www.kaggle.com/code) will hand you a browser-based notebook\n",
    "attached to a fresh virtual machine — usually with a GPU — *free of charge*,\n",
    "up to reasonable limits. For a reader, that removes every excuse: the gap\n",
    "between \"I wonder what happens if…\" and a running experiment is one click,\n",
    "even on a tablet or a locked-down work laptop. Both services exist because\n",
    "free notebooks funnel users toward paid compute (Colab) and toward a\n",
    "data-science community and competitions (Kaggle), but the free tiers are\n",
    "genuinely usable: every notebook in this book trains comfortably within\n",
    "them.\n",
    "\n",
    "The trade you make is control. The provider creates a temporary machine with\n",
    "a browser editor, a Python environment, and an accelerator; when the session\n",
    "ends — after roughly twelve hours, or sooner if it sits idle — the machine\n",
    "and everything written to its local disk vanish. Your notebook and any\n",
    "artifacts you explicitly saved survive; nothing else does.\n",
    "\n",
    "![A hosted runtime is temporary; notebooks, data, and checkpoints become durable only when we save them explicitly.](../img/tools-hosted-lifecycle.svg)\n",
    "\n",
    "The lifecycle in the figure explains most hosted\n",
    "notebook surprises. A runtime may stop after inactivity, hit a session\n",
    "limit, or come back with a different software image. Conversely, rerunning a\n",
    "setup cell is cheap when the notebook records everything needed to\n",
    "reconstruct the runtime — which is exactly how the notebooks in this book\n",
    "are written.\n",
    "\n",
    "## Launching a Book Notebook\n",
    "\n",
    "Every code-bearing page of the book has a **Run notebook** control that\n",
    "follows the active framework tab: framework-specific pages offer PyTorch,\n",
    "TensorFlow, or JAX; framework-independent pages use a single NumPy notebook.\n",
    "The generated notebooks live at a stable path on a public GitHub branch and\n",
    "record the exact source revision they were built from.\n",
    "\n",
    "![The source page, the generated notebook branch, and the provider launch are separate stages with a stable page-to-notebook mapping.](../img/tools-notebook-pipeline.svg)\n",
    "\n",
    "The two launch buttons behave differently, and the difference is worth\n",
    "understanding because you will meet it all over the ML ecosystem:\n",
    "\n",
    "* **Colab opens a pointer to GitHub.** The URL has the form\n",
    "  `colab.research.google.com/github/<org>/<repo>/blob/<branch>/<path>.ipynb`,\n",
    "  and Colab fetches the notebook from GitHub every time it is opened. You\n",
    "  are always looking at the current published version — but your edits are\n",
    "  *not* written back. To keep changes, use **File → Save a copy in Drive**\n",
    "  (or download the `.ipynb`).\n",
    "* **Kaggle imports a copy.** The book passes the notebook's raw URL to\n",
    "  Kaggle's importer (`kaggle.com/kernels/welcome?src=...`), which creates a\n",
    "  new private scratchpad *in your Kaggle account* containing that notebook.\n",
    "  You can inspect it without signing in; editing and running require an\n",
    "  account. Your copy is now independent of the book — it will not update\n",
    "  when the book does, and keeping your changes means saving a version on\n",
    "  Kaggle.\n",
    "\n",
    "In short: Colab launches a live view of the repository, Kaggle clones a\n",
    "snapshot into your workspace. Either way, the launch button never uploads an\n",
    "arbitrary local file — it refers to a readable notebook at a stable public\n",
    "path, which you can and should inspect before running. Treat that as a habit\n",
    "for *any* \"open in Colab\" badge on the internet: check the repository origin\n",
    "and the setup cell before executing someone else's code on your account.\n",
    "\n",
    "## Colab\n",
    "\n",
    "### What the Free Tier Buys\n",
    "\n",
    "A free Colab session (as of mid-2026) typically provides an NVIDIA T4 GPU\n",
    "with 16 GB of memory, a dozen gigabytes of RAM, and a session that runs for\n",
    "at most about twelve hours. All limits are deliberately dynamic — Google's\n",
    "FAQ states plainly that it does not publish them \"in part because they can\n",
    "vary over time.\" Availability responds to demand: at busy times you may wait\n",
    "for a GPU or be offered none. The free tier also includes a small TPU\n",
    "allocation and, since Colab's AI-first redesign, a built-in Gemini assistant\n",
    "that can write and fix notebook code.\n",
    "\n",
    "Do not infer the hardware from the menu — verify it in code:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "hosted-notebooks-resource-check"
   },
   "source": [
    "import os\n",
    "\n",
    "resource = {\n",
    "    \"cpu_count_visible\": os.cpu_count(),\n",
    "    \"colab\": \"COLAB_RELEASE_TAG\" in os.environ,\n",
    "    \"kaggle\": \"KAGGLE_KERNEL_RUN_TYPE\" in os.environ,\n",
    "}\n",
    "resource"
   ],
   "execution_count": 1,
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "{'cpu_count_visible': 64, 'colab': False, 'kaggle': False}"
     },
     "metadata": {},
     "execution_count": 1
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=hosted-notebooks-md-2 fw=all -->\n",
    "\n",
    "For PyTorch, check `torch.cuda.is_available()` and\n",
    "`torch.cuda.get_device_properties(0)`; for TensorFlow,\n",
    "`tf.config.list_physical_devices(\"GPU\")`; for JAX, `jax.devices()`. A\n",
    "reported accelerator is still not a guarantee that your workload fits its\n",
    "memory.\n",
    "\n",
    "When the free tier is not enough, Colab sells *compute units*: about \\$10\n",
    "buys 100 units, which a T4 burns at roughly 2 per hour and an A100 at\n",
    "roughly 15 per hour (mid-2026 figures; check the current pricing page).\n",
    "Subscriptions (Pro, Pro+) bundle units with faster GPUs, more RAM, and —\n",
    "on Pro+ — background execution. The units are a burst budget, not a\n",
    "guaranteed floor: when they run out, you are back on free-tier terms.\n",
    "\n",
    "Two recent additions are worth knowing. *Pinned runtime versions* let a\n",
    "notebook request a dated environment image, taming the \"worked yesterday,\n",
    "broke today\" package drift that plagues hosted runtimes. And the *Colab\n",
    "CLI* (`colab exec`, `colab repl`) drives the same runtimes from a terminal\n",
    "or a coding agent, which makes Colab usable as a scriptable free GPU rather\n",
    "than only an interactive page.\n",
    "\n",
    "### Saving Work\n",
    "\n",
    "Colab is Drive-centric: **Save a copy in Drive** is the persistence story,\n",
    "and Google Drive mounts (`drive.mount`) are the common way to keep datasets\n",
    "and checkpoints across sessions. A notebook opened from GitHub is never\n",
    "saved back automatically. Colab can also attach to a *local runtime* — the\n",
    "browser UI controlling a Jupyter server on your own machine — which changes\n",
    "the security boundary completely: the notebook then executes with the\n",
    "permissions of your local Jupyter process. Connect only notebooks you trust.\n",
    "\n",
    "## Kaggle\n",
    "\n",
    "### A Data-Centric Model\n",
    "\n",
    "Where Colab orbits Drive, Kaggle orbits *datasets and competitions*, and its\n",
    "notebook product reflects that. Three directories define the mental model:\n",
    "\n",
    "* `/kaggle/input/` holds attached datasets and models, mounted **read-only**\n",
    "  and versioned. Attaching an existing dataset is instant and costs no\n",
    "  download time or quota.\n",
    "* `/kaggle/working/` is your writable output directory (about 20 GB); its\n",
    "  contents persist only into *saved versions* of the notebook.\n",
    "* everything else is scratch that disappears with the session.\n",
    "\n",
    "The second defining feature is versioning. **Save & Run All** executes the\n",
    "whole notebook top to bottom in a fresh session and stores the result as an\n",
    "immutable, named version — inputs, code, outputs, and logs. This is restart\n",
    "and run all (that section) elevated to a platform\n",
    "primitive, and it is why Kaggle notebooks attached to competitions are\n",
    "reproducible in a way ad-hoc notebooks rarely are.\n",
    "\n",
    "### Quotas and Hardware\n",
    "\n",
    "Kaggle publishes its limits, which makes it the more predictable free tier\n",
    "(figures as of mid-2026): roughly **30 GPU-hours per week** on a P100 or a\n",
    "2×T4 machine, about 20 TPU-hours per week, 12-hour sessions, and around\n",
    "30 GB of RAM. Phone verification unlocks the GPU and internet toggles.\n",
    "Internet access is a per-notebook setting and is disabled in some\n",
    "competitions, so a well-behaved notebook attaches data as inputs rather\n",
    "than downloading it mid-run. The\n",
    "[Kaggle CLI](https://github.com/Kaggle/kaggle-cli) can push, run, and pull\n",
    "notebooks and datasets from your terminal; keep its token in the provider's\n",
    "secret store, never in a cell.\n",
    "\n",
    "## Choosing and Working Portably\n",
    "\n",
    "### Colab or Kaggle?\n",
    "\n",
    "<!-- tbl-caption:Hosted notebook trade-offs (mid-2026) -->\n",
    "\n",
    "| Need | Colab | Kaggle |\n",
    "|---|---|---|\n",
    "| Open a GitHub notebook directly | Yes — live fetch per open | Import creates your own copy |\n",
    "| Free GPU | T4; limits opaque, demand-driven | P100 or 2×T4; ~30 h/week published |\n",
    "| Predictable quota | No | Yes |\n",
    "| Persistent files | Google Drive | Versioned datasets and outputs |\n",
    "| Reproducible runs | Manual restart-and-run-all | Save & Run All versions |\n",
    "| Competition workflow | External | Native |\n",
    "| Paid upgrade path | Compute units, Pro/Pro+ | None needed — quota is fixed |\n",
    "\n",
    "The right choice is often wherever your data already lives. For running a\n",
    "book section, Colab's direct GitHub opening is the shortest path. For a\n",
    "dataset-centered experiment you want to share or rerun reproducibly,\n",
    "Kaggle's versioned inputs and outputs are more natural. For long training\n",
    "runs, private data, or guaranteed hardware, use a machine you control — the\n",
    "subject of that section.\n",
    "\n",
    "### Setup Cells That Survive\n",
    "\n",
    "Because the runtime is replaceable, the notebook must carry its own setup.\n",
    "A good setup cell is short, idempotent, and explicit: it pins revisions,\n",
    "installs only what is missing, and contains no secrets."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "hosted-notebooks-portable-setup"
   },
   "source": [
    "import importlib.util\n",
    "import platform\n",
    "\n",
    "required = [\"numpy\", \"matplotlib\"]\n",
    "missing = [name for name in required\n",
    "           if importlib.util.find_spec(name) is None]\n",
    "{\n",
    "    \"python\": platform.python_version(),\n",
    "    \"missing\": missing,\n",
    "    \"reconstructible\": not missing,\n",
    "}"
   ],
   "execution_count": 2,
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "{'python': '3.12.3', 'missing': [], 'reconstructible': True}"
     },
     "metadata": {},
     "execution_count": 2
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=hosted-notebooks-md-3 fw=all -->\n",
    "\n",
    "Avoid an unconditional `pip install --upgrade ...` at the top of a notebook:\n",
    "it discards a tested provider environment, slows every start, and makes\n",
    "yesterday's notebook resolve different packages today. Install the specific\n",
    "missing package at a pinned version instead. Since a provider image can\n",
    "change under an unmodified notebook, printing a small environment\n",
    "fingerprint makes results interpretable and bug reports useful:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "hosted-notebooks-environment-fingerprint"
   },
   "source": [
    "import json\n",
    "import numpy as np\n",
    "\n",
    "fingerprint = {\n",
    "    \"python\": platform.python_version(),\n",
    "    \"numpy\": np.__version__,\n",
    "    \"machine\": platform.machine(),\n",
    "}\n",
    "print(json.dumps(fingerprint, indent=2))"
   ],
   "execution_count": 3,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "{\n  \"python\": \"3.12.3\",\n  \"numpy\": \"2.4.4\",\n  \"machine\": \"x86_64\"\n}\n"
     ]
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=hosted-notebooks-md-4 fw=all -->\n",
    "\n",
    "Portable notebooks also avoid hard-coding provider paths. Keep the\n",
    "provider-specific part in one small adapter and use `pathlib` everywhere\n",
    "else:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "id": "hosted-notebooks-work-directory"
   },
   "source": [
    "from pathlib import Path\n",
    "\n",
    "if Path(\"/kaggle/working\").exists():\n",
    "    work = Path(\"/kaggle/working\")\n",
    "elif Path(\"/content\").exists():\n",
    "    work = Path(\"/content\")\n",
    "else:\n",
    "    work = Path.cwd()\n",
    "work"
   ],
   "execution_count": 4,
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "PosixPath('/home/smola/d2l-neu/_notebooks/pytorch/chapter_appendix-tools-for-deep-learning')"
     },
     "metadata": {},
     "execution_count": 4
    }
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- d2l:prose id=hosted-notebooks-md-5 fw=all -->\n",
    "\n",
    "Finally, secrets: both providers offer a secret manager for API tokens. Use\n",
    "it. Never print a token, store it in an output, or commit it in a saved\n",
    "copy — a public notebook is an executable publication, and its outputs are\n",
    "part of what you publish.\n",
    "\n",
    "## Summary\n",
    "\n",
    "* Colab and Kaggle run this book's notebooks free of charge within\n",
    "  reasonable limits — a T4-class GPU is enough for every notebook here.\n",
    "* The launch buttons differ: Colab opens a live pointer to the notebook on\n",
    "  GitHub (edits are not saved back); Kaggle imports a snapshot into your\n",
    "  own account.\n",
    "* Colab's limits are deliberately opaque and demand-driven, with paid\n",
    "  compute units as the escape valve; Kaggle publishes a weekly quota and\n",
    "  makes reproducible versioned runs a platform primitive.\n",
    "* A hosted runtime is replaceable: idempotent setup cells, explicit saving\n",
    "  of artifacts, and secrets kept in the secret manager make notebooks\n",
    "  portable across providers and time.\n",
    "\n",
    "## Exercises\n",
    "\n",
    "1. Open this section on both Colab and Kaggle via the **Run notebook**\n",
    "   control. Where does your edited copy live in each case, and what happens\n",
    "   to it when the session ends?\n",
    "1. Extend the environment fingerprint with the framework version and\n",
    "   accelerator name, without failing on a CPU-only runtime.\n",
    "1. On Kaggle, produce two versions of a notebook with **Save & Run All**\n",
    "   and compare them. What exactly does Kaggle store per version?\n",
    "1. Estimate how long a free weekly Kaggle GPU quota would take to fine-tune\n",
    "   the BERT model of that section, using the timings\n",
    "   reported there."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "name": "d2l-pytorch",
   "display_name": "d2l (PyTorch)",
   "language": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
