这是我的代码,
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
感兴趣。