<commit_before>---
layout: post
title: Building a standalone C++ Tensorflow program on Windows
date: 2017-06-21
categories: machine-learning
image:
  feature: constellations3.jpg
---

In the [last post][1] we built a static C++ Tensorflow library on Windows.
Here we'll write a small Tensorflow program in Visual Studio independent
from the Tensorflow repository and link to the Tensorflow library.  The
tutorials I have been able to find about writing a new Tensorflow C++
program all seem to require that the new C++ project live within the
Tensorflow repository itself.  But this is not practical for many projects,
nor does it turn out to be necessary.  If you haven't built a static
Tensorflow library, [do that first][2].

This program will simply read some data that has been hard-coded into
memory, and then feed it into a graph that just multiplies it by another
hard-coded matrix.

## A simple C++ Tensorflow program

Create a new solution with the following code:

```
// matmul.cpp

#include <vector>
#include <eigen/Dense>

#include "matmul.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/cc/ops/standard_ops.h"

using namespace tensorflow;

// Build a computation graph that takes a tensor of shape [?, 2] and
// multiplies it by a hard-coded matrix.
GraphDef CreateGraphDef()
{
  Scope root = Scope::NewRootScope();

  auto X = ops::Placeholder(root.WithOpName("x"), DT_FLOAT, ops::Placeholder::Shape({ -1, 2 }));
  auto A = ops::Const(root, { { 3.f, 2.f },{ -1.f, 0.f } });

  auto Y = ops::MatMul(root.WithOpName("y"), A, X, ops::MatMul::TransposeB(true));

  GraphDef def;
  TF_CHECK_OK(root.ToGraphDef(&def));

  return def;
}

int main()
{
  GraphDef graph_def = CreateGraphDef();

  // Start up the session
  SessionOptions options;
  std::unique_ptr<Session> session(NewSession(options));
  TF_CHECK_OK(session->Create(graph_def));

  // Define some data.  This needs to be converted to an Eigen Tensor to be
  // fed into the placeholder.  Note that this will be broken up into two
  // separate vectors of length 2: [1, 2] and [3, 4], which will separately
  // be multiplied by the matrix.

  std::vector<float> data = { 1, 2, 3, 4 };
  auto mapped_X_ = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>(&data[0], 2, 2);
  auto eigen_X_ = Eigen::Tensor<float, 2, Eigen::RowMajor>(mapped_X_);

  Tensor X_(DT_FLOAT, TensorShape({ 2, 2 }));
  X_.tensor<float, 2>() = eigen_X_;

  std::vector<Tensor> outputs;
  TF_CHECK_OK(session->Run({ { "x", X_ } }, { "y" }, {}, &outputs));

  // Get the result and print it out
  Tensor Y_ = outputs[0];
  std::cout << Y_.tensor<float, 2>() << std::endl;
  
  session->Close();
}
```

As a digression, I would write something a little fancier, but the C++ API
is fairly limited relative to the Python API, and seems to be designed with
inference in mind more than training.  It is fairly straightforward to load
a computation graph that has already been built in Python, but building a
new graph from scratch in C++ is harder.  In particular, in Python it is
easy add training operations to the graph --- the `minimize` method of the
`Optimizer` class will automatically add gradient Ops that will use backprop
to calculate the gradient for every Op in the graph.  The C++ API does not
yet have this functionality.  In theory one could go through the graph and
add these gradients oneself, but at that point it would probably be best
just to write an `Optimizer` class in C++.  (This is currently an [open<commit_msg>Fix alignment in C++ code block<commit_after>---
layout: post
title: Building a standalone C++ Tensorflow program on Windows
date: 2017-06-21
categories: machine-learning
image:
  feature: constellations3.jpg
---

In the [last post][1] we built a static C++ Tensorflow library on Windows.
Here we'll write a small Tensorflow program in Visual Studio independent
from the Tensorflow repository and link to the Tensorflow library.  The
tutorials I have been able to find about writing a new Tensorflow C++
program all seem to require that the new C++ project live within the
Tensorflow repository itself.  But this is not practical for many projects,
nor does it turn out to be necessary.  If you haven't built a static
Tensorflow library, [do that first][1].

This program will simply read some data that has been hard-coded into
memory, and then feed it into a graph that just multiplies it by another
hard-coded matrix.

## A simple C++ Tensorflow program

Create a new solution with the following code:

```
// matmul.cpp

#include <vector>
#include <eigen/Dense>

#include "matmul.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/cc/ops/standard_ops.h"

using namespace tensorflow;

// Build a computation graph that takes a tensor of shape [?, 2] and
// multiplies it by a hard-coded matrix.
GraphDef CreateGraphDef()
{
  Scope root = Scope::NewRootScope();

  auto X = ops::Placeholder(root.WithOpName("x"), DT_FLOAT, 
                            ops::Placeholder::Shape({ -1, 2 }));
  auto A = ops::Const(root, { { 3.f, 2.f },{ -1.f, 0.f } });

  auto Y = ops::MatMul(root.WithOpName("y"), A, X, 
                       ops::MatMul::TransposeB(true));

  GraphDef def;
  TF_CHECK_OK(root.ToGraphDef(&def));

  return def;
}

int main()
{
  GraphDef graph_def = CreateGraphDef();

  // Start up the session
  SessionOptions options;
  std::unique_ptr<Session> session(NewSession(options));
  TF_CHECK_OK(session->Create(graph_def));

  // Define some data.  This needs to be converted to an Eigen Tensor to be
  // fed into the placeholder.  Note that this will be broken up into two
  // separate vectors of length 2: [1, 2] and [3, 4], which will separately
  // be multiplied by the matrix.

  std::vector<float> data = { 1, 2, 3, 4 };
  auto mapped_X_ = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>
                     (&data[0], 2, 2);
  auto eigen_X_ = Eigen::Tensor<float, 2, Eigen::RowMajor>(mapped_X_);

  Tensor X_(DT_FLOAT, TensorShape({ 2, 2 }));
  X_.tensor<float, 2>() = eigen_X_;

  std::vector<Tensor> outputs;
  TF_CHECK_OK(session->Run({ { "x", X_ } }, { "y" }, {}, &outputs));

  // Get the result and print it out
  Tensor Y_ = outputs[0];
  std::cout << Y_.tensor<float, 2>() << std::endl;
  
  session->Close();
}
```

As a digression, I would write something a little fancier, but the C++ API
is fairly limited relative to the Python API, and seems to be designed with
inference in mind more than training.  It is fairly straightforward to load
a computation graph that has already been built in Python, but building a
new graph from scratch in C++ is harder.  In particular, in Python it is
easy add training operations to the graph --- the `minimize` method of the
`Optimizer` class will automatically add gradient Ops that will use backprop
to calculate the gradient for every Op in the graph.  The C++ API does not
yet have this functionality.  In theory one could go through the graph and
add these gradients oneself, but at that point it would probably be best
just to write an `Optimizer` class in C++.  (This is currently an [open
{'fraction_non_alphanumeric': 0.10524834670043619, 'fraction_numerical': 0.01041226959335866, 'mean_word_length': 3.9810791871058164, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3733152', 'n_tokens_mistral': 2204, 'n_tokens_neox': 2083, 'n_words': 933}