# Kernodeck Resume v1 — a genuinely resumed checkpoint

This original exercise learns a small numerical relationship on 24 synthetic rows. Its purpose is to **verify that a training run resumes**, not to obtain the best model or to benchmark a GPU. The computation is explicitly forced onto the **CPU**, in `float64`, with one PyTorch thread.

The check compares 10 continuous steps against 5 steps, a checkpoint, then 5 new steps in **a separate Python process**. A fourth process deliberately omits restoring the random generators: its drift must be detected. No remote resource, client data, or pretrained weights are downloaded.

## Prerequisites

- A Python environment with PyTorch and NumPy already installed. The supplied proof was run with **Python 3.14.6, PyTorch 2.11.0+cu128, and NumPy 2.4.4**.
- About 1 MB free for the four small output folders. The Python dependencies take up their own space.
- Run the commands from the extracted `kernodeck-reprise-v1` folder.

The `+cu128` suffix describes the package present during the test; it does not mean this exercise used CUDA. **No CUDA, ROCm, AMP, multi-GPU, or distributed computation is validated by this resource.** It uses no DataLoader workers. Another environment must produce its own proof; equality is not guaranteed across versions or platforms.

## The verification command

```console
python -B verify_resume.py --output runs/preuve-cpu
```

`-B` avoids bytecode caches in the project folder. The output directory must be new: no existing run is overwritten. To start over, use for example `runs/preuve-cpu-2`.

The program runs four commands with the same Python interpreter, then writes `runs/preuve-cpu/verification.json`. A complete run produces:

```json
{"device":"cpu","all_checks_passed":true,"positive":true,"negative_divergence_detected":true,"report":"verification.json"}
```

The exit code is **0** if the protocol succeeds, **1** if the comparison fails, **2** if the verification could not be completed. Success requires both the positive resume and the observable failure of the negative control. A checkpoint file that is merely present is not enough.

## Doing the three steps by hand

```console
python -B train.py --steps 10 --output runs/continu
python -B train.py --steps 5 --output runs/coupure
python -B train.py --steps 5 --resume runs/coupure/checkpoint.pt --output runs/reprise
```

Each line launches a separate process. `--steps` means **additional steps**, so the third command finishes at step 10. Each folder contains `checkpoint.pt`, its `checkpoint.pt.sha256` hash, and a readable `summary.json`. The checkpoints are created by the exercise at runtime; they are not distributed in the archive.

To observe the incomplete case, use a new folder:

```console
python -B train.py --steps 5 --resume runs/coupure/checkpoint.pt --omit-rng-restore --output runs/reprise-incomplete
```

This last command may finish without a Python error. **That does not prove a correct resume.** The `verify_resume.py` command compares the results and detects the difference.

## What the model actually does

`data.csv` contains a grid of two variables and a synthetic target: `target = 0.7*x1 - 0.4*x2 + 0.15*x1*x2 + 0.1`. It imitates no client record. The network has two inputs, one layer of eight neurons, `Tanh`, a dropout of 0.25, and one output, for 33 parameters.

Training uses Adam with an initial rate of 0.03. StepLR halves that rate every three steps. Each batch contains four rows: 10 steps therefore consume 40 observations, revisiting some rows after the first epoch. The permutation, the epoch, the cursor, and the number of observations consumed are all preserved. At the cutoff after five steps, the cursor is at 20 out of 24: the resume happens **inside the data traversal**.

Three random sources influence the work: Python sets a slight gain on the inputs, a NumPy PCG64 generator produces the noise and the permutations, and PyTorch produces the dropout. Setting the initial seed again does not reconstruct the states reached at the cutoff.

## What the checkpoint preserves, and in what order it is read back

The dictionary contains the weights, the Adam state, the StepLR state, the data progress, the three RNGs, the loss and rate history, as well as the code and CSV fingerprints. The `train()` mode is restored for the resume; the final MSE measurement uses `eval()` and does not consume the dropout.

On resume, the code first builds the model, the optimizer and **the scheduler**, then loads the weights, the scheduler state and the optimizer state. The RNGs are restored last, after the constructions that consume randomness. This choice respects the warning in the documentation for [Optimizer.load_state_dict](https://docs.pytorch.org/docs/2.11/generated/torch.optim.Optimizer.load_state_dict.html).

The Python state is a structure of primitives. PCG64 provides a dictionary of integers and strings; no NumPy `ndarray` object is serialized as RNG state. The PyTorch CPU state is a byte tensor. The next draws are checked without modifying the saved state.

## Reading the proof and tolerance

`verification-cpu.json` is the public proof from a real run of this version. `source` contains the SHA-256 hashes of the scripts and the CSV. `protocol` describes the four processes, the precision and the tolerance. `resume_boundary` verifies the next draw of each RNG and the next rate used after the cut.

The comparison requires the same row order, the same progress and the same scheduler state. The maximum absolute deviation accepted for the weights, the optimizer state, the losses, the MSE and the rates is **1e-12**, with no relative tolerance (`rtol=0`). The report keeps the measured deviations, even when they are zero. It also verifies the next RNG draw at the end of both runs.

The negative control must show that omitting the RNGs changes the result. Its MSE may be lower or higher: this test verifies a resume trajectory, not a ranking of quality. An expected divergence therefore yields `passed: false` in this sub-test and `divergence_detected: true`; the overall protocol can then succeed.

## Loading only your own checkpoint

The loader explicitly uses `torch.load(..., map_location="cpu", weights_only=True)` and offers no fallback to `weights_only=False`. It first verifies the associated fingerprint, limits the size and checks the schema, the versions, the code and the data. It rejects an incomplete state instead of silently reinitializing part of the training.

Use only the checkpoints that **you created with this exercise and kept under your control**. The fingerprint serves to detect a modification; it does not authenticate a sender. Restricted loading does not make an unknown file trustworthy. See [torch.load](https://docs.pytorch.org/docs/2.11/generated/torch.load.html) and [PyTorch serialization](https://docs.pytorch.org/docs/2.11/notes/serialization.html).

## Adapting the exercise to your project

Identify the states that your own training actually consumes: sampler, augmentation, optimizer, scheduler and specific generators. If you use AMP, add the scaler state at a consistent boundary; this exercise does not. A distributed training run also requires handling its processes and their data distribution.

Do not infer from this small proof a rental duration, a throughput, a VRAM footprint or a resume guarantee for a different model. Follow the method: a short representative run, a cut in the middle of the work, another process, an explicit comparison and a negative control.

## Contents and licenses

- `train.py`, `verify_resume.py`, this documentation and the manifest: MIT license, see `LICENSE-MIT.txt`.
- `data.csv`: original synthetic data offered under CC0 1.0, see `DATA-LICENSE-CC0.txt`.
- `verification-cpu.json`: measurements from this exercise, with no personal data, full environment, local paths, tokens or session identifiers.
- `manifest.json`: exact list of the distributed files and their SHA-256 hashes. The manifest does not reference itself.
- `SOURCES.md`: official links and documentation limits.

The PyTorch, NumPy and Python dependencies retain their own licenses. They are not redistributed in the ZIP.


## Kernodeck presentation and project compatibility

This September 25, 2026 reissue updates the archive name, the documentation, and the brand. The scripts `train.py` and `verify_resume.py`, the CSV, and `verification-cpu.json` remain identical to the delivery executed on September 24, 2026. The `project` technical field keeps its identifier for readers of existing reports. No CPU/GPU computation or check was rerun for this reissue.
