sgd_classifier / index.html
nanye's picture
added example scenarios + changed default minibatch to random subset
69f60de
Raw
History Blame Contribute Delete
12.2 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Build a 2D dataset and use SGD to train a classifier one step at a time." />
<title>SGD Classifier Visualizer</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<main class="shell">
<header class="page-header">
<div>
<!--p class="eyebrow">Interactive machine learning</p--!>
<h1>SGD Classifier</h1>
<p class="subtitle">Draw a dataset, then watch the decision boundary move one SGD step at a time.</p>
</div>
<div id="runtime-status" class="status loading"><span></span>Loading Python runtime…</div>
</header>
<section class="workspace">
<div class="plot-card">
<div class="plot-toolbar">
<div>
<h2>Decision boundary</h2>
<!--p id="plot-instructions">Hover over a point to inspect its coordinates.</p--!>
</div>
<div class="legend" aria-label="Class legend">
<span><i class="dot dot-a"></i>Class A (+)</span>
<span><i class="dot dot-b"></i>Class B (-)</span>
<span><i class="batch-ring"></i>Next batch</span>
</div>
</div>
<div class="canvas-wrap">
<canvas id="plot" aria-label="Interactive classifier decision boundary"></canvas>
<div id="empty-hint" class="empty-hint">Select a class and click to place points</div>
</div>
<div class="plot-footer">
<span id="point-count">0 points</span>
<span id="step-count">Step 0</span>
<span id="batch-summary">No batch selected</span>
</div>
</div>
<aside class="control-card">
<nav class="tabs" aria-label="Visualizer sections">
<button id="configure-tab" class="tab active" type="button">Configure</button>
<button id="train-tab" class="tab" type="button">Train</button>
<button id="examples-tab" class="tab" type="button">Examples</button>
<button id="usage-tab" class="tab" type="button">Usage</button>
</nav>
<div id="configure-panel" class="tab-panel active">
<section class="control-section">
<div class="section-heading"><span>1</span><h2>Specify data</h2></div>
<div class="inline-field">
<label for="dataset-select">Type</label>
<select id="dataset-select">
<option value="easy-linear">Builtin linearly separable data (easy)</option>
<option value="hard-linear">Builtin linearly separable data (hard)</option>
<option value="nonlinear">Builtin non-linearly separable data</option>
<option value="custom">Custom data</option>
</select>
</div>
<div id="custom-data-controls" hidden>
<label>Point label</label>
<div class="segment" role="group" aria-label="Point label">
<button id="label-a" class="label-button active" type="button"><i class="dot dot-a"></i>Class A (+)</button>
<button id="label-b" class="label-button" type="button"><i class="dot dot-b"></i>Class B (-)</button>
</div>
<div class="button-row data-buttons">
<button id="undo" class="secondary" type="button">Undo</button>
<button id="redo" class="secondary" type="button">Redo</button>
<button id="clear" class="secondary danger" type="button">Clear</button>
</div>
</div>
</section>
<section class="control-section">
<div class="section-heading"><span>2</span><h2>Configure model</h2></div>
<div class="inline-field">
<label for="loss">Loss</label>
<select id="loss">
<option>perceptron</option>
<option>squared_error</option><option>log_loss</option>
<option>hinge</option><option>squared_hinge</option>
<option>huber</option><option>modified_huber</option>
<option>epsilon_insensitive</option><option>squared_epsilon_insensitive</option>
</select>
</div>
<div class="field-grid">
<div><label for="learning-rate">Learning rate</label><input id="learning-rate" type="number" value="1" min="0.000001" step="0.01" /></div>
<div><label for="batch-size">Batch size</label><input id="batch-size" type="number" value="1" min="1" step="1" /></div>
</div>
<label for="batch-selection">Mini-batch selection</label>
<select id="batch-selection">
<option value="random">Random subset</option>
<option value="permutation">Permutation Β· non-overlapping</option>
</select>
<p id="sampling-help" class="help">Each point is used once before the dataset is shuffled again.</p>
</section>
<section class="control-section additional-options-section">
<div class="section-heading"><span>3</span><h2>Additional options</h2></div>
<div class="field-grid">
<div><label for="random-seed">Random seed</label><input id="random-seed" type="number" value="42" min="0" max="4294967295" step="1" /></div>
<div><label for="animation-speed">Animation speed</label><select id="animation-speed"><option value="200" selected>Fast</option><option value="900">Normal</option><option value="1500">Slow</option></select></div>
</div>
</section>
</div>
<div id="train-panel" class="tab-panel">
<section class="control-section train-section">
<div class="metrics-panel">
<div class="metrics-heading"><h2>Metrics</h2><div><span class="metric-key loss-key"></span>Loss <span class="metric-key accuracy-key"></span>Accuracy</div></div>
<canvas id="metrics-chart" aria-label="Loss and accuracy over training steps"></canvas>
</div>
<div class="train-heading"><h2>Parameters</h2><span id="history-position">Step 0 of 0</span></div>
<div class="parameter-panel" aria-live="polite">
<div class="parameter-block">
<span>Class A parameters</span><small>Weight vector and bias for the positive class</small>
<code id="model-parameters">w_A = β€”<br>b_A = β€”</code>
</div>
<div class="parameter-block update-values">
<span>Pending Class A update</span><small>Negative learning rate Γ— derivatives</small>
<code id="model-update">Ξ”w_A = β€”<br>Ξ”b_A = β€”</code>
</div>
</div>
<div class="history-buttons">
<button id="history-next" class="primary" type="button" disabled><span class="button-text">Next</span></button>
<button id="history-prev" class="secondary" type="button">Previous</button>
<button id="history-reset" class="secondary" type="button">Reset</button>
</div>
<div class="animation-buttons">
<button id="animate" class="secondary" type="button">Animate</button>
<button id="pause" class="secondary" type="button" disabled>Pause</button>
</div>
<p id="message" class="message">Add at least one point from each class to begin.</p>
</section>
</div>
<div id="examples-panel" class="tab-panel">
<section class="control-section examples-section">
<h2>Example scenarios</h2>
<p class="examples-intro">Load a scenario, then use Next or Animate in the Train tab to observe its behavior.</p>
<article class="example-card">
<button class="example-button" data-dataset="easy-linear" type="button">Perceptron – easy</button>
<p>This uses the easy linearly separable dataset and the perceptron loss. The decision boundary eventually converges to one with zero loss and perfect classification accuracy on the data.</p>
</article>
<article class="example-card">
<button class="example-button" data-dataset="hard-linear" type="button">Perceptron – hard</button>
<p>This uses the perceptron loss and hard linearly separable dataset. The decision boundary eventually converges to one with zero loss and perfect classification accuracy on the data.</p>
</article>
<article class="example-card">
<button class="example-button" data-dataset="nonlinear" type="button">Perceptron – nonseparable</button>
<p>This uses the perceptron loss and the non-linearly separable dataset. The decision boundary does not converge.</p>
</article>
<article class="example-card">
<button class="example-button" data-dataset="hard-linear" data-loss="squared_error" data-learning-rate="1" type="button">Adaline – hard (default learning rate)</button>
<p>This uses squared error and the hard linearly separable dataset with the default learning rate of 1. The parameters diverge and the decision boundary does not converge.</p>
</article>
<article class="example-card">
<button class="example-button" data-dataset="hard-linear" data-loss="squared_error" data-learning-rate="0.1" type="button">Adaline – hard (small learning rate)</button>
<p>This uses squared error and the hard linearly separable dataset with a small learning rate of 0.1.
The parameters and decision boundary eventually fluctuates slightly around a perfect classifier.</p>
</article>
<article class="example-card"> <button class="example-button" data-dataset="hard-linear" data-loss="log_loss" data-learning-rate="1" type="button">Logistic regression – hard</button>
<p>This uses log loss and the hard linearly separable dataset.
The parameters and decision boundary eventually fluctuates very slightly around a perfect classifer.</p>
</article>
</section>
</div>
<div id="usage-panel" class="tab-panel">
<section class="control-section usage-section">
<h2>Using the visualizer</h2>
<ol>
<li><strong>Choose data.</strong> Select a built-in dataset, or choose Custom data and click the plot to add Class A and Class B points.</li>
<li><strong>Configure SGD.</strong> Select a loss, learning rate, mini-batch size, and selection strategy. A fixed random seed reproduces the same batch order.</li>
<li><strong>Open Train.</strong> Points with amber rings form the mini-batch that will be used by the next update.</li>
<li><strong>Step through training.</strong> Next performs one SGD step. Previous and Reset inspect earlier states without deleting later history.</li>
<li><strong>Animate.</strong> Animate advances automatically at the configured speed; Pause stops it.</li>
</ol>
<h2>Reading the display</h2>
<ul>
<li>The solid line is the current decision boundary. The dotted line is the initial reference boundary.</li>
<li>Background colors show the predicted class regions.</li>
<li>The Parameters panel shows Class A's current weight and bias and its pending update.</li>
<li>The Metrics chart evaluates loss and accuracy on the entire dataset. Larger outlined markers identify the step currently displayed.</li>
<li>Hover over any point to inspect its class and coordinates.</li>
</ul>
</section>
</div>
</aside>
</section>
</main>
<script type="module" src="app.js"></script>
</body>
</html>