Mercurial > pylearn
comparison doc/v2_planning/plugin.txt @ 1135:a1957faecc9b
revised plugin interface and implementation
author | Olivier Breuleux <breuleuo@iro.umontreal.ca> |
---|---|
date | Thu, 16 Sep 2010 02:58:24 -0400 |
parents | 81ea57c6716d |
children |
comparison
equal
deleted
inserted
replaced
1134:0653a85ff2e8 | 1135:a1957faecc9b |
---|---|
65 ============== | 65 ============== |
66 | 66 |
67 I have implemented the feature in plugin.py, in this directory. Simply | 67 I have implemented the feature in plugin.py, in this directory. Simply |
68 run python plugin.py to test it. | 68 run python plugin.py to test it. |
69 | 69 |
70 | |
71 | |
72 =============== | |
73 Revised version | |
74 =============== | |
75 | |
76 Taking into account ideas thrown around during the September 16 | |
77 meeting I (OB) have made the following modifications to my original | |
78 proposal: | |
79 | |
80 Event objects | |
81 ============= | |
82 | |
83 In the revised framework, an Event is a generic object which can | |
84 contain any attributes you want, with one privileged attribute, the | |
85 'type' attribute, which is a string. I expect the following attributes | |
86 to be used widely: | |
87 | |
88 * type: this is a string describing the abstract semantics of this | |
89 event ("tick", "second", "millisecond", "batch", etc.) | |
90 | |
91 * issuer: a pointer to the plugin that issued this event. This allows | |
92 for fine grained filtering in the case where several plugins can | |
93 fire the same event type | |
94 | |
95 * time: an integer or float index on an abstract timeline. For | |
96 instance, the "tick" event would have a "time" field, which would be | |
97 increased by one every time the event is fired. Pretty much all | |
98 recurrent events should include this. | |
99 | |
100 * data: some data associated to the event. presumably it doesn't have | |
101 to be named "data", and more than one data field could be given. | |
102 | |
103 The basic idea is that it should be possible to say: "I want this | |
104 plugin to be executed every tenth time an event of this type is fired | |
105 by this plugin", or any subset of these conditions. | |
106 | |
107 Matching events | |
108 =============== | |
109 | |
110 When registering a plugin, you specify a sort of "abstract event" that | |
111 an event must "match" in order to be fed to the plugin. This can be | |
112 done by simply instantiating an event with the fields you want to | |
113 match. I think examples would explain best my idea | |
114 (sch.schedule_plugin = add a plugin to the scheduler): | |
115 | |
116 # Print the error on every parameter update (learner given in the event) | |
117 sch.schedule_plugin(Event("parameter_update"), PrintError()) | |
118 # Print the reconstruction error of daa0 whenever it does a parameter update | |
119 sch.schedule_plugin(Event("parameter_update", issuer = daa0), PrintReconstructionError()) | |
120 # Save the learner every 10 minutes | |
121 sch.schedule_plugin(Event("minute", time = each(10)), Save(learner)) | |
122 | |
123 The events given as first argument to schedule_plugin are not real | |
124 events: they are "template events" meant to be *matched* against the | |
125 real events that will be fired. If the terminology is confusing, it | |
126 would not be a problem to use another class with a better name (for | |
127 example, On("minute", time = each(10)) could be clearer than | |
128 Event(...), I don't know). | |
129 | |
130 Note that fields in these Event objects can be a special kind of | |
131 object, a Matcher, which allows to filter events based on arbitrary | |
132 conditions. My Schedule objects (each, at, etc.) now inherit from | |
133 Matcher. You could easily have a matcher that allows you to match | |
134 issuers that are instances of a certain class, or matches every single | |
135 event (I have an example of the latter in plugin.py). | |
136 | |
137 Plugins | |
138 ======= | |
139 | |
140 The plugin class would have the following methods: | |
141 | |
142 * attach(scheduler): tell the plugin that it is being scheduled by the | |
143 scheduler, store the scheduler in self. The method can return self, | |
144 or a copy of itself. | |
145 | |
146 * fire(type, **attributes): adds Event(type, issuer = self, **attributes) | |
147 to the event queue of self.scheduler | |
148 | |
149 Scheduler | |
150 ========= | |
151 | |
152 A Scheduler would have a schedule_plugin(event_template, plugin) | |
153 method to add plugins, a queue(event) method to queue a new event, and | |
154 it would be callable. | |
155 | |
156 My current version proceeds as follows: | |
157 | |
158 * Fire Event("begin"). Somewhat equivalent to "tick" at time 0, but I | |
159 find it cleaner to have a special event to mark the beginning of the | |
160 event loop. | |
161 * Infinite loop | |
162 * Fire Event("tick", time = <iteration#>) | |
163 * Loop until the queue is empty | |
164 * Pop event, execute all plugins that respond to it | |
165 * Check if event.type == "terminate". If so, stop. | |
166 | |
167 Varia | |
168 ===== | |
169 | |
170 I've made a very simple implementation of a DispatchPlugin which, upon | |
171 reception of an event, dispatches it to its "on_<event.type>" method | |
172 (or calls a fallback). It seems nice. However, in order for it to work | |
173 reliably, it has to be registered on all events, and I'm not sure it | |
174 can scale well to more complex problems where the source of events is | |
175 important. | |
176 | |
177 Implementation | |
178 ============== | |
179 | |
180 See plugin.py. | |
181 |