I agree with @KFrank also also think that the model, criterion, and optimizer are separate units, which can be independently used and changed.
E.g. reusing your “model” to finetune it in another scenario would also recreate your optimizer, which would not be needed. Restoring a checkpoint also would need some additional check to see where the optimizer is located and used. In case you are using utilities, such as mixed-precision training via torch.cuda.amp, you would also need to manipulate the forward method of your model to add e.g. the GradScaler, and would need to add the “amp logic” to the model itself, which I would also like to avoid.