如何在C ++中从Tensor对象获取数据

时间:2019-02-12 01:38:22

标签: c++ tensorflow eigen

我正在运行一个Tensorflow模型,将3D数组作为输出返回,但我无法从张量中获取该数据数组。

我确实打印了模型输出的形状,没有任何问题。

std::vector<tf::Tensor>        outputs;
 auto start_inference = std::chrono::high_resolution_clock::now();
 _status = _session->Run({inputs}, {"k2tfout_0", "k2tfout_1"}, {}, &outputs);
if (!_status.ok())
 {
   std::cerr << _status.ToString() << std::endl;
   return 0;
 }
unsigned int output_img_n0 = outputs[0].shape().dim_size(0);
unsigned int output_img_h0 = outputs[0].shape().dim_size(1);
unsigned int output_img_w0 = outputs[0].shape().dim_size(2);
unsigned int output_img_c0 = outputs[0].shape().dim_size(3);

该代码可以正常工作,并且显示了数组的形状。但是,我仍然无法从输出Tensor对象获取数据。

唯一起作用的功能是

float_t *plant_pointer = outputs[1].flat<float_t>().data();

但是会破坏数组的形状。

编辑:
张量的输出形状为[num,high,width,channel] === [1,480,600,3]。因此,输出是模型的语义分割图像的图像。我只想要没有第一个昏暗的图像部分,总是第一个。

1 个答案:

答案 0 :(得分:1)

tensorflow::Tensor类允许您通过几种方法访问其内容。使用.flat,您可以得到数组的扁平化版本,.tensor为您提供完整的Eigen tensor,然后还有其他类似.vec / .matrix(像.tensor,其维数固定为1或2)和flat_inner_dims / flat_outer_dims / flat_inner_outer_dims(会给您一个张量,其中某些维数已折叠)。您可以使用最适合您的一种。在这种情况下,例如,如果要打印张量中的所有值,则可以使用.flat并计算相应的偏移量,或者如果知道维数为4:<{1}}: / p>

.tensor

请注意,尽管这些方法创建的Eigen::TensorMap对象并不是很昂贵,但是您可能更喜欢只调用一次,然后多次查询张量对象。例如:

std::vector<tf::Tensor>        outputs;
auto start_inference = std::chrono::high_resolution_clock::now();
_status = _session->Run({inputs}, {"k2tfout_0", "k2tfout_1"}, {}, &outputs);
if (!_status.ok())
{
  std::cerr << _status.ToString() << std::endl;
  return 0;
}
unsigned int output_img_n0 = outputs[0].shape().dim_size(0);
unsigned int output_img_h0 = outputs[0].shape().dim_size(1);
unsigned int output_img_w0 = outputs[0].shape().dim_size(2);
unsigned int output_img_c0 = outputs[0].shape().dim_size(3);

for (unsigned int ni = 0; ni < output_img_n0; ni++)
{
  for (unsigned int hi = 0; hi < output_img_h0; hi++)
  {
    for (unsigned int wi = 0; wi < output_img_w0; wi++)
    {
      for (unsigned int ci = 0; ci < output_img_c0; ci++)
      {
        float_t value;
        // Get vaule through .flat()
        unsigned int offset = ni * output_img_h0 * output_img_w0 * output_img_c0 +
                              hi * output_img_w0 * output_img_c0 +
                              wi * output_img_c0 +
                              ci;
        value = outputs[0].flat<float_t>()(offset);
        // Get value through .tensor()
        value = outputs[0].tensor<float_t, 4>()(ni, hi, wi, ci);
        std::cout << "output[0](" << ni << ", " << hi << ", " << wi << ", " << ci << ") = ";
        std::cout << value << std::endl;
      }
    }
  }
}

编辑:

如果要获取指向张量数据的指针(例如,从同一缓冲区构建另一个对象以避免复制或迭代),也可以这样做。一种选择是使用// Make tensor tf::TTypes<float_t, 4>::Tensor outputTensor0 = outputs[0].tensor<float_t, 4>(); // Query tensor multiple times for (...) { std::cout << outputTensor0(ni, hi, wi, ci) << std::endl; } 方法,该方法返回一个.tensor_data,这又是一个absl::string_view,它只是std::string_view的一个polyfill。因此,此对象的tensorflow::StringPiece方法将为您提供指向张量的基础字节缓冲区的指针(请注意.data文档中的警告:“已对基础张量缓冲区进行了计数”,因此请不要让您在使用缓冲区时销毁返回的对象)。因此,您可以这样做:

.tensor_data

但是,这为您提供了指向tf::StringPiece output0Str = outputs[0].tensor_data(); const char* output0Ptr = output0Str.data(); 的指针,因此您必须将其强制转换为浮点数才能使用。它应该是安全的,但是看起来很丑陋,所以您可以让Eigen为您做到这一点。所有本征对象都有一个char方法,该方法将其类型的指针返回到基础缓冲区。例如:

.data