我正在运行一个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]。因此,输出是模型的语义分割图像的图像。我只想要没有第一个昏暗的图像部分,总是第一个。
答案 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