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!