Hi!
So when I do:
def log_engine_output(
engine: Engine,
fields: Dict[LOG_OP, Union[List[str], List[VisPlot], List[VisImg]]],
epoch_num=None,
) -> None:
"""Log numerical fields in the engine output dictionary to stdout"""
print(epoch_num)
for mode in fields.keys():
if (
mode is LOG_OP.NUMBER_TO_VISDOM
or mode is LOG_OP.VECTOR_TO_VISDOM
or mode is LOG_OP.IMAGE_TO_VISDOM
):
mode(
engine,
engine.state.vis,
fields[mode],
engine_attr="output",
epoch_num=epoch_num,
)
else:
mode(engine, fields[mode], engine_attr="output")
trainer.add_event_handler(
Events.EPOCH_COMPLETED(every=1),
log_engine_output,
{
# Log fields as message in logfile
LOG_OP.LOG_MESSAGE: ["loss"],
# Log fields as separate data files
LOG_OP.SAVE_IN_DATA_FILE: ["loss"],
# Plot fields to Visdom
LOG_OP.NUMBER_TO_VISDOM: [
# First plot, key is "p1"
VisPlot(
"loss",
plot_key="p1",
split="nll_1",
title="Train loss: ",
x_label="Iters",
y_label="nll",
env=cfg.env,
),
],
},
trainer.state.epoch,
)
The epoch_num that is printed is always 0. Thatâs not right since it prints every epoch - why would this happen?
Iâm also confusing about the structure of doing trainer.add_event_handler() vs. the decorator of
@trainer.on(Events.EPOCH_COMPLETED(every=1)).
I thought that the only difference between the decorator and the add_event_handler(some_function, variable1, variable2) was that with add_event_handler you could pass in the variables that are the arguments to the function (variable 1, variable 2), whereas with the decorator @train you can only pass in âengineâ as your argument. Is this correct? If so, why isnât passing the arguments working for me?
Also - what is the situation with add_event_handler automatically checking to see if the first argument it finds (after the function),is âengineâ? From the tutorial, âThe first argument can be optionally engine, but not necessary.â.
def log_metrics(engine, title):
print("Epoch: {} - {} accuracy: {:.2f}"
.format(trainer.state.epoch, title, engine.state.metrics["acc"]))
@trainer.on(Events.EPOCH_COMPLETED)
def evaluate(trainer):
with evaluator.add_event_handler(Events.COMPLETED, log_metrics, "train"):
evaluator.run(train_loader)
Here it automatically passes âevaluatorâ as the âengineâ argument to log_metrics. However, here:
trainer = Engine(update_model)
trainer.add_event_handler(Events.STARTED, lambda _: print("Start training"))
# or
@trainer.on(Events.STARTED)
def on_training_started(engine):
print("Another message of start training")
# or even simpler, use only what you need !
@trainer.on(Events.STARTED)
def on_training_started():
print("Another message of start training")
# attach handler with args, kwargs
mydata = [1, 2, 3, 4]
def on_training_ended(data):
print("Training is ended. mydata={}".format(data))
trainer.add_event_handler(Events.COMPLETED, on_training_ended, mydata)
The first argument is not âengineâ. Does this mean that somehow ignite checks the function passed into add_event_handler to see if the first argument is called âengineâ? And if so, does the nomenclature have to be exactly called âengineâ in order for it to pass the engine that add_event_handler is attached to to the function?
Thanks!