1 # C++ API 2 3 Note: By default [tensorflow.org](https://www.tensorflow.org) shows docs for the 4 most recent stable version. The instructions in this doc require building from 5 source. You will probably want to build from the `master` version of tensorflow. 6 You should, as a result, be sure you are following the 7 [`master` version of this doc](https://www.tensorflow.org/versions/master/api_guides/cc/guide), 8 in case there have been any changes. 9 10 [TOC] 11 12 TensorFlow's C++ API provides mechanisms for constructing and executing a data 13 flow graph. The API is designed to be simple and concise: graph operations are 14 clearly expressed using a "functional" construction style, including easy 15 specification of names, device placement, etc., and the resulting graph can be 16 efficiently run and the desired outputs fetched in a few lines of code. This 17 guide explains the basic concepts and data structures needed to get started with 18 TensorFlow graph construction and execution in C++. 19 20 ## The Basics 21 22 Let's start with a simple example that illustrates graph construction and 23 execution using the C++ API. 24 25 ```c++ 26 // tensorflow/cc/example/example.cc 27 28 #include "tensorflow/cc/client/client_session.h" 29 #include "tensorflow/cc/ops/standard_ops.h" 30 #include "tensorflow/core/framework/tensor.h" 31 32 int main() { 33 using namespace tensorflow; 34 using namespace tensorflow::ops; 35 Scope root = Scope::NewRootScope(); 36 // Matrix A = [3 2; -1 0] 37 auto A = Const(root, { {3.f, 2.f}, {-1.f, 0.f} }); 38 // Vector b = [3 5] 39 auto b = Const(root, { {3.f, 5.f} }); 40 // v = Ab^T 41 auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true)); 42 std::vector<Tensor> outputs; 43 ClientSession session(root); 44 // Run and fetch v 45 TF_CHECK_OK(session.Run({v}, &outputs)); 46 // Expect outputs[0] == [19; -3] 47 LOG(INFO) << outputs[0].matrix<float>(); 48 return 0; 49 } 50 ``` 51 52 Place this example code in the file `tensorflow/cc/example/example.cc` inside a 53 clone of the 54 TensorFlow 55 [github repository](http://www.github.com/tensorflow/tensorflow). Also place a 56 `BUILD` file in the same directory with the following contents: 57 58 ```python 59 load("//tensorflow:tensorflow.bzl", "tf_cc_binary") 60 61 tf_cc_binary( 62 name = "example", 63 srcs = ["example.cc"], 64 deps = [ 65 "//tensorflow/cc:cc_ops", 66 "//tensorflow/cc:client_session", 67 "//tensorflow/core:tensorflow", 68 ], 69 ) 70 ``` 71 72 Use `tf_cc_binary` rather than Bazel's native `cc_binary` to link in necessary 73 symbols from `libtensorflow_framework.so`. You should be able to build and run 74 the example using the following command (be sure to run `./configure` in your 75 build sandbox first): 76 77 ```shell 78 bazel run -c opt //tensorflow/cc/example:example 79 ``` 80 81 This example shows some of the important features of the C++ API such as the 82 following: 83 84 * Constructing tensor constants from C++ nested initializer lists 85 * Constructing and naming of TensorFlow operations 86 * Specifying optional attributes to operation constructors 87 * Executing and fetching the tensor values from the TensorFlow session. 88 89 We will delve into the details of each below. 90 91 ## Graph Construction 92 93 ### Scope 94 95 @{tensorflow::Scope} is the main data structure that holds the current state 96 of graph construction. A `Scope` acts as a handle to the graph being 97 constructed, as well as storing TensorFlow operation properties. The `Scope` 98 object is the first argument to operation constructors, and operations that use 99 a given `Scope` as their first argument inherit that `Scope`'s properties, such 100 as a common name prefix. Multiple `Scope`s can refer to the same graph, as 101 explained further below. 102 103 Create a new `Scope` object by calling `Scope::NewRootScope`. This creates 104 some resources such as a graph to which operations are added. It also creates a 105 @{tensorflow::Status} object which will be used to indicate errors encountered 106 when constructing operations. The `Scope` class has value semantics, thus, a 107 `Scope` object can be freely copied and passed around. 108 109 The `Scope` object returned by `Scope::NewRootScope` is referred 110 to as the root scope. "Child" scopes can be constructed from the root scope by 111 calling various member functions of the `Scope` class, thus forming a hierarchy 112 of scopes. A child scope inherits all of the properties of the parent scope and 113 typically has one property added or changed. For instance, `NewSubScope(name)` 114 appends `name` to the prefix of names for operations created using the returned 115 `Scope` object. 116 117 Here are some of the properties controlled by a `Scope` object: 118 119 * Operation names 120 * Set of control dependencies for an operation 121 * Device placement for an operation 122 * Kernel attribute for an operation 123 124 Please refer to @{tensorflow::Scope} for the complete list of member functions 125 that let you create child scopes with new properties. 126 127 ### Operation Constructors 128 129 You can create graph operations with operation constructors, one C++ class per 130 TensorFlow operation. Unlike the Python API which uses snake-case to name the 131 operation constructors, the C++ API uses camel-case to conform to C++ coding 132 style. For instance, the `MatMul` operation has a C++ class with the same name. 133 134 Using this class-per-operation method, it is possible, though not recommended, 135 to construct an operation as follows: 136 137 ```c++ 138 // Not recommended 139 MatMul m(scope, a, b); 140 ``` 141 142 Instead, we recommend the following "functional" style for constructing 143 operations: 144 145 ```c++ 146 // Recommended 147 auto m = MatMul(scope, a, b); 148 ``` 149 150 The first parameter for all operation constructors is always a `Scope` object. 151 Tensor inputs and mandatory attributes form the rest of the arguments. 152 153 For optional arguments, constructors have an optional parameter that allows 154 optional attributes. For operations with optional arguments, the constructor's 155 last optional parameter is a `struct` type called `[operation]:Attrs` that 156 contains data members for each optional attribute. You can construct such 157 `Attrs` in multiple ways: 158 159 * You can specify a single optional attribute by constructing an `Attrs` object 160 using the `static` functions provided in the C++ class for the operation. For 161 example: 162 163 ```c++ 164 auto m = MatMul(scope, a, b, MatMul::TransposeA(true)); 165 ``` 166 167 * You can specify multiple optional attributes by chaining together functions 168 available in the `Attrs` struct. For example: 169 170 ```c++ 171 auto m = MatMul(scope, a, b, MatMul::TransposeA(true).TransposeB(true)); 172 173 // Or, alternatively 174 auto m = MatMul(scope, a, b, MatMul::Attrs().TransposeA(true).TransposeB(true)); 175 ``` 176 177 The arguments and return values of operations are handled in different ways 178 depending on their type: 179 180 * For operations that return single tensors, the object returned by 181 the operation object can be passed directly to other operation 182 constructors. For example: 183 184 ```c++ 185 auto m = MatMul(scope, x, W); 186 auto sum = Add(scope, m, bias); 187 ``` 188 189 * For operations producing multiple outputs, the object returned by the 190 operation constructor has a member for each of the outputs. The names of those 191 members are identical to the names present in the `OpDef` for the 192 operation. For example: 193 194 ```c++ 195 auto u = Unique(scope, a); 196 // u.y has the unique values and u.idx has the unique indices 197 auto m = Add(scope, u.y, b); 198 ``` 199 200 * Operations producing a list-typed output return an object that can 201 be indexed using the `[]` operator. That object can also be directly passed to 202 other constructors that expect list-typed inputs. For example: 203 204 ```c++ 205 auto s = Split(scope, 0, a, 2); 206 // Access elements of the returned list. 207 auto b = Add(scope, s[0], s[1]); 208 // Pass the list as a whole to other constructors. 209 auto c = Concat(scope, s, 0); 210 ``` 211 212 ### Constants 213 214 You may pass many different types of C++ values directly to tensor 215 constants. You may explicitly create a tensor constant by calling the 216 @{tensorflow::ops::Const} function from various kinds of C++ values. For 217 example: 218 219 * Scalars 220 221 ```c++ 222 auto f = Const(scope, 42.0f); 223 auto s = Const(scope, "hello world!"); 224 ``` 225 226 * Nested initializer lists 227 228 ```c++ 229 // 2x2 matrix 230 auto c1 = Const(scope, { {1, 2}, {2, 4} }); 231 // 1x3x1 tensor 232 auto c2 = Const(scope, { { {1}, {2}, {3} } }); 233 // 1x2x0 tensor 234 auto c3 = ops::Const(scope, { { {}, {} } }); 235 ``` 236 237 * Shapes explicitly specified 238 239 ```c++ 240 // 2x2 matrix with all elements = 10 241 auto c1 = Const(scope, 10, /* shape */ {2, 2}); 242 // 1x3x2x1 tensor 243 auto c2 = Const(scope, {1, 2, 3, 4, 5, 6}, /* shape */ {1, 3, 2, 1}); 244 ``` 245 246 You may directly pass constants to other operation constructors, either by 247 explicitly constructing one using the `Const` function, or implicitly as any of 248 the above types of C++ values. For example: 249 250 ```c++ 251 // [1 1] * [41; 1] 252 auto x = MatMul(scope, { {1, 1} }, { {41}, {1} }); 253 // [1 2 3 4] + 10 254 auto y = Add(scope, {1, 2, 3, 4}, 10); 255 ``` 256 257 ## Graph Execution 258 259 When executing a graph, you will need a session. The C++ API provides a 260 @{tensorflow::ClientSession} class that will execute ops created by the 261 operation constructors. TensorFlow will automatically determine which parts of 262 the graph need to be executed, and what values need feeding. For example: 263 264 ```c++ 265 Scope root = Scope::NewRootScope(); 266 auto c = Const(root, { {1, 1} }); 267 auto m = MatMul(root, c, { {42}, {1} }); 268 269 ClientSession session(root); 270 std::vector<Tensor> outputs; 271 session.Run({m}, &outputs); 272 // outputs[0] == {42} 273 ``` 274 275 Similarly, the object returned by the operation constructor can be used as the 276 argument to specify a value being fed when executing the graph. Furthermore, the 277 value to feed can be specified with the different kinds of C++ values used to 278 specify tensor constants. For example: 279 280 ```c++ 281 Scope root = Scope::NewRootScope(); 282 auto a = Placeholder(root, DT_INT32); 283 // [3 3; 3 3] 284 auto b = Const(root, 3, {2, 2}); 285 auto c = Add(root, a, b); 286 ClientSession session(root); 287 std::vector<Tensor> outputs; 288 289 // Feed a <- [1 2; 3 4] 290 session.Run({ {a, { {1, 2}, {3, 4} } } }, {c}, &outputs); 291 // outputs[0] == [4 5; 6 7] 292 ``` 293 294 Please see the @{tensorflow::Tensor} documentation for more information on how 295 to use the execution output. 296