III-01 · What Machine Learning Actually Learns
A learned rule is still a rule you can inspect
Follow one observation from input to prediction, then see exactly which numbers training changes.
Follow an observation through the predictor
Five explicit hand-authored toy observations. Parameters are learned from targets; a new query has no supplied target.
- 1 · Input0Observed sample s3
- 2 · Features[0]1 × 1 column
- 3 · Prediction≈ 0Shared affine predictor
- 4 · Error≈ −1Prediction − target
- 5 · Updatew ≈ 1.02; b ≈ 0.16Proposed batch update
- Query column
- 1 × 1
- Batch X
- 5 × 1
- Weight W
- 1 × 1
- Training targets
- 5 × 1
- Current modeTargets are observed; an update can be proposed.
- training
- Selected observation prediction
- ≈ 0
- Selected observation residual
- ≈ −1
- Training batch MSE
- ≈ 4.1
| ID | x | Target | Prediction | Residual |
|---|---|---|---|---|
| s1 | -2 | -3 | ≈ −1 | ≈ 2 |
| s2 | -1 | -1 | ≈ −0.5 | ≈ 0.5 |
| s3 | 0 | 1 | ≈ 0 | ≈ −1 |
| s4 | 1 | 3 | ≈ 0.5 | ≈ −2.5 |
| s5 | 2 | 4 | ≈ 1 | ≈ −3 |
Frame 1 / 1 · edits start from the displayed state.
What changed when the machine learned?
Start with the selected observation at , whose target is . The initial rule predicts . Change the bias to : its prediction becomes . Every other prediction shifts by the same amount. Change the weight instead: predictions change in proportion to their inputs. You are editing two numbers in a family of rules.
A learning algorithm chooses those numbers using examples and a criterion. Here the family is the affine predictor
The model is this parameterized mapping. Its parameters are and . The data are observed input–target pairs . The algorithm evaluates candidate parameters using a loss, then returns a new parameter vector. Learning need not discover a symbolic law or remember each example; in this experiment, five rows influence two shared coefficients.
The input and target have different jobs. An input is information available when a prediction must be made. A target is the observed quantity the prediction is supposed to match. Targets must not quietly become input features when they would be unavailable at prediction time.
Trace the complete mechanism
For a supervised training batch, the pipeline is:
- Observe inputs and targets with stable sample identities.
- Represent inputs as compatible numerical features.
- Apply the current predictor.
- Compare predictions with targets and aggregate the error.
- Use that error to choose changed parameters.
The sheet stores scalar features in a batch of shape . Each sample occupies a row; a single sample’s feature vector is a column. The weight matrix is , the target column is , and bias broadcasts separately. A column convention does not mean that every batch must have only one row.
Define and the mean squared error
Differentiation gives and . The weight gradient contains because the sensitivity of a prediction to is . Both partial derivatives are calculated before either parameter changes. The algorithm then returns and , where the user chooses the positive learning rate .
The selected row is a microscope, not a switch to one-row training. The loss and update still use all five observations. A selected sample with contributes nothing directly to , although its target can change .
Work through the first learned rule
The five inputs are and targets are . These are explicit hand-authored toy values, with no units or claim about a real population. At , predictions are and residuals are .
The squared errors sum to , so . The residual sum is and the residual-times-input sum is . Consequently and . At ,
The selected input now predicts , with residual . Across the batch the new squared errors sum to , giving MSE . The update improves this criterion on these observations. It does not establish performance on future data.
Inference uses the returned parameters
Reset and choose inference. For query , the original parameters predict . There is no observed query target, so an observed residual and query loss are undefined. The sheet displays that reason and disables the supervised update.
After training once, the same query predicts . No additional learning is required to evaluate the mapping. A later measured target could be used to evaluate it; deciding to retrain is a separate operation.
Execute the actual Python
The imported source uses NumPy column arrays for query prediction and calls the accepted affine reference for batch loss, gradient and update. There is one authoritative affine engine, rather than a second optimizer with a slightly different convention. From the book root, run .venv/bin/python -B code/python/p01/pipeline.py; the output contains training, inference and full-state trace frames.
"""III-01: observed targets train parameters; an unlabelled query only predicts."""
from copy import deepcopy
import json
from pathlib import Path
import sys
import numpy as np
from numeric import is_finite_number
ROOT = Path(__file__).resolve().parents[3]
sys.path.insert(0, str(ROOT / 'code/python/p02'))
import linear_regression as reference
PIPELINE_CANONICAL = dict(regression=deepcopy(reference.CANONICAL_REGRESSION), mode='training', sampleId='s3', query=1.5)
def derive_pipeline(state):
if state['mode'] not in ('training', 'inference') or not is_finite_number(state['query']) or abs(state['query']) > 5:
raise ValueError('Choose training/inference and a finite query between -5 and 5')
numerical = reference.derive_regression(state['regression'])
r = state['regression']
if abs(r['weight']) > 4 or abs(r['bias']) > 4 or r['learningRate'] < .001 or any(abs(s['x']) > 5 or abs(s['y']) > 5 for s in r['samples']):
raise ValueError('Predictor or observations are outside the supported sheet range')
row = next((row for row in numerical['rows'] if row['id'] == state['sampleId']), None)
if row is None:
raise ValueError('Select an existing sample ID')
x = row['x'] if state['mode'] == 'training' else state['query']
X = np.array([[x]], dtype=np.float64)
W = np.array([[r['weight']]], dtype=np.float64)
prediction = float((X @ W + r['bias'])[0, 0])
training = state['mode'] == 'training'
return dict(state=deepcopy(state), numerical=numerical, x=x, prediction=prediction,
target=row['y'] if training else None, residual=row['residual'] if training else None,
loss=numerical['mse'] if training else None,
reason=None if training else 'The query has no observed target. Inference produces a prediction, without an error or parameter update.',
inputShape=list(X.shape), batchShape=numerical['shapes']['X'], weightShape=list(W.shape))
def pipeline_update(state):
if state['mode'] != 'training':
raise ValueError('Inference does not update parameters')
result = {**deepcopy(state), 'regression': reference.regression_step(state['regression'])}
derive_pipeline(result)
return result
def pipeline_trace(state):
derive_pipeline(state)
if state['mode'] == 'inference':
explanations = ['1. Receive a query x; no target is observed.', '2. Represent x as a 1 × 1 feature column.', '3. Apply the learned predictor. Parameters remain fixed.']
states = [state] * 3
else:
explanations = ['1. Observe the selected sample’s input and target.', '2. Represent its input as a feature column; samples occupy rows in the batch.', '3. Predict with the current shared weight and bias.', '4. Compare prediction with target; compute the batch loss and gradient.', '5. Subtract one old-state gradient from both parameters simultaneously.']
states = [state] * 4 + [pipeline_update(state)]
return [dict(index=i, state=deepcopy(item), explanation=explanations[i]) for i, item in enumerate(states)]
if __name__ == '__main__':
print(json.dumps(dict(training=derive_pipeline(PIPELINE_CANONICAL), inference=derive_pipeline({**PIPELINE_CANONICAL, 'mode': 'inference'}), trace=pipeline_trace(PIPELINE_CANONICAL)), indent=2, allow_nan=False))The committed golden before/after/trace is independently checked by exact Fraction arithmetic. Matching two implementations alone would not prove that either used the intended normalization or residual sign.
Explore, replay and diagnose
Try changing the selected target while its input is zero. Then reset, change the selected input, and inspect both gradients through the later optimization chapter. Explain why a data edit and a parameter edit affect different parts of the pipeline.
Replay records four explanatory frames at the old parameters, followed by one updated state. These are mathematical snapshots, not an animation that changes the model between frames. Selecting a frame changes every numeric control, equation and table to that frame. Editing begins from the displayed state and ends replay. Reset restores the original observations and parameters.
Limits and common mistakes
This sheet supports weights and biases in , observations and queries in , and rates from to . An unsupported update is rejected with the previous valid state retained. A permitted rate does not guarantee decreasing loss.
Numbers use binary64 arithmetic. Given coordinates retain round-trip decimal text; computed results carry an approximation sign. Display rounding never feeds training. Constant inputs and one-sample data can support prediction without identifying a unique weight and bias. This example neither proves causation nor justifies extrapolation.
Generalization needs an evaluation design, introduced in training, validation and testing. More elaborate models change the feature representation or parameter family while preserving the distinction between observations, predictions, objectives and decisions.
Check your understanding
Checkpoints
You can name the observed data, chosen family, learned parameters and update rule; follow the entire supervised pipeline; and apply a returned predictor to a query without inventing an error. Training chooses a mapping from examples. Inference evaluates that mapping with parameters held fixed.