为什么图像张量的形状是(?, ?, ?)

  • 本文关键字:图像 张量 tensorflow
  • 更新时间 :
  • 英文 :


这是我的代码,

img_path = tf.read_file(testqueue[0])
my_img = tf.image.decode_jpeg(img_path)
sess.run(my_img)
print my_img.get_shape()

这导致,

(?, ?, ?)

为什么我得到这个结果?

回答这个问题并提供一些细节。

静态信息

tensor_name.shape返回图形编译时可用的形状信息。它依赖于张量属性

tf.decode_jpeg在这里注册。在创建图形期间,TensorFlow 在InferenceContext下运行形状传播。给定输入张量已知的形状属性,每个操作都提供了其输出张量的外观提示。

例如,"rgb2gray"操作将只复制输入张量的形状(例如[b',h',w',c']并将输出设置为[b',h',w',1]。它不需要知道 b'、h'、w' 的确切值,因为它可以复制这些以前的值。

查看tf.decode_jpeg的具体实现,此操作显然可以处理channels属性:

// read the attribute "channels from "tf.image.decode_jpeg(..., channels)"
TF_RETURN_IF_ERROR(c->GetAttr("channels", &channels));
// ....
// set the tensor information "my_img.get_shape()" will have
c->set_output(0, c->MakeShape({InferenceContext::kUnknownDim,
InferenceContext::kUnknownDim, channels_dim})); 

前两个维度设置为InferenceContext::kUnknownDim,因为操作只知道存在高度和宽度,但特定值可能会有所不同。它可以最好地猜测通道轴的外观。如果指定属性tf.decode_jpeg(..., channels=3)它可以并且将设置最后一个

这将生成一个形状 (?, ?, ?),因为 if 分支channels ==0在此处处于活动状态。

运行时信息

另一方面,这里定义的tf.shape在这里结束。这将检查此处的实际张量内容

// get actual tensor-shape from the value itself
TensorShape shape;
OP_REQUIRES_OK(ctx, shape_op_helpers::GetRegularOrVariantShape(ctx, 0, &shape));
const int rank = shape.dims();
// write the tensor result from "tf.shape(...)"
for (int i = 0; i < rank; ++i) {
int64 dim_size = shape.dim_size(i);
// ...
vec(i) = static_cast<OutType>(dim_size); // the actual size for dim "i"
}

就像tf.shape对它之前的操作说的那样:

你可以告诉我你几分钟前得出的任何结论。我不在乎你此时有多聪明,也不在乎你对形状的猜测做了多少工作。看,我只看一下现在有内容的混凝土张量,我就完成了。

后果

这会产生一些重要后果:

  • tf.shape是张量,而tensorname.shape不是
  • 某些属性需要整数。因此,无法使用张量tf.shape
  • 图形优化(如XLA)只能依赖于tensorname.shape中给出的信息
  • 如果您知道图像的形状(数据库只有 128x128x3 图像),您应该设置形状,例如,使用tf.reshape(img, [128, 128, 3]

您可能也对此处实现tf.image.extract_jpeg_shape感兴趣。

最新更新