{"action":"created","issue":{"url":"https://api.github.com/repos/fchollet/keras/issues/219","labels_url":"https://api.github.com/repos/fchollet/keras/issues/219/labels{/name}","comments_url":"https://api.github.com/repos/fchollet/keras/issues/219/comments","events_url":"https://api.github.com/repos/fchollet/keras/issues/219/events","html_url":"https://github.com/fchollet/keras/pull/219","id":87731759,"number":219,"title":"Callback <-> Model message passing","user":{"login":"tdhd","id":8267636,"avatar_url":"https://avatars.githubusercontent.com/u/8267636?v=3","gravatar_id":"","url":"https://api.github.com/users/tdhd","html_url":"https://github.com/tdhd","followers_url":"https://api.github.com/users/tdhd/followers","following_url":"https://api.github.com/users/tdhd/following{/other_user}","gists_url":"https://api.github.com/users/tdhd/gists{/gist_id}","starred_url":"https://api.github.com/users/tdhd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tdhd/subscriptions","organizations_url":"https://api.github.com/users/tdhd/orgs","repos_url":"https://api.github.com/users/tdhd/repos","events_url":"https://api.github.com/users/tdhd/events{/privacy}","received_events_url":"https://api.github.com/users/tdhd/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":8,"created_at":"2015-06-12T13:37:12Z","updated_at":"2015-06-20T22:47:47Z","closed_at":"2015-06-20T22:47:47Z","pull_request":{"url":"https://api.github.com/repos/fchollet/keras/pulls/219","html_url":"https://github.com/fchollet/keras/pull/219","diff_url":"https://github.com/fchollet/keras/pull/219.diff","patch_url":"https://github.com/fchollet/keras/pull/219.patch"},"body":"Hi,\r\n\r\nthis is the PR I mentioned in #213.\r\n\r\nA brief summary of what I did:\r\n- make https://github.com/ReactiveX/RxPY a dependency of keras (lightweight reactive extensions for python)\r\n- with `rx` I added a communication channel to every callback and the model class\r\n- these channels replace the callback logic which was implemented earlier\r\n- every object can now subscribe to certain events either from the callbacks or the model (or basically any object which has such a channel)\r\n- ported all existing callbacks to use the channel to subscribe and to publish messages\r\n\r\nTo describe in a little more detail:\r\n\r\n`Model` now has `self.pub_stream` to which callbacks can subscribe, to receive messages like `TrainBegin` and so on. As before the `Model.fit` receives a list of callbacks. Inside `fit`, all passed callbacks are notified of the event source (which is `self.pub_stream` of `Model`) and in turn the model subscribes to events like `StopTraining` and `SaveModel`. These are currently the only events we had to include.\r\nTo subscribe, take `callback.pub_stream` (the output channel of the callback), filter all messages down to a single type, for instance `StopTraining`, and then subscribe to the filtered stream of messages. All messages received are now of instance `StopTraining`.\r\nDuring the training the model emits the newly added messages from `messages.py` to it own channel by calling `on_next`. Since the callbacks are all subscribed to the messages they are interested in, they will be notified when the model publishes a message. In turn the model receives all events it needs to know about from the callbacks.\r\nIn a GUI, events can be received and sent in the same manner as they are with the callbacks at the moment.\r\n\r\nWith this, the model is decoupled a lot better from the callbacks than it was before. All of the callbacks, except for the `DrawActivations` one in `test_callbacks.py` (which I will probably fix) don't have a copy of the model object anymore. No methods of the model are called directly but are accessed through passed messages.\r\n\r\nIn this PR I had to remove the performance measurements of the callbacks which were done by `CallbackList`, sorry. :) Maybe there is way to measure it with the streams too.\r\n\r\nAbout the docs: It would be a good idea to avoid referring to this as callbacks. They are not callbacks anymore. :) I can write up documentation for the current implementation.\r\n\r\nIf you have any questions, please let me know."},"comment":{"url":"https://api.github.com/repos/fchollet/keras/issues/comments/113834733","html_url":"https://github.com/fchollet/keras/pull/219#issuecomment-113834733","issue_url":"https://api.github.com/repos/fchollet/keras/issues/219","id":113834733,"user":{"login":"fchollet","id":710255,"avatar_url":"https://avatars.githubusercontent.com/u/710255?v=3","gravatar_id":"","url":"https://api.github.com/users/fchollet","html_url":"https://github.com/fchollet","followers_url":"https://api.github.com/users/fchollet/followers","following_url":"https://api.github.com/users/fchollet/following{/other_user}","gists_url":"https://api.github.com/users/fchollet/gists{/gist_id}","starred_url":"https://api.github.com/users/fchollet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fchollet/subscriptions","organizations_url":"https://api.github.com/users/fchollet/orgs","repos_url":"https://api.github.com/users/fchollet/repos","events_url":"https://api.github.com/users/fchollet/events{/privacy}","received_events_url":"https://api.github.com/users/fchollet/received_events","type":"User","site_admin":false},"created_at":"2015-06-20T22:47:47Z","updated_at":"2015-06-20T22:47:47Z","body":"I have added an `EarlyStopping` callback that works by way of setting a `model.stop_training` flag. In the future, I suggest we keep working under this (extremely simple) model, at least until issues arise (you never know). Then we will be able to use our experience to figure out a better way."}}