1--- 2layout: page_api 3title: Symbol API 4permalink: /api/scala/docs/tutorials/symbol 5is_tutorial: true 6tag: scala 7--- 8<!--- Licensed to the Apache Software Foundation (ASF) under one --> 9<!--- or more contributor license agreements. See the NOTICE file --> 10<!--- distributed with this work for additional information --> 11<!--- regarding copyright ownership. The ASF licenses this file --> 12<!--- to you under the Apache License, Version 2.0 (the --> 13<!--- "License"); you may not use this file except in compliance --> 14<!--- with the License. You may obtain a copy of the License at --> 15 16<!--- http://www.apache.org/licenses/LICENSE-2.0 --> 17 18<!--- Unless required by applicable law or agreed to in writing, --> 19<!--- software distributed under the License is distributed on an --> 20<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY --> 21<!--- KIND, either express or implied. See the License for the --> 22<!--- specific language governing permissions and limitations --> 23<!--- under the License. --> 24 25# MXNet Scala Symbolic API 26 27Topics: 28 29* [How to Compose Symbols](#how-to-compose-symbols) introduces operator overloading of symbols. 30* [Symbol Attributes](#symbol-attributes) describes how to attach attributes to symbols. 31* [Serialization](#serialization) explains how to save and load symbols. 32* [Executing Symbols](#executing-symbols) explains how to evaluate the symbols with data. 33* [Execution API Reference]({{'/api/scala/docs/api/#org.apache.mxnet.Executor'|relative_url}}) documents the execution APIs. 34* [Multiple Outputs](#multiple-outputs) explains how to configure multiple outputs. 35* [Symbol Creation API Reference]({{'/api/scala/docs/api/#org.apache.mxnet.Symbol'|relative_url}}) documents functions. 36 37We also highly encourage you to read [Symbolic Configuration and Execution in Pictures](symbol_in_pictures). 38 39## How to Compose Symbols 40 41The symbolic API provides a way to configure computation graphs. 42You can configure the graphs either at the level of neural network layer operations or as fine-grained operations. 43 44The following example configures a two-layer neural network. 45 46```scala 47 import org.apache.mxnet._ 48 val data = Symbol.Variable("data") 49 val fc1 = Symbol.api.FullyConnected(Some(data), num_hidden = 128, name = "fc1") 50 val act1 = Symbol.api.Activation(Some(fc1), "relu", "relu1") 51 val fc2 = Symbol.api.FullyConnected(Some(act1), num_hidden = 64, name = "fc2") 52 val net = Symbol.api.SoftmaxOutput(Some(fc2), name = "out") 53 :type net 54 // org.apache.mxnet.Symbol 55``` 56 57The basic arithmetic operators (plus, minus, div, multiplication) are overloaded for 58*element-wise operations* of symbols. 59 60The following example creates a computation graph that adds two inputs together. 61 62```scala 63 import org.apache.mxnet._ 64 val a = Symbol.Variable("a") 65 val b = Symbol.Variable("b") 66 val c = a + b 67``` 68 69## Symbol Attributes 70 71You can add an attribute to a symbol by providing an attribute dictionary when you create a symbol. 72 73```scala 74 val data = Symbol.Variable("data", Map("mood"-> "angry")) 75 val op = Symbol.api.Convolution(Some(data), kernel = Shape(1, 1), num_filter = 1, attr = Map("mood" -> "so so")) 76``` 77For 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)`: 78 79``` 80 data.attr("mood") 81 // Option[String] = Some(angry) 82``` 83 84To 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: 85 86```scala 87 val (data, gdata) = 88 AttrScope(Map("group" -> "4", "data" -> "great")).withScope { 89 val data = Symbol.Variable("data", attr = Map("dtype" -> "data", "group" -> "1")) 90 val gdata = Symbol.Variable("data2") 91 (data, gdata) 92 } 93 assert(gdata.attr("group").get === "4") 94 assert(data.attr("group").get === "1") 95 96 val exceedScopeData = Symbol.Variable("data3") 97 assert(exceedScopeData.attr("group") === None, "No group attr in global attr scope") 98``` 99 100## Serialization 101 102There 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. 103The advantage of using `save` and `load` functions is that it is language agnostic and cloud friendly. 104The symbol is saved in JSON format. You can also get a JSON string directly using `mxnet.Symbol.toJson`. 105Refer to [API documentation]({{'/api/scala/docs/api/#org.apache.mxnet.Symbol'|relative_url}}) for more details. 106 107The following example shows how to save a symbol to an S3 bucket, load it back, and compare two symbols using a JSON string. 108 109```scala 110 import org.apache.mxnet._ 111 val a = Symbol.Variable("a") 112 val b = Symbol.Variable("b") 113 val c = a + b 114 c.save("s3://my-bucket/symbol-c.json") 115 val c2 = Symbol.load("s3://my-bucket/symbol-c.json") 116 c.toJson == c2.toJson 117 // Boolean = true 118``` 119 120## Executing Symbols 121 122After you have assembled a set of symbols into a computation graph, the MXNet engine can evaluate them. 123If you are training a neural network, this is typically 124handled by the high-level [Model class](model) and the [`fit()`] function. 125 126For neural networks used in "feed-forward", "prediction", or "inference" mode (all terms for the same 127thing: running a trained network), the input arguments are the 128input data, and the weights of the neural network that were learned during training. 129 130To manually execute a set of symbols, you need to create an [`Executor`] object, 131which is typically constructed by calling the [`simpleBind(<parameters>)`] method on a symbol. 132 133## Multiple Outputs 134 135To group the symbols together, use the [mxnet.symbol.Group](#mxnet.symbol.Group) function. 136 137```scala 138 import org.apache.mxnet._ 139 val data = Symbol.Variable("data") 140 val fc1 = Symbol.api.FullyConnected(Some(data), num_hidden = 128, name = "fc1") 141 val act1 = Symbol.api.Activation(Some(fc1), "relu", "relu1") 142 val fc2 = Symbol.api.FullyConnected(Some(act1), num_hidden = 64, name = "fc2") 143 val net = Symbol.api.SoftmaxOutput(Some(fc2), name = "out") 144 val group = Symbol.Group(fc1, net) 145 group.listOutputs() 146 // IndexedSeq[String] = ArrayBuffer(fc1_output, out_output) 147``` 148 149After you get the ```group```, you can bind on ```group``` instead. 150The resulting executor will have two outputs, one for fc1_output and one for softmax_output. 151 152## Next Steps 153* See [IO Data Loading API](io) for parsing and loading data. 154* See [NDArray API](ndarray) for vector/matrix/tensor operations. 155* See [KVStore API](kvstore) for multi-GPU and multi-host distributed training. 156