Async notifications and values observed but not used to reevaluate

I’m working on creating a notebook on machine learning with synaptic.
see

I have two questions. First, Synaptic uses can be trained by asynchronously and can log to the javascript console and/or run a function at an interval.

Since the function is called async, I can’t yield from the method, but I wanted to get a progress report I can rely on. So I created a raise_event method similar to the Generator notify pattern.

the raise_event function looks like this:

function raise_event(event_name, data){
   var event; // The custom event that will be created

   if (document.createEvent) {
     event = document.createEvent("HTMLEvents");
     event.initEvent(event_name, true, true);
   } else {
     event = document.createEventObject();
     event.eventType = event_name;
  }
  event.custom_data = data;
  event.eventName = event_name;

  if (document.createEvent) {
    window.dispatchEvent(event);
  } else {
    window.fireEvent("on" + event.eventType, event);
  }
}

And is used by a generator like this:

progress_report = Generators.queue(notify => {
  const received_data = event => {notify(event.custom_data)};
  window.addEventListener("progress_report", received_data);
  return () => window.removeEventListener("progress_report", received_data);
})

So the first question: Does this stink? See cells "synaptic_network, “raise_event”, and “progress_report”.

The second question is related to the ability to cancel the async training. Returning true from the scheduled function in synaptic’s trainer will cause the training to stop. I want to be able to abort training without re-evaluating the network cell and restarting the trainer.

For example, if I was to add a toggle training button producing a true false by relying on “this” and reference its value within the function, I would successfully stop the training, but immediately restart because the cell is being re-evaluated. Maybe I have to utilize the value of “this”? If so, I don’t know how for this particular case.

Maybe this doesn’t fit in Observablehq?

Any advice you have would be great.

Disclaimer: late night code, and maybe not the absolute purest expression of the concept, but here goes:

So, for the two issues:

  • Progress + finished values: the issue is that trainAsync generates progress notifications through the callback, and also returns a Promise that contains the finished network. I decided to embrace that and create one cell - bundle, which is pinned, that returns an object containing both. Then I can break out the parts of that bundle into separate cells. Ideally we’ll implement destructuring assignment soon, so this’ll be doable in a single cell declaration that exports two variables. Your solution isn’t bad - really - and it works, but relying on the event system and making things global is a bit of a bummer.
  • Abort: this notebook also implements abort, but as I glean from the issue tracker, aborting through a schedule function is only available with train, rather than trainAsync, because the latter works in a WebWorker and, as far as my coderead goes, synaptic hasn’t yet implemented messaging to the worker to abort it. And, I’m using kind of a little trick for mutable values: by changing an object property, it doesn’t trigger a reactive re-evaluation of the cell. There’ll be a first-class way to represent mutable values like this very :soon:

Hope that helps! Very cool notebook!

1 Like

Thanks for the guidance. I’ll have to study the notebook when I get some time away from work. I like the bundle idea for the progress. That feels so much better than the global.

–JJ