Samediff Quickstart
Samediff is a lower level and more flexible api for composing neural networks. It is a compliment to nd4j. It provides a declarative api for creating computation graphs. If you are not familiar with the idea of computation graphs, here are a few references: 1. https://www.codingame.com/playgrounds/9487/deep-learning-from-scratch---theory-and-implementation/computational-graphs 2. https://www.machinecurve.com/index.php/2020/09/13/tensorflow-eager-execution-what-is-it/
It is very similar to more popular frameworks such as tensorflow and pytorch.
In short, a computation graph allows a user to declare a series of math operats to get to a desired output. Deeplearning4j itself has a computation graph api. More about that can be found here
Note that the samediff api is a completely separate, standalone api that shares some code via nd4j, but is otherwise a standalone framework for executing neural networks. It has a distinct file format, training/graph execution, and apis for execution. Samediff will be the main api going forward. The dl4j api most people know will still be supported, but should otherwise be treated as a feature in maintenance mode. Consider samediff a rewrite of sorts. Samediff has a set of examples here that cover the basics.
Follow this example for imports and other important aspects. Please treat this page as a simple walkthrough of the concepts in samediff for people unfamiliar with the framework itself.
In short, in order to create a graph a user starts by calling Samediff.create() as follows:
Nd4j's INDArray is used as the core data structure for holding results that have been compute. Graph declarations are done via samediff's SDVariable. Assuming you have read the above references on computation graphs, a samediff graph declaration can happen as follows:
Note we pass an INDArray in here, then call sd.var(..). Within the samediff graph that was declared, a variable referencing this INDArray is created and stored and can then be references within the graph. The SDVariable then holds a reference to the samediff graph that created it. This allows us to then chain operations off those variables delegating the call to samediff graph internally. In essence, all we're doing above is declaring a graph that adds 1 to the input, then multiplies it by 10.
To print out the graph, you can use sd.summary() as follows:
In order to execute the graph and get some real results out, there are a few ways to do this. One can call sd.output(..) as follows:
The user will notice we pass an empty map in. The reason you have to pass in variables, is inputs in to a neural network tend to be dynamic. This graph does not have dynamic inputs and can there for execute without user input. A dynamic input is typically called a placeholder.
In order to obtain results, (read: real INDArrays with actual data) there are a few ways to do so:
Another way of executing results is to use the SDVariable eval(..) api as follows:
eval(..) returns the resulting value for that variable from the forward pass. You may also obtain the result from getArr(..) since the actual SDVariable stores the current state of the computation.
Breaking down what happens a bit:
A neural network forward pass requires computing state in a sequence construted as a DAG.
Each node in the graph is an operation that has input and output variables.
Variables represent a named parameter for an operation and may or may not contain a current value as an INDArray.