Files
cs249r_book/tinytorch/resources.html
T

2297 lines
105 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.9.38">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Learning Resources TinyTorch</title>
<style>
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
vertical-align: middle;
}
</style>
<script src="site_libs/quarto-nav/quarto-nav.js"></script>
<script src="site_libs/clipboard/clipboard.min.js"></script>
<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
<script src="site_libs/quarto-search/fuse.min.js"></script>
<script src="site_libs/quarto-search/quarto-search.js"></script>
<meta name="quarto:offset" content="./">
<link href="./team.html" rel="next">
<link href="./datasets.html" rel="prev">
<link href="./assets/images/favicon.svg" rel="icon" type="image/svg+xml">
<script src="site_libs/quarto-html/quarto.js" type="module"></script>
<script src="site_libs/quarto-html/tabsets/tabsets.js" type="module"></script>
<script src="site_libs/quarto-html/popper.min.js"></script>
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
<script src="site_libs/quarto-html/anchor.min.js"></script>
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
<link href="site_libs/quarto-html/quarto-syntax-highlighting-d58168542e1b05ab509c510cbeb13b13.css" rel="stylesheet" class="quarto-color-scheme" id="quarto-text-highlighting-styles">
<link href="site_libs/quarto-html/quarto-syntax-highlighting-dark-88e37a8f5ac5aee93fe4de4f1f74577c.css" rel="stylesheet" class="quarto-color-scheme quarto-color-alternate" id="quarto-text-highlighting-styles">
<link href="site_libs/quarto-html/quarto-syntax-highlighting-d58168542e1b05ab509c510cbeb13b13.css" rel="stylesheet" class="quarto-color-scheme-extra" id="quarto-text-highlighting-styles">
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="site_libs/bootstrap/bootstrap-2bab33dbe7817173bbc4a78ab485562b.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme" id="quarto-bootstrap" data-mode="light">
<link href="site_libs/bootstrap/bootstrap-dark-41c6c8aaa029f41185ba15883681b9bb.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme quarto-color-alternate" id="quarto-bootstrap" data-mode="light">
<link href="site_libs/bootstrap/bootstrap-2bab33dbe7817173bbc4a78ab485562b.min.css" rel="stylesheet" append-hash="true" class="quarto-color-scheme-extra" id="quarto-bootstrap" data-mode="light">
<script id="quarto-search-options" type="application/json">{
"location": "navbar",
"copy-button": false,
"collapse-after": 3,
"panel-placement": "end",
"type": "overlay",
"limit": 50,
"keyboard-shortcut": [
"/"
],
"language": {
"search-no-results-text": "No results",
"search-matching-documents-text": "matching documents",
"search-copy-link-title": "Copy link to search",
"search-hide-matches-text": "Hide additional matches",
"search-more-match-text": "more match in this document",
"search-more-matches-text": "more matches in this document",
"search-clear-button-title": "Clear",
"search-text-placeholder": "",
"search-detached-cancel-button-title": "Cancel",
"search-submit-button-title": "Submit",
"search-label": "Search"
}
}</script>
<!-- Shared head includes — MLSysBook ecosystem -->
<!--
theme-persist (inline, sync) — applies stored color-scheme before first paint.
Inlined deliberately: runs before any other <script>, no extra round-trip,
and avoids per-subsite asset path differences. Canonical source:
shared/scripts/theme-persist.js (kept identical for documentation/testability).
If you change one, mirror the change to the other.
-->
<script>
(function () {
'use strict';
var STORAGE_KEY = 'quarto-color-scheme';
// Quarto's toggle writes 'alternate'/'default' (alternate = dark, the
// layered sheet); sibling non-Quarto sites write 'dark'/'light'. Both
// hit the same key, so we accept either. Quarto's own startup still
// checks `=== 'alternate'`, so we mirror onto <html> rather than rewrite.
function normalize(v) {
if (v === 'dark' || v === 'alternate') return 'dark';
if (v === 'light' || v === 'default') return 'light';
return null;
}
function preferredScheme() {
try {
var n = normalize(window.localStorage.getItem(STORAGE_KEY));
if (n) return n;
} catch (e) {}
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
}
function apply(scheme) {
var html = document.documentElement;
if (!html) return;
html.setAttribute('data-bs-theme', scheme);
html.setAttribute('data-quarto-color-scheme', scheme);
html.style.colorScheme = scheme;
// Bridge to legacy `.quarto-dark` body class — about.css,
// community.css, and newsletter.css key their dark-mode CSS
// variables off `.quarto-dark { ... }`. Quarto's own toggle adds
// that class on click, but the OS-pref / first-paint path never
// does. Mirror the scheme onto body so those CSS variables fire
// on every dark path, not just toggle clicks. body may not exist
// yet on the first call (this script runs in <head>); a
// MutationObserver below catches it as soon as it parses.
var body = document.body;
if (body) body.classList.toggle('quarto-dark', scheme === 'dark');
}
apply(preferredScheme());
// Catch the FOUC window between <head> apply() and DOMContentLoaded:
// <body> may not exist yet at first apply(), but as soon as the
// parser appends it we want the legacy class bridge in place so any
// CSS keyed on `.quarto-dark` paints correctly on first render.
if (!document.body) {
var earlyObserver = new MutationObserver(function () {
if (document.body) {
apply(preferredScheme());
earlyObserver.disconnect();
}
});
earlyObserver.observe(document.documentElement, { childList: true });
}
// Quarto's toggle updates localStorage but not <html>, so wrap it to
// mirror the new value onto data-bs-theme; otherwise clicking the toggle
// leaves CSS keyed off [data-bs-theme="dark"] rendering against the wrong
// stylesheet until the next reload.
function syncFromStorage() {
try {
var n = normalize(window.localStorage.getItem(STORAGE_KEY));
if (n) apply(n);
} catch (e) {}
}
function wrapToggle() {
var orig = window.quartoToggleColorScheme;
if (typeof orig !== 'function' || orig.__mlsbWrapped) return;
var wrapped = function () { var r = orig.apply(this, arguments); syncFromStorage(); return r; };
wrapped.__mlsbWrapped = true;
window.quartoToggleColorScheme = wrapped;
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { wrapToggle(); syncFromStorage(); });
} else {
wrapToggle(); syncFromStorage();
}
// Defend the legacy `.quarto-dark` body class against Quarto's own
// `toggleBodyColor(mode)`, which runs *after* this script and re-asserts
// the body class based on `mode` — and `mode` defaults to 'light' when
// there's no stored quarto-color-scheme value, even when the OS / first
// paint already resolved to dark via `data-bs-theme`. Without this
// observer, on every fresh visit Quarto would clobber our bridge and
// restore `.quarto-light`, leaving `.quarto-dark`-keyed CSS variables
// (about/community/newsletter pages) at their light-mode defaults
// against the dark `data-bs-theme="dark"` background.
function bridgeBody() {
var body = document.body;
if (!body) return;
var wantDark = document.documentElement.getAttribute('data-bs-theme') === 'dark';
if (wantDark && !body.classList.contains('quarto-dark')) {
body.classList.add('quarto-dark');
body.classList.remove('quarto-light');
} else if (!wantDark && body.classList.contains('quarto-dark')) {
body.classList.remove('quarto-dark');
body.classList.add('quarto-light');
}
}
function watchBody() {
if (!document.body) return;
bridgeBody();
var bodyObs = new MutationObserver(bridgeBody);
bodyObs.observe(document.body, { attributes: true, attributeFilter: ['class'] });
var htmlObs = new MutationObserver(bridgeBody);
htmlObs.observe(document.documentElement, { attributes: true, attributeFilter: ['data-bs-theme'] });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', watchBody);
} else {
watchBody();
}
window.addEventListener('storage', function (ev) {
if (ev.key !== STORAGE_KEY) return;
var n = normalize(ev.newValue);
if (n) apply(n);
});
if (window.matchMedia) {
try {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (ev) {
try { if (window.localStorage.getItem(STORAGE_KEY)) return; } catch (e) {}
apply(ev.matches ? 'dark' : 'light');
});
} catch (e) {}
}
})();
</script>
<!--
Build-stamp styling. Tiny, neutral, dark-mode aware. The actual stamp text
is injected by shared/scripts/inject-build-stamp.sh into footer markup
containing the literal MLSB_BUILD_STAMP HTML-comment token (see that
script for the exact pattern — we cannot write it here because HTML
comments cannot nest and the inner closer would terminate this block).
-->
<style>
.mlsb-build-stamp {
display: inline-block;
margin-top: 0.25rem;
font-size: 0.75rem;
opacity: 0.6;
font-variant-numeric: tabular-nums;
}
[data-bs-theme="dark"] .mlsb-build-stamp { opacity: 0.5; }
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&amp;family=JetBrains+Mono:wght@400;500&amp;display=swap" rel="stylesheet">
<link rel="icon" href="https://mlsysbook.ai/vol1/assets/images/icons/favicon.png" type="image/png">
<!--
navbar-theme-toggle-relocate — moves the Quarto theme toggle into the
navbar's right-side .navbar-nav group at page load, so it collapses into
the hamburger menu alongside Subscribe/Star/Support/GitHub at narrow widths
instead of being stranded in the middle by Quarto's mx-auto brand layout.
Why JS: Quarto auto-injects the toggle into .quarto-navbar-tools (outside
.navbar-collapse). CSS can't move DOM nodes between containers, and CSS
positioning hacks (absolute/right: 50px) fight Bootstrap's responsive
layout below 992px. Moving the node once at startup is the standard
approach used across Quarto-based sites with the same problem.
-->
<script>
(function () {
'use strict';
function relocateThemeToggle() {
var tools = document.querySelector('.quarto-navbar-tools');
if (!tools) return;
var toggle = tools.querySelector('.quarto-color-scheme-toggle');
if (!toggle) return;
var navRight = document.querySelector(
'.navbar .navbar-collapse .navbar-nav.ms-auto'
) || document.querySelector(
'.navbar .navbar-collapse .navbar-nav:last-of-type'
);
if (!navRight) return;
var li = document.createElement('li');
li.className = 'nav-item navbar-theme-toggle-item';
toggle.classList.add('nav-link');
li.appendChild(toggle);
navRight.appendChild(li);
tools.style.display = 'none';
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', relocateThemeToggle);
} else {
relocateThemeToggle();
}
})();
</script>
<!--
navbar-brand-href-fix — force the navbar brand link to the ecosystem root
(https://mlsysbook.ai/) on every subsite.
Quarto sets each subsite's `site-url` to `https://mlsysbook.ai/<subsite>/`
and then relativizes any navbar.href value that lives inside the
site-url's domain. The shared `href: https://mlsysbook.ai/` in
navbar-common.yml therefore gets emitted as `./index.html`, which on
vol1/vol2/tinytorch/etc. resolves to *that subsite's* root rather than
the ecosystem landing page. Override the brand link href in JS after
Quarto's render: this is a one-line user-experience fix that does not
fight Quarto's URL machinery.
-->
<script>
(function () {
'use strict';
function fixBrandHref() {
var brand = document.querySelectorAll(
'.navbar .navbar-brand, .navbar .navbar-brand-logo'
);
for (var i = 0; i < brand.length; i++) {
brand[i].setAttribute('href', 'https://mlsysbook.ai/');
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fixBrandHref);
} else {
fixBrandHref();
}
})();
</script>
<link rel="apple-touch-icon" href="./assets/images/logos/logo-tinytorch.png">
<meta name="theme-color" content="#D4740C">
<!-- Release identity (rendered into the footer pill below).
The publish workflow drops release-manifest.json at
/tinytorch/release-manifest.json before deploy; preview
and local renders silently no-op. -->
<meta name="release-manifest" content="/tinytorch/release-manifest.json">
<meta property="og:title" content="Learning Resources TinyTorch">
<meta property="og:description" content="An interactive course for building machine learning systems from the ground up. Learn by implementing your own PyTorch-style framework with hands-on coding, real datasets, and production-ready practices.">
<meta property="og:image" content="https://mlsysbook.ai/tinytorch/assets/images/logos/logo-tinytorch.png">
<meta property="og:site_name" content="TinyTorch">
<meta property="og:locale" content="en_US">
<meta property="og:image:height" content="328">
<meta property="og:image:width" content="583">
<meta name="twitter:title" content="Learning Resources TinyTorch">
<meta name="twitter:description" content="An interactive course for building machine learning systems from the ground up. Learn by implementing your own PyTorch-style framework with hands-on coding, real datasets, and production-ready practices.">
<meta name="twitter:image" content="https://mlsysbook.ai/tinytorch/assets/images/logos/logo-tinytorch.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image-height" content="328">
<meta name="twitter:image-width" content="583">
</head>
<body class="nav-sidebar floating nav-fixed quarto-light"><script id="quarto-html-before-body" type="application/javascript">
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap:not([rel=disabled-stylesheet])");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
const setColorSchemeToggle = (alternate) => {
const toggles = window.document.querySelectorAll('.quarto-color-scheme-toggle');
for (let i=0; i < toggles.length; i++) {
const toggle = toggles[i];
if (toggle) {
if (alternate) {
toggle.classList.add("alternate");
} else {
toggle.classList.remove("alternate");
}
}
}
};
const toggleColorMode = (alternate) => {
// Switch the stylesheets
const primaryStylesheets = window.document.querySelectorAll('link.quarto-color-scheme:not(.quarto-color-alternate)');
const alternateStylesheets = window.document.querySelectorAll('link.quarto-color-scheme.quarto-color-alternate');
manageTransitions('#quarto-margin-sidebar .nav-link', false);
if (alternate) {
// note: dark is layered on light, we don't disable primary!
enableStylesheet(alternateStylesheets);
for (const sheetNode of alternateStylesheets) {
if (sheetNode.id === "quarto-bootstrap") {
toggleBodyColorMode(sheetNode);
}
}
} else {
disableStylesheet(alternateStylesheets);
enableStylesheet(primaryStylesheets)
toggleBodyColorPrimary();
}
manageTransitions('#quarto-margin-sidebar .nav-link', true);
// Switch the toggles
setColorSchemeToggle(alternate)
// Hack to workaround the fact that safari doesn't
// properly recolor the scrollbar when toggling (#1455)
if (navigator.userAgent.indexOf('Safari') > 0 && navigator.userAgent.indexOf('Chrome') == -1) {
manageTransitions("body", false);
window.scrollTo(0, 1);
setTimeout(() => {
window.scrollTo(0, 0);
manageTransitions("body", true);
}, 40);
}
}
const disableStylesheet = (stylesheets) => {
for (let i=0; i < stylesheets.length; i++) {
const stylesheet = stylesheets[i];
stylesheet.rel = 'disabled-stylesheet';
}
}
const enableStylesheet = (stylesheets) => {
for (let i=0; i < stylesheets.length; i++) {
const stylesheet = stylesheets[i];
if(stylesheet.rel !== 'stylesheet') { // for Chrome, which will still FOUC without this check
stylesheet.rel = 'stylesheet';
}
}
}
const manageTransitions = (selector, allowTransitions) => {
const els = window.document.querySelectorAll(selector);
for (let i=0; i < els.length; i++) {
const el = els[i];
if (allowTransitions) {
el.classList.remove('notransition');
} else {
el.classList.add('notransition');
}
}
}
const isFileUrl = () => {
return window.location.protocol === 'file:';
}
const hasAlternateSentinel = () => {
let styleSentinel = getColorSchemeSentinel();
if (styleSentinel !== null) {
return styleSentinel === "alternate";
} else {
return false;
}
}
const setStyleSentinel = (alternate) => {
const value = alternate ? "alternate" : "default";
if (!isFileUrl()) {
window.localStorage.setItem("quarto-color-scheme", value);
} else {
localAlternateSentinel = value;
}
}
const getColorSchemeSentinel = () => {
if (!isFileUrl()) {
const storageValue = window.localStorage.getItem("quarto-color-scheme");
return storageValue != null ? storageValue : localAlternateSentinel;
} else {
return localAlternateSentinel;
}
}
const toggleGiscusIfUsed = (isAlternate, darkModeDefault) => {
const baseTheme = document.querySelector('#giscus-base-theme')?.value ?? 'light';
const alternateTheme = document.querySelector('#giscus-alt-theme')?.value ?? 'dark';
let newTheme = '';
if(authorPrefersDark) {
newTheme = isAlternate ? baseTheme : alternateTheme;
} else {
newTheme = isAlternate ? alternateTheme : baseTheme;
}
const changeGiscusTheme = () => {
// From: https://github.com/giscus/giscus/issues/336
const sendMessage = (message) => {
const iframe = document.querySelector('iframe.giscus-frame');
if (!iframe) return;
iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
}
sendMessage({
setConfig: {
theme: newTheme
}
});
}
const isGiscussLoaded = window.document.querySelector('iframe.giscus-frame') !== null;
if (isGiscussLoaded) {
changeGiscusTheme();
}
};
const authorPrefersDark = false;
const queryPrefersDark = window.matchMedia('(prefers-color-scheme: dark)');
const darkModeDefault = queryPrefersDark.matches;
document.querySelector('link#quarto-text-highlighting-styles.quarto-color-scheme-extra').rel = 'disabled-stylesheet';
document.querySelector('link#quarto-bootstrap.quarto-color-scheme-extra').rel = 'disabled-stylesheet';
let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default';
// Dark / light mode switch
window.quartoToggleColorScheme = () => {
// Read the current dark / light value
let toAlternate = !hasAlternateSentinel();
toggleColorMode(toAlternate);
setStyleSentinel(toAlternate);
toggleGiscusIfUsed(toAlternate, darkModeDefault);
window.dispatchEvent(new Event('resize'));
};
queryPrefersDark.addEventListener("change", e => {
if(window.localStorage.getItem("quarto-color-scheme") !== null)
return;
const alternate = e.matches
toggleColorMode(alternate);
localAlternateSentinel = e.matches ? 'alternate' : 'default'; // this is used alongside local storage!
toggleGiscusIfUsed(alternate, darkModeDefault);
});
// Switch to dark mode if need be
if (hasAlternateSentinel()) {
toggleColorMode(true);
} else {
toggleColorMode(false);
}
</script>
<div id="quarto-search-results"></div>
<header id="quarto-header" class="headroom fixed-top">
<nav class="navbar navbar-expand-xl " data-bs-theme="dark">
<div class="navbar-container container-fluid">
<div class="navbar-brand-container mx-auto">
<a href="./index.html" class="navbar-brand navbar-brand-logo">
<img src="./assets/images/logo.png" alt="" class="navbar-logo light-content">
<img src="./assets/images/logo.png" alt="" class="navbar-logo dark-content">
</a>
<a class="navbar-brand" href="./index.html">
<span class="navbar-title">Machine Learning Systems</span>
</a>
</div>
<div id="quarto-search" class="" title="Search"></div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav navbar-nav-scroll me-auto">
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-tinytorch" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<span class="menu-text">TinyTorch</span>
</a>
<ul class="dropdown-menu" aria-labelledby="nav-menu-tinytorch">
<li>
<a class="dropdown-item" href="./index.html"><i class="bi bi-fire" role="img">
</i>
<span class="dropdown-text">TinyTorch Home</span></a>
</li>
<li>
<a class="dropdown-item" href="./getting-started.html">
<span class="dropdown-text">Getting Started</span></a>
</li>
<li>
<a class="dropdown-item" href="./big-picture.html">
<span class="dropdown-text">Big Picture</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="./tiers/foundation.html">
<span class="dropdown-text">Foundation Tier</span></a>
</li>
<li>
<a class="dropdown-item" href="./tiers/architecture.html">
<span class="dropdown-text">Architecture Tier</span></a>
</li>
<li>
<a class="dropdown-item" href="./tiers/optimization.html">
<span class="dropdown-text">Optimization Tier</span></a>
</li>
<li>
<a class="dropdown-item" href="./tiers/olympics.html">
<span class="dropdown-text">Torch Olympics</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="./milestones/index.html">
<span class="dropdown-text">Historical Milestones</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="./tito/overview.html">
<span class="dropdown-text">TITO CLI</span></a>
</li>
<li>
<a class="dropdown-item" href="./datasets.html">
<span class="dropdown-text">Datasets Guide</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="./assets/downloads/TinyTorch-Guide.pdf" target="_blank"><i class="bi bi-file-pdf" role="img">
</i>
<span class="dropdown-text">TinyTorch Guide (PDF)</span></a>
</li>
<li>
<a class="dropdown-item" href="./assets/downloads/TinyTorch-Paper.pdf" target="_blank"><i class="bi bi-file-pdf" role="img">
</i>
<span class="dropdown-text">TinyTorch Paper (PDF)</span></a>
</li>
</ul>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-read" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<span class="menu-text">Read</span>
</a>
<ul class="dropdown-menu" aria-labelledby="nav-menu-read">
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/vol1/"><i class="bi bi-journal" role="img">
</i>
<span class="dropdown-text">Volume I: Foundations</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/vol2/"><i class="bi bi-journal" role="img">
</i>
<span class="dropdown-text">Volume II: At Scale</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/vol1/assets/downloads/Machine-Learning-Systems-Vol1.pdf" target="_blank"><i class="bi bi-file-pdf" role="img">
</i>
<span class="dropdown-text">Volume I PDF</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/vol1/assets/downloads/Machine-Learning-Systems-Vol1.epub" target="_blank"><i class="bi bi-journal-text" role="img">
</i>
<span class="dropdown-text">Volume I EPUB</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/vol2/assets/downloads/Machine-Learning-Systems-Vol2.pdf" target="_blank"><i class="bi bi-file-pdf" role="img">
</i>
<span class="dropdown-text">Volume II PDF</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/vol2/assets/downloads/Machine-Learning-Systems-Vol2.epub" target="_blank"><i class="bi bi-journal-text" role="img">
</i>
<span class="dropdown-text">Volume II EPUB</span></a>
</li>
</ul>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-build" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<span class="menu-text">Build</span>
</a>
<ul class="dropdown-menu" aria-labelledby="nav-menu-build">
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/labs/"><i class="bi bi-sliders" role="img">
</i>
<span class="dropdown-text">Labs</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/tinytorch/"><i class="bi bi-fire" role="img">
</i>
<span class="dropdown-text">TinyTorch</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/kits/"><i class="bi bi-cpu" role="img">
</i>
<span class="dropdown-text">Hardware Kits</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/mlsysim/"><i class="bi bi-calculator" role="img">
</i>
<span class="dropdown-text">MLSys·im</span></a>
</li>
</ul>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-teach" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<span class="menu-text">Teach</span>
</a>
<ul class="dropdown-menu" aria-labelledby="nav-menu-teach">
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/instructors/course-map.html"><i class="bi bi-signpost-split" role="img">
</i>
<span class="dropdown-text">Course Map</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/slides/"><i class="bi bi-easel" role="img">
</i>
<span class="dropdown-text">Lecture Slides</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/instructors/"><i class="bi bi-person-video3" role="img">
</i>
<span class="dropdown-text">Instructor Hub</span></a>
</li>
</ul>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-prepare" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<span class="menu-text">Prepare</span>
</a>
<ul class="dropdown-menu" aria-labelledby="nav-menu-prepare">
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/staffml/"><i class="bi bi-mortarboard" role="img">
</i>
<span class="dropdown-text">StaffML</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/staffml/plans"><i class="bi bi-map" role="img">
</i>
<span class="dropdown-text">Study Plans</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/staffml/gauntlet"><i class="bi bi-lightning" role="img">
</i>
<span class="dropdown-text">Gauntlet Mode</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/staffml/downloads/StaffML-Paper.pdf" target="_blank"><i class="bi bi-file-pdf" role="img">
</i>
<span class="dropdown-text">StaffML Paper</span></a>
</li>
</ul>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-connect" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<span class="menu-text">Connect</span>
</a>
<ul class="dropdown-menu" aria-labelledby="nav-menu-connect">
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/newsletter/"><i class="bi bi-envelope" role="img">
</i>
<span class="dropdown-text">Newsletter</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/community/"><i class="bi bi-globe" role="img">
</i>
<span class="dropdown-text">Global Network</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/community/events.html"><i class="bi bi-calendar-event" role="img">
</i>
<span class="dropdown-text">Workshops &amp; Events</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/community/partners.html"><i class="bi bi-people" role="img">
</i>
<span class="dropdown-text">Partners &amp; Sponsors</span></a>
</li>
</ul>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-about" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<span class="menu-text">About</span>
</a>
<ul class="dropdown-menu" aria-labelledby="nav-menu-about">
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/about/"><i class="bi bi-bullseye" role="img">
</i>
<span class="dropdown-text">Mission</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/about/#story"><i class="bi bi-book" role="img">
</i>
<span class="dropdown-text">Our Story</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/about/people.html"><i class="bi bi-person-lines-fill" role="img">
</i>
<span class="dropdown-text">People</span></a>
</li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/about/contributors.html"><i class="bi bi-people" role="img">
</i>
<span class="dropdown-text">Contributors</span></a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="https://mlsysbook.ai/about/license.html"><i class="bi bi-cc-circle" role="img">
</i>
<span class="dropdown-text">License</span></a>
</li>
</ul>
</li>
</ul>
<ul class="navbar-nav navbar-nav-scroll ms-auto">
<li class="nav-item">
<a class="nav-link" href="./#subscribe"> <i class="bi bi-envelope" role="img">
</i>
<span class="menu-text">Subscribe</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/harvard-edge/cs249r_book" target="_blank"> <i class="bi bi-star" role="img">
</i>
<span class="menu-text">Star</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://opencollective.com/mlsysbook" target="_blank"> <i class="bi bi-heart" role="img">
</i>
<span class="menu-text">Support</span></a>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="#" id="nav-menu-github" role="link" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-github" role="img">
</i>
<span class="menu-text">GitHub</span>
</a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="nav-menu-github">
<li>
<a class="dropdown-item" href="https://github.com/harvard-edge/cs249r_book/discussions" target="_blank"><i class="bi bi-chat" role="img">
</i>
<span class="dropdown-text">Discussions</span></a>
</li>
<li>
<a class="dropdown-item" href="https://github.com/harvard-edge/cs249r_book" target="_blank"><i class="bi bi-pencil" role="img">
</i>
<span class="dropdown-text">Edit this page</span></a>
</li>
<li>
<a class="dropdown-item" href="https://github.com/harvard-edge/cs249r_book/issues/new" target="_blank"><i class="bi bi-bug" role="img">
</i>
<span class="dropdown-text">Report an issue</span></a>
</li>
<li>
<a class="dropdown-item" href="https://github.com/harvard-edge/cs249r_book" target="_blank"><i class="bi bi-code" role="img">
</i>
<span class="dropdown-text">View source</span></a>
</li>
</ul>
</li>
</ul>
</div> <!-- /navcollapse -->
<div class="quarto-navbar-tools">
<a href="" class="quarto-color-scheme-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleColorScheme(); return false;" title="Toggle dark mode"><i class="bi"></i></a>
</div>
</div> <!-- /container-fluid -->
</nav>
<nav class="quarto-secondary-nav">
<div class="container-fluid d-flex">
<button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" role="button" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
<i class="bi bi-layout-text-sidebar-reverse"></i>
</button>
<nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./datasets.html">📚 Reference</a></li><li class="breadcrumb-item"><a href="./resources.html">Learning Resources</a></li></ol></nav>
<a class="flex-grow-1" role="navigation" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
</a>
</div>
</nav>
<div id="quarto-announcement" data-announcement-id="c1dc8b193ceca4e572bc367803d37925" class="alert alert-primary hidden"><i class="bi bi-megaphone quarto-announcement-icon"></i><div class="quarto-announcement-content">
<p>🔥 <strong>TinyTorch</strong> — build your own ML framework from scratch; the companion framework to the textbook.<br> 📘 <strong>The book:</strong> <a href="https://mlsysbook.ai/vol1/">Vol I: Foundations</a> · <a href="https://mlsysbook.ai/vol2/">Vol II: At Scale</a> — open access, free forever.<br> 🛠️ <strong>Alongside the book:</strong> <a href="https://mlsysbook.ai/kits/">Hardware Kits</a> (deploy) · <a href="https://mlsysbook.ai/mlsysim/">MLSys·im</a> (model) · <a href="https://mlsysbook.ai/labs/">Labs</a> (explore) · <a href="https://mlsysbook.ai/staffml/">StaffML</a> (practice)<br> 📬 <strong>Newsletter:</strong> ML Systems insights &amp; updates — <a href="https://mlsysbook.ai/newsletter/">Subscribe →</a></p>
</div><i class="bi bi-x-lg quarto-announcement-action"></i></div>
</header>
<!-- content -->
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
<!-- sidebar -->
<nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation floating overflow-auto">
<div class="pt-lg-2 mt-2 text-left sidebar-header">
<a href="./index.html" class="sidebar-logo-link">
<img src="./assets/images/logos/logo-tinytorch-transparent.png" alt="" class="sidebar-logo light-content py-0 d-lg-inline d-none">
<img src="./assets/images/logos/logo-tinytorch-transparent.png" alt="" class="sidebar-logo dark-content py-0 d-lg-inline d-none">
</a>
</div>
<div class="sidebar-menu-container">
<ul class="list-unstyled mt-1">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./index.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">TinyTorch Home</span></a>
</div>
</li>
<li class="px-0"><hr class="sidebar-divider hi "></li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" role="navigation" aria-expanded="true">
<span class="menu-text">🚀 Getting Started</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./preface.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Welcome</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./big-picture.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Big Picture</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./getting-started.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Quick Start</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" role="navigation" aria-expanded="true">
<span class="menu-text">🏗 Foundation Tier</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tiers/foundation.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">📖 Tier Overview</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/01_tensor.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">01. Tensor</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/02_activations.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">02. Activations</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/03_layers.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">03. Layers</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/04_losses.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">04. Losses</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/05_dataloader.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">05. DataLoader</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/06_autograd.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">06. Autograd</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/07_optimizers.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">07. Optimizers</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/08_training.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">08. Training</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" role="navigation" aria-expanded="true">
<span class="menu-text">🏛️ Architecture Tier</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tiers/architecture.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">📖 Tier Overview</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/09_convolutions.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">09. Convolutions</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/10_tokenization.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">10. Tokenization</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/11_embeddings.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">11. Embeddings</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/12_attention.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">12. Attention</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/13_transformers.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">13. Transformers</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" role="navigation" aria-expanded="true">
<span class="menu-text">⏱️ Optimization Tier</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tiers/optimization.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">📖 Tier Overview</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/14_profiling.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">14. Profiling</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/15_quantization.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">15. Quantization</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/16_compression.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">16. Compression</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/17_acceleration.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">17. Acceleration</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/18_memoization.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">18. Memoization</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/19_benchmarking.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">19. Benchmarking</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" role="navigation" aria-expanded="true">
<span class="menu-text">🏅 Capstone</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tiers/olympics.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">📖 Competition Overview</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./modules/20_capstone.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">20. Torch Olympics</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" role="navigation" aria-expanded="true">
<span class="menu-text">🎓 Conclusion</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./conclusion.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">You Built Something Real</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" role="navigation" aria-expanded="true">
<span class="menu-text">🛠️ TITO CLI</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tito/overview.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Command Overview</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tito/modules.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Module Workflow</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tito/milestones.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Milestone System</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tito/data.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Progress &amp; Data</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tito/testing.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Developer Testing</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./tito/troubleshooting.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Troubleshooting</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-8" role="navigation" aria-expanded="true">
<span class="menu-text">📚 Reference</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-8" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-8" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./datasets.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Datasets Guide</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./resources.html" class="sidebar-item-text sidebar-link active">
<span class="menu-text">Learning Resources</span></a>
</div>
</li>
</ul>
</li>
<li class="sidebar-item sidebar-item-section">
<div class="sidebar-item-container">
<a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-9" role="navigation" aria-expanded="true">
<span class="menu-text">🤝 Community</span></a>
<a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-9" role="navigation" aria-expanded="true" aria-label="Toggle section">
<i class="bi bi-chevron-right ms-2"></i>
</a>
</div>
<ul id="quarto-sidebar-section-9" class="collapse list-unstyled sidebar-section depth1 show">
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./team.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Team</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./community.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Ecosystem</span></a>
</div>
</li>
<li class="sidebar-item">
<div class="sidebar-item-container">
<a href="./credits.html" class="sidebar-item-text sidebar-link">
<span class="menu-text">Acknowledgments</span></a>
</div>
</li>
</ul>
</li>
</ul>
</div>
</nav>
<div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div>
<!-- margin-sidebar -->
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
<nav id="TOC" role="doc-toc" class="toc-active">
<h2 id="toc-title">On this page</h2>
<ul>
<li><a href="#companion-textbook" id="toc-companion-textbook" class="nav-link active" data-scroll-target="#companion-textbook">Companion Textbook</a>
<ul class="collapse">
<li><a href="#machine-learning-systems" id="toc-machine-learning-systems" class="nav-link" data-scroll-target="#machine-learning-systems">Machine Learning Systems</a></li>
</ul></li>
<li><a href="#related-academic-courses" id="toc-related-academic-courses" class="nav-link" data-scroll-target="#related-academic-courses">Related Academic Courses</a></li>
<li><a href="#other-textbooks" id="toc-other-textbooks" class="nav-link" data-scroll-target="#other-textbooks">Other Textbooks</a></li>
<li><a href="#minimal-frameworks" id="toc-minimal-frameworks" class="nav-link" data-scroll-target="#minimal-frameworks">Minimal Frameworks</a></li>
<li><a href="#production-framework-internals" id="toc-production-framework-internals" class="nav-link" data-scroll-target="#production-framework-internals">Production Framework Internals</a></li>
</ul>
</nav>
</div>
<!-- main -->
<main class="content" id="quarto-document-content">
<header id="title-block-header" class="quarto-title-block default"><nav class="quarto-page-breadcrumbs quarto-title-breadcrumbs d-none d-lg-block" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./datasets.html">📚 Reference</a></li><li class="breadcrumb-item"><a href="./resources.html">Learning Resources</a></li></ol></nav>
<div class="quarto-title">
<h1 class="title">Learning Resources</h1>
</div>
<div class="quarto-title-meta">
</div>
</header>
<p><strong>TinyTorch teaches you to <em>build</em> ML systems. These resources help you understand the <em>why</em> behind what youre building.</strong></p>
<section id="companion-textbook" class="level2">
<h2 class="anchored" data-anchor-id="companion-textbook">Companion Textbook</h2>
<section id="machine-learning-systems" class="level3">
<h3 class="anchored" data-anchor-id="machine-learning-systems">Machine Learning Systems</h3>
<p><strong><a href="https://mlsysbook.ai">mlsysbook.ai</a></strong> by Prof.&nbsp;Vijay Janapa Reddi (Harvard University)</p>
<div style="background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%); border-left: 5px solid #1976d2; padding: 1.5rem; border-radius: 0.5rem; margin: 1.5rem 0;">
<p style="margin: 0; color: #0d47a1; font-size: 1.05rem; line-height: 1.6;">
</p><p><strong>TinyTorch began as hands-on labs for this textbook.</strong> While TinyTorch can be used standalone, the ML Systems book provides the theoretical depth and production context behind every module you build.</p>
<p></p>
</div>
<p><strong>What it teaches</strong>: Systems engineering for production ML—memory hierarchies, performance optimization, deployment strategies, and the engineering decisions behind modern ML frameworks.</p>
<p><strong>How it connects to TinyTorch</strong>: - TinyTorch modules directly implement concepts from the books chapters - The book explains <em>why</em> PyTorch, TensorFlow, and JAX make certain design decisions - Together, they provide both hands-on implementation and theoretical understanding</p>
<p><strong>When to use it</strong>: Read in parallel with TinyTorch. When you implement Module 06 (Autograd), read the books chapter on automatic differentiation to understand the systems engineering behind your code.</p>
</section>
</section>
<section id="related-academic-courses" class="level2">
<h2 class="anchored" data-anchor-id="related-academic-courses">Related Academic Courses</h2>
<ul>
<li><p><strong><a href="https://stanford-cs329s.github.io/">CS 329S: Machine Learning Systems Design</a></strong> (Stanford) <em>Production ML systems and deployment</em></p></li>
<li><p><strong><a href="https://efficientml.ai">TinyML and Efficient Deep Learning</a></strong> (MIT 6.5940) <em>Edge computing, model compression, and efficient ML</em></p></li>
<li><p><strong><a href="https://sites.google.com/g.harvard.edu/tinyml/home">CS 249r: Tiny Machine Learning</a></strong> (Harvard) <em>TinyML systems and resource-constrained ML</em></p></li>
<li><p><strong><a href="http://cs231n.stanford.edu/">CS 231n: Convolutional Neural Networks</a></strong> (Stanford) <em>Computer vision - complements TinyTorch Modules 08-09</em></p></li>
<li><p><strong><a href="http://web.stanford.edu/class/cs224n/">CS 224n: Natural Language Processing</a></strong> (Stanford) <em>Transformers and NLP - complements TinyTorch Modules 10-13</em></p></li>
</ul>
</section>
<section id="other-textbooks" class="level2">
<h2 class="anchored" data-anchor-id="other-textbooks">Other Textbooks</h2>
<ul>
<li><p><strong><a href="https://www.deeplearningbook.org/">Deep Learning</a></strong> by Goodfellow, Bengio, Courville <em>Mathematical foundations behind what you implement in TinyTorch</em></p></li>
<li><p><strong><a href="https://www.oreilly.com/library/view/hands-on-machine-learning/9781098125967/">Hands-On Machine Learning</a></strong> by Aurélien Géron <em>Practical implementations using established frameworks</em></p></li>
</ul>
</section>
<section id="minimal-frameworks" class="level2">
<h2 class="anchored" data-anchor-id="minimal-frameworks">Minimal Frameworks</h2>
<p><strong>Alternative approaches to building ML from scratch:</strong></p>
<ul>
<li><p><strong><a href="https://github.com/karpathy/micrograd">micrograd</a></strong> by Andrej Karpathy <em>Autograd in 100 lines. Perfect 2-hour intro before TinyTorch.</em></p></li>
<li><p><strong><a href="https://github.com/karpathy/nanoGPT">nanoGPT</a></strong> by Andrej Karpathy <em>Minimalist GPT implementation. Complements TinyTorch Modules 12-13.</em></p></li>
<li><p><strong><a href="https://github.com/geohot/tinygrad">tinygrad</a></strong> by George Hotz <em>Performance-focused educational framework with GPU acceleration.</em></p></li>
</ul>
</section>
<section id="production-framework-internals" class="level2">
<h2 class="anchored" data-anchor-id="production-framework-internals">Production Framework Internals</h2>
<ul>
<li><p><strong><a href="http://blog.ezyang.com/2019/05/pytorch-internals/">PyTorch Internals</a></strong> by Edward Yang <em>How PyTorch actually works under the hood</em></p></li>
<li><p><strong><a href="https://pytorch.org/docs/stable/notes/extending.html">PyTorch: Extending PyTorch</a></strong> <em>Custom operators and autograd functions</em></p></li>
</ul>
<p><strong>Ready to start?</strong> See the <strong><a href="./getting-started.html">Quick Start</a></strong> for a 15-minute hands-on introduction.</p>
</section>
<a onclick="window.scrollTo(0, 0); return false;" role="button" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a></main> <!-- /main -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
// Ensure there is a toggle, if there isn't float one in the top right
if (window.document.querySelector('.quarto-color-scheme-toggle') === null) {
const a = window.document.createElement('a');
a.classList.add('top-right');
a.classList.add('quarto-color-scheme-toggle');
a.href = "";
a.onclick = function() { try { window.quartoToggleColorScheme(); } catch {} return false; };
const i = window.document.createElement("i");
i.classList.add('bi');
a.appendChild(i);
window.document.body.appendChild(a);
}
setColorSchemeToggle(hasAlternateSentinel())
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const isCodeAnnotation = (el) => {
for (const clz of el.classList) {
if (clz.startsWith('code-annotation-')) {
return true;
}
}
return false;
}
const onCopySuccess = function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
let tooltip;
if (window.bootstrap) {
button.setAttribute("data-bs-toggle", "tooltip");
button.setAttribute("data-bs-placement", "left");
button.setAttribute("data-bs-title", "Copied!");
tooltip = new bootstrap.Tooltip(button,
{ trigger: "manual",
customClass: "code-copy-button-tooltip",
offset: [0, -8]});
tooltip.show();
}
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute("data-bs-title");
button.removeAttribute("data-bs-toggle");
button.removeAttribute("data-bs-placement");
}
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
}
const getTextToCopy = function(trigger) {
const outerScaffold = trigger.parentElement.cloneNode(true);
const codeEl = outerScaffold.querySelector('code');
for (const childEl of codeEl.children) {
if (isCodeAnnotation(childEl)) {
childEl.remove();
}
}
return codeEl.innerText;
}
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
text: getTextToCopy
});
clipboard.on('success', onCopySuccess);
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
text: getTextToCopy,
container: window.document.getElementById('quarto-embedded-source-code-modal')
});
clipboardModal.on('success', onCopySuccess);
}
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
var mailtoRegex = new RegExp(/^mailto:/);
var filterRegex = new RegExp("https:\/\/mlsysbook\.ai\/tinytorch\/");
var isInternal = (href) => {
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
}
// Inspect non-navigation links and adorn them if external
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
for (var i=0; i<links.length; i++) {
const link = links[i];
if (!isInternal(link.href)) {
// undo the damage that might have been done by quarto-nav.js in the case of
// links that we want to consider external
if (link.dataset.originalHref !== undefined) {
link.href = link.dataset.originalHref;
}
// target, if specified
link.setAttribute("target", "_blank");
if (link.getAttribute("rel") === null) {
link.setAttribute("rel", "noopener");
}
}
}
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
const config = {
allowHTML: true,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start',
};
if (contentFn) {
config.content = contentFn;
}
if (onTriggerFn) {
config.onTrigger = onTriggerFn;
}
if (onUntriggerFn) {
config.onUntrigger = onUntriggerFn;
}
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note) {
return note.innerHTML;
} else {
return "";
}
});
}
const xrefs = window.document.querySelectorAll('a.quarto-xref');
const processXRef = (id, note) => {
// Strip column container classes
const stripColumnClz = (el) => {
el.classList.remove("page-full", "page-columns");
if (el.children) {
for (const child of el.children) {
stripColumnClz(child);
}
}
}
stripColumnClz(note)
if (id === null || id.startsWith('sec-')) {
// Special case sections, only their first couple elements
const container = document.createElement("div");
if (note.children && note.children.length > 2) {
container.appendChild(note.children[0].cloneNode(true));
for (let i = 1; i < note.children.length; i++) {
const child = note.children[i];
if (child.tagName === "P" && child.innerText === "") {
continue;
} else {
container.appendChild(child.cloneNode(true));
break;
}
}
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(container);
}
return container.innerHTML
} else {
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
return note.innerHTML;
}
} else {
// Remove any anchor links if they are present
const anchorLink = note.querySelector('a.anchorjs-link');
if (anchorLink) {
anchorLink.remove();
}
if (window.Quarto?.typesetMath) {
window.Quarto.typesetMath(note);
}
if (note.classList.contains("callout")) {
return note.outerHTML;
} else {
return note.innerHTML;
}
}
}
for (var i=0; i<xrefs.length; i++) {
const xref = xrefs[i];
tippyHover(xref, undefined, function(instance) {
instance.disable();
let url = xref.getAttribute('href');
let hash = undefined;
if (url.startsWith('#')) {
hash = url;
} else {
try { hash = new URL(url).hash; } catch {}
}
if (hash) {
const id = hash.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note !== null) {
try {
const html = processXRef(id, note.cloneNode(true));
instance.setContent(html);
} finally {
instance.enable();
instance.show();
}
} else {
// See if we can fetch this
fetch(url.split('#')[0])
.then(res => res.text())
.then(html => {
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(html, "text/html");
const note = htmlDoc.getElementById(id);
if (note !== null) {
const html = processXRef(id, note);
instance.setContent(html);
}
}).finally(() => {
instance.enable();
instance.show();
});
}
} else {
// See if we can fetch a full url (with no hash to target)
// This is a special case and we should probably do some content thinning / targeting
fetch(url)
.then(res => res.text())
.then(html => {
const parser = new DOMParser();
const htmlDoc = parser.parseFromString(html, "text/html");
const note = htmlDoc.querySelector('main.content');
if (note !== null) {
// This should only happen for chapter cross references
// (since there is no id in the URL)
// remove the first header
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
note.children[0].remove();
}
const html = processXRef(null, note);
instance.setContent(html);
}
}).finally(() => {
instance.enable();
instance.show();
});
}
}, function(instance) {
});
}
let selectedAnnoteEl;
const selectorForAnnotation = ( cell, annotation) => {
let cellAttr = 'data-code-cell="' + cell + '"';
let lineAttr = 'data-code-annotation="' + annotation + '"';
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
return selector;
}
const selectCodeLines = (annoteEl) => {
const doc = window.document;
const targetCell = annoteEl.getAttribute("data-target-cell");
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
const lineIds = lines.map((line) => {
return targetCell + "-" + line;
})
let top = null;
let height = null;
let parent = null;
if (lineIds.length > 0) {
//compute the position of the single el (top and bottom and make a div)
const el = window.document.getElementById(lineIds[0]);
top = el.offsetTop;
height = el.offsetHeight;
parent = el.parentElement.parentElement;
if (lineIds.length > 1) {
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
height = bottom - top;
}
if (top !== null && height !== null && parent !== null) {
// cook up a div (if necessary) and position it
let div = window.document.getElementById("code-annotation-line-highlight");
if (div === null) {
div = window.document.createElement("div");
div.setAttribute("id", "code-annotation-line-highlight");
div.style.position = 'absolute';
parent.appendChild(div);
}
div.style.top = top - 2 + "px";
div.style.height = height + 4 + "px";
div.style.left = 0;
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
if (gutterDiv === null) {
gutterDiv = window.document.createElement("div");
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
gutterDiv.style.position = 'absolute';
const codeCell = window.document.getElementById(targetCell);
const gutter = codeCell.querySelector('.code-annotation-gutter');
gutter.appendChild(gutterDiv);
}
gutterDiv.style.top = top - 2 + "px";
gutterDiv.style.height = height + 4 + "px";
}
selectedAnnoteEl = annoteEl;
}
};
const unselectCodeLines = () => {
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
elementsIds.forEach((elId) => {
const div = window.document.getElementById(elId);
if (div) {
div.remove();
}
});
selectedAnnoteEl = undefined;
};
// Handle positioning of the toggle
window.addEventListener(
"resize",
throttle(() => {
elRect = undefined;
if (selectedAnnoteEl) {
selectCodeLines(selectedAnnoteEl);
}
}, 10)
);
function throttle(fn, ms) {
let throttle = false;
let timer;
return (...args) => {
if(!throttle) { // first call gets through
fn.apply(this, args);
throttle = true;
} else { // all the others get throttled
if(timer) clearTimeout(timer); // cancel #2
timer = setTimeout(() => {
fn.apply(this, args);
timer = throttle = false;
}, ms);
}
};
}
// Attach click handler to the DT
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
for (const annoteDlNode of annoteDls) {
annoteDlNode.addEventListener('click', (event) => {
const clickedEl = event.target;
if (clickedEl !== selectedAnnoteEl) {
unselectCodeLines();
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
if (activeEl) {
activeEl.classList.remove('code-annotation-active');
}
selectCodeLines(clickedEl);
clickedEl.classList.add('code-annotation-active');
} else {
// Unselect the line
unselectCodeLines();
clickedEl.classList.remove('code-annotation-active');
}
});
}
const findCites = (el) => {
const parentEl = el.parentElement;
if (parentEl) {
const cites = parentEl.dataset.cites;
if (cites) {
return {
el,
cites: cites.split(' ')
};
} else {
return findCites(el.parentElement)
}
} else {
return undefined;
}
};
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const citeInfo = findCites(ref);
if (citeInfo) {
tippyHover(citeInfo.el, function() {
var popup = window.document.createElement('div');
citeInfo.cites.forEach(function(cite) {
var citeDiv = window.document.createElement('div');
citeDiv.classList.add('hanging-indent');
citeDiv.classList.add('csl-entry');
var biblioDiv = window.document.getElementById('ref-' + cite);
if (biblioDiv) {
citeDiv.innerHTML = biblioDiv.innerHTML;
}
popup.appendChild(citeDiv);
});
return popup.innerHTML;
});
}
}
});
</script>
<nav class="page-navigation">
<div class="nav-page nav-page-previous">
<a href="./datasets.html" class="pagination-link" aria-label="Datasets Guide">
<i class="bi bi-arrow-left-short"></i> <span class="nav-page-text">Datasets Guide</span>
</a>
</div>
<div class="nav-page nav-page-next">
<a href="./team.html" class="pagination-link" aria-label="Team">
<span class="nav-page-text">Team</span> <i class="bi bi-arrow-right-short"></i>
</a>
</div>
</nav>
</div> <!-- /content -->
<footer class="footer">
<div class="nav-footer">
<div class="nav-footer-left">
<p>© 2024-2026 Harvard University. Licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC-BY-NC-SA 4.0</a></p>
</div>
<div class="nav-footer-center">
<p>Part of the <a href="https://mlsysbook.ai">Machine Learning Systems</a> textbook</p>
</div>
<div class="nav-footer-right">
<ul class="footer-items list-unstyled">
<li class="nav-item compact">
<a class="nav-link" href="https://github.com/harvard-edge/cs249r_book">
<i class="bi bi-github" role="img" aria-label="View source on GitHub">
</i>
</a>
</li>
<li class="nav-item compact">
<a class="nav-link" href="https://github.com/harvard-edge/cs249r_book">
<i class="bi bi-star" role="img" aria-label="Star this repository">
</i>
</a>
</li>
</ul>
</div>
</div>
</footer>
<script>
/**
* Subscribe Modal Component for TinyTorch (Quarto version)
* Elegant popup subscription form
*/
(function() {
'use strict';
function createModalHTML() {
return `
<div id="subscribe-modal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<button class="modal-close" data-close-modal aria-label="Close">&times;</button>
<div class="modal-content">
<div class="modal-header">
<div class="modal-brand-row">
<span class="modal-brand-item">📚 MLSysBook</span>
</div>
<h2 class="modal-title">Stay in the Loop</h2>
<p class="modal-subtitle">Get updates on new chapters, hands-on labs, and ML systems resources.</p>
</div>
<form id="subscribe-modal-form" class="subscribe-form" action="https://buttondown.email/api/emails/embed-subscribe/mlsysbook" method="post">
<div class="form-row">
<div class="form-group">
<label for="modal-first-name">First name</label>
<input type="text" id="modal-first-name" name="metadata__first_name" required placeholder="Jane">
</div>
<div class="form-group">
<label for="modal-last-name">Last name</label>
<input type="text" id="modal-last-name" name="metadata__last_name" required placeholder="Smith">
</div>
</div>
<div class="form-group">
<label for="modal-email">Email</label>
<input type="email" id="modal-email" name="email" required placeholder="jane@university.edu">
</div>
<div class="form-group">
<label>I am a...</label>
<div class="role-options role-options-three-compact">
<label class="role-option">
<input type="radio" name="metadata__role" value="educator" required>
<span class="role-label">👨‍🏫 Educator</span>
</label>
<label class="role-option">
<input type="radio" name="metadata__role" value="student">
<span class="role-label">🎓 Student</span>
</label>
<label class="role-option">
<input type="radio" name="metadata__role" value="industry">
<span class="role-label">💼 Industry</span>
</label>
</div>
</div>
<div class="form-group">
<label for="modal-organization">Organization <span class="optional-label">(optional)</span></label>
<input type="text" id="modal-organization" name="metadata__organization" placeholder="University or company">
</div>
<div class="form-group">
<label for="modal-motivation">What brings you here? <span class="optional-label">(optional)</span></label>
<textarea id="modal-motivation" name="metadata__motivation" rows="2" placeholder="e.g., teaching a course, learning ML systems, building edge devices..."></textarea>
</div>
<input type="hidden" name="tag" value="tinytorch-site">
<button type="submit" class="btn btn-primary subscribe-btn">Subscribe</button>
<p class="form-note">No spam, ever. Unsubscribe anytime.</p>
</form>
<div id="modal-subscribe-success" class="subscribe-success" style="display: none;">
<div class="success-icon">🎉</div>
<h3>You're in!</h3>
<p>Welcome to the ML systems community. We'll keep you updated on new content.</p>
</div>
</div>
</div>
</div>
`;
}
function createModalCSS() {
const style = document.createElement('style');
style.textContent = `
.modal-overlay {
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
background: rgba(15, 23, 42, 0.6); backdrop-filter: blur(4px);
z-index: 10001; align-items: center; justify-content: center;
padding: 1rem; animation: fadeIn 0.2s ease;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { opacity: 0; transform: translateY(20px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
.modal-container {
background: white; border-radius: 16px; max-width: 440px; width: 100%;
max-height: 90vh; overflow-y: auto; position: relative;
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
animation: slideUp 0.3s ease; margin: auto;
}
.modal-close {
position: absolute; top: 1rem; right: 1rem; width: 36px; height: 36px;
border: none; background: #f8fafc; border-radius: 50%; font-size: 1.5rem;
color: #64748b; cursor: pointer; display: flex; align-items: center;
justify-content: center; transition: all 0.2s ease; z-index: 10; line-height: 1;
}
.modal-close:hover { background: white; color: #0f172a; transform: scale(1.05); }
.modal-content { padding: 2rem 2.5rem 2.5rem 2.5rem; }
.modal-header { text-align: center; margin-bottom: 1.5rem; display: flex; flex-direction: column; align-items: center; }
.modal-brand-row { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; margin-bottom: 1rem; }
.modal-brand-item { font-size: 0.8rem; font-weight: 600; color: #374151; background: #f3f4f6; padding: 0.3rem 0.6rem; border-radius: 5px; }
.modal-title { font-size: 1.5rem; font-weight: 700; color: #0f172a; margin: 0 0 0.4rem 0; line-height: 1.2; width: 100%; }
.modal-subtitle { font-size: 0.9rem; color: #64748b; margin: 0; line-height: 1.5; max-width: 320px; }
.subscribe-form { display: flex; flex-direction: column; gap: 1.25rem; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.form-row .form-group { min-width: 0; }
.form-row .form-group input { width: 100%; box-sizing: border-box; }
.form-group { display: flex; flex-direction: column; gap: 0.5rem; }
.form-group label { font-size: 0.9rem; font-weight: 600; color: #0f172a; }
.optional-label { font-weight: 400; color: #64748b; }
.form-group input[type="text"], .form-group input[type="email"], .form-group textarea {
padding: 0.875rem 1rem; border: 1px solid #cbd5e1; border-radius: 8px;
font-size: 1rem; transition: all 0.2s ease; background: #f8fafc; font-family: inherit;
}
.form-group textarea { resize: vertical; min-height: 60px; }
.form-group input:focus, .form-group textarea:focus {
outline: none; border-color: #3b82f6; background: white;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.form-group input::placeholder, .form-group textarea::placeholder { color: #94a3b8; }
.role-options { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.role-options-three-compact { grid-template-columns: repeat(3, 1fr); }
.role-option { cursor: pointer; }
.role-option input[type="radio"] { position: absolute; opacity: 0; width: 0; height: 0; }
.role-label {
display: flex; align-items: center; justify-content: center; gap: 0.5rem;
padding: 0.75rem 1rem; border: 2px solid #e2e8f0; border-radius: 8px;
font-size: 0.9rem; font-weight: 500; color: #475569; transition: all 0.2s ease; background: #f8fafc;
}
.role-options-three-compact .role-label { padding: 0.625rem 0.5rem; font-size: 0.8rem; text-align: center; }
.role-option input[type="radio"]:checked + .role-label { border-color: #3b82f6; background: rgba(59, 130, 246, 0.08); color: #3b82f6; }
.role-option:hover .role-label { border-color: #cbd5e1; background: white; }
.subscribe-btn { width: 100%; padding: 1rem; font-size: 1rem; margin-top: 0.5rem;
display: inline-flex; align-items: center; justify-content: center;
border-radius: 8px; text-decoration: none; font-weight: 600; border: none; cursor: pointer;
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%); color: white; font-family: inherit;
}
.subscribe-btn:hover { background: linear-gradient(135deg, #fb923c 0%, #f97316 100%); transform: translateY(-1px); box-shadow: 0 4px 12px rgba(249, 115, 22, 0.3); }
.form-note { text-align: center; font-size: 0.85rem; color: #64748b; margin: 0; }
.subscribe-success { text-align: center; padding: 2rem 1rem; }
.success-icon { font-size: 3rem; margin-bottom: 1rem; }
.subscribe-success h3 { font-size: 1.5rem; font-weight: 600; color: #0f172a; margin-bottom: 0.5rem; }
.subscribe-success p { color: #475569; font-size: 1rem; }
/* Quarto dark mode */
.quarto-dark .modal-container, html[data-bs-theme="dark"] .modal-container { background: #1e293b; }
.quarto-dark .modal-close, html[data-bs-theme="dark"] .modal-close { background: #0f172a; color: #94a3b8; }
.quarto-dark .modal-title, html[data-bs-theme="dark"] .modal-title,
.quarto-dark .form-group label, html[data-bs-theme="dark"] .form-group label { color: #f1f5f9; }
.quarto-dark .modal-subtitle, html[data-bs-theme="dark"] .modal-subtitle { color: #cbd5e1; }
.quarto-dark .form-group input, html[data-bs-theme="dark"] .form-group input,
.quarto-dark .form-group textarea, html[data-bs-theme="dark"] .form-group textarea { background: #0f172a; border-color: #334155; color: #f1f5f9; }
.quarto-dark .role-label, html[data-bs-theme="dark"] .role-label { background: #0f172a; border-color: #334155; color: #cbd5e1; }
@media (max-width: 640px) { .modal-content { padding: 2rem 1.5rem; } .form-row { grid-template-columns: 1fr; } }
`;
return style;
}
function initModal() {
document.head.appendChild(createModalCSS());
const modalDiv = document.createElement('div');
modalDiv.innerHTML = createModalHTML();
document.body.appendChild(modalDiv.firstElementChild);
const modal = document.getElementById('subscribe-modal');
const form = document.getElementById('subscribe-modal-form');
const success = document.getElementById('modal-subscribe-success');
window.openSubscribeModal = function() {
modal.style.display = 'flex';
document.body.style.overflow = 'hidden';
setTimeout(() => { const fi = document.getElementById('modal-first-name'); if (fi) fi.focus(); }, 100);
};
window.closeSubscribeModal = function() {
modal.style.display = 'none';
document.body.style.overflow = '';
setTimeout(() => { form.style.display = 'flex'; form.reset(); success.style.display = 'none'; }, 300);
};
modal.addEventListener('click', (e) => { if (e.target === modal) closeSubscribeModal(); });
const closeBtn = modal.querySelector('[data-close-modal]');
if (closeBtn) closeBtn.addEventListener('click', closeSubscribeModal);
document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && modal.style.display === 'flex') closeSubscribeModal(); });
form.addEventListener('submit', function() {
setTimeout(() => { form.style.display = 'none'; success.style.display = 'block'; setTimeout(closeSubscribeModal, 5000); }, 100);
});
if (window.location.hash === '#subscribe') setTimeout(() => openSubscribeModal(), 300);
window.addEventListener('hashchange', function() { if (window.location.hash === '#subscribe') openSubscribeModal(); });
setTimeout(() => {
document.querySelectorAll('#navbar-subscribe-btn, a[href*="#subscribe"], a.subscribe-link').forEach(link => {
link.addEventListener('click', function(e) { e.preventDefault(); openSubscribeModal(); });
});
}, 1000);
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initModal);
else initModal();
})();
</script>
<script>
/**
* Interactive ML History Timeline (Quarto version)
* Handles popup functionality for milestone cards
*/
document.addEventListener('DOMContentLoaded', function() {
const timelineData = {
perceptron: {
year: "1958", title: "The Perceptron", researcher: "Frank Rosenblatt",
subtitle: "The first neural network architecture starts the field",
achievement: "Binary classification with a forward pass",
architecture: "Input → Linear → Sigmoid → Output",
whatYouBuild: ["Binary classification with random weights", "Simple but revolutionary architecture", "YOUR Linear layer recreates history"],
systemsInsights: ["Memory: O(n) parameters", "Compute: O(n) operations", "Limitation: Only linearly separable problems"],
modules: "After Modules 01-03", expectedResults: "~50% with untrained random weights",
commands: ["tito milestone run perceptron"]
},
xor: {
year: "1969", title: "The XOR Crisis", researcher: "Minsky & Papert",
subtitle: "Hidden layers solve non-linear problems that nearly ended AI research",
achievement: "Non-linear learning through hidden representations",
architecture: "Input → Linear → ReLU → Linear → Output",
whatYouBuild: ["Hidden layers enable non-linear solutions", "Multi-layer networks break through limitations", "YOUR autograd makes it possible"],
systemsInsights: ["Memory: O(n²) with hidden layers", "Compute: O(n²) operations", "Breakthrough: Hidden representations"],
modules: "After Modules 02-06", expectedResults: "50% (single layer) → 100% (multi-layer) on XOR",
commands: ["tito milestone run xor"]
},
mlp: {
year: "1986", title: "MLP Revival", researcher: "Backpropagation Era",
subtitle: "Backpropagation enables training deep networks on real datasets",
achievement: "Multi-class digit recognition",
architecture: "Images → Flatten → Linear → ReLU → Linear → ReLU → Linear → Classes",
whatYouBuild: ["XOR solved with hidden layers", "TinyDigits classification", "YOUR training pipeline learns real images"],
systemsInsights: ["Memory: ~2.4K parameters for TinyDigits", "Compute: Dense matrix operations", "Architecture: Multi-layer feature learning"],
modules: "After Modules 01-08", expectedResults: "Solves XOR, 85%+ on TinyDigits",
commands: ["tito milestone run mlp"]
},
cnn: {
year: "1998", title: "CNN Revolution", researcher: "Yann LeCun",
subtitle: "CNNs exploit spatial structure for computer vision—enabling modern AI",
achievement: "Spatial intelligence for computer vision",
architecture: "Images → Conv → ReLU → Pool → Conv → ReLU → Pool → Flatten → Linear → Classes",
whatYouBuild: ["Convolutional feature extraction", "Natural image classification (CIFAR-10)", "YOUR Conv2d + MaxPool2d unlock spatial intelligence"],
systemsInsights: ["Memory: ~1M parameters (weight sharing reduces vs dense)", "Compute: Convolution is intensive but parallelizable", "Architecture: Local connectivity + translation invariance"],
modules: "After Modules 02-09", expectedResults: "75%+ accuracy on CIFAR-10 ✨",
commands: ["tito milestone run cnn"], northStar: true
},
transformer: {
year: "2017", title: "Transformer Era", researcher: "Vaswani et al.",
subtitle: "Attention mechanism launches the LLM revolution (GPT, BERT, ChatGPT)",
achievement: "Self-attention for language understanding",
architecture: "Tokens → Embeddings → Attention → FFN → ... → Attention → Output",
whatYouBuild: ["Self-attention mechanisms", "Autoregressive text generation", "YOUR attention implementation generates language"],
systemsInsights: ["Memory: O(n²) attention requires careful management", "Compute: Highly parallelizable", "Architecture: Long-range dependencies"],
modules: "After Modules 02-13", expectedResults: "Loss < 1.5, coherent responses to questions",
commands: ["tito milestone run transformer"]
},
olympics: {
year: "2018", title: "MLPerf Torch Olympics", researcher: "MLCommons (founded 2018)",
subtitle: "Systematic optimization becomes essential as models grow larger",
achievement: "Production-ready optimization",
architecture: "Profile → Compress → Accelerate",
whatYouBuild: ["Performance profiling and bottleneck analysis", "Model compression (quantization + pruning)", "Inference acceleration (KV-cache + batching)"],
systemsInsights: ["Memory: 4-16× compression through quantization/pruning", "Speed: 12-40× faster generation with KV-cache + batching", "Workflow: Systematic 'measure → optimize → validate' methodology"],
modules: "After Modules 14-18", expectedResults: "8-16× smaller models, 12-40× faster inference",
commands: ["tito milestone run mlperf"]
}
};
// Create popup element
let popup = document.getElementById('ml-timeline-popup');
if (!popup) {
popup = document.createElement('div');
popup.id = 'ml-timeline-popup';
popup.className = 'ml-timeline-popup-overlay';
popup.innerHTML = '<div class="ml-timeline-popup"></div>';
document.body.appendChild(popup);
}
// Handle clicks on timeline items
document.querySelectorAll('.ml-timeline-content').forEach(card => {
card.style.cursor = 'pointer';
card.addEventListener('click', function() {
const item = this.closest('.ml-timeline-item');
// Get milestone type from class list (second class after 'ml-timeline-item' and 'left'/'right')
const classes = Array.from(item.classList);
const milestoneType = classes.find(c => !['ml-timeline-item', 'left', 'right'].includes(c));
const data = timelineData[milestoneType];
if (!data) return;
const popupInner = popup.querySelector('.ml-timeline-popup');
popupInner.innerHTML = `
<button class="ml-timeline-popup-close" aria-label="Close">&times;</button>
<h3><span style="color: #f97316; font-size: 0.85rem; display: block; margin-bottom: 0.25rem;">${data.year}</span>${data.title}</h3>
<p style="color: #64748b; margin: 0.5rem 0 1rem 0;">${data.subtitle}</p>
${data.northStar ? '<div style="background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); padding: 1rem; border-radius: 0.5rem; margin: 1rem 0; border-left: 4px solid #f59e0b;"><strong>🎯 North Star Achievement</strong> — This is a major milestone in your TinyTorch journey!</div>' : ''}
<div style="margin: 1rem 0;"><h4 style="font-size: 0.95rem; margin: 0 0 0.5rem 0;">The ${data.researcher} Breakthrough</h4><p><strong>${data.achievement}</strong></p></div>
<div style="margin: 1rem 0;"><h4 style="font-size: 0.95rem; margin: 0 0 0.5rem 0;">Architecture</h4><div style="background: #f8fafc; padding: 0.75rem; border-radius: 0.375rem; font-family: monospace; font-size: 0.85rem;">${data.architecture}</div></div>
<div style="margin: 1rem 0;"><h4 style="font-size: 0.95rem; margin: 0 0 0.5rem 0;">What You'll Build</h4><ul>${data.whatYouBuild.map(i => `<li>${i}</li>`).join('')}</ul></div>
<div style="margin: 1rem 0;"><h4 style="font-size: 0.95rem; margin: 0 0 0.5rem 0;">Systems Insights</h4><ul>${data.systemsInsights.map(i => `<li>${i}</li>`).join('')}</ul></div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1rem 0;">
<div style="background: #f8fafc; padding: 0.75rem; border-radius: 0.375rem;"><div style="font-size: 0.75rem; color: #64748b; margin-bottom: 0.25rem;">Prerequisites</div><div style="font-weight: 600;">${data.modules}</div></div>
<div style="background: #f8fafc; padding: 0.75rem; border-radius: 0.375rem;"><div style="font-size: 0.75rem; color: #64748b; margin-bottom: 0.25rem;">Expected Results</div><div style="font-weight: 600;">${data.expectedResults}</div></div>
</div>
<div style="margin: 1rem 0;"><h4 style="font-size: 0.95rem; margin: 0 0 0.5rem 0;">Try It Yourself</h4><div style="background: #f8fafc; padding: 0.75rem; border-radius: 0.375rem; font-family: monospace; font-size: 0.85rem;">${data.commands.join('\n')}</div></div>
`;
popup.classList.add('active');
popup.style.display = 'flex';
popup.querySelector('.ml-timeline-popup-close').addEventListener('click', () => {
popup.classList.remove('active');
popup.style.display = 'none';
});
});
});
// Close on background click
popup.addEventListener('click', function(e) { if (e.target === popup) { popup.classList.remove('active'); popup.style.display = 'none'; } });
// Close on ESC
document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && popup.classList.contains('active')) { popup.classList.remove('active'); popup.style.display = 'none'; } });
});
</script>
<script>
// Inject subtitle + framework version chip under sidebar logo.
// The chip's version literal is sourced from tinytorch/settings.ini and
// kept in sync by the tinytorch-publish-live workflow's UPDATE_VERSION
// step on each release. Update marker for sed: TINYTORCH_VERSION_CHIP.
document.addEventListener('DOMContentLoaded', function() {
const sidebarLogo = document.querySelector('.sidebar-logo');
if (!sidebarLogo) return;
// The logo <img> sits inside Quarto's <a class="sidebar-logo-link"> wrapper.
// Inserting our subtitle as a sibling of the <img> would nest the subtitle's
// link INSIDE that anchor — invalid HTML, so the browser fires the outer logo
// link (./index.html) instead of navigating to the textbook. Insert AFTER the
// logo anchor, as a child of .sidebar-header, so our links are not nested.
const logoLink = sidebarLogo.closest('.sidebar-logo-link') || sidebarLogo;
const anchorHost = logoLink.parentElement;
// 1. Existing subtitle — what TinyTorch IS in relation to the textbook.
const subtitle = document.createElement('div');
subtitle.className = 'sidebar-subtitle';
subtitle.innerHTML = 'A Build-It-Yourself Companion to the<br><a href="https://mlsysbook.ai" style="color: #D4740C; text-decoration: none;">Machine Learning Systems</a> textbook';
anchorHost.insertBefore(subtitle, logoLink.nextSibling);
// 2. Framework version chip — explicitly identifies TinyTorch's version,
// not the textbook's. Visually separated so the reader does not parse
// the version as part of the subtitle prose. Click → GitHub Releases
// filtered for tinytorch tags (the canonical changelog destination).
const chipWrap = document.createElement('div');
chipWrap.className = 'tinytorch-version-chip-wrap';
const chip = document.createElement('a');
chip.className = 'tinytorch-version-chip';
chip.href = 'https://github.com/harvard-edge/cs249r_book/releases?q=tinytorch';
chip.target = '_blank';
chip.rel = 'noopener';
chip.innerHTML = '🔥 TinyTorch v0.1.13 →'; // TINYTORCH_VERSION_CHIP
chipWrap.appendChild(chip);
subtitle.parentNode.insertBefore(chipWrap, subtitle.nextSibling);
});
</script>
<style>
.sidebar-subtitle {
text-align: center;
font-size: 0.8rem;
color: #6b7280;
line-height: 1.4;
padding: 0 1rem 0.5rem 1rem;
margin-top: 0.5rem;
}
.sidebar-subtitle a:hover {
color: #f97316 !important;
}
/* Version chip — divider above + amber pill anchored to TinyTorch brand */
.tinytorch-version-chip-wrap {
text-align: center;
margin: 0 1rem;
padding: 0.5rem 0 0.75rem;
border-top: 1px solid #e5e7eb;
}
.tinytorch-version-chip {
display: inline-block;
padding: 0.15rem 0.65rem;
border: 1px solid #D4740C;
border-radius: 999px;
background: rgba(212, 116, 12, 0.08);
color: #D4740C !important; /* override Quarto's default link color */
font-size: 0.72rem;
font-weight: 600;
text-decoration: none !important;
white-space: nowrap;
letter-spacing: 0.01em;
transition: background-color 0.15s ease;
}
.tinytorch-version-chip:hover {
background: rgba(212, 116, 12, 0.18);
color: #D4740C !important;
text-decoration: none;
}
/* Dark-mode overrides — brighter amber to match dark-mode.scss $accent */
[data-bs-theme="dark"] .tinytorch-version-chip-wrap {
border-top-color: #454d55;
}
[data-bs-theme="dark"] .tinytorch-version-chip {
border-color: #F59E0B;
color: #F59E0B !important;
background: rgba(245, 158, 11, 0.1);
}
[data-bs-theme="dark"] .tinytorch-version-chip:hover {
background: rgba(245, 158, 11, 0.2);
color: #F59E0B !important;
}
</style>
<!--
MLSysBook release-pill — shared footer version chip for Quarto + static sites.
Renders a small "v0.1.0 · Apr 26, 2026" chip from a deployed
release-manifest.json. Best-effort chrome: silent on any fetch failure
(manifest missing, offline, CORS). Use at any site that emits a manifest
via scripts/version/release.py emit-manifest.
── Standardized placement (all MLSysBook sites) ──
The chip lives in the page-footer, right slot, so it reads as an
intentional part of the footer bar (not dangling below the page). Two
pieces per site:
1. This file loads the style + populator script site-wide:
format:
html:
include-in-header:
- text: |
<meta name="release-manifest" content="/<project-base>/release-manifest.json">
include-after-body:
- file: ../shared/release/release-pill.html
2. Each page-footer places the chip span where it should render:
website:
page-footer:
right:
- text: |
<span class="release-pill" data-release-pill></span>
- icon: github
href: ...
The meta tag tells the script where to find the manifest. The script
populates every span carrying data-release-pill, so the chip can sit in
the footer (canonical), an about page, or anywhere else.
── Manifest contract ──
The manifest is the JSON written by scripts/version/release.py
emit-manifest. Required keys: releaseId, releaseHash. Optional but
recommended: buildDate, project. Anything else is ignored.
── Why runtime fetch instead of build-time templating ──
Build-time templating would be deterministic but requires per-project
Lua/template machinery. Runtime fetch is project-agnostic and works
identically across Quarto, Next.js, and plain HTML. The one fetch per
page-load is cheap and the chip degrades to nothing on failure.
-->
<style>
/* Fixed muted gray on every site — the chip must look identical regardless of
each Quarto theme's accent colors (do NOT inherit --bs-secondary / link color). */
.release-pill {
display: inline-flex;
align-items: baseline;
gap: 0.25em;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
font-size: 0.75rem;
line-height: 1;
color: var(--release-pill-color, #6c757d);
}
.release-pill a,
.release-pill a:visited,
.release-pill-version,
.release-pill-date {
color: var(--release-pill-color, #6c757d);
text-decoration: none;
}
.release-pill a:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
.release-pill-date {
opacity: 0.75;
}
</style>
<script>
(function () {
var pills = document.querySelectorAll('[data-release-pill]');
if (!pills.length) return;
// Manifest URL resolution order:
// 1. data-manifest attribute on the pill (per-page override)
// 2. <meta name="release-manifest" content="..."> in <head>
// 3. './release-manifest.json' relative to current page (fallback)
var meta = document.querySelector('meta[name="release-manifest"]');
var metaPath = meta && meta.getAttribute('content');
fetch(metaPath || './release-manifest.json', { cache: 'no-store' })
.then(function (res) { return res.ok ? res.json() : null; })
.then(function (m) {
if (!m || !m.releaseId || !m.releaseHash) return;
var date = m.buildDate
? new Date(m.buildDate).toLocaleDateString('en-US',
{ year: 'numeric', month: 'short', day: 'numeric' })
: '';
var shortHash = String(m.releaseHash).slice(0, 7);
var title =
(m.project ? m.project + ' ' : '') +
'v' + m.releaseId +
(date ? ' · built ' + date : '') +
' · hash ' + shortHash;
pills.forEach(function (el) {
var linkHref = el.getAttribute('data-link') || '#release';
var a = document.createElement('a');
a.href = linkHref;
a.title = title;
a.setAttribute('aria-label',
'Release v' + m.releaseId + (date ? ', built ' + date : ''));
var v = document.createElement('span');
v.className = 'release-pill-version';
v.textContent = 'v' + m.releaseId;
a.appendChild(v);
if (date) {
var d = document.createElement('span');
d.className = 'release-pill-date';
d.textContent = ' · ' + date;
a.appendChild(d);
}
el.innerHTML = '';
el.appendChild(a);
});
})
.catch(function () { /* silent: best-effort chrome */ });
})();
</script>
</body></html>