Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/tensorflow/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在TensorFlow中创建图形时确定张量形状_Python_Tensorflow - Fatal编程技术网

Python 在TensorFlow中创建图形时确定张量形状

Python 在TensorFlow中创建图形时确定张量形状,python,tensorflow,Python,Tensorflow,我试图编写一段可重用代码,读取一个张量的形状,然后使用生成的对象定义其他张量的形状。我可以选择使用tf.shape(tensor)读取张量的动态形状,或者使用tensor.get\u shape()读取张量的静态形状。玩具示例如下所示(使用两种不同的策略): 我想在不同的图中使用这段代码。有时输入张量的形状已知,有时未知: graph_A = tf.Graph() with graph_A.as_default(): x = tf.placeholder(tf.float32, [2,

我试图编写一段可重用代码,读取一个张量的形状,然后使用生成的对象定义其他张量的形状。我可以选择使用
tf.shape(tensor)
读取张量的动态形状,或者使用
tensor.get\u shape()
读取张量的静态形状。玩具示例如下所示(使用两种不同的策略):

我想在不同的图中使用这段代码。有时输入张量的形状已知,有时未知:

graph_A = tf.Graph()
with graph_A.as_default():
    x = tf.placeholder(tf.float32, [2, 4])
    y = tf.placeholder(tf.float32, [8])
    a, b, c, d = my_function(x, y)

with graph_B.as_default():
    x = tf.placeholder(tf.float32)
    y = tf.placeholder(tf.float32)
    a, b, c, d = my_function(x, y)
我想要的行为是:(A)当输入张量的形状已知时(如
graph_A
),我希望TensorFlow在图形创建时计算图形中的所有形状(以便它可以有效地分配资源等),以及(B)当输入张量的形状未知时(如
graph_B
),我希望TensorFlow等到运行时才计算图形中的所有形状

函数的
strategy_1
版本几乎可以做到这一点。它达到了(B),但并没有完全达到(A),因为张量流使一些张量的形状未知。例如,在上面的玩具示例中,
a
b
c
的形状是在图形创建时计算的,但是
d
的形状是未知的(即使
d
使用非常类似的操作)。您可以通过打印
a.get\u shape()
b.get\u shape()
等来检查这一点

相反,函数的
strategy_2
版本实现了(A)图中的所有张量,但没有实现(B),因为TensorFlow(可以理解)在尝试使用输入张量的(未知)静态形状来塑造其他张量时抛出异常


是否有一种方法可以在单个功能中同时实现(a)和(B)?
策略1
版本如何/为什么适用于图形中的大多数张量,但不是所有张量?

您可以仔细挑选形状的元素,您知道这些元素具有“两全其美”的结果:

您可以看到,虽然正确地检查了
tf.fill([2],3)
,但TensorFlow没有发现
2*tf.fill([2],3)
[6,6]
,可能是因为静态跟踪乘法之类的操作,即使操作数是已知常量,也被认为太昂贵了


我没有发现的是ops在哪里声明可以静态地知道它们的值,或者在哪里/如何准确地检索这些值。例如,对于
tf.shape
,它似乎能够专门选择已知值,而将其余值保留为未定义。

请您进一步解释为什么有时x_数组的形状未知?这不是我真正的代码。这应该是一个最低限度的例子。但我的真实代码中的模拟代码是一块可重用代码,它被插入到不同的计算图中,用于不同的目的。x_阵列的模拟通常来自占位符。在某些图形中,占位符具有指定的形状。在其他图形中,占位符没有(因此它可以在运行时接受不同的形状)。这有帮助吗?这说明
x\u array\u shape=tf.shape(x\u array)
是传递动态形状的正确方法。在你的例子中显示了
(?,4)
,因为x_数组_形状是一个需要计算的张量(例如通过session.run)。对。但请注意,在前三个示例中,TensorFlow能够在图形创建时确定输出对象的静态形状(无需会话运行),这正是我想要的行为。只有在最后一种情况下才会失败,即使最后一个输出对象与其他对象非常相似。这可能是一个愚蠢的问题。使用
tf.shape
时,代码是否在图形创建时失败?是。这也是我能想到的最好的了。我一直/正在期待一个更简单的解决方案,因为策略1非常接近我想要的行为。你知道TensorFlow如何/为什么能够在大多数时间(但不是所有时间)检查张量的值来推断下游张量的形状吗?@tcquinn这是一个有趣的问题,我编辑了答案。似乎有一些机制可以猜测张量输出的形状,这些形状在大多数常见情况下都很有效,
tf.shape
对于您的情况应该总是很有效的。感谢您的后续关注。非常有趣。我的同事还发现,如果只有一个新维度未知(但如果多个新维度未知),则
tf.reformate()
乐于从输入形状推断输出形状。似乎结论是TensorFlow在许多常见操作的图形创建时都非常擅长于推断形状,但并非所有操作都如此,因此这种机制不可依赖。
graph_A = tf.Graph()
with graph_A.as_default():
    x = tf.placeholder(tf.float32, [2, 4])
    y = tf.placeholder(tf.float32, [8])
    a, b, c, d = my_function(x, y)

with graph_B.as_default():
    x = tf.placeholder(tf.float32)
    y = tf.placeholder(tf.float32)
    a, b, c, d = my_function(x, y)
def my_get_shape(tensor):
    if tensor.shape.ndims is None:
        # Fully dynamic
        return tf.shape(tensor)
    if tensor.shape.is_fully_defined():
        # Fully static
        return tensor.shape
    # Partially static
    dyn_shape = tf.shape(tensor)
    shape = []
    for i, d in enumerate(tensor.shape):
        shape.append(d.value if d.value is not None else dyn_shape[i])
    return shape

def my_function(x, y):
    x_shape = my_get_shape(x)  # Or just tf.shape(x)! - see edit
    a = tf.reshape(y, x_shape)
    b = tf.zeros(x_shape)
    num_x_values = x_shape[0]
    c = tf.reshape(y, [num_x_values, 4])
    d = tf.zeros([num_x_values, 4])
    return a, b, c, d

# Fully static
with tf.Graph().as_default():
    x = tf.placeholder(tf.float32, [2, 4])
    y = tf.placeholder(tf.float32, [8])
    a, b, c, d = my_function(x, y)
print('a:', a.shape, ', b:', b.shape, ', c:', c.shape, ', d:', d.shape)
# a: (2, 4) , b: (2, 4) , c: (2, 4) , d: (2, 4)

# Fully dynamic
with tf.Graph().as_default():
    x = tf.placeholder(tf.float32)
    y = tf.placeholder(tf.float32)
    a, b, c, d = my_function(x, y)
print('a:', a.shape, ', b:', b.shape, ', c:', c.shape, ', d:', d.shape)
# a: <unknown> , b: <unknown> , c: (?, 4) , d: (?, 4)

# Partially static
with tf.Graph().as_default():
    x = tf.placeholder(tf.float32, [None, 4])
    y = tf.placeholder(tf.float32)
    a, b, c, d = my_function(x, y)
print('a:', a.shape, ', b:', b.shape, ', c:', c.shape, ', d:', d.shape)
# a: (?, 4) , b: (?, 4) , c: (?, 4) , d: (?, 4)
from tensorflow.python.framework.common_shapes import call_cpp_shape_fn
with tf.Graph().as_default():
    print(call_cpp_shape_fn(tf.reshape(tf.placeholder(tf.float32), tf.fill([2], 3)).op))
    # Shows this:
    # {
    #   'shapes': [dim { size: 3 } dim { size: 3 }],
    #   'handle_data': [None],
    #   'inputs_needed': b'\x12\x01\x01'
    # }
    print(call_cpp_shape_fn(tf.reshape(tf.placeholder(tf.float32), (2 * tf.fill([2], 3))).op))
    # Shows this:
    # {
    #   'shapes': [dim { size: -1 } dim { size: -1 }],
    #   'handle_data': [None],
    #   'inputs_needed': b'\x12\x01\x01'
    # }