PyTorch / Storage, restoration, and transformed execution / Lesson 18
Complete synthetic model acceptance
Assemble a small PyTorch inference contract and separate local implementation evidence from model-quality claims.
On this page
Lesson goals
- Combine registered preprocessing state, module composition, and fixed parameters.
- Verify known inputs and a deliberate restoration boundary.
- State input semantics, unsupported cases, and execution evidence precisely.
Acceptance begins with a complete function contract
The final fixture consumes two ordered measurements in centimeters, subtracts stored training means, divides by stored scales, applies a fixed hidden transformation and ReLU, and returns one numeric score. Its architecture and assigned weights are chosen for transparent arithmetic, not learned from an external population. State observation identity, feature order, units, missingness, valid domain, output shape, and score meaning beside a tensor interface. A result shaped like a prediction does not acquire a real-world interpretation automatically. This lesson accepts only a local synthetic behavior contract, not a product, policy, or statistical model quality.
Registration preserves the required inference state
The illustrative module registers center and scale buffers and composes its layers through Sequential. Explicit assignments make the first linear map identity and the final map a difference. The two raw inputs normalize to [1,1] and [2,0], remain unchanged by ReLU, and yield zero and two. A compatible fresh module receives a deep-copied state_dict under strict loading and uses evaluation mode. The code then compares results under inference_mode. These are reasoned expectations that connect earlier interfaces; no module construction, tensor kernel, loading, or inference context was executed in torch.
import copy
import torch
from torch import nn
class Fixture(nn.Module):
def __init__(self):
super().__init__()
self.register_buffer("center",torch.tensor([10.0,20.0],dtype=torch.float64,device="cpu"))
self.register_buffer("scale",torch.tensor([2.0,4.0],dtype=torch.float64,device="cpu"))
self.body = nn.Sequential(nn.Linear(2,2,bias=False,dtype=torch.float64,device="cpu"),nn.ReLU(),
nn.Linear(2,1,bias=False,dtype=torch.float64,device="cpu"))
with torch.no_grad():
self.body[0].weight.copy_(torch.eye(2,dtype=torch.float64,device="cpu"))
self.body[2].weight.copy_(torch.tensor([[1.0,-1.0]],dtype=torch.float64,device="cpu"))
def forward(self,x):
return self.body((x-self.center)/self.scale)
model = Fixture().eval()
restored = Fixture()
restored.load_state_dict(copy.deepcopy(model.state_dict()),strict=True)
restored.eval()
x = torch.tensor([[12.0,24.0],[14.0,20.0]],dtype=torch.float64,device="cpu")
with torch.inference_mode():
output = model(x)
repeated = restored(x)
print("shape", tuple(output.shape))
print("predictions", output.tolist())
print("same restored", torch.equal(output,repeated))
shape (2, 1)
predictions [[0.0], [2.0]]
same restored True
The registered transform buffers and assigned weights define a fully inspectable inference fixture; no Module, state restoration, inference_mode, or model output was executed.
Input validation must preserve semantic meaning
The standard-library companion checks the declared centimeter units and rejects incompatible units rather than guessing a conversion. It also rejects malformed, Boolean, or nonfinite measurement values under its exact numeric-type policy. A different product might permit an explicit unit conversion, but that would need a defined, tested rule. Keep invalid input distinguishable from a legitimate score of zero. The companion calculates normalization and the fixed hidden/output arithmetic independently, yet does not test PyTorch registration, dtype behavior, batching, buffers, or autograd. Its output supports the mathematical fixture only.
from math import isfinite
def score(values,units):
if units != ["cm","cm"]:
raise ValueError("expected centimeters")
if len(values)!=2 or not all(type(x) in (int,float) and isfinite(x) for x in values):
raise ValueError("expected two finite measurements")
z = [(x-m)/s for x,m,s in zip(values,[10.0,20.0],[2.0,4.0])]
hidden = [max(0.0,x) for x in z]
return hidden[0]-hidden[1]
print("scores", [score(row,["cm","cm"]) for row in [[12.0,24.0],[14.0,20.0]]])
try:
score([12.0,24.0],["mm","mm"])
except ValueError as error:
print(str(error))
scores [0.0, 2.0]
expected centimeters
The executed companion verifies named unit policy, finite input, normalization, rectification, and score arithmetic. It does not establish framework acceptance or real predictive quality.
Behavioral checks include boundaries and state
Use known inputs, swapped features, invalid units, missing values, permitted batches, and threshold-near cases if a decision consumes the score. Compare named state and mode-dependent behavior before and after restoration. If a compiler or export transformation is later introduced, reassess its own supported domain and compare complete raw-input behavior. Training continuation requires additional next-update evidence beyond this inference round trip. A passing local fixture does not prove absence of leakage, calibrated probabilities, subgroup suitability, robustness to a new population, or a resource limit in an actual execution environment.
Report what was reviewed and what actually ran
Preserve the pinned documentation target, architecture, state contract, examples, expected results, validation policy, and limitations. Separate mathematical derivation, Python companion execution, and unavailable framework verification. A learner using a compatible runtime should run the framework fixtures in a clean CPU environment and investigate warnings or mismatches before relying on them. No installation or external artifact is required by the public renderer, which displays code without executing it. This course’s tests run standard-library companions only; no PyTorch parser, runtime, model, GPU, compiler, profiler, loader, or exported program was tested.
Common errors and fixes
A synthetic inference fixture is advertised as trained accuracy
- Why it happens
- Hand-assigned behavior was confused with learning and held-out evidence.
- How to fix it
- Label the fixed fixture and evaluate real candidates separately under a valid protocol.
- Prevent it next time
- Keep implementation correctness and statistical acceptance records distinct.
A score of zero hides invalid input
- Why it happens
- Failure was replaced by a plausible ordinary output.
- How to fix it
- Reject or return a documented explicit status before scoring.
- Prevent it next time
- Test unsupported units, types, shape, and missingness.
A restored tensor state is treated as the entire application
- Why it happens
- Preprocessing meaning, mode, and consumer decision rules were omitted.
- How to fix it
- Verify the complete raw-input-to-decision contract.
- Prevent it next time
- Keep known-input, named-state, compatibility, and limitation evidence together.
Check your understanding
1. Derive both scores in the final fixture step by step.
Show worked solution
For [12,24], subtract [10,20] to get [2,4], divide by [2,4] to get [1,1], retain those positives through ReLU, and subtract to obtain zero. For [14,20], subtraction gives [4,0], division gives [2,0], ReLU leaves [2,0], and the final difference is two. The output has one score for each of two observations.
2. What must a learner still verify before claiming the PyTorch program ran correctly?
Show worked solution
They need an actual supported torch runtime and should execute the CPU program, inspect warnings, shapes, named state, expected values, and the restoration behavior under the declared environment. The executed Python companion is not evidence that those framework operations occurred. Statistical usefulness and operational performance require additional task-specific evidence.
Key takeaways
- Accept the complete input-to-output contract at its stated scope.
- Registered state and semantic validation both matter.
- Report actual execution separately from derived framework expectations.