Mesh Components #70
thorwhalen
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
What is a mesh component? Don't know. Defining well it is the objective of this discussion.
But in a nutshell, it's about making it easy to use some common design patterns within
meshed
.It involves meshed objects (example, DAGs) templates as well as their "operationalization" -- that is, how they are attached to an existing DAG (think decorators), how they render in a graphviz diagram, how they can be created, etc.
Background
We've been pushing back this moment for some time, to focus on the
meshed
foundations. Now, though, the need's itch is increasing. So: Mesh Components.For now (and maybe forever?) we've managed to get away with having only one type of functional node: The
FuncNode
. That is, a node that wraps a function, which pretty much just takes care of binding it's inputs and output to the var nodes that indicate how they relate to the current data scope. We'll keep it that way for now.Yet, to make it easier to implement some common patterns with
meshed
, the time has come to bundle these up into some components that encapsulate these. The plan is that the only changes that need to be made in the existing objects (FuncNode
,DAG
, ...) are backward compatible and do not make these depend on the components, but instead depend on the abstractions that will allow existing objects and components to function together.For example, we will not change the default execution model, nor will we build a new one to accommodate for some conditional, caching or extractor component. That is, we won't tell the
_call
method that it must check the type of node it's about to execute, and do things accordingly. Instead, we will just call theFuncNode
, which will call a function, as usual -- but the concern of conditioning, caching, or extracting will be taken care of instead that function.At least, for the sake of keeping the design of execution simple, and separate (remember that there can be several execution models!), we hope that we can achieve our goals within these constraints.
That said, we are aware that operating (e.g. making, or viewing) computational flow in this strictly functional form can be cumbersome. The design we aim for, therefore, will allow us to let one define convenient ways to operate with them.
For example, say we have a
if_then_else
component. We can register it withcode_to_dag
, giving it the ability to parse (some simple)if/then/else
blocks and transform them into the functional form that aDAG
needs to use, as well as register it withFuncNode.dot_lines
to tell it how to render in a graphviz output.Examples of components
Consider the following examples in thinking of components, to make sure the design is not myopic.
if_then_else
: A flow-control component to implement condition logic.switch_case
: A flow-control generalization ofif_then_else
(see flow-control notebook)extractor
: See "Extractors" section in meshed - ideas.ipynb notebookcollapsed/packed
: A container of a subgraph (mainly so it can be rendered as single node)tee_cache
: One solution to Consuming iterators/generator multiple timescrudifyier
and other cache tools: Persist function outputs, possibly under keys that are computed from other parts of the DAG.gurglers
: Components that come to "latch on" to some nodes so as to "track" them, recording statistics that will serve to diagnose ML model drift, changes in an acoustic environment, etc.. Ideas expressed in the gurgle project.Implementation notes
In the examples above we described a component as just being a
FuncNode
with some extras. That was just an example. We don't know at this point if we should use inheritance (where a component is aFuncNode
) or composition (where a component has aFuncNode
), but we know which one we favor a priori.Further, a
FuncNode
is appropriate when the component can completely be defined by a single function, but we'd need something more in general. For example, anextractor
, which is really meant to produce the effect of "several outputs", can't really be expressed by aFuncNode
since aFuncNode
has only oneout
(and we'd like to keep it that way if possible). It can be represented as such in the rendering, but in essence, it's a little star-shaped DAG that is attached (or merged with) the single output it's extracting from.So we see that, perhaps, a
DAG
would be a better representation of a components functionality, not theFuncNode
-- or more generally, aMesh
(that is a container of python objects of all sorts).This is another good argument to use composition (delegation here) over inheritance: We don't have to lock ourselves into a type at this point. We'll start with the
DAG
as our wrapped type though, since it makes pragmatic sense.So at this point, what is a meshed component? It's a DAG, or a DAG-template, along with special ways to operate with it (how can we create one, how can we view one, how does it "attach" to an existing DAG, etc.). Note too that the actual component may not just be the DAG-template itself, but the embodied (template made concrete) version of the template plus the subdag it is attached too.
Take the extractor as an example: The star-shaped extractor is attached to an existing var-node, but the component itself is probably best seen as being the extractor, plus the var-node it's attached to, plus the func node that feeds that var-node.
Beta Was this translation helpful? Give feedback.
All reactions