【问题标题】:tf.nn.conv2d_transpose output_shape dynamic batch_sizetf.nn.conv2d_transpose output_shape 动态batch_size
【发布时间】:2017-10-23 08:45:42
【问题描述】:

tf.nn.conv2d_transpose 的文档说:

tf.nn.conv2d_transpose(
    value,
    filter,
    output_shape,
    strides,
    padding='SAME',
    data_format='NHWC',
    name=None
)

output_shape 参数需要一个一维张量,指定此操作输出的张量的形状。在这里,由于我的 conv-net 部分完全建立在动态 batch_length 占位符上,我似乎无法为此操作的 output_shape 的静态 batch_size 要求提供解决方法。

网络上有很多关于这个问题的讨论,但是,我找不到任何可靠的解决方案。它们中的大多数都是定义了global_batch_size 变量的hacky。我想知道这个问题的最佳解决方案。这个经过训练的模型将作为已部署的服务提供。

【问题讨论】:

    标签: tensorflow deconvolution


    【解决方案1】:

    您可以使用参考张量的动态形状,而不是静态形状。

    通常,如果您使用conv2d_transpose 操作,您是在“上采样”一层以获得网络中另一个张量的某种形状。

    例如,如果您想复制 input_tensor 张量的形状,您可以执行以下操作:

    import tensorflow as tf
    
    input_tensor = tf.placeholder(dtype=tf.float32, shape=[None, 16, 16, 3])
    # static shape
    print(input_tensor.shape)
    
    conv_filter = tf.get_variable(
        'conv_filter', shape=[2, 2, 3, 6], dtype=tf.float32)
    conv1 = tf.nn.conv2d(
        input_tensor, conv_filter, strides=[1, 2, 2, 1], padding='SAME')
    # static shape
    print(conv1.shape)
    
    deconv_filter = tf.get_variable(
        'deconv_filter', shape=[2, 2, 6, 3], dtype=tf.float32)
    
    deconv = tf.nn.conv2d_transpose(
        input_tensor,
        filter=deconv_filter,
        # use tf.shape to get the dynamic shape of the tensor
        # know at RUNTIME
        output_shape=tf.shape(input_tensor),
        strides=[1, 2, 2, 1],
        padding='SAME')
    print(deconv.shape)
    

    程序输出:

    (?, 16, 16, 3)
    (?, 8, 8, 6)
    (?, ?, ?, ?)
    

    如您所见,最后一个形状在编译时完全未知,因为我将conv2d_transpose 的输出形状设置为tf.shape 操作的结果,该操作返回,因此其值可以在运行时更改.

    【讨论】:

    • 这个解决方案可行,但是我设计我的服务的方式是有一个用于编码和解码的功能接口。在编码期间创建的所有中间张量对于编码函数都是本地的。我通过返回张量形状信息列表并将该字典传递给解码函数来解决这个问题。这仍然有点 hacky,但绝对比早期的 global batch_size hack 更好。
    • 在我看来这不是 hacky,这是正确的做法。
    【解决方案2】:

    您可以使用以下代码根据该层的输入 (input) 和输出数量计算 tf.nn.conv2d_transpose 的输出形状参数来自这一层(num_outputs)。当然,您还有过滤器大小、填充、步幅和 data_format。

    def calculate_output_shape(input, filter_size_h, filter_size_w, 
        stride_h, stride_w, num_outputs, padding='SAME', data_format='NHWC'):
    
        #calculation of the output_shape:
        if data_format == "NHWC":
            input_channel_size = input.get_shape().as_list()[3]
            input_size_h = input.get_shape().as_list()[1]
            input_size_w = input.get_shape().as_list()[2]
            stride_shape = [1, stride_h, stride_w, 1]
            if padding == 'VALID':
                output_size_h = (input_size_h - 1)*stride_h + filter_size_h
                output_size_w = (input_size_w - 1)*stride_w + filter_size_w
            elif padding == 'SAME':
                output_size_h = (input_size_h - 1)*stride_h + 1
                output_size_w = (input_size_w - 1)*stride_w + 1
            else:
                raise ValueError("unknown padding")
    
            output_shape = tf.stack([tf.shape(input)[0], 
                                output_size_h, output_size_w, 
                                num_outputs])
        elif data_format == "NCHW":
            input_channel_size = input.get_shape().as_list()[1]
            input_size_h = input.get_shape().as_list()[2]
            input_size_w = input.get_shape().as_list()[3]
            stride_shape = [1, 1, stride_h, stride_w]
            if padding == 'VALID':
                output_size_h = (input_size_h - 1)*stride_h + filter_size_h
                output_size_w = (input_size_w - 1)*stride_w + filter_size_w
            elif padding == 'SAME':
                output_size_h = (input_size_h - 1)*stride_h + 1
                output_size_w = (input_size_w - 1)*stride_w + 1
            else:
                raise ValueError("unknown padding")
    
            output_shape = tf.stack([tf.shape(input)[0], 
                                    output_size_h, output_size_w, num_outputs])
        else:
            raise ValueError("unknown data_format")
    
        return output_shape
    

    【讨论】:

      【解决方案3】:

      您可以使用 -1 的值替换 batch_size 的确切值。考虑下面的例子,我将形状为 (16, 16, 3) 的可变批量大小的输入张量转换为 (32, 32, 6)。

      import tensorflow as tf
      
      input_tensor = tf.placeholder(dtype = tf.float32, shape = [None, 16, 16, 3])
      print (input_tensor.shape)
      
      my_filter = tf.get_variable('filter', shape = [2, 2, 6, 3], dtype = tf.float32)
      conv = tf.nn.conv2d_transpose(input_tensor,
                                    filter = my_filter,
                                    output_shape = [-1, 32, 32, 6],
                                    strides = [1, 2, 2, 1],
                                    padding = 'SAME')
      print (conv.shape)
      

      会输出你:

      (?, 16, 16, 3)
      (?, 32, 32, 6)
      

      【讨论】:

      • 嘿,不幸的是,当我尝试使用 -1 特殊维度时,图形编译得很好,但在运行时,即在运行会话时,我收到一个错误 Dimension -1 should be >= 0
      【解决方案4】:

      当你需要 train_batch_size 时,只需使用 tf.shape(X_batch)[0]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-24
        • 1970-01-01
        相关资源
        最近更新 更多