6

I'm trying to run a sample through a pre trained model on ios. session->Run() takes as input a tensor to my understanding. I have initialized a tensor, but how do i set it's value? I don't have much experience using C++.

I have successfully created a test model that accepts 3 dimensional tensor of shape {1, 1, 10}.

I pulled the following line of code from Tensorflow's simple example to create the input tensor.

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/ios_examples/simple/RunModelViewController.mm#L189

tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1,1,10}));

From here, I cannot figure out how I would set the data of input_tensor. I would like to set the tensor to something like {{{.0, .1, .2, .3, .4, .5, .6, .7, .8, .9}}}

agsolid
  • 1,288
  • 2
  • 14
  • 23
  • not familiar with the tensorflow library, but I can't help but think anyone who is would like a bit more context on your problem. I could be off base here, but with stuff I do know, I generally need more than a line of code and a one sentence, "how do I...?" problem description to provide a decent answer. What are you trying to do? What is the shape you need to represent? – user4581301 Aug 09 '16 at 18:01
  • I added more context. I figured this would be a simple question for anyone experienced with Tensorflow. – agsolid Aug 09 '16 at 18:17
  • I don't think you can get the fractions: [`tensorflow::TensorShape::TensorShape(std::initializer_list< int64 > dim_sizes)`](https://www.tensorflow.org/versions/r0.10/api_docs/cc/ClassTensorShape.html) Looks like the constructor takes a list of `int64`s, not `float`s or `double`s. – user4581301 Aug 09 '16 at 18:22
  • TensorShape defines the the shape of the tensor. The fractional values are my desired input. – agsolid Aug 09 '16 at 18:26
  • Bit of a problem with that plan. `int64` only holds whole numbers. Best case scenario is compiler warning and all of those .0 through .9 get truncated to 0. What happens next, I dunno. You may have to scale your numbers up ( multiply by ten in this case) to be representable as integers and then scale the output back down. – user4581301 Aug 09 '16 at 18:33
  • Thanks for your help, but i don't think you are familiar enough with the domain. I'm not trying to set the shape using fractional values. TensorShape defines the "Shape" of the tensor, which I already defined as "tensorflow::TensorShape({1,1,10}). – agsolid Aug 09 '16 at 18:44
  • @user4581301 - you are missing the point here. OP asks about filling in values of the tensor, and you are looking at the constructor of shape, which is only used as an argument to specify shape of the tensor. Going back to the original question - you have to first go through TF tutorials and whole concept - tensors are not usually filled in in applications, they are populated with ops, unless you are developing your own op and want to go low-level. Either way, this requires much broader context to be clearly answered. TF is quite specific library. – lejlot Aug 09 '16 at 18:44
  • @lejlot - I have a model and I want to run a sample through it. The input has to be a tensor. – agsolid Aug 09 '16 at 18:49
  • @user4581301 the `initializer_list` is for specifying the sizes, not the values. – kfsone Aug 09 '16 at 18:55

2 Answers2

6

I had a similar problem and was trying to set the tensor input values in C++ for a model trained in Python. The model is a simple NN with one hidden layer to learn to calculate the XOR operation.

I first created an output graph file with both the graph structure and the model parameters by following steps 1-4 of this nice post: https://medium.com/@hamedmp/exporting-trained-tensorflow-models-to-c-the-right-way-cf24b609d183#.j4l51ptvb.

Then in C++ (the TensorFlow iOS simple example), I used the following code:

tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({4,2}));

// input_tensor_mapped is an interface to the data of a tensor and used to copy data into the tensor
auto input_tensor_mapped = input_tensor.tensor<float, 2>();

// set the (4,2) possible input values for XOR
input_tensor_mapped(0, 0) = 0.0;
input_tensor_mapped(0, 1) = 0.0;
input_tensor_mapped(1, 0) = 0.0;
input_tensor_mapped(1, 1) = 1.0;
input_tensor_mapped(2, 0) = 1.0;
input_tensor_mapped(2, 1) = 0.0;
input_tensor_mapped(3, 0) = 1.0;
input_tensor_mapped(3, 1) = 1.0;

tensorflow::Status run_status = session->Run({{input_layer, input_tensor}},
                                             {output_layer}, {}, &outputs);

After this, GetTopN(output->flat<float>(), kNumResults, kThreshold, &top_results); returns the same 4 values (0.94433498, 0.94425952, 0.06565627, 0.05823805), as in my Python test code for XOR after the model is trained, in top_results.

So if your tensor's shape is {1,1,10}, you can set the values as follows:

auto input_tensor_mapped = input_tensor.tensor<float, 3>();
input_tensor_mapped(0, 0, 0) = 0.0;
input_tensor_mapped(0, 0, 1) = 0.1;
....
input_tensor_mapped(0, 0, 9) = 0.9;

Credit: the answer at How do I pass an OpenCV Mat into a C++ Tensorflow graph? is very helpful.

Community
  • 1
  • 1
Jeff Tang
  • 1,804
  • 15
  • 16
1

If you want to directly set the value of a tensor you can use few utilities functions provided by the Tensor interface. For the most common linear access you can use flat<T>.

From tensor_test

void ExpectClose(const Tensor& x, const Tensor& y, double atol, double rtol) {
  auto Tx = x.flat<T>();
  auto Ty = y.flat<T>();
  for (int i = 0; i < Tx.size(); ++i) {
    if (!IsClose(Tx(i), Ty(i), atol, rtol)) {
      LOG(ERROR) << "x = " << x.DebugString();
      LOG(ERROR) << "y = " << y.DebugString();
      LOG(ERROR) << "atol = " << atol << " rtol = " << rtol
                 << " tol = " << atol + rtol * std::fabs(Tx(i));
      EXPECT_TRUE(false) << i << "-th element is not close " << Tx(i) << " vs. "
                         << Ty(i);
    }
  }
}

to create a tensor you can use one of the constructors

Tensor(DT_FLOAT, new TensorShape(..))

If you want to set the value of a tensor or a placeholder at run time you need to pass it through the Run() interface:

  Status run_status = session->Run({{input_layer, resized_tensor}},
                                   {output_layer}, {}, &outputs);
  if (!run_status.ok()) {
    LOG(ERROR) << "Running model failed: " << run_status;
    return -1;
  }

If you want to have a predefine value of a tensor you can use the Const constructor

tensorflow::ops::Const({input_height, input_width})
fabrizioM
  • 46,639
  • 15
  • 102
  • 119