changeset 1043:3f528656855b

v2planning learner.txt - updated API recommendation
author James Bergstra <bergstrj@iro.umontreal.ca>
date Wed, 08 Sep 2010 11:33:33 -0400
parents 4eaf576c3e9a
children 3b1fd599bafd
files doc/v2_planning/learner.txt
diffstat 1 files changed, 73 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/doc/v2_planning/learner.txt	Wed Sep 08 11:18:00 2010 -0400
+++ b/doc/v2_planning/learner.txt	Wed Sep 08 11:33:33 2010 -0400
@@ -173,116 +173,97 @@
 the picture and make a useful boosting implementation.
 
 
+Using External Hyper-Parameter Optimization Software
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TODO: use-case - show how we could use the optimizer from
+http://www.cs.ubc.ca/labs/beta/Projects/ParamILS/
+
 
 Implementation Details / API
 ----------------------------
 
-TODO: PUT IN TERMINOLOGY OF LEARNER, HYPER-LEARNER.
-
-TODO: SEPARATE DISCUSSION OF PERSISTENT STORAGE FROM LEARNER INTERFACE.
-
-TODO: API describing hyperparameters (categorical, integer, bounds on values, etc.)
-
-TODO: use-case - show how we could use the optimizer from
-      http://www.cs.ubc.ca/labs/beta/Projects/ParamILS/
-
-ExperimentGraph
-~~~~~~~~~~~~~~~
-
-One API that needs to be defined for this perspective to be practical is the
-ExperimentGraph.  I'll present it in terms of global functions, but an
-object-oriented things probably makes more sense in the code itself.
-
-
-    def explored_nodes(graph):
-       """Return iterator over explored nodes (ints? objects?)"""
+Learner
+~~~~~~~
+    An object that allows us to explore the graph discussed above.  Specifically, it represents
+    an explored node in that graph.
 
-    def forget_nodes(graph, nodes):
-       """Clear the nodes from memory (save space)"""
-
-    def all_edges_from(graph, node):
-       """Return iterator over all possible edges
-
-       Edges might be parametric - like "set learn_rate to (float)"
-
-       Edges might contain a reference to their 'from' end... not sure.
-       
-       """
-    def explored_edges_from(graph, node):
-        """Return the edges that have been explored
-        """
-
-    def add_node(graph, new_node):
-        """add a node.  It may be serialized."""
-
-    def add_edge(graph, edge):
-        """add edge, it may be serialize"""
-
-    def connect(graph, from_node, to_node, edge):
-        """
-        to_node = None for un-explored edge
+    def active_instructions()
+        """ Return a list/set of Instruction instances (see below) that the Learner is prepared
+        to handle.
         """
 
-It makes sense to have one ExperimentGraph implementation for each storage
-mechanism - Memory, JobMan, sqlite, couchdb, mongodb, etc.
-
-The nodes should be serializable objects (like the 'learner' objects in Yoshua's
-text above, so that you can do node.learner.predict() if the edge leading to
-`node` trained something new).
-
-The nodes could also contain the various costs (train, valid, test), and other
-experiment statistics that are node-specific.
+    def copy(), deepcopy()
+        """ Learners should be serializable """
 
 
-Some implementations might also include functions for asynchronous updating of
-the ExperimentGraph:
+    To make the implementation easier, I found it was helpful to introduce a string-valued
+    `fsa_state` member attribute and associate methods to these states.  That made it
+    syntactically easy to build relatively complex finite-state transition graphs to describe
+    which instructions were active at which times in the life-cycle of a learner.
 
 
-ExperimentGraphEdge
-~~~~~~~~~~~~~~~~~~~
-
-The ExperimentGraph is primarily a dictionary container for nodes and edges.
-An ExperimentGraphEdge implementation is the model-dependent component that
-actually interprets the edges as computations.
-
-    def estimate_compute_time(graph, node, edge):
-       """Return an estimated walltime expense for the computation"""
+Instruction
+~~~~~~~~~~~
+    An object that represents a potential edge in the graph discussed above.  It is an
+    operation that a learner can perform.
 
-    def compute_edge(graph, node, edge, async=False, priority=1):
-       """Run the computations assocated with this graph edge, and store the
-       resulting 'to_node' to the graph when complete.
-
-       If async is True, the function doesn't return until the graph is updated
-       with `to_node`.
+    arg_types
+        """a list of Type object (see below) indicating what args are required by execute"""
 
-       The priority is used by implementations that use cluster software or
-       something to manage a worker pool that computes highest-priority edges
-       first.
-
-       """
-
-    def list_compute_queue(graph):
-        """Return edges scheduled for exploration (and maybe a handle for
-        where/when they started running and other backend details)
+    def execute(learner, args, kwargs):
+        """ Perform some operation on the learner (follow an edge in the graph discussed above)
+        and modify the learner in-place.  Calling execute 'moves' the learner from one node in
+        the graph along an edge.  To have the old learner as well, it must be copied prior to
+        calling execute().
         """
 
-Different implementations of ExperimentGraphExplorer will correspond to
-different experiments.  There can also be ExperimentGraphExplorer
-implementations that are proxies, and perform the computations in different
-threads, or across ssh, or cluster software.
+    def expense(learner, args, kwargs, resource_type='CPUtime'):
+        """ Return an estimated cost of performing this instruction (calling execute), in time,
+        space, number of computers, disk requierement, etc.
+        """
+
+Type
+~~~~
+    An object that describes a parameter domain for a call to Instruction.execute.
+    It is not necessary that a Type specifies exactly which arguments are legal, but it should
+    `include` all legal arguments, and exclude as many illegal ones as possible.
+
+    def includes(value):
+        """return True if value is a legal argument"""
 
 
-Learner
-~~~~~~~
-
-A learner is a program that implements a policy for graph exploration by
-exploiting the ExperimentGraph and ExperimentGraphEdge interfaces.
-
-The convenience of the API hinges on the extent to which we can implement
-policies that work on different experiment-graphs (where the labels on the edges
-and semantics are different).  The use-cases above make me optimistic that it
-will work sufficiently well to be worth doing in the absence of better ideas.
+    To make things a bit more practical, there are some Type subclasses like Int, Float, Str,
+    ImageDataset, SgdOptimizer, that include additional attributes (e.g. min, max, default) so
+    that automatic graph exploration algorithms can generate legal arguments with reasonable
+    efficiency.
 
 
 
+The proxy pattern is a powerful way to combine learners. Especially when proxy Learner
+instances also introduce Proxy Instruction classes.
 
+For example, it is straightforward to implement a hyper-learner by implementing a Learner with
+another learner (sub-learner) as a member attribute.  The hyper-learner makes some
+modifications to the instruction_set() return value of the sub-learner, typically to introduce
+more powerful instructions and hide simpler ones.
+
+It is less straightforward, but consistent with the design to implement a Learner that
+encompasses job management.  Such a learner would retain the semantics of the
+instruction_set of the sub-learner, but would replace the Instruction objects themselves with
+Instructions that arranged for remote procedure calls (e.g. jobman, multiprocessing, bqtools,
+etc.)  Such a learner would replace synchronous instructions (return on completion) with
+asynchronous ones (return after scheduling) and the active instruction set would also change
+asynchronously, but neither of these things is inconsistent with the Learner API.
+
+
+TODO
+~~~~
+
+I feel like something is missing from the API - and that is an interface to the graph structure
+discussed above.  The nodes in this graph are natural places to store meta-information for
+visualization, statistics-gathering etc.   But none of the APIs above corresponds to the graph
+itself. In other words, there is no API through which to attach information to nodes.  It is
+not good to say that the Learner instance *is* the node because (a) learner instances change
+during graph exploration and (b) learner instances are big, and we don't want to have to keep a
+whole saved model just to attach meta-info e.g. validation score.    Choosing this API spills
+over into other committees, so we should get their feedback about how to resolve it.