blob: 33afc66fcb9ebfe9afc2e252e80360a04f551f13 [file] [log] [blame]
# MXNet Scala Symbolic API
Topics:
* [How to Compose Symbols](#overloaded-operators) introduces operator overloading of symbols.
* [Symbol Attributes](#symbol-attributes) describes how to attach attributes to symbols.
* [Serialization](#serialization) explains how to save and load symbols.
* [Executing Symbols](#executing-symbols) explains how to evaluate the symbols with data.
* [Execution API Reference](http://mxnet.io/api/scala/docs/index.html#ml.dmlc.mxnet.Executor) documents the execution APIs.
* [Multiple Outputs](#multiple-outputs) explains how to configure multiple outputs.
* [Symbol Creation API Reference](http://mxnet.io/api/scala/docs/index.html#ml.dmlc.mxnet.Symbol) documents functions.
We also highly encourage you to read [Symbolic Configuration and Execution in Pictures](symbol_in_pictures.md).
## How to Compose Symbols
The symbolic API provides a way to configure computation graphs.
You can configure the graphs either at the level of neural network layer operations or as fine-grained operations.
The following example configures a two-layer neural network.
```scala
scala> import ml.dmlc.mxnet._
scala> val data = Symbol.Variable("data")
scala> val fc1 = Symbol.FullyConnected(name = "fc1")()(Map("data" -> data, "num_hidden" -> 128))
scala> val act1 = Symbol.Activation(name = "relu1")()(Map("data" -> fc1, "act_type" -> "relu"))
scala> val fc2 = Symbol.FullyConnected(name = "fc2")()(Map("data" -> act1, "num_hidden" -> 64))
scala> val net = Symbol.SoftmaxOutput(name = "out")()(Map("data" -> fc2))
scala> :type net
ml.dmlc.mxnet.Symbol
```
The basic arithmetic operators (plus, minus, div, multiplication) are overloaded for
*element-wise operations* of symbols.
The following example creates a computation graph that adds two inputs together.
```scala
scala> import ml.dmlc.mxnet._
scala> val a = Symbol.Variable("a")
scala> val b = Symbol.Variable("b")
scala> val c = a + b
```
## Symbol Attributes
You can add an attribute to a symbol by providing an attribute dictionary when you create a symbol.
```scala
val data = Symbol.Variable("data", Map("mood"-> "angry"))
val op = Symbol.Convolution()()(
Map("data" -> data, "kernel" -> "(1, 1)", "num_filter" -> 1, "mood"-> "so so"))
```
For proper communication with the C++ backend, both the key and values of the attribute dictionary should be strings. To retrieve the attributes, use `attr(key)`:
```
data.attr("mood")
res6: Option[String] = Some(angry)
```
To attach attributes, you can use ```AttrScope```. ```AttrScope``` automatically adds the specified attributes to all of the symbols created within that scope. The user can also inherit this object to change naming behavior. For example:
```scala
val (data, gdata) =
AttrScope(Map("group" -> "4", "data" -> "great")).withScope {
val data = Symbol.Variable("data", attr = Map("dtype" -> "data", "group" -> "1"))
val gdata = Symbol.Variable("data2")
(data, gdata)
}
assert(gdata.attr("group").get === "4")
assert(data.attr("group").get === "1")
val exceedScopeData = Symbol.Variable("data3")
assert(exceedScopeData.attr("group") === None, "No group attr in global attr scope")
```
## Serialization
There are two ways to save and load the symbols. You can use the `mxnet.Symbol.save` and `mxnet.Symbol.load` functions to serialize the ```Symbol``` objects.
The advantage of using `save` and `load` functions is that it is language agnostic and cloud friendly.
The symbol is saved in JSON format. You can also get a JSON string directly using `mxnet.Symbol.toJson`.
Refer to [API documentation](http://mxnet.io/api/scala/docs/index.html#ml.dmlc.mxnet.Symbol) for more details.
The following example shows how to save a symbol to an S3 bucket, load it back, and compare two symbols using a JSON string.
```scala
scala> import ml.dmlc.mxnet._
scala> val a = Symbol.Variable("a")
scala> val b = Symbol.Variable("b")
scala> val c = a + b
scala> c.save("s3://my-bucket/symbol-c.json")
scala> val c2 = Symbol.load("s3://my-bucket/symbol-c.json")
scala> c.toJson == c2.toJson
Boolean = true
```
## Executing Symbols
After you have assembled a set of symbols into a computation graph, the MXNet engine can evaluate them.
If you are training a neural network, this is typically
handled by the high-level [Model class](model.md) and the [`fit()`] function.
For neural networks used in "feed-forward", "prediction", or "inference" mode (all terms for the same
thing: running a trained network), the input arguments are the
input data, and the weights of the neural network that were learned during training.
To manually execute a set of symbols, you need to create an [`Executor`] object,
which is typically constructed by calling the [`simpleBind(<parameters>)`] method on a symbol.
## Multiple Outputs
To group the symbols together, use the [mxnet.symbol.Group](#mxnet.symbol.Group) function.
```scala
scala> import ml.dmlc.mxnet._
scala> val data = Symbol.Variable("data")
scala> val fc1 = Symbol.FullyConnected(name = "fc1")()(Map("data" -> data, "num_hidden" -> 128))
scala> val act1 = Symbol.Activation(name = "relu1")()(Map("data" -> fc1, "act_type" -> "relu"))
scala> val fc2 = Symbol.FullyConnected(name = "fc2")()(Map("data" -> act1, "num_hidden" -> 64))
scala> val net = Symbol.SoftmaxOutput(name = "out")()(Map("data" -> fc2))
scala> val group = Symbol.Group(fc1, net)
scala> group.listOutputs()
IndexedSeq[String] = ArrayBuffer(fc1_output, out_output)
```
After you get the ```group```, you can bind on ```group``` instead.
The resulting executor will have two outputs, one for fc1_output and one for softmax_output.
## Next Steps
* See [IO Data Loading API](io.md) for parsing and loading data.
* See [NDArray API](ndarray.md) for vector/matrix/tensor operations.
* See [KVStore API](kvstore.md) for multi-GPU and multi-host distributed training.