When users create an engine, they use Engine(process_function) and the process_funtion will be saved as self._process_function. The requirements for process_function is that it must be callable and return output for future handlers. Since an nn.Module matchs these requirements, it can be used as an alternative.
And my question is would it be better to use nn.Module and expose it as self.module or self.net?
Here are my reasons:
To use a function, we need define a model out of this function which will make the model a "global variable". However, if we use a model to initialize an engine, it can be a local variable.
By using a model, we can access this model easily and flexibly in other handlers. For example, a user can attach a debugger to a model and call model.debug() to display information in some handlers. Or, when certain events are triggered, the user can change the behavior of the model.
@lzcn thanks for the feedback and a suggestion. If I understand correctly your point, in this case engine is a sort of associated with a single model, however the role of the engine to be generic and also handle other situations with multiple models: GAN, self-ensembling methods, etc. IMO, adopting your strategy would restrict the usage of the package.
If you would like to avoid global variables for model, criterion, optimizer, you can, for example, put them into engine.state or create a structure holding them:
def process_function(engine, batch):
model = engine.state.model
optimizer = engine.state.optimizer
criterion = engine.state.criterion
...
trainer = Engine(process_function)
@trainer.on(Events.STARTED, model, optimizer, criterion)
def initialize_params(engine, _model, _opt, _crit):
engine.state.model = _model
engine.state.optimizer = _opt
engine.state.criterion = _crit
# or simply just put them as attributes of the engine
trainer.model = model
trainer.optimizer = optimizer
trainer.criterion = criterion
What do you think ?
HTH
@lzcn thanks for the feedback and a suggestion. If I understand correctly your point, in this case engine is a sort of associated with a single model, however the role of the engine to be generic and also handle other situations with multiple models: GAN, self-ensembling methods, etc. IMO, adopting your strategy would restrict the usage of the package.
If you would like to avoid global variables for model, criterion, optimizer, you can, for example, put them into
engine.stateor create a structure holding them:def process_function(engine, batch): model = engine.state.model optimizer = engine.state.optimizer criterion = engine.state.criterion ... trainer = Engine(process_function) @trainer.on(Events.STARTED, model, optimizer, criterion) def initialize_params(engine, _model, _opt, _crit): engine.state.model = _model engine.state.optimizer = _opt engine.state.criterion = _crit # or simply just put them as attributes of the engine trainer.model = model trainer.optimizer = optimizer trainer.criterion = criterionWhat do you think ?
HTH
I'm so grateful for your solution and it solved my problem completely. :)
Most helpful comment
@lzcn thanks for the feedback and a suggestion. If I understand correctly your point, in this case engine is a sort of associated with a single model, however the role of the engine to be generic and also handle other situations with multiple models: GAN, self-ensembling methods, etc. IMO, adopting your strategy would restrict the usage of the package.
If you would like to avoid global variables for model, criterion, optimizer, you can, for example, put them into
engine.stateor create a structure holding them:What do you think ?
HTH