Module: special_purpose

Special-purpose nodes.

This package contains nodes that support specialized workflows in NeuroPype that do not yet have their own package. Nodes with the generic (cycle) icon support internal operations of the NeuroPype engine and are not currently considered ready for general use.

DeclareGraphSignature

Declare arguments that can be passed into the graph, when the graph is called as a function.

The purpose of this node is to annotate a graph as a whole to have a specific call signature (e.g., defining positional and/or keyword-only arguments when the graph is called as a function, for example from Python). See documentation of the "signature" property for more details on the format. A graph may have at most one such node in it, and the node must be freestanding (i.e., not connected to anything).

Version 0.3.0

Ports/Properties

  • metadata
    User-definable meta-data associated with the node. Usually reserved for technical purposes.

    • verbose name: Metadata
    • default value: {}
    • port type: DictPort
    • value type: dict (can be None)
  • signature
    Argument signature of the overall graph. This is formatted the same way as signatures in graph-accepting ports. This is mostly used to annotate a graph with a positional argument list so as to make it callable with positional arguments, i.e., mygraph(arg1,arg2). As in normal graph signatures, this is specified as in (myargument1, myargument2), using whichever placeholder names you wish to bind in this fashion. You may optionally also speciff arguments that can be passed only by name, by listing these after a + symbol, as in: (myargument1, myargument2, +, mykeywordargument1, mykeywordargument2). However, note that the latter serves mostly a documentation purpose, since the user can always pass in unlisted keyword arguments, which inside the graph with be picked up by any free (i.e., not otherwise bound) Placeholder and ParameterPort names. Also note that the * and ~ symbols have no meaning in the context of the overall graph, but may be added to document the original signature that may have been used to define the graph.

    • verbose name: Signature
    • default value: (myargument1,myargument2)
    • port type: Port
    • value type: object (can be None)
  • set_breakpoint
    Set a breakpoint on this node. If this is enabled, your debugger (if one is attached) will trigger a breakpoint.

    • verbose name: Set Breakpoint (Debug Only)
    • default value: False
    • port type: BoolPort
    • value type: bool (can be None)

GraphCompile

Compile the given graph for more efficient processing.

This is a graph transformation node that can be used to compile a graph into a more efficient to run (but less inspectable) representation. The resulting graph can then be wired into a node that will run the graphs, e.g., the Call node. Note that only a modest subset of nodes can be used in compilable graphs; this includes most of the nodes with a backend option (e.g., elementwise math, most purely mathematical operations like ConcatInputs, ArrayReshape, MatrixMultiplication, the Loss nodes, but not including most stateful nodes even if they have a backend option, like, e.g., IncrementalWhitening). Also supported are stateless deep learning nodes like NetInitialize and NetApply and optimizer step nodes (e.g., StepInit and StepApply). Future releases will support greater subsets of graph operations. If you find that your code appears to run slower with the compile node enabled, chances are that it is recompiling your code each time it is run; the most common causes of this are that a) either some input arguments that are marked as "static" are varying between calls, or - more likely - if you are passing Packets into the graph, that any axes or props of the packet are changing between calls (these also count as static). The most common culprit here is the instance axis (if present) or time axis (otherwise), and the simplest fix is to reset that axis to a dummy instance (or time) axis before passing it into the compiled portion of the graph. Or b) your graph itself changes between calls, which is most likely due to some node properties varying, which can be caused by wires that feed variable data into the graph from its upstream (left-hand) side. A more rare cause is that the previous execution modified the graph in some way, e.g., updating the state of some nodes; this can be determined by inspecting (e.g., printing) the graph and looking for node properties that are changing between calls. However, note that then you should also get errors about "unexpected" or "leaked" tracers (from the jit backend), and if you are not seeing those, this is not the first thing to suspect (although it is still a possibility). This node will implicily configure any upstream nodes (those wired into this node's graph port) that support multiple backends to default to the selected compiler backend when being compiled.

Version 0.8.0

Ports/Properties

  • metadata
    User-definable meta-data associated with the node. Usually reserved for technical purposes.

    • verbose name: Metadata
    • default value: {}
    • port type: DictPort
    • value type: dict (can be None)
  • graph
    Graph to compile.

    • verbose name: Graph
    • default value: None
    • port type: GraphPort
    • value type: Graph
  • graph__signature
    Optional list of input argument names to the graph being compiled. Similarly to the loop body of a loop node, the graph being compiled is a function of one or more arguments, whose names are listed here. The graph must then contain, for each listed arguments name, one Placeholder node with its slotname matching that name. The graph is then all nodes that are downstream reachable from those placeholders. The final node of the graph is then wired into the graph port of the CompileGraph node. In graphical UIs this edge will show as dotted to indicate that this is not normal forward data flow but a subgraph (i.e., the graph being compiled) is being passed to the Compile Graph node for compilation. The output of this node is then the compiled graph, which can be wired into, for example, the Call node in order to invoke it with some positional arguments.

    • verbose name: Graph [Signature]
    • default value: (inputs)~>()
    • port type: Port
    • value type: object (can be None)
  • annotations
    Additional annotations to supply per argument.

    • verbose name: Annotations
    • default value: {}
    • port type: DictPort
    • value type: dict (can be None)
  • backend
    Optional compiler backend to use. Keep defaults to the current context and/or global setting, which defaults to not compiling unless it was specifically enabled by the user -- it can, for example, be overridden for a part of a graph using the WithBackend node. The jax backend uses the JIT (Just-in-time) compiler from the jax library, which works in conjunction with numeric operations using the jax backend. Numpy is an alias for not compiling the graph and using plain numpy operations.

    • verbose name: Backend
    • default value: keep
    • port type: EnumPort
    • value type: str (can be None)
  • disabled
    Enable/disable compilation. This can be used to bypass compilation for debugging purposes, regardless of the current backend setting.

    • verbose name: Disabled
    • default value: False
    • port type: BoolPort
    • value type: bool (can be None)
  • static
    List of argument names (if any) that are compiled-in "static" constants as opposed to dynamic parameters. Static parameters require a recomilation whenever they change, but there is no restriction on their contents and they can be used to optimize the compiled code. Dynamic parameters instead have to be arrays or data structures containing arrays for the current backend (e.g., values that were created by a node with a backend option set to "jax", or values that were moved to jax either explicitly using MoveToBackend or possibly implicitly by a node that this node is directly or indirectly wired into). Note that not every backend may recognize this option and may treat all arguments as dynamic.

    • verbose name: Static
    • default value: []
    • port type: ListPort
    • value type: list (can be None)
  • automove_data
    Automatically move data to the chosen backend. This adds a slight performance overhead if the data is already on the desired backend and is only included for convenience.

    • verbose name: Automove Data
    • default value: True
    • port type: BoolPort
    • value type: bool (can be None)
  • detect_changes
    How often to check for changes in the graph. The eager mode checks for changes before every run, which is safest during interactive editing of the graph being compiled, but this adds considerable overhead. The lax mode checks for changes only occasionally (every few calls), and logs a warning when a change is detected, and recompiles the graph then. It will run with the old graph until the change is detected. The never mode never checks for changes, and only compiles the graph at the beginning; this is useful for production runs where the graph being compiled is no longer modified. Note that downstream graph edits can be made freely in any mode as they do not affect the compiled portion of the graph. Note that, for this to work, you need to enable the stateful option on any Call nodes that are used to invoke the compiled graph (otherwise the compile node will not have its state persisted across calls).

    • verbose name: Detect Changes
    • default value: eager
    • port type: EnumPort
    • value type: str (can be None)
  • sanity_checks
    Optionally perform sanity checks on the graph.

    • verbose name: Sanity Checks
    • default value: False
    • port type: BoolPort
    • value type: bool (can be None)
  • set_breakpoint
    Set a breakpoint on this node. If this is enabled, your debugger (if one is attached) will trigger a breakpoint.

    • verbose name: Set Breakpoint (Debug Only)
    • default value: False
    • port type: BoolPort
    • value type: bool (can be None)

OutputSlot

A placeholder node in a subgraph that will be merged into an ambient graph.

The node represents the place where a numbered output goes from the subgraph out to the ambient graph, and is used to designate edges from specific nodes of he subgraph graph to specific destinations in the ambient graph. Two scenarios in which this node can occur are: 1) when creating a graph using the Create Graph (Graph Template) node. In this context the overall template is a static literal graph which may have slots for subgraphs that are computed at runtime; these slots are indicated with Template Slot nodes in the graph, and they are to be substituted by the computed subgraphs. In order to determine precisely how the subgraph should connect with the ambient graph (from what nodes and ports the edges go out, and what nodes/ports those edges go to), the template placeholder can have one or more numberd out-edges that can go anywhere in the ambient graph. When the template placeholder is replaced by the computed graph, it is still necessary to indiate from what nodes/ports inside that graph these out-edges emanate. This is done by placing a numbered Next Node Placeholder node in the computed graph (the number pairs with the number of the out-edge of the template placeholder). Once inserted, the Output Slot node disappears, but the edge going to it continues on to the destination node/edge of the out-edge of the template placeholder. 2) when using the graph_mode() context manager in a Python script to create graphs using a define-by-run approach. In this context, any node invocation (e.g., MyNode(...)() will create a a graph that has a Output Slot node in it that indicates the connection point for the next node in the graph. When the result of MyNode(...)() is then passed to another node invocation (e.g., MyOtherNode()(...)), the Output Slot node is replaced by that other node, and the result is a two-node graph. This process can be repeated to create larger graphs (generally tree-shaped, although additional edges can be inserted explicitly to it). See also the Input Slot node for a corresponding node for designating inbound edges of the subgraph.

Version 1.0.0

Ports/Properties

  • metadata
    User-definable meta-data associated with the node. Usually reserved for technical purposes.

    • verbose name: Metadata
    • default value: {}
    • port type: DictPort
    • value type: dict (can be None)
  • data
    Outgoing data.

    • verbose name: Data
    • default value: None
    • port type: DataPort
    • value type: object (can be None)
    • data direction: IN
  • number
    Number of the output slot. In places where there can be multiple such nodes, this one indicates the node's place in the ordering.

    • verbose name: Number
    • default value: 0
    • port type: IntPort
    • value type: int (can be None)
  • usage
    Usage of the output slot. Slots can be used in two scenarios: for use with Create Graph (Graph Template) nodes, or for internal use by with the Python-side graph_mode() context manager. The latter is used for creating graphs using a define-by-run approach, where the graph is created on the fly as the nodes are executed in Python code. Do not manually set this to "python graph mode".

    • verbose name: Usage (Reserved)
    • default value: graph template
    • port type: EnumPort
    • value type: str (can be None)
  • set_breakpoint
    Set a breakpoint on this node. If this is enabled, your debugger (if one is attached) will trigger a breakpoint.

    • verbose name: Set Breakpoint (Debug Only)
    • default value: False
    • port type: BoolPort
    • value type: bool (can be None)