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

Zah*_*abd 2 c++ eigen tensorflow

我正在运行一个 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);
Run Code Online (Sandbox Code Playgroud)

该代码运行时没有任何错误,并显示了数组的形状。但是,我仍然无法从输出 Tensor 对象中获取数据。

唯一的功能是

float_t *plant_pointer = outputs[1].flat<float_t>().data();
Run Code Online (Sandbox Code Playgroud)

但它破坏了阵列形状。

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

jde*_*esa 6

tensorflow::Tensor类可以通过多种方法访问其内容。随着.flat您获得数组的扁平版本,.tensor为您提供完整的特征张量,然后还有其他一些类似.vec/ .matrix(例如.tensor维度数固定为 1 或 2)和flat_inner_dims/ flat_outer_dims/ flat_inner_outer_dims(为您提供一些维度折叠的张量)。您可以使用最适合您的那一种。在这种情况下,例如,如果要打印张量中的所有值,则可以使用.flat并计算相应的偏移量,或者.tensor如果您知道维数为 4,则使用:

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;
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

// 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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

如果您想获得指向张量数据的指针(例如,从同一缓冲区构建另一个对象,避免复制或迭代),您也可以这样做。一种选择是使用该.tensor_data方法,该方法返回 a tensorflow::StringPiece,而后者又是 a absl::string_view,它只是 的 polyfill std::string_view。所以.data这个对象的方法会给你一个指向张量的底层字节缓冲区的指针(注意文档中的警告.tensor_data:“底层张量缓冲区被引用”,所以不要让返回的对象在使用时被销毁缓冲)。因此,您可以这样做:

tf::StringPiece output0Str = outputs[0].tensor_data();
const char* output0Ptr = output0Str.data();
Run Code Online (Sandbox Code Playgroud)

但是,这为您提供了一个指针,char因此您必须将其强制转换才能将其用作浮点数。它应该是安全的,但它看起来很丑,所以你可以让 Eigen 为你做。所有 Eigen 对象都有一个.data方法,该方法将其类型的指针返回到底层缓冲区。例如:

const float_t* output0Ptr = outputs[0].flat<float_t>().data();
Run Code Online (Sandbox Code Playgroud)