context

package
v0.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2024 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package context defines the Context and Variable types: Context organizes variablesMap and variablesMap manages the storage of values typically used as variablesMap.

Index

Constants

View Source
const (
	// ScopeSeparator is used between levels of scope. Scope names cannot use this character.
	ScopeSeparator = "/"

	// RootScope is the scope at the very root.
	// Some internal variables (e.g.: default random number generator state) are stored there.
	RootScope = ScopeSeparator
)
View Source
const GraphParamIsTraining = "training"
View Source
const (
	RngStateVariableName = "#rngState"
)
View Source
const VariableParameterPrefix = "var:"

VariableParameterPrefix is used to prefix Graph parameter names for variablesMap.

Variables

This section is empty.

Functions

func EscapeScopeName

func EscapeScopeName(scopeName string) string

EscapeScopeName replaces ScopeSeparator in the string and replaces them by "_".

func GetGraphParamOr added in v0.8.0

func GetGraphParamOr[T any](ctx *Context, g *Graph, key string, defaultValue T) T

GetGraphParamOr either returns the value for the given param key for the given graph, searching successively from the current scope back to the root scope ("/"), or if the key is not found, returns the given default value.

It tries to cast the value to the given type. If it fails, it tries to convert the value to the given type (so an `int` will be converted to a `float64` transparently). If that also fails, an explaining exception is thrown.

It's a convenience method around `ctx.GetGraphParam`.

This is very similar to GetParamOr, but used for parameters that are graph specific. For example Context.IsTraining and Context.SetTraining uses a Graph parameter to set this state, as the same Context is used for evaluation/inference graphs and training graphs, and they will have different values.

func GetParamOr added in v0.8.0

func GetParamOr[T any](ctx *Context, key string, defaultValue T) T

GetParamOr either returns the value for the given param key in the context `ctx`, searching successively from the current scope back to the root scope ("/"), or if the key is not found, returns the given default value.

It tries to cast the value to the given type. If it fails, it tries to convert the value to the given type (so an `int` will be converted to a `float64` transparently). If that also fails, an explaining exception is thrown.

It's a convenience method around `ctx.GetParam`.

func VariableParameterNameFromScopeAndName added in v0.9.0

func VariableParameterNameFromScopeAndName(scope, name string) string

VariableParameterNameFromScopeAndName creates the Variable.ParameterName from its scope and name.

func VariableScopeAndNameFromParameterName added in v0.9.0

func VariableScopeAndNameFromParameterName(parameterName string) (scope, name string)

VariableScopeAndNameFromParameterName extracts the scope and name from a variable's [ParameterName]. It will return empty strings for an invalid parameter name.

Types

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context organizes information shared in a model (or anything else). A model can spawn multiple computation graphs, e.g: one computation for a training step, one for an evaluation step running on batch, and one for a prediction computation on exactly one example. All these computation graphs should share the same variable (weight) values (and other information). These variables and (hyper-) parameters are organized here.

The Context organizes 3 types of information used by a model, and its graphs:

  1. Variables: model variables or weights.
  2. Parameters (normal): hyperparameters and also any arbitrary information that needs sharing among the graph building functions using the Context.
  3. Per-graph parameters: each graph will have it's own value. E.g: the parameter "training" indicates if the model is being used for training or inference, and this value will be different for a training or evaluation graph.

All 3 types of information are organized in "scopes". The Context object is actually a thin wrapper that contains the current scope (similar to a current directory) and a link to the actual data. One can change scopes by using Context.In("new_scope"): it returns a new Context with the new scope set, but still pointing (sharing) all the data with the previous Context. E.g:

One could create a new context with:

```

	func main() {
		ctx := context.NewContext(manager)
		ctx.SetParam("dropout_rate") = 0.2  // Set default dropout to 0.2
		...
	}

	func ModelGraph(ctx *context.Context, inputs []*Node) (logits *Node) {
		...
		{
			ctx := ctx.In("output_layer")  // Enter "output_layer" scope in temporary new context (same data, different scope)
        	ctx.SetParam("dropout_rate", 0.6)  // Let's say we want the "output_layer" only to have dropout=0.6
         	logits = Dense(ctx, logits, output_dim)
		}  // Exiting "output_later" scope, ctx is back to it's original scope.
	}

Finally, Context also allows one to checkpoint the variable values (save and load). See checkpoint package.

TODO: Handling of devices with multiple instances (e.g.: multiple GPUs/TPUs).

func NewContext

func NewContext(manager *Manager) *Context

NewContext constructs a new and empty context.

func (*Context) BuildTrainableVariablesGradientsGraph added in v0.5.0

func (ctx *Context) BuildTrainableVariablesGradientsGraph(loss *Node) []*Node

BuildTrainableVariablesGradientsGraph returns the gradient of the loss with respect to each trainable variable in the context that was used in the current graph. It returns a tuple Node. Non-trainable variables (Variable.Trainable == false) are not touched.

Typically, this is used by an optimizer.

Note, if during the computation graph the value of the variable is changed with Variable.SetValueGraph, this will calculate the gradient with respect to the new value (*Node) set.

func (*Context) Checked

func (ctx *Context) Checked(checked bool) *Context

Checked returns a new context with the checked flag set accordingly. If checked is true checks for reuse/uniqueness are checked according to IsReuse(). If checked is false Variables are dynamically reused or created when needed, without any checks. Usually it is set to true when building models -- to prevent layers to overstepping on each other -- and set to false for supporting variables (like optimizers, metrics and preprocessing).

Notice that re-usability is part of the "reference" component of a Context.

func (*Context) DeleteVariable added in v0.8.0

func (ctx *Context) DeleteVariable(scope, name string) bool

DeleteVariable if it exists. Returns whether the variable existed before being deleted.

This should not be called from a graph building function or from within EnumerateVariables: the results are undefined if you do.

func (*Context) DeleteVariablesInScope added in v0.8.0

func (ctx *Context) DeleteVariablesInScope()

DeleteVariablesInScope deletes all variables under the current scope (ctx.Scope()).

This should not be called from a graph building function or from within EnumerateVariables: the results are undefined if you do.

func (*Context) EnumerateGraphParams

func (ctx *Context) EnumerateGraphParams(g *Graph, fn func(scope, key string, value any))

EnumerateGraphParams enumerates all parameters for the graph, for all scopes calls fn with their values.

func (*Context) EnumerateParams

func (ctx *Context) EnumerateParams(fn func(scope, key string, value any))

EnumerateParams enumerates all parameters for all scopes calls fn with their values.

func (*Context) EnumerateVariables

func (ctx *Context) EnumerateVariables(fn func(v *Variable))

EnumerateVariables will call fn for each variable in the context. Notice the order of visitation is deterministic.

Notice that variables' information is stored in the "data" component of Context objects, and is shared among all connected context references.

Example:

fmt.Println("\nVariables:")
ctx.EnumerateVariables(func(v *context.Variable) {
	fmt.Printf("\t%s::%s: shape=%s\n", v.Scope(), v.Name(), v.Shape())
})

func (*Context) EnumerateVariablesInScope added in v0.8.0

func (ctx *Context) EnumerateVariablesInScope(fn func(v *Variable))

EnumerateVariablesInScope is similar to EnumerateVariables, but enumerate only those under the current context scope.

func (*Context) ExecPopulateGraphParamsMap

func (ctx *Context) ExecPopulateGraphParamsMap(g *Graph, params graph.ParamsMap)

ExecPopulateGraphParamsMap will enter the parameter values for every variable used in the given graph.

`Exec*` methods are used by those implementing an executor (context.Exec) or related tests, not normally needed by end users.

func (*Context) ExecSetVariablesInParams

func (ctx *Context) ExecSetVariablesInParams(params graph.ParamsMap, g *Graph)

ExecSetVariablesInParams adds all variables (all scopes) used by the graph to the ParamsMap objects.

`Exec*` methods are used by those implementing an executor (context.Exec) or related tests, not normally needed by end users.

func (*Context) GetGraphParam

func (ctx *Context) GetGraphParam(g *Graph, key string) (value any, found bool)

GetGraphParam returns the value for the given param key for the given graph, searching successively from the current scope back to the root scope ("/"), in case the key is not found.

E.g: if current scope is "/a/b", it will search for the key in "/a/b" scope, then in "/a" and finally in "/", and return the first result found.

This is very similar to GetParam, but used for parameters that are graph specific. For example Context.IsTraining and Context.SetTraining uses a Graph parameter to set this state, as the same Context is used for evaluation/inference graphs and training graphs, and they will have different values.

func (*Context) GetParam

func (ctx *Context) GetParam(key string) (value any, found bool)

GetParam returns the value for the given param key, searching successively from the current scope back to the root scope ("/"), in case the key is not found.

E.g: if current scope is "/a/b", it will search for the key in "/a/b" scope, then in "/a" and finally in "/", and return the first result found.

See also:

* GetParamOr to get a parameter with a default, if one doesn't exist. * GetGraphParam for parameters that are graph specific.

func (*Context) In

func (ctx *Context) In(scope string) *Context

In returns a new reference to the Context with the extra given scope. No ScopeSeparator ("/") is allowed in scope.

Notice that Scope is part of the "reference" component of a Context.

func (*Context) InAbsPath

func (ctx *Context) InAbsPath(scopePath string) *Context

InAbsPath returns a new reference to the Context with the extra given scope. It should start and have each element separated by ScopeSeparator. Use RootScope for the root scope.

Notice that Scope is part of the "reference" component of a Context.

func (*Context) InitializeVariables

func (ctx *Context) InitializeVariables()

InitializeVariables initializes all variables in the Context that don't yet have a value. Variables create with VariableWithValue or for which values were preloaded are not initialized. Errors are returned in Context.Error().

Notice that variables information is stored in the "data" component of Context objects, and is shared among all connected context references.

func (*Context) InspectVariable

func (ctx *Context) InspectVariable(scope, name string) *Variable

InspectVariable returns the variable with the given name for inspection. It returns nil if a variable with the given name hasn't been created.

It is not affected by Context.Reuse checks.

This will trigger the loading of the variable if a loader (like `checkpoint.Checkpoint`) is attached.

Notice that variables' information is stored in the "data" component of Context objects, and is shared among all connected context references.

The root scope is "/" (RootScope).

func (*Context) InspectVariableIfLoaded added in v0.9.0

func (ctx *Context) InspectVariableIfLoaded(scope, name string) *Variable

InspectVariableIfLoaded returns the variable if it exists already, but it won't attempt to load it.

It is similar to [InspectVariable] but won't attempt to load the variable.

func (*Context) InspectVariableInScope added in v0.9.0

func (ctx *Context) InspectVariableInScope(name string) *Variable

InspectVariableInScope works like InspectVariable, but looks for the variable in the current scope.

func (*Context) IsChecked

func (ctx *Context) IsChecked() bool

IsChecked returns whether context is checking reuse rules.

Notice that re-usability is part of the "reference" component of a Context.

func (*Context) IsReuse

func (ctx *Context) IsReuse() bool

IsReuse returns whether Context is marked for reuse. This is irrelevant if IsChecked is false.

Notice that re-usability is part of the "reference" component of a Context.

func (*Context) IsTraining

func (ctx *Context) IsTraining(g *Graph) bool

IsTraining returns whether context is being used for training. This is only a convention adopted by the library components, and it is read with Context.GetGraphParam and GraphParamIsTraining for the current scope. See [SetTraining] to change this value.

Notice that graph parameters is part of the "reference" component of a Context, so this change won't affect other connected context references.

func (*Context) Loader

func (ctx *Context) Loader() Loader

Loader returns the current configured Loader for this context. See SetLoader for details on how the Loader is used.

Notice that loader configuration is stored in the "data" component of Context objects, and is shared among all connected context references.

func (*Context) Manager added in v0.9.0

func (ctx *Context) Manager() *Manager

Manager returns the manager associated with this context.

func (*Context) Memory added in v0.4.0

func (ctx *Context) Memory() int64

Memory returns the total number of bytes summed across all variables. It does not include associated pointers and structures, just the bytes used by the raw data.

Example:

fmt.Printf("Model memory usage: %s", data.ByteCountIEC(ctx.Memory()))

func (*Context) NeedsInitialization

func (ctx *Context) NeedsInitialization() bool

NeedsInitialization returns whether there are variables that needs initialization.

Notice that variables information is stored in the "data" component of Context objects, and is shared among all connected context references.

func (*Context) NumParameters added in v0.4.0

func (ctx *Context) NumParameters() int

NumParameters returns the summed-up number of all variables. It ignores the `DType`, so a `float64` will count as much as a `uint8`.

func (*Context) NumVariables

func (ctx *Context) NumVariables() int

NumVariables return the number of variables in this Context.

func (*Context) RandomNormal added in v0.4.0

func (ctx *Context) RandomNormal(g *graph.Graph, shape shapes.Shape) (values *Node)

RandomNormal generates random numbers from a normal distribution, with mean 0.0 and standard deviation 1.0. It generates values with the given shape, each value pseudo-randomly generated.

If you need a different mean and standard deviation, just do something like the example below, where `mean` and `stddev` are the desired mean and standard deviation:

rngState, numbers = RandomNormal(rngState, myShape)
numbers = AddScalar(MulScalar(numbers, stddev), mean)

The random number generator (RNG) state is stored in a variable on the root scope of the context, called "#rngState" (RngStateVariableName). The state is initialized with the nanosecond clock, the first time it is used -- so pretty random. But you can initialize it with a fixed seed before using any of the Random* methods.

See details in graph.RandomNormal.

func (*Context) RandomUniform added in v0.4.0

func (ctx *Context) RandomUniform(g *graph.Graph, shape shapes.Shape) (values *Node)

RandomUniform generates random uniform values from 0.0 to 1.0 (half-open `[0.0, 1.0)`, so 1.0 is never returned) for float numbers in the given shape.

The random number generator (RNG) state is stored in a variable on the root scope of the context, called "#rngState" (RngStateVariableName). The state is initialized with the nanosecond clock, the first time it is used -- so pretty random. But you can initialize it with a fixed seed before using any of the Random* methods.

See details in graph.RandomNormal.

func (*Context) Reuse

func (ctx *Context) Reuse() *Context

Reuse returns a new reference to the Context set to reuse of variables, if it is not already in reuse mode. Otherwise, returns itself. If checked is false, this setting is irrelevant.

Notice that re-usability is part of the "reference" component of a Context.

func (*Context) RngStateFromSeed added in v0.4.0

func (ctx *Context) RngStateFromSeed(seed int64)

RngStateFromSeed initializes the default context random number generator (RNG) state with a static seed. If the state has already been created, it is reset to a value based on the seed.

The random number generator (RNG) state is stored in a variable on the root scope of the context, called "#rngState" (RngStateVariableName).

func (*Context) RngStateReset added in v0.4.0

func (ctx *Context) RngStateReset()

RngStateReset resets the default context random number generator (RNG) to a random seed based on the nanosecond clock.

This is done automatically for new contexts, but if the context was loaded from a checkpoint, and one wants to reset it (as opposed to continue the previous state), one can call this.

The random number generator (RNG) state is stored in a variable on the root scope of the context, called "#rngState" (RngStateVariableName).

func (*Context) Scope

func (ctx *Context) Scope() string

Scope returns the full scope path.

Notice that Scope is part of the "reference" component of a Context.

func (*Context) SetGraphParam

func (ctx *Context) SetGraphParam(g *Graph, key string, value any)

SetGraphParam sets the given Graph param in the current scope. It will be visible (by GetGraphParam) for this Graph within this scope and descendant scopes (but not by other scopes).

Notice each time a new graph is created, the associated "graph parameters" in the context will be empty.

This is very similar to SetParam, but used for parameters that are graph specific. For example Context.IsTraining and Context.SetTraining uses a Graph parameter to set this state, as the same Context is used for evaluation/inference graphs and training graphs, and they should have different values.

func (*Context) SetLoader

func (ctx *Context) SetLoader(loader Loader)

SetLoader configures given loader to be used as the default Loader for this Context.

Loader is used just after any new variable is created, either with VariableWithValue or VariableWithShape. If the Loader has a value of the variable created, it will override the value given in VariableWithValue, or skip the initializer for VariableWithShape.

An example of a loader in gomlx/context/checkpoints.

Notice that loader configuration is stored in the "data" component of Context objects, and is shared among all connected context references.

func (*Context) SetParam

func (ctx *Context) SetParam(key string, value any)

SetParam sets the given param in the current scope. It will be visible (by GetParam) within this scope and descendant scopes (but not by other scopes).

Note: the scoped parameters of the context are saved in `checkpoints` package using Json encoding. This works well for `string`, `float64` and `int` and slices of those values, but other types may not be recovered correctly later. See `checkpoints` package to add support for some other specific type, if you get a different type when loading the json.

See also SetGraphParam for parameters that are graph-specific.

func (*Context) SetParams added in v0.9.0

func (ctx *Context) SetParams(keyValues map[string]any)

SetParams sets a collection of parameters in the current scope. It will be visible (by GetParam) within this scope and descendant scopes (but not by other scopes).

This is a shortcut to multiple calls to `Context.SetParam` and the same observations apply.

func (*Context) SetTraining

func (ctx *Context) SetTraining(g *Graph, value bool)

SetTraining marks the context for the given graph as training. This is a convention adopted by the library components, and it simply sets it with Context.SetGraphParam and GraphParamIsTraining to the given value. See IsTraining to check for this value.

Notice that the graph parameters is part of the "reference" component of a Context, so this change won't affect other connected context references.

func (*Context) Unique

func (ctx *Context) Unique() *Context

Unique returns a new reference to the Context, set to only allow new variables, if it is not already in unique mode. If checked is false, this setting is irrelevant.

Notice that re-usability is part of the "reference" component of a Context.

func (*Context) VariableWithShape

func (ctx *Context) VariableWithShape(name string, shape shapes.Shape) *Variable

VariableWithShape creates or returns an existing variable with the given shape in the current scope. It is initialized with the current variable initializer set for the context. By default, variables are marked as trainable.

If a Loader is configured (see SetLoader), and the value is available to load, it will override the value given here -- e.g.: the value could be actually loaded from the last checkpoint.

Notice that variables information is stored in the "data" component of Context objects, and is shared among all connected context references.

func (*Context) VariableWithValue

func (ctx *Context) VariableWithValue(name string, value any) *Variable

VariableWithValue creates a variable that is initialized with the given value in the current scope. By default, variables are marked as trainable. The value given must be concrete, that is a tensor or a normal Go value, that can be converted to a tensor -- a graph *Node does not work here, this is assumed to be a constant.

If a Loader is configured (see SetLoader), and the value is available to load, it will override the value given here -- e.g.: the value could be actually loaded from the last checkpoint.

Notice that variables' information is stored in the "data" component of Context objects, and is shared among all connected context references.

func (*Context) WithInitializer

func (ctx *Context) WithInitializer(initializer VariableInitializer) *Context

WithInitializer returns a new reference to the Context, with the initializer set.

Notice that default variable initialization is part of the "reference" component of a Context, so this change won't affect other context references.

type Exec

type Exec struct {
	// contains filtered or unexported fields
}

Exec creates and executes computation graphs that take as input a Context as needed based on the inputs shapes, to allow the function to access (both read and set) variables and everything in the Context. Otherwise very similar to graph.Exec.

It simplifies the process of executing a graph building function with real values.

For example, assume you wrote:

def LogitsGraph(ctx *context.Context, inputs *Node) *Node {
    logits := layers.Dense(ctx.In("dense0", inputs, 5))
	logits = layers.Dense(ctx.In("dense1", logits, 5))
	logits = Sigmoid(logits)
	return logits
}

And then with Exec one can do:

 ctx := context.NewContext(manager)
	var logitsFn = context.NewExec(manager, ctx, LogitsGraph)
	batch := [][]float32{ {1, 2, 3}, {4, 5, 6} } // 2 examples with 3 features (shape=[2,3])
	fmt.Printf("Logits(%v) = %v\n", batch, logitsFn.Call(batch)[0].Value())

Call method always outputs a slice with all the outputs, even when there are no outputs (in which case it returns nil). Call takes as input the materialized values (tensors) you want to execute the graph with -- you don't need to path the *Context of *Graph to Call, those are filled automatically by Exec.

Notice ctxGraphFn, the function that builds the computation graph, is only called the first time Call is used -- so it's slower the first time, since it has to compile the graph. After that the execution is much faster. But that means that changes to Context.SetParams() or Context.SetGraphParams() after the first execution will not have any effect.

Exec also manages updates to variables automatically. Example: we implement a counter, which takes no input values (just the *Graph object), it just creates a variable if not there yet, increments it and returns its value.

```

 ctx := context.NewContext(manager)
 counter := context.NewExec(manager, ctx, func(ctx *context.Context, g *Graph) *Node {
	  dtype := types.Int64
	  counterVar := ctx.WithInitializer(initializers.Zeros).VariableWithShape("counter", types.MakeShape(dtype))
	  counterNode := counterVar.ValueGraph(graph)
	  counterNode = Add(counterNode, OnesLike(counterNode))
	  counterVar.SetValueGraph(counterNode)
	  return counterNode
	})
 fmt.Printf("%s\n", counter.Call()[0])  // == 1
 fmt.Printf("%s\n", counter.Call()[0])  // == 2
 fmt.Printf("%s\n", ctx.InspectVariable(ctx.Scope(), "counter").Value())  // == 2

```

Behind the scenes it automatically adds the used variables (Variable.ValueGraph) as side inputs, and the updated variables (Variable.SetValueGraph) as extra outputs of the graph, and during the graph execution it automatically use these values to update the materialized variable values in Context variables. It will also automatically initialize Context variables when needed.

Notice, like with graph.Exec, the need to build different graphs for different shapes can be expensive when sizes of the inputs varies a lot. The usual solution is to use shapes with size in a power scale (for instance powers of 2) and masking of tensors for unused slices. For safety concerns there are a maximum number of different instantiations of the graph. It can be set or disabled with SetMaxCache.

Errors in Call are returned inside the returned tensors.

There is concurrency safety with the cache of Graphs, but XLA concurrency is not documented. TODO: figure it out.

func NewExec

func NewExec[F ExecGraphFn](manager *Manager, ctx *Context, ctxGraphFn F) *Exec

NewExec constructs an Exec object that uses the given ctxGraphFn to build computation graphs with a Context. ctxGraphFn must take a *Context input parameter followed by one or more *Node parameters as input and return one or more *Node.

The Context ctx passed will be passed to all computation graph construction calls (ctxGraphFn), as well as during the graph execution later. If set to nil, it automatically creates a new one.

Before the execution of a graph, if needed, it initializes the variables in the context.

This is a generic wrapper around NewExecAny that check that types are correct (but doesn't support all possible types of ctxGraphFn).

func NewExecAny

func NewExecAny(manager *Manager, ctx *Context, ctxGraphFn any) (*Exec, error)

NewExecAny constructs an Exec object that uses the given ctxGraphFn to build computation graphs with a Context. ctxGraphFn must take a *Context input parameter followed by one or more *Node parameters as input and return one or more *Node. Alternatively it can, instead of *Node inputs, take a *Graph object -- if effectively no tensors will be used as input.

The Context ctx passed will be passed to all computation graph construction calls (ctxGraphFn), as well as during the graph execution later. If set to nil, it automatically creates a new one.

Before the execution of a graph, if needed, it initializes the variables in the context. And updated variables in the graph are updated also during execution. More details see Exec.

If any input or output parameter of ctxGraphFn is not a *Node (except the *Context and optionally a *Graph), or if there are no inputs or outputs, it returns an error.

func (*Exec) Call

func (e *Exec) Call(args ...any) []tensor.Tensor

Call parses the arguments into tensors (if they are not yet) and executes the graph corresponding to the shapes of the arguments.

Notice Context shouldn't be passed by Call, it will use automatically the context stored in context.Exec -- you can change it with SetContext.

If a graph does not yet exist one is created, compiled and cached for the shapes of the inputs. It passes the context to the registered ctxGraphFn. After the very first invocation of Call the context is marked as Context.Reuse().

It returns the outputs in a slice, even if there is only one output.

It panics with an informative error if something goes wrong.

func (*Exec) CallWithGraph

func (e *Exec) CallWithGraph(args ...any) (outputs []tensor.Tensor, g *Graph)

CallWithGraph is similar to Call, but it also returns the computation graph used in the call. Since Exec creates different computation graphs for different set of parameters, this can help disambiguate in case the user needs to use the Graph for something else.

It returns the outputs in a slice, even if there is only one output, and the graph used to execute the computation.

It panics with an informative error if something goes wrong.

func (*Exec) Context

func (e *Exec) Context() *Context

Context returns the associated Context object, usually created during the creation of the Exec object. It can be set to something different with SetContext().

func (*Exec) Finalize

func (e *Exec) Finalize()

Finalize clears the cache, finalizing the graphs. The Exec object shouldn't be used after that.

func (*Exec) GetNodeLogger

func (e *Exec) GetNodeLogger() graph.LoggerFn

GetNodeLogger returns the currently registered LoggerFn.

func (*Exec) InDevice

func (e *Exec) InDevice(deviceNum int) *Exec

InDevice sets the device num to be used by graphs constructed by Exec. This should be called before any invocations of Call(). It returns a reference to itself so calls can be cascaded.

func (*Exec) Name

func (e *Exec) Name() string

Name returns the Exec name, a string used as prefix for Graph construction.

func (*Exec) SetContext

func (e *Exec) SetContext(context *Context) *Exec

SetContext associates the given Context to the Exec object. Should be called before the first Call is made. Notice that only after the first time context is used to build a graph, it is set to Reuse. If the Context variables were already created, it should be marked with Context.Reuse. It returns a reference to itself so calls can be cascaded.

func (*Exec) SetMaxCache

func (e *Exec) SetMaxCache(maxCacheSize int) *Exec

SetMaxCache sets the maximum size of the cache. Set it to -1 to have unlimited cache size. It returns a reference to itself so calls can be cascaded.

func (*Exec) SetNodeLogger

func (e *Exec) SetNodeLogger(loggerFn graph.LoggerFn)

SetNodeLogger with the function to be called for the nodes marked for logging during execution. If set to nil nothing will be logged.

func (*Exec) WithName

func (e *Exec) WithName(name string) *Exec

WithName sets the name of Exec, used to provide the name to graphs created. This should be called before any invocations of Call(). It returns a reference to itself so calls can be cascaded.

type ExecGraphFn added in v0.5.0

type ExecGraphFn interface {
	func(*Context, *Graph) |
		func(*Context, []*Node) |
		func(*Context, *Node) |
		func(*Context, *Node, *Node) |
		func(*Context, *Node, *Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node, *Node, *Node) |
		func(*Context, *Graph) *Node |
		func(*Context, []*Node) *Node |
		func(*Context, *Node) *Node |
		func(*Context, *Node, *Node) *Node |
		func(*Context, *Node, *Node, *Node) *Node |
		func(*Context, *Node, *Node, *Node, *Node) *Node |
		func(*Context, *Node, *Node, *Node, *Node, *Node) *Node |
		func(*Context, *Node, *Node, *Node, *Node, *Node, *Node) *Node |
		func(*Context, *Graph) (*Node, *Node) |
		func(*Context, []*Node) (*Node, *Node) |
		func(*Context, *Node) (*Node, *Node) |
		func(*Context, *Node, *Node) (*Node, *Node) |
		func(*Context, *Node, *Node, *Node) (*Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node) (*Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node, *Node) (*Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node, *Node, *Node) (*Node, *Node) |
		func(*Context, *Graph) (*Node, *Node, *Node) |
		func(*Context, []*Node) (*Node, *Node, *Node) |
		func(*Context, *Node) (*Node, *Node, *Node) |
		func(*Context, *Node, *Node) (*Node, *Node, *Node) |
		func(*Context, *Node, *Node, *Node) (*Node, *Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node) (*Node, *Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node, *Node) (*Node, *Node, *Node) |
		func(*Context, *Node, *Node, *Node, *Node, *Node, *Node) (*Node, *Node, *Node) |
		func(*Context, *Graph) []*Node |
		func(*Context, []*Node) []*Node |
		func(*Context, *Node) []*Node |
		func(*Context, *Node, *Node) []*Node |
		func(*Context, *Node, *Node, *Node) []*Node |
		func(*Context, *Node, *Node, *Node, *Node) []*Node |
		func(*Context, *Node, *Node, *Node, *Node, *Node) []*Node |
		func(*Context, *Node, *Node, *Node, *Node, *Node, *Node) []*Node
}

ExecGraphFn is a type parameter for accepted function types for NewExec constructor.

type Graph

type Graph = graph.Graph

Graph is an alias to graph.Graph.

type Loader

type Loader interface {
	// LoadVariable tries to load the variable v pointed by its scope and name.
	// If it's not found, returns false, and initialization continues as usual.
	// Errors can be reported with Context.Panic.
	//
	// It is called at most once for each variable: if a values is loaded owner is transferred and the Loader
	// can "forget" about that variable, it's assumed to be transferred to the context.
	LoadVariable(ctx *Context, scope, name string) (value tensor.Tensor, found bool)
}

Loader can be implemented by any library providing loading of variables for Context. Loader implementations need to provide values on demand -- as a variables are used, even if they load everything up-front.

An example of a loader in gomlx/context/checkpoints. An example for testing can be found in context_test.go:ConstantLoader.

type Manager

type Manager = graph.Manager

Manager is an alias to graph.Manager.

type Node

type Node = graph.Node

Node is an alias to graph.Node.

type ScopedParams

type ScopedParams struct {
	// contains filtered or unexported fields
}

ScopedParams provides a mapping from string to any data type that is "scoped":

  • For every scope there is a map of string to data.
  • Accessing a key triggers a search from the current scope up to the root scope, the first result found is returned.

Example: let's say the current ScopedParams hold:

Scope: "/": { "x":10, "y": 20, "z": 40 }
Scope: "/a": { "y": 30 }
Scope: "/a/b": { "x": 100 }

ScopedParams.Get("/a/b", "x") -> 100
ScopedParams.Get("/a/b", "y") -> 30
ScopedParams.Get("/a/b", "z") -> 40
ScopedParams.Get("/a/b", "w") -> Not found.

Notice that "/" (== ScopeSeparator constant) separates parts of the scope path, and the root scope is referred to as "/". There is no "empty" scope, and every scope name must start with a ScopeSeparator.

The Context object uses ScopedParams to store the normal hyperparameters (see `Context.GetParam` and `Context.SetParam`) and to store the graph hyperparameters (see `Context.GetGraphParam` and `Context.SetGraphParam`).

Usually there will be no need for the end user to use this.

func NewScopedParams

func NewScopedParams() *ScopedParams

NewScopedParams create an empy ScopedParams.

func (*ScopedParams) Enumerate

func (p *ScopedParams) Enumerate(fn func(scope, key string, value any))

Enumerate enumerates all parameters stored in the ScopedParams structure and calls the given closure with them.

func (*ScopedParams) Get

func (p *ScopedParams) Get(scope, key string) (value any, found bool)

Get retrieves the value for the given key in the given scope or any parent scope. E.g: Get("/a/b", "myKey") will search for "myKey" in scopes "/a/b", "/a" and "/" consecutively until "myKey" is found.

It returns the first value found if any, and whether some value was found.

func (*ScopedParams) Set

func (p *ScopedParams) Set(scope, key string, value any)

Set sets the value for the given key, in the given scope.

type Variable

type Variable struct {

	// Trainable indicates whether variable is trainable. If set to false it won't be
	// touched by trainers of the model.
	Trainable bool
	// contains filtered or unexported fields
}

Variable is a value shared among computation graphs, or across multiple executions of the same graph. It's commonly used to store the weights (aka. parameters) of an ML model. It's defined in a scope in a Context.

The materialized value can be accessed in between graph executions by Value and SetValue methods.

During the computation graph building, for a particular graph, one can access the graph value (Node) of a variable with the methods

They are only initialized when Context.InitializeVariables. That is, they are created and used in graph building possibly before they are actually initialized -- when building a graph they are passed as parameters (the corresponding graph node is called ParameterNode), and have their values passed only during execution.

func (*Variable) AssertValid added in v0.5.0

func (v *Variable) AssertValid()

AssertValid panics if the variable is in an invalid state: if it's nil or it's shape is not yet set.

func (*Variable) ChangedInGraph

func (v *Variable) ChangedInGraph(g *Graph) bool

ChangedInGraph returns whether the variable is in use and was changed in the computation graph g.

func (*Variable) InUseByGraph

func (v *Variable) InUseByGraph(g *Graph) bool

InUseByGraph returns whether the variable is currently in use by the given graph.

func (*Variable) Name

func (v *Variable) Name() string

Name of the variable within the scope.

func (*Variable) ParamNode

func (v *Variable) ParamNode(g *Graph) *Node

ParamNode returns the given Graph g's Node that corresponds to the parameter that will be fed with the current variable value when the graph is executed. It's the initial value of the variable in the computation Graph.

If parameter Node hasn't been created for the Graph g yet, one is created.

Since the value of a variable can change in the middle of the graph (e.g: something that uses the variable after a gradient descent is applied) consider using ValueGraph to read the current associated value of a variable in a graph.

func (*Variable) ParameterName

func (v *Variable) ParameterName() string

ParameterName used when creating a parameter node in a Graph to access the variable, or as a key when saving. It is a unique name for the variable that includes the scope and the variable name, and is reversible.

func (*Variable) Scope

func (v *Variable) Scope() string

Scope where the variable was created.

func (*Variable) SetTrainable

func (v *Variable) SetTrainable(trainable bool) *Variable

SetTrainable sets the variable trainable status. Returns itself, so calls can be cascated.

func (*Variable) SetValue

func (v *Variable) SetValue(value tensor.Tensor)

SetValue updates the tensor holding the variable value. NOTE: Because often variables are large in size, the previous value is immediately freed (as opposed to wait for garbage collection). If the previous value is used somewhere else, use SetValuePreservingOld.

func (*Variable) SetValueGraph

func (v *Variable) SetValueGraph(value *Node)

SetValueGraph sets the Node associated with the current value of the variable for the computation graph where value is defined.

This is used to "communicate" among different parts of the graph building that this value Node should be used as the variable value.

train.Trainer will use the last value set here during graph building and use it as output of the graph execution and then update the variables (with SetValue) accordingly after each graph execution, for example, after each Trainer.TrainStep call.

func (*Variable) SetValuePreservingOld

func (v *Variable) SetValuePreservingOld(value tensor.Tensor)

SetValuePreservingOld updates the tensor holding the variable value, and dont' free old value. If previous value is not used, use SetValue instead that will free it immediately.

func (*Variable) Shape

func (v *Variable) Shape() shapes.Shape

Shape returns the variable shape.

func (*Variable) String

func (v *Variable) String() string

String implements stringer.

func (*Variable) Value

func (v *Variable) Value() tensor.Tensor

Value returns the tensor holding the variable value. Use this to manipulate the value in Go. If building a computation Graph use Node().

WARNING: memory management here is tricky: a call to SetValue will trigger the current value to be deallocated, and what is returned by a previous call to Value to become invalid. The recommendation is not to use this is a concurrent set up -- or to create proper locking mechanisms.

func (*Variable) ValueGraph

func (v *Variable) ValueGraph(g *Graph) *Node

ValueGraph returns the Node of the Graph that holds the current value of the variable. It can be changed for the graph (for instance when applying a gradient descent) by SetGraph.

type VariableInitializer

type VariableInitializer = initializers.VariableInitializer

VariableInitializer builds a valueNode that returns a value to initialize a variable of the given shape. It is defined in the Context.

Directories

Path Synopsis
Package checkpoints implements checkpoint management: saving and loading of checkpoints.
Package checkpoints implements checkpoint management: saving and loading of checkpoints.
Package ctxtest holds test utilities for packages that depend on context package.
Package ctxtest holds test utilities for packages that depend on context package.
Package initializers include several weight initializers, to be used with context.
Package initializers include several weight initializers, to be used with context.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL