Variables in SameDiff
What are variables
All values defining or passing through each SameDiff
instance - be it weights, bias, inputs, activations orgeneral parameters - all are handled by objects of class SDVariable
.
Observe that by variables we normally mean not just single values - as it is done in various online examples describingautodifferentiation - but rather whole multidimensional arrays of them.
Variable types
All variables in SameDiff
belong to one of four variable types, constituting an enumeration VariableType
.Here they are:
VARIABLE
: are trainable parameters of your network, e.g. weights and bias of a layer. Naturally, we want themto be both stored for further usage - we say, that they are persistent - as well as being updated during training.CONSTANT
: are those parameters which, like variables, are persistent for the network, but are not beingtrained; they, however, may be changed externally by the user.PLACEHOLDER
: store temporary values that are to be supplied from the outside, like inputs and labels.Accordingly, since new placeholders’ values are provided at each iteration, they are not stored: in other words,unlikeVARIABLE
andCONSTANT
,PLACEHOLDER
is not persistent.ARRAY
: are temporary values as well, representing outputs of operations within aSameDiff
, forinstance sums of vectors, activations of a layer, and many more. They are being recalculated at each iteration, andtherefor, likePLACEHOLDER
, are not persistent.To infer the type of a particular variable, you may use the methodgetVariableType
, like so:
VariableType varType = yourVariable.getVariableType();
The current value of a variable in a form of INDArray
may be obtained using getArr
or getArr(true)
- the latterone if you wish the program to throw an exception if the variable’s value is not initialized.
Data types
The data within each variable also has its data type, contained in DataType
enum. Currently in DataType
thereare three floating point types: FLOAT
, DOUBLE
and HALF
; four integer types: LONG
, INT
, SHORT
andUBYTE
; one boolean type BOOL
- all of them will be referred as numeric types. In addition, there is astring type dubbed UTF8
; and two helper data types COMPRESSED
and UNKNOWN
. The 16-bit floating point format BFLOAT16
and unsigned integer types (UINT16
, UINT32
and UINT64
) will be available in 1.0.0-beta5
.
To infer the data type of your variable, use
DataType dataType = yourVariable.dataType();
You may need to trace your variable’s data type since at times it does matter, which types you use in an operation. Forexample, a convolution product, like this one
SDVariable prod = samediff.cnn.conv1d(input, weights, config);
will require its SDVariable
arguments input
and weights
to be of one of the floating point data types, and willthrow an exception otherwise. Also, as we shall discuss just below, all the SDVariables
of type VARIABLE
aresupposed to be of floating point type.
Common features of variables
Before we go to the differences between variables, let us first look at the properties they all share
- All variables are ultimately derived from an instance of
SameDiff
, serving as parts of itsgraph. In fact, each variable has aSameDiff
as one of its fields. - Results (outputs) of all operations are of
ARRAY
type. - All
SDVariable
’s involved in an operation are to belong to the sameSameDiff
. - All variables may or may not be given names - in the latter case, a name is actually created automatically. Eitherway, the names need to be/are created unique. We shall come back to naming below.
Differences between variable types
Let us now have a closer look at each type of variables, and what distinguish them from each other.
Variables
Variables are the trainable parameters of your network. This predetermines their nature in SameDiff
. As we brieflymentioned above, variables’ values need to beboth preserved for application, and updated during training. Training means, that we iterativelyupdate the values by small fractions of their gradients, and this only makes sense if variables are of floatingpoint types (see data types above).
Variables may be added to your SameDiff
using different versions of var
function from your SameDiff
instance.For example, the code
SDVariable weights = samediff.var("weights", DataType.FLOAT, 784, 10);
adds a variable constituting of a 784x10 array of float
numbers - weights for a single layer MNIST perceptronin this case - to a pre-existing SameDiff
instance samediff
.
However, this way the values within a variable will be set as zeros. You may also create a variable with values froma preset INDArray
. Say
SDVariable weights = samediff.var("weigths", Nd4j.nrand(784, 10).div(28));
will create a variable filled with normally distributed randomly generated numbers with variance 1/28
. You may putany other array creation methods instead of nrand
, or any preset array, of course. Also, you may use some popularinitialization scheme, like so:
SDVariable weights = samediff.var("weights", new XavierInitScheme('c', 784, 10), DataType.FLOAT, 784, 10);
Now, the weights will be randomly initialized using the Xavier scheme. There are other ways to create and
fill variables: you may look them up in the ‘known subclasses’ section of our javadoc.
Constants
Constants hold values that are stored, but - unlike variables - remain unchanged during training. These, forinstance, may be some hyperparamters you wish to have in your network and be able to access from the outside. Orthey may be pretrained weights of a neural network that you wish to keep unchanged (see more on that inChanging Variable Type below). Constants may be of any data type
- so e.g.
int
andboolean
are allowed alongside withfloat
anddouble
.In general, constants are added toSameDiff
by means ofconstant
methods. A constant may be created form anINDArray
, like that:
SDVariable constant = samediff.constant("constants", Nd4j.create(new float[] {3.1415f, 42f}));
A constant consisting of a single scalar value may be created using one of the scalar
methods:
INDArray someScalar = samediff.scalar("scalar", 42);
Again, we refer to the javadoc for the whole reference.
Placeholders
The most common placeholders you’ll normally have in a SameDiff
are inputs and, when applicable, labels. You maycreate placeholders of any data type, depending on the operations you use them in. To add a placeholder to a SameDiff
,you may call one of placeHolder
methods, e.g. like that:
SDVariable in = samediff.placeHolder("input", DataType.FLOAT, -1, 784);
as in MNIST example. Here we specify name, data type and then shape of your placeholder - here, we have28x28 grayscale pictures rendered as 1d vectors (therefore 784) coming in batches of length we don’t know beforehand(therefore -1).
Arrays
Variables of ARRAY
type appear as outputs of operations within SameDiff
.Accordingly, the data type of an array-type variable depends on the kind of operation it is produced by and variabletype(s) ot its argument(s). Arrays are not persistent - they are one-time values that will be recalculated from scratchat the next step. However, unlike placeholders, gradients are computed for them, as those are needed to update the valuesof VARIABLE
’s.
There are as many ways array-type variables are created as there are operations, so you’re better up focusing onour operations section, our javadoc and examples.
Recap table
Let us summarize the main properties of variable types in one table:
Trainable | Gradients | Persistent | Workspaces | Datatypes | Instantiated from | |
---|---|---|---|---|---|---|
VARIABLE | Yes | Yes | Yes | Yes | Float only | Instance |
CONSTANT | No | No | Yes | No | Any | Instance |
PLACEHOLDER | No | No | No | No | Any | Instance |
ARRAY | No | Yes | No | Yes | Any | Operations |
We haven’t discussed what ‘Workspaces’ mean - if you do not know, do not worry, this is an internal technical term that basically describes how memory is managed internally.
Changing variable types
You may change variable types as well. For now, there are three of such options:
Variable to constant
At times - for instance if you perform transfer learning - you may wish to turn a variable into a constant. This isdone like so:
samediff.convertToConstant(someVariable);
where someVariable
is an instance of SDVariable
of VARIABLE
type. The variable someVariable
will not be trainedany more.
Constant to variable
Conversely, constants - if they are of floating point data type - may be converted to variables. So, for instance, ifyou wish your frozen weights to become trainable again
samediff.convertToVariable(frozenWeights); //not frozen any more
Placeholder to constant
Placeholders may be converted to constants as well - for instance, if you need to freeze one of the inputs. There are norestrictions on the data type, yet, since placeholder values are not persistent, their value should be set before youturn them into constants. This can be done as follows
placeHolder.setArray(someArray);
samediff.convertToConstant(placeHolder);
For now it is not possible to turn a constant back into a placeholder, we may consider adding this functionality ifthere is a need for that. For now, if you wish to effectively freeze your placeholder but be able to use it again,consider supplying it with constant values rather than turning it into a constant.
Variables’ names and values
Getting variables from SameDiff
Recall that every variable in an instance of SameDiff
has its unique String
name. Your SameDiff
actually tracks yourvariables by their names, and allows you to retrieve them by using getVariable(String name)
method.
Consider the following line:
SDVariable regressionCost = weights.mmul(input).sub("regression_prediction", bias).squaredDifference(labels);
Here, in the function sub
we actually have implicitly introduced a variable (of type ARRAY
) that holds theresult of the subtraction. By adding a name into the operations’s argument, we’ve secured ourselves the possibilityto retrieve the variable from elsewhere: say, if later you need to infer the difference between the labels and theprediction as a vector, you may just write:
SDVariable errorVector = samediff.getVariable("regressionPrediction").sub(labels);
This becomes especially handy if your whole SameDiff
instance is initialized elsewhere, and you still need to gethold of some of its variables - say, multiple outputs.
You can get and set the name of an SDVariable
the methods getVarName
and setVarName
respectively. When renaming, note that variable’s name is to remain unique within its SameDiff
.
Getting variable’s value
You may retrieve any variable’s current value as an INDArray
using the method eval()
. Note that for non-persistentvariables, the value should first be set. For variables with gradients, the gradient’s value may also be inferred usingthe method getGradient
.