Spaces:
Runtime error
Runtime error
File size: 10,566 Bytes
d9a2578 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Beacon Forecast</title>
<style>
:root {
--accent: #F5A524;
--accent-dim: rgba(245,165,36,0.26);
--bg: #0E1420;
--panel: #171F30;
--border: #2A3448;
--text: #F2F3F5;
--muted: #97A0AE;
}
* { box-sizing: border-box; }
body {
margin: 0; background: var(--bg); color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
-webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
.wrap { max-width: 980px; margin: 0 auto; padding: 0 28px; }
nav {
position: sticky; top: 0; z-index: 10;
background: rgba(10,10,12,0.75); backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border);
}
nav .wrap { display: flex; align-items: center; justify-content: space-between; height: 64px; }
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; letter-spacing: 0.01em; }
.dot { width: 10px; height: 10px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 10px var(--accent); }
.navlinks { display: flex; gap: 28px; font-size: 0.92rem; color: var(--muted); }
.navlinks a:hover { color: var(--text); }
.hero {
position: relative; padding: 110px 0 80px; text-align: center; overflow: hidden;
}
.hero::before {
content: ""; position: absolute; top: -220px; left: 50%; transform: translateX(-50%);
width: 900px; height: 500px; background: radial-gradient(ellipse at center, var(--accent-dim) 0%, transparent 70%);
pointer-events: none;
}
.badge {
display: inline-block; padding: 6px 16px; border-radius: 999px; border: 1px solid var(--accent);
color: var(--accent); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; margin-bottom: 28px;
position: relative;
}
.hero h1 {
font-size: 4.2rem; line-height: 1.02; font-weight: 800; letter-spacing: -0.03em; margin: 0 0 24px;
background: linear-gradient(180deg, #fff 0%, #d7dbe2 100%); -webkit-background-clip: text; background-clip: text; color: transparent;
position: relative;
}
.hero p.sub {
max-width: 640px; margin: 0 auto 40px; color: var(--muted); font-size: 1.15rem; line-height: 1.6;
position: relative;
}
.cta-row { display: flex; gap: 14px; justify-content: center; position: relative; flex-wrap: wrap; }
.btn {
padding: 15px 28px; border-radius: 12px; font-weight: 700; font-size: 0.98rem; display: inline-block;
transition: transform 0.15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn-primary { background: var(--accent); color: #0A0A0C; box-shadow: 0 8px 30px var(--accent-dim); }
.btn-secondary { background: var(--panel); color: var(--text); border: 1px solid var(--border); }
section { padding: 60px 0; border-top: 1px solid var(--border); }
.eyebrow { color: var(--accent); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.1em; margin-bottom: 14px; }
.headline-card {
background: var(--panel); border: 1px solid var(--border); border-radius: 18px; padding: 36px 40px;
font-size: 1.55rem; font-weight: 600; line-height: 1.45;
}
.headline-card b { color: var(--accent); }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-top: 20px; }
.metric-card {
background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 22px 20px;
}
.metric-value { font-size: 2.1rem; font-weight: 800; color: var(--accent); margin-bottom: 6px; }
.metric-label { color: var(--muted); font-size: 0.88rem; line-height: 1.4; }
.steps { counter-reset: step; margin-top: 24px; }
.step { display: flex; gap: 18px; padding: 18px 0; border-bottom: 1px solid var(--border); }
.step:last-child { border-bottom: none; }
.step-num {
counter-increment: step; flex-shrink: 0; width: 34px; height: 34px; border-radius: 10px;
background: var(--panel); border: 1px solid var(--accent); color: var(--accent);
display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.9rem;
}
.step-num::before { content: counter(step); }
.step-title { font-weight: 700; margin-bottom: 4px; }
.step-desc { color: var(--muted); font-size: 0.95rem; line-height: 1.55; }
.findings { display: grid; gap: 14px; margin-top: 20px; }
.finding {
background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--accent);
border-radius: 10px; padding: 18px 20px; font-size: 0.98rem; line-height: 1.6; color: #DCE1E8;
}
footer { padding: 50px 0 70px; text-align: center; color: var(--muted); font-size: 0.88rem; }
footer a { color: var(--accent); font-weight: 600; }
.footer-links { margin-top: 14px; display: flex; gap: 24px; justify-content: center; }
code, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
@media (max-width: 640px) {
.hero h1 { font-size: 2.6rem; }
.navlinks { display: none; }
}
</style>
</head>
<body>
<nav>
<div class="wrap">
<div class="brand"><span class="dot"></span> BCF · Beacon Forecast Lab</div>
<div class="navlinks">
<a href="#results">Results</a>
<a href="#method">Method</a>
<a href="#findings">Findings</a>
<a href="https://github.com/data-geek-astronomy/BEACON_FORECAST">GitHub</a>
</div>
</div>
</nav>
<section class="hero">
<div class="wrap">
<span class="badge">RESEARCH PREVIEW · BCF</span>
<h1>Beacon Forecast</h1>
<p class="sub">A demand forecaster that watches its own forecast errors day by day, and automatically retrains itself the moment a supply shock or other disruption breaks its assumptions — without waiting for a human to notice.</p>
<div class="cta-row">
<a class="btn btn-primary" href="https://huggingface.co/spaces/Darkweb007/BEACON_FORECAST">Launch live demo</a>
<a class="btn btn-secondary" href="https://github.com/data-geek-astronomy/BEACON_FORECAST">Read the code</a>
</div>
</div>
</section>
<section id="results">
<div class="wrap">
<div class="eyebrow">HEADLINE RESULT</div>
<div class="headline-card">A synthetic supply-shock event triggered an <b>automatic retrain within 4 days</b>, with the largest drift z-score (−6.55) of any retrain event across a 2-year, 4-SKU walk-forward simulation.</div>
<div class="grid">
<div class="metric-card"><div class="metric-value">4 days</div><div class="metric-label">from injected shock to automated retrain trigger</div></div>
<div class="metric-card"><div class="metric-value">−6.55</div><div class="metric-label">z-score at the shock-triggered retrain, the largest of any event</div></div>
<div class="metric-card"><div class="metric-value">4 SKUs × 2yr</div><div class="metric-label">walked forward day by day in the simulation</div></div>
<div class="metric-card"><div class="metric-value">~20</div><div class="metric-label">forecast MAE (units/day) after tuning, down from 117+ before a real bug fix</div></div>
</div>
</div>
</section>
<section id="method">
<div class="wrap">
<div class="eyebrow">METHOD</div>
<h2 style="margin:0 0 6px; font-size:1.6rem;">Forecast, monitor, retrain — automatically</h2>
<p style="color:var(--muted); max-width:640px; margin:0 0 10px;">The drift monitor doesn't wait for a scheduled retrain: it watches forecast error day by day and reacts as soon as the error pattern stops looking normal.</p>
<div class="steps">
<div class="step"><div class="step-num"></div><div><div class="step-title">Forecast</div><div class="step-desc">A trend + weekly + yearly-seasonality model (Ridge regression, regularized to stay stable on short retrain windows) predicts one day ahead at a time.</div></div></div>
<div class="step"><div class="step-num"></div><div><div class="step-title">Monitor</div><div class="step-desc">Every 5 days, a z-test compares the last 14 days of forecast error against the baseline error distribution from right after the last training.</div></div></div>
<div class="step"><div class="step-num"></div><div><div class="step-title">Detect</div><div class="step-desc">A Kolmogorov-Smirnov test runs alongside as a secondary check on error *shape*, not just mean — catching variance changes a pure mean-shift test would miss.</div></div></div>
<div class="step"><div class="step-num"></div><div><div class="step-title">Retrain</div><div class="step-desc">If |z| exceeds 4.0, the model is automatically refit on the most recent 120 days — a stand-in for an Airflow-triggered Lambda retrain.</div></div></div>
<div class="step"><div class="step-num"></div><div><div class="step-title">Repeat</div><div class="step-desc">The cycle continues for the full 2-year simulation, with every retrain event logged and its trigger statistics recorded.</div></div></div>
</div>
</div>
</section>
<section id="findings">
<div class="wrap">
<div class="eyebrow">FINDINGS</div>
<h2 style="margin:0 0 20px; font-size:1.6rem;">What the synthetic test runs showed</h2>
<div class="findings">
<div class="finding">An early version of the forecaster used plain OLS regression and produced forecasts that exploded to 1,000+ units/day on a series that never exceeds 300 — caused by trend and yearly-seasonality terms becoming collinear on short retrain windows. Switching to Ridge regularization and rescaling the trend feature fixed it, cutting MAE from 117+ to ~20.</div>
<div class="finding">The injected supply-shock SKU triggered a retrain within 4 days of the disruption, with a z-score nearly 40% larger in magnitude than any of its own routine periodic retrains.</div>
<div class="finding">Non-shocked SKUs still retrain periodically (roughly every 6-10 weeks) as ordinary forecast staleness accumulates — a real, expected MLOps pattern rather than noise, since even a well-fit lightweight model drifts stale over time without an external shock.</div>
</div>
</div>
</section>
<footer>
<div class="wrap">
<div>All data on this page is synthetic — part of a 5-project AI engineering portfolio.</div>
<div class="footer-links">
<a href="https://huggingface.co/spaces/Darkweb007/BEACON_FORECAST">Live demo</a>
<a href="https://github.com/data-geek-astronomy/BEACON_FORECAST">GitHub repo</a>
</div>
</div>
</footer>
</body>
</html>
|