## 1. Project Overview & Quickstart (Blaizzy/LICENSE) # LICENSE Open-source repository Blaizzy/LICENSE ### Repository Details - **Repository:** [Blaizzy/LICENSE](https://github.com/Blaizzy/LICENSE) - **Primary Language:** Code *Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.* ## 2. Official Technical Reference & Guides (Blaizzy/docs) ## File: README.md # TensorFlow Documentation This is the TensorFlow documentation for [tensorflow.org](https://www.tensorflow.org). We welcome contributions to the TensorFlow documentation from the community. See the [Writing TensorFlow Documentation](https://www.tensorflow.org/community/documentation) guide. To file an issue, use the tracker in the [tensorflow/tensorflow](https://github.com/tensorflow/tensorflow/issues/new?template=20-documentation-issue.md) repo. ## Contribution guidelines To contribute documentation, review the [contribution guidelines](CONTRIBUTING.md). ## License [Apache License 2.0](LICENSE) --- ## File: site/en/xla/README.md Welcome to the warp zone! # XLA: Accelerated Linear Algebra These docs are available here: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/compiler/xla/g3doc --- ## File: site/en/tfx/README.md Welcome to the warp zone! # TensorFlow Extended (TFX) These docs are available here: * Data Validation: https://github.com/tensorflow/data-validation/tree/master/g3doc * Transform: https://github.com/tensorflow/transform/tree/master/docs * Model Analysis: https://github.com/tensorflow/model-analysis/tree/master/g3doc --- ## File: site/en/serving/README.md Welcome to the warp zone! # TensorFlow Serving These docs are available here: https://github.com/tensorflow/serving/tree/master/tensorflow_serving/g3doc --- ## File: site/en/probability/README.md Welcome to the warp zone! # TensorFlow Probability These docs are available here: https://github.com/tensorflow/probability/tree/master/tensorflow_probability/g3doc --- ## File: site/en/lite/README.md Welcome to the warp zone! # TensorFlow Lite These docs are available here: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/g3doc --- ## File: site/en/hub/README.md Welcome to the warp zone! # TensorFlow Hub These docs are available here: https://github.com/tensorflow/hub/tree/master/docs --- ## File: site/en/guide/extend/architecture.md # TensorFlow Architecture We designed TensorFlow for large-scale distributed training and inference, but it is also flexible enough to support experimentation with new machine learning models and system-level optimizations. This document describes the system architecture that makes this combination of scale and flexibility possible. It assumes that you have basic familiarity with TensorFlow programming concepts such as the computation graph, operations, and sessions. See [this document](../low_level_intro.md) for an introduction to these topics. Some familiarity with [distributed TensorFlow](../../deploy/distributed.md) will also be helpful. This document is for developers who want to extend TensorFlow in some way not supported by current APIs, hardware engineers who want to optimize for TensorFlow, implementers of machine learning systems working on scaling and distribution, or anyone who wants to look under Tensorflow's hood. By the end of this document you should understand the TensorFlow architecture well enough to read and modify the core TensorFlow code. ## Overview The TensorFlow runtime is a cross-platform library. Figure 1 illustrates its general architecture. A C API separates user level code in different languages from the core runtime. {: width="300"} **Figure 1** This document focuses on the following layers: * **Client**: * Defines the computation as a dataflow graph. * Initiates graph execution using a [**session**]( https://www.tensorflow.org/code/tensorflow/python/client/session.py). * **Distributed Master** * Prunes a specific subgraph from the graph, as defined by the arguments to Session.run(). * Partitions the subgraph into multiple pieces that run in different processes and devices. * Distributes the graph pieces to worker services. * Initiates graph piece execution by worker services. * **Worker Services** (one for each task) * Schedule the execution of graph operations using kernel implementations appropriate to the available hardware (CPUs, GPUs, etc). * Send and receive operation results to and from other worker services. * **Kernel Implementations** * Perform the computation for individual graph operations. Figure 2 illustrates the interaction of these components. "/job:worker/task:0" and "/job:ps/task:0" are both tasks with worker services. "PS" stands for "parameter server": a task responsible for storing and updating the model's parameters. Other tasks send updates to these parameters as they work on optimizing the parameters. This particular division of labor between tasks is not required, but is common for distributed training. {: width="500"} **Figure 2** Note that the Distributed Master and Worker Service only exist in distributed TensorFlow. The single-process version of TensorFlow includes a special Session implementation that does everything the distributed master does but only communicates with devices in the local process. The following sections describe the core TensorFlow layers in greater detail and step through the processing of an example graph. ## Client Users write the client TensorFlow program that builds the computation graph. This program can either directly compose individual operations or use a convenience library like the Estimators API to compose neural network layers and other higher-level abstractions. TensorFlow supports multiple client languages, and we have prioritized Python and C++, because our internal users are most familiar with these languages. As features become more established, we typically port them to C++, so that users can access an optimized implementation from all client languages. Most of the training libraries are still Python-only, but C++ does have support for efficient inference. The client creates a session, which sends the graph definition to the distributed master as a `tf.GraphDef` protocol buffer. When the client evaluates a node or nodes in the graph, the evaluation triggers a call to the distributed master to initiate computation. In Figure 3, the client has built a graph that applies weights (w) to a feature vector (x), adds a bias term (b) and saves the result in a variable (s). {: width="700"} **Figure 3** ### Code * `tf.Session` ## Distributed master The distributed master: * prunes the graph to obtain the subgraph required to evaluate the nodes requested by the client, * partitions the graph to obtain graph pieces for each participating device, and * caches these pieces so that they may be re-used in subsequent steps. Since the master sees the overall computation for a step, it applies standard optimizations such as common subexpression elimination and constant folding. It then coordinates execution of the optimized subgraphs across a set of tasks. {: width="700"} **Figure 4** Figure 5 shows a possible partition of our example graph. The distributed master has grouped the model parameters in order to place them together on the parameter server. {: width="700"} **Figure 5** Where graph edges are cut by the partition, the distributed master inserts send and receive nodes to pass information between the distributed tasks (Figure 6). {: width="700"} **Figure 6** The distributed master then ships the graph pieces to the distributed tasks. {: width="700"} **Figure 7** ### Code * [MasterService API definition](https://www.tensorflow.org/code/tensorflow/core/protobuf/master_service.proto) * [Master interface](https://www.tensorflow.org/code/tensorflow/core/distributed_runtime/master_interface.h) ## Worker Service The worker service in each task: * handles requests from the master, * schedules the execution of the kernels for the operations that comprise a local subgraph, and * mediates direct communication between tasks. We optimize the worker service for running large graphs with low overhead. Our current implementation can execute tens of thousands of subgraphs per second, which enables a large number of replicas to make rapid, fine-grained training steps. The worker service dispatches kernels to local devices and runs kernels in parallel when possible, for example by using multiple CPU cores or GPU streams. We specialize Send and Recv operations for each pair of source and destination device types: * Transfers between local CPU and GPU devices use the `cudaMemcpyAsync()` API to overlap computation and data transfer. * Transfers between two local GPUs use peer-to-peer DMA, to avoid an expensive copy via the host CPU. For transfers between tasks, TensorFlow uses multiple protocols, including: * gRPC over TCP. * RDMA over Converged Ethernet. We also have preliminary support for NVIDIA's NCCL library for multi-GPU communication, see: [`tf.contrib.nccl`](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/nccl_ops.py). {: width="700"} **Figure 8** ### Code * [WorkerService API definition](https://www.tensorflow.org/code/tensorflow/core/protobuf/worker_service.proto) * [Worker interface](https://www.tensorflow.org/code/tensorflow/core/distributed_runtime/worker_interface.h) * [Remote rendezvous (for Send and Recv implementations)](https://www.tensorflow.org/code/tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.h) ## Kernel Implementations The runtime contains over 200 standard operations including mathematical, array manipulation, control flow, and state management operations. Each of these operations can have kernel implementations optimized for a variety of devices. Many of the operation kernels are implemented using Eigen::Tensor, which uses C++ templates to generate efficient parallel code for multicore CPUs and GPUs; however, we liberally use libraries like cuDNN where a more efficient kernel implementation is possible. We have also implemented [quantization](../../lite/performance/post_training_quantization.md), which enables faster inference in environments such as mobile devices and high-throughput datacenter applications, and use the [gemmlowp](https://github.com/google/gemmlowp) low-precision matrix library to accelerate quantized computation. If it is difficult or inefficient to represent a subcomputation as a composition of operations, users can register additional kernels that provide an efficient implementation written in C++. For example, we recommend registering your own fused kernels for some performance critical operations, such as the ReLU and Sigmoid activation functions and their corresponding gradients. The [XLA Compiler](../../xla/) has an experimental implementation of automatic kernel fusion. ### Code * [`OpKernel` interface](https://www.tensorflow.org/code/tensorflow/core/framework/op_kernel.h) --- ## File: site/en/guide/extend/bindings.md # TensorFlow in other languages ## Background This document is intended as a guide for those interested in the creation or development of TensorFlow functionality in other programming languages. It describes the features of TensorFlow and recommended steps for making the same available in other programming languages. Python was the first client language supported by TensorFlow and currently supports the most features. More and more of that functionality is being moved into the core of TensorFlow (implemented in C++) and exposed via a [C API]. Client languages should use the language's [foreign function interface (FFI)](https://en.wikipedia.org/wiki/Foreign_function_interface) to call into this [C API] to provide TensorFlow functionality. ## Overview Providing TensorFlow functionality in a programming language can be broken down into broad categories: - *Run a predefined graph*: Given a `GraphDef` (or `MetaGraphDef`) protocol message, be able to create a session, run queries, and get tensor results. This is sufficient for a mobile app or server that wants to run inference on a pre-trained model. - *Graph construction*: At least one function per defined TensorFlow op that adds an operation to the graph. Ideally these functions would be automatically generated so they stay in sync as the op definitions are modified. - *Gradients (AKA automatic differentiation)*: Given a graph and a list of input and output operations, add operations to the graph that compute the partial derivatives (gradients) of the inputs with respect to the outputs. Allows for customization of the gradient function for a particular operation in the graph. - *Functions*: Define a subgraph that may be called in multiple places in the main `GraphDef`. Defines a `FunctionDef` in the `FunctionDefLibrary` included in a `GraphDef`. - *Control Flow*: Construct "If" and "While" with user-specified subgraphs. Ideally these work with gradients (see above). - *Neural Network library*: A number of components that together support the creation of neural network models and training them (possibly in a distributed setting). While it would be convenient to have this available in other languages, there are currently no plans to support this in languages other than Python. These libraries are typically wrappers over the features described above. At a minimum, a language binding should support running a predefined graph, but most should also support graph construction. The TensorFlow Python API provides all these features. ## Current Status New language support should be built on top of the [C API]. However, as you can see in the table below, not all functionality is available in C yet. Providing more functionality in the [C API] is an ongoing project. Feature | Python | C :--------------------------------------------- | :---------------------------------------------------------- | :-- Run a predefined Graph | `tf.import_graph_def`, `tf.Session` | `TF_GraphImportGraphDef`, `TF_NewSession` Graph construction with generated op functions | Yes | Yes (The C API supports client languages that do this) Gradients | `tf.gradients` | Functions | `tf.python.framework.function.Defun` | Control Flow | `tf.cond`, `tf.while_loop` | Neural Network library | `tf.train`, `tf.nn`, `tf.contrib.layers`, `tf.contrib.slim` | ## Recommended Approach ### Run a predefined graph A language binding is expected to define the following classes: - `Graph`: A graph representing a TensorFlow computation. Consists of operations (represented in the client language by `Operation`s) and corresponds to a `TF_Graph` in the C API. Mainly used as an argument when creating new `Operation` objects and when starting a `Session`. Also supports iterating through the operations in the graph (`TF_GraphNextOperation`), looking up operations by name (`TF_GraphOperationByName`), and converting to and from a `GraphDef` protocol message (`TF_GraphToGraphDef` and `TF_GraphImportGraphDef` in the C API). - `Operation`: Represents a computation node in the graph. Corresponds to a `TF_Operation` in the C API. - `Output`: Represents one of the outputs of an operation in the graph. Has a `DataType` (and eventually a shape). May be passed as an input argument to a function for adding operations to a graph, or to a `Session`'s `Run()` method to fetch that output as a tensor. Corresponds to a `TF_Output` in the C API. - `Session`: Represents a client to a particular instance of the TensorFlow runtime. Its main job is to be constructed with a `Graph` and some options and then field calls to `Run()` the graph. Corresponds to a `TF_Session` in the C API. - `Tensor`: Represents an N-dimensional (rectangular) array with elements all the same `DataType`. Gets data into and out of a `Session`'s `Run()` call. Corresponds to a `TF_Tensor` in the C API. - `DataType`: An enumerant with all the possible tensor types supported by TensorFlow. Corresponds to `TF_DataType` in the C API and often referred to as `dtype` in the Python API. ### Graph construction TensorFlow has many ops, and the list is not static, so we recommend generating the functions for adding ops to a graph instead of writing them by individually by hand (though writing a few by hand is a good way to figure out what the generator should generate). The information needed to generate a function is contained in an `OpDef` protocol message. There are a few ways to get a list of the `OpDef`s for the registered ops: - `TF_GetAllOpList` in the C API retrieves all registered `OpDef` protocol messages. This can be used to write the generator in the client language. This requires that the client language have protocol buffer support in order to interpret the `OpDef` messages. - The C++ function `OpRegistry::Global()->GetRegisteredOps()` returns the same list of all registered `OpDef`s (defined in [`tensorflow/core/framework/op.h`](https://www.tensorflow.org/code/tensorflow/core/framework/op.h)). This can be used to write the generator in C++ (particularly useful for languages that do not have protocol buffer support). - The ASCII-serialized version of that list is periodically checked in to [`tensorflow/core/ops/ops.pbtxt`](https://www.tensorflow.org/code/tensorflow/core/ops/ops.pbtxt) by an automated process. The `OpDef` specifies the following: - Name of the op in CamelCase. For generated functions follow the conventions of the language. For example, if the language uses snake_case, use that instead of CamelCase for the op's function name. - A list of inputs and outputs. The types for these may be polymorphic by referencing attributes, as described in the inputs and outputs section of [Adding an op](./op.md). - A list of attributes, along with their default values (if any). Note that some of these will be inferred (if they are determined by an input), some will be optional (if they have a default), and some will be required (no default). - Documentation for the op in general and the inputs, outputs, and non-inferred attributes. - Some other fields that are used by the runtime and can be ignored by the code generators. An `OpDef` can be converted into the text of a function that adds that op to the graph using the `TF_OperationDescription` C API (wrapped in the language's FFI): - Start with `TF_NewOperation()` to create the `TF_OperationDescription*`. - Call `TF_AddInput()` or `TF_AddInputList()` once per input (depending on whether the input has a list type). - Call `TF_SetAttr*()` functions to set non-inferred attributes. May skip attributes with defaults if you don't want to override the default value. - Set optional fields if necessary: - `TF_SetDevice()`: force the operation onto a specific device. - `TF_AddControlInput()`: add requirements that another operation finish before this operation starts running - `TF_SetAttrString("_kernel")` to set the kernel label (rarely used) - `TF_ColocateWith()` to colocate one op with another - Call `TF_FinishOperation()` when done. This adds the operation to the graph, after which it can't be modified. The existing examples run the code generator as part of the build process (using a Bazel genrule). Alternatively, the code generator can be run by an automated cron process, possibly checking in the result. This creates a risk of divergence between the generated code and the `OpDef`s checked into the repository, but is useful for languages where code is expected to be generated ahead of time like `go get` for Go and `cargo ops` for Rust. At the other end of the spectrum, for some languages the code could be generated dynamically from [`tensorflow/core/ops/ops.pbtxt`](https://www.tensorflow.org/code/tensorflow/core/ops/ops.pbtxt). #### Handling Constants Calling code will be much more concise if users can provide constants to input arguments. The generated code should convert those constants to operations that are added to the graph and used as input to the op being instantiated. #### Optional parameters If the language allows for optional parameters to a function (like keyword arguments with defaults in Python), use them for optional attributes, operation names, devices, control inputs etc. In some languages, these optional parameters can be set using dynamic scopes (like "with" blocks in Python). Without these features, the library may resort to the "builder pattern", as is done in the C++ version of the TensorFlow API. #### Name scopes It is a good idea to have support for naming graph operations using some sort of scoping hierarchy, especially considering the fact that TensorBoard relies on it to display large graphs in a reasonable way. The existing Python and C++ APIs take different approaches: In Python, the "directory" part of the name (everything up to the last "/") comes from `with` blocks. In effect, there is a thread-local stack with the scopes defining the name hierarchy. The last component of the name is either supplied explicitly by the user (using the optional `name` keyword argument) or defaults to the name of the type of the op being added. In C++ the "directory" part of the name is stored in an explicit `Scope` object. The `NewSubScope()` method appends to that part of the name and returns a new `Scope`. The last component of the name is set using the `WithOpName()` method, and like Python defaults to the name of the type of op being added. `Scope` objects are explicitly passed around to specify the name of the context. #### Wrappers It may make sense to keep the generated functions private for some ops so that wrapper functions that do a little bit of additional work can be used instead. This also gives an escape hatch for supporting features outside the scope of generated code. One use of a wrapper is for supporting `SparseTensor` input and output. A `SparseTensor` is a tuple of 3 dense tensors: indices, values, and shape. values is a vector size [n], shape is a vector size [rank], and indices is a matrix size [n, rank]. There are some sparse ops that use this triple to represent a single sparse tensor. Another reason to use wrappers is for ops that hold state. There are a few such ops (e.g. a variable) that have several companion ops for operating on that state. The Python API has classes for these ops where the constructor creates the op, and methods on that class add operations to the graph that operate on the state. #### Other Considerations - It is good to have a list of keywords used to rename op functions and arguments that collide with language keywords (or other symbols that will cause trouble, like the names of library functions or variables referenced in the generated code). - The function for adding a `Const` operation to a graph typically is a wrapper since the generated function will typically have redundant `DataType` inputs. ### Gradients, functions and control flow At this time, support for gradients, functions and control flow operations ("if" and "while") is not available in languages other than Python. This will be updated when the [C API] provides necessary support. [C API]: https://www.tensorflow.org/code/tensorflow/c/c_api.h --- ## File: site/en/guide/extend/cc.md # C++ API Note: The instructions in this doc require [building from source](../../install/source.md). You probably want to build from the `master` branch of TensorFlow. TensorFlow's C++ API provides mechanisms for constructing and executing a data flow graph. The API is designed to be simple and concise: graph operations are clearly expressed using a "functional" construction style, including easy specification of names, device placement, etc., and the resulting graph can be efficiently run and the desired outputs fetched in a few lines of code. This guide explains the basic concepts and data structures needed to get started with TensorFlow graph construction and execution in C++. The C++ API is only designed to work with TensorFlow `bazel build`. If you need a stand-alone option, use the [C API](../../install/lang_c.md). See [these instructions](https://docs.bazel.build/versions/master/external.html) for details on how to include TensorFlow as a subproject (instead of building your project from inside TensorFlow, as in this example). ## The Basics Let's start with a simple example that illustrates graph construction and execution using the C++ API. ```c++ // tensorflow/cc/example/example.cc #include "tensorflow/cc/client/client_session.h" #include "tensorflow/cc/ops/standard_ops.h" #include "tensorflow/core/framework/tensor.h" int main() { using namespace tensorflow; using namespace tensorflow::ops; Scope root = Scope::NewRootScope(); // Matrix A = [3 2; -1 0] auto A = Const(root, { {3.f, 2.f}, {-1.f, 0.f} }); // Vector b = [3 5] auto b = Const(root, { {3.f, 5.f} }); // v = Ab^T auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true)); std::vector outputs; ClientSession session(root); // Run and fetch v TF_CHECK_OK(session.Run({v}, &outputs)); // Expect outputs[0] == [19; -3] LOG(INFO) << outputs[0].matrix(); return 0; } ``` Place this example code in the file `tensorflow/cc/example/example.cc` inside a clone of the TensorFlow [GitHub repository](http://www.github.com/tensorflow/tensorflow). Also place a `BUILD` file in the same directory with the following contents: ```python load("//tensorflow:tensorflow.bzl", "tf_cc_binary") tf_cc_binary( name = "example", srcs = ["example.cc"], deps = [ "//tensorflow/cc:cc_ops", "//tensorflow/cc:client_session", "//tensorflow/core:tensorflow", ], ) ``` Use `tf_cc_binary` rather than Bazel's native `cc_binary` to link in necessary symbols from `libtensorflow_framework.so`. You should be able to build and run the example using the following command (be sure to run `./configure` in your build sandbox first): ```shell bazel run -c opt //tensorflow/cc/example:example ``` This example shows some of the important features of the C++ API such as the following: * Constructing tensor constants from C++ nested initializer lists * Constructing and naming of TensorFlow operations * Specifying optional attributes to operation constructors * Executing and fetching the tensor values from the TensorFlow session. We will delve into the details of each below. ## Graph Construction ### Scope `tensorflow::Scope` is the main data structure that holds the current state of graph construction. A `Scope` acts as a handle to the graph being constructed, as well as storing TensorFlow operation properties. The `Scope` object is the first argument to operation constructors, and operations that use a given `Scope` as their first argument inherit that `Scope`'s properties, such as a common name prefix. Multiple `Scope`s can refer to the same graph, as explained further below. Create a new `Scope` object by calling `Scope::NewRootScope`. This creates some resources such as a graph to which operations are added. It also creates a `tensorflow::Status` object which will be used to indicate errors encountered when constructing operations. The `Scope` class has value semantics, thus, a `Scope` object can be freely copied and passed around. The `Scope` object returned by `Scope::NewRootScope` is referred to as the root scope. "Child" scopes can be constructed from the root scope by calling various member functions of the `Scope` class, thus forming a hierarchy of scopes. A child scope inherits all of the properties of the parent scope and typically has one property added or changed. For instance, `NewSubScope(name)` appends `name` to the prefix of names for operations created using the returned `Scope` object. Here are some of the properties controlled by a `Scope` object: * Operation names * Set of control dependencies for an operation * Device placement for an operation * Kernel attribute for an operation Please refer to `tensorflow::Scope` for the complete list of member functions that let you create child scopes with new properties. ### Operation Constructors You can create graph operations with operation constructors, one C++ class per TensorFlow operation. Unlike the Python API which uses snake-case to name the operation constructors, the C++ API uses camel-case to conform to C++ coding style. For instance, the `MatMul` operation has a C++ class with the same name. Using this class-per-operation method, it is possible, though not recommended, to construct an operation as follows: ```c++ // Not recommended MatMul m(scope, a, b); ``` Instead, we recommend the following "functional" style for constructing operations: ```c++ // Recommended auto m = MatMul(scope, a, b); ``` The first parameter for all operation constructors is always a `Scope` object. Tensor inputs and mandatory attributes form the rest of the arguments. For optional arguments, constructors have an optional parameter that allows optional attributes. For operations with optional arguments, the constructor's last optional parameter is a `struct` type called `[operation]:Attrs` that contains data members for each optional attribute. You can construct such `Attrs` in multiple ways: * You can specify a single optional attribute by constructing an `Attrs` object using the `static` functions provided in the C++ class for the operation. For example: ```c++ auto m = MatMul(scope, a, b, MatMul::TransposeA(true)); ``` * You can specify multiple optional attributes by chaining together functions available in the `Attrs` struct. For example: ```c++ auto m = MatMul(scope, a, b, MatMul::TransposeA(true).TransposeB(true)); // Or, alternatively auto m = MatMul(scope, a, b, MatMul::Attrs().TransposeA(true).TransposeB(true)); ``` The arguments and return values of operations are handled in different ways depending on their type: * For operations that return single tensors, the object returned by the operation object can be passed directly to other operation constructors. For example: ```c++ auto m = MatMul(scope, x, W); auto sum = Add(scope, m, bias); ``` * For operations producing multiple outputs, the object returned by the operation constructor has a member for each of the outputs. The names of those members are identical to the names present in the `OpDef` for the operation. For example: ```c++ auto u = Unique(scope, a); // u.y has the unique values and u.idx has the unique indices auto m = Add(scope, u.y, b); ``` * Operations producing a list-typed output return an object that can be indexed using the `[]` operator. That object can also be directly passed to other constructors that expect list-typed inputs. For example: ```c++ auto s = Split(scope, 0, a, 2); // Access elements of the returned list. auto b = Add(scope, s[0], s[1]); // Pass the list as a whole to other constructors. auto c = Concat(scope, s, 0); ``` ### Constants You may pass many different types of C++ values directly to tensor constants. You may explicitly create a tensor constant by calling the `tensorflow::ops::Const` function from various kinds of C++ values. For example: * Scalars ```c++ auto f = Const(scope, 42.0f); auto s = Const(scope, "hello world!"); ``` * Nested initializer lists ```c++ // 2x2 matrix auto c1 = Const(scope, { {1, 2}, {2, 4} }); // 1x3x1 tensor auto c2 = Const(scope, { { {1}, {2}, {3} } }); // 1x2x0 tensor auto c3 = ops::Const(scope, { { {}, {} } }); ``` * Shapes explicitly specified ```c++ // 2x2 matrix with all elements = 10 auto c1 = Const(scope, 10, /* shape */ {2, 2}); // 1x3x2x1 tensor auto c2 = Const(scope, {1, 2, 3, 4, 5, 6}, /* shape */ {1, 3, 2, 1}); ``` You may directly pass constants to other operation constructors, either by explicitly constructing one using the `Const` function, or implicitly as any of the above types of C++ values. For example: ```c++ // [1 1] * [41; 1] auto x = MatMul(scope, { {1, 1} }, { {41}, {1} }); // [1 2 3 4] + 10 auto y = Add(scope, {1, 2, 3, 4}, 10); ``` ## Graph Execution When executing a graph, you will need a session. The C++ API provides a `tensorflow::ClientSession` class that will execute ops created by the operation constructors. TensorFlow will automatically determine which parts of the graph need to be executed, and what values need feeding. For example: ```c++ Scope root = Scope::NewRootScope(); auto c = Const(root, { {1, 1} }); auto m = MatMul(root, c, { {41}, {1} }); ClientSession session(root); std::vector outputs; session.Run({m}, &outputs); // outputs[0] == {42} ``` Similarly, the object returned by the operation constructor can be used as the argument to specify a value being fed when executing the graph. Furthermore, the value to feed can be specified with the different kinds of C++ values used to specify tensor constants. For example: ```c++ Scope root = Scope::NewRootScope(); auto a = Placeholder(root, DT_INT32); // [3 3; 3 3] auto b = Const(root, 3, {2, 2}); auto c = Add(root, a, b); ClientSession session(root); std::vector outputs; // Feed a <- [1 2; 3 4] session.Run({ {a, { {1, 2}, {3, 4} } } }, {c}, &outputs); // outputs[0] == [4 5; 6 7] ``` Please see the `tensorflow::Tensor` documentation for more information on how to use the execution output.