This the API I adapted for my current project. It can work fine.
Though the primary motivator was that I didn’t want to assume the models were just pytorch, and wanted to let models be black boxes which used any sort of learning, optimizers, or extra operations. Then there is a Trainer which handles feeding in data into something implementing the interface, no matter what kind of model it is.
There have been some times I have slightly regretted it, as it makes things like using a different learning rate for different datasets is somewhat more annoying. Also, quickly extra complexity was needed on the interface to let the model know when training started, whether it should be in eval or train mode, methods to move in and out of cuda, etc…
So I think it really depends on use case and things like how many models you plan to have for whether this extra complexity and extra wrapper is worth it. In base pytorch it does make sense why they are not coupled, as it is a higher level and fairly opinionated choice. If you just trying train one model for one task you don’t really need all that abstraction.