# Kernodeck Ripresa v1 — un checkpoint realmente riavviato

Questo esercizio originale apprende una piccola relazione numerica su 24 righe sintetiche. Il suo obiettivo è **verificare la ripresa di un addestramento**, non ottenere il modello migliore o misurare una GPU. Il calcolo è esplicitamente forzato su **CPU**, in `float64`, con un thread PyTorch.

Il controllo confronta 10 step continui con 5 step, un checkpoint e poi 5 nuovi step in **un altro processo Python**. Un quarto processo omette volontariamente il ripristino dei generatori casuali: la sua deriva deve essere rilevata. Nessuna risorsa remota, dato cliente o peso preaddestrato viene scaricato.

## Prerequisiti

- Un ambiente Python con PyTorch e NumPy già installati. La prova fornita è stata eseguita con **Python 3.14.6, PyTorch 2.11.0+cu128 e NumPy 2.4.4**.
- Circa 1 GB disponibile per le quattro piccole cartelle di output. Le dipendenze Python occupano il proprio spazio.
- Eseguire i comandi dalla cartella estratta `kernodeck-reprise-v1`.

Il suffisso `+cu128` descrive il pacchetto presente al momento del test; non significa che questo esercizio abbia utilizzato CUDA. **Nessun calcolo CUDA, ROCm, AMP, multi-GPU o distribuito è validato da questa risorsa.** Non utilizza worker DataLoader. Un altro ambiente deve produrre la propria prova; l'uguaglianza non è garantita tra versioni o piattaforme.

## Il comando di verifica

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

`-B` evita le cache di bytecode nella cartella del progetto. La directory di output deve essere nuova: nessun tentativo esistente viene sovrascritto. Per ricominciare, usa ad esempio `runs/preuve-cpu-2`.

Il programma esegue quattro comandi con lo stesso interprete Python, poi scrive `runs/preuve-cpu/verification.json`. Un'esecuzione completa produce:

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

Il codice di uscita vale **0** se il protocollo ha successo, **1** se il confronto fallisce, **2** se la verifica non è potuta arrivare a termine. Il successo richiede sia la ripresa positiva sia il fallimento osservabile del controllo negativo. Un file di checkpoint semplicemente presente non basta.

## Eseguire i tre passaggi a mano

```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
```

Ogni riga avvia un processo distinto. `--steps` significa **step aggiuntivi**, quindi il terzo comando termina allo step 10. Ogni cartella contiene `checkpoint.pt`, la sua impronta `checkpoint.pt.sha256` e un riepilogo leggibile `summary.json`. I checkpoint sono creati dall'esercizio durante l'esecuzione; non sono distribuiti nell'archivio.

Per osservare il caso incompleto, usa una nuova cartella:

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

Quest'ultimo comando può terminare senza errori Python. **Ciò non prova una ripresa corretta.** Il comando `verify_resume.py` confronta i risultati e constata la differenza.

## Cosa fa realmente il modello

`data.csv` contiene una griglia di due variabili e un target sintetico: `target = 0.7*x1 - 0.4*x2 + 0.15*x1*x2 + 0.1`. Non imita alcun rilevamento cliente. La rete ha due input, uno strato di otto neuroni, `Tanh`, un dropout di 0,25 e un output, ovvero 33 parametri.

L'addestramento utilizza Adam con un tasso iniziale di 0,03. StepLR dimezza questo tasso ogni tre step. Ogni batch contiene quattro righe: 10 step consumano quindi 40 osservazioni, ripercorrendo alcune righe dopo la prima epoca. La permutazione, l'epoca, il cursore e il numero di osservazioni consumate sono conservati. Alla coupure dopo cinque step, il cursore vale 20 su 24: la ripresa avviene **all'interno del percorso dei dati**.

Tre sorgenti casuali influenzano il lavoro: Python imposta un leggero guadagno sugli input, un generatore NumPy PCG64 produce il rumore e le permutazioni, PyTorch produce il dropout. Fissare di nuovo il seed iniziale non ricostituisce gli stati raggiunti alla coupure.

## Cosa conserva il checkpoint e in quale ordine viene riletto

Il dizionario contiene i pesi, lo stato Adam, lo stato StepLR, la progressione dei dati, i tre RNG, la cronologia delle perdite e dei tassi, nonché le impronte del codice e del CSV. La modalità `train()` viene ripristinata per la ripresa; la misura finale della MSE utilizza `eval()` e non consuma il dropout.

Alla ripresa, il codice costruisce prima il modello, l'ottimizzatore e **lo scheduler**, poi carica i pesi, lo stato dello scheduler e quello dell'ottimizzatore. I RNG vengono ripristinati per ultimi, dopo le costruzioni che consumano casualità. Questa scelta rispetta l'avvertimento della documentazione [Optimizer.load_state_dict](https://docs.pytorch.org/docs/2.11/generated/torch.optim.Optimizer.load_state_dict.html).

Lo stato Python è una struttura di primitive. PCG64 fornisce un dizionario di interi e stringhe; nessun oggetto `ndarray` NumPy viene serializzato come stato RNG. Lo stato PyTorch CPU è un tensore di byte. I prossimi sorteggi sono controllati senza modificare lo stato salvato.

## Lettura della prova e tolleranza

`verification-cpu.json` è la prova pubblica derivante da un'esecuzione reale di questa versione. `source` contiene gli SHA-256 degli script e del CSV. `protocol` descrive i quattro processi, la precisione e la tolleranza. `resume_boundary` verifica il prossimo sorteggio di ciascun RNG e il prossimo tasso utilizzato dopo l'interruzione.

Il confronto richiede lo stesso ordine di righe, la stessa progressione e lo stesso stato dello scheduler. Lo scarto assoluto massimo accettato per i pesi, lo stato dell'ottimizzatore, le perdite, la MSE e i tassi è **1e-12**, senza tolleranza relativa (`rtol=0`). Il rapporto conserva gli scarti misurati, anche quando valgono zero. Verifica inoltre il prossimo sorteggio dei RNG alla fine di entrambi i percorsi.

Il controllo negativo deve mostrare che l'oblio dei RNG cambia il risultato. La sua MSE può essere più bassa o più alta: questo test verifica una traiettoria di ripresa, non una classificazione di qualità. Una divergenza attesa dà quindi `passed: false` in questo sotto-test e `divergence_detected: true`; il protocollo globale può allora riuscire.

## Caricare solo il proprio checkpoint

Il caricatore utilizza esplicitamente `torch.load(..., map_location="cpu", weights_only=True)` e non propone alcun fallback verso `weights_only=False`. Verifica prima l'impronta associata, limita la dimensione e verifica lo schema, le versioni, il codice e i dati. Rifiuta uno stato incompleto invece di reinizializzare silenziosamente una parte dell'addestramento.

Utilizza unicamente i checkpoint che **hai creato con questo esercizio e conservato sotto il tuo controllo**. L'impronta serve a rilevare una modifica; non autentica un mittente. Il caricamento ristretto non rende affidabile un file sconosciuto. Vedi [torch.load](https://docs.pytorch.org/docs/2.11/generated/torch.load.html) e [la serializzazione PyTorch](https://docs.pytorch.org/docs/2.11/notes/serialization.html).

## Adattare l'esercizio al tuo progetto

Identifica gli stati che il tuo addestramento consuma realmente: sampler, augmentation, ottimizzatore, scheduler e generatori particolari. Se utilizzi AMP, aggiungi lo stato dello scaler a una frontiera coerente; questo esercizio non lo fa. Un addestramento distribuito richiede anche di gestire i suoi processi e la loro ripartizione dei dati.

Non dedurre da questa piccola prova una durata di noleggio, un throughput, un'impronta VRAM o una garanzia di ripresa per un modello diverso. Riprendi il metodo: set breve rappresentativo, interruzione a metà del lavoro, altro processo, confronto esplicito e controllo negativo.

## Contenuti e licenze

- `train.py`, `verify_resume.py`, questa documentazione e il manifest: licenza MIT, vedi `LICENSE-MIT.txt`.
- `data.csv`: dati sintetici originali proposti sotto CC0 1.0, vedi `DATA-LICENSE-CC0.txt`.
- `verification-cpu.json`: misurazioni di questo esercizio, senza dati personali, ambiente completo, percorsi della macchina, token o identificatori di sessione.
- `manifest.json`: elenco esatto dei file distribuiti e dei loro SHA-256. Il manifest non fa riferimento a sé stesso.
- `SOURCES.md`: link ufficiali e limiti documentali.

Le dipendenze PyTorch, NumPy e Python conservano le proprie licenze. Non sono ridistribuite nello ZIP.


## Presentazione Kernodeck e compatibilità del progetto

Questa riedizione del 25 settembre 2026 aggiorna il nome dell'archivio, la documentazione e il marchio. Gli script `train.py` e `verify_resume.py`, il CSV e `verification-cpu.json` restano identici alla consegna eseguita il 24 settembre 2026. Il campo tecnico `project` conserva il suo identificatore per i lettori di report esistenti. Nessun calcolo né controllo CPU/GPU è stato rilanciato per questa riedizione.
