【问题标题】:Organizing tensor into batches of dynamically shaped tensors将张量组织成一批动态形状的张量
【发布时间】:2017-09-17 18:06:44
【问题描述】:

我有以下情况:

  • 我想使用 Tensorflow Serving 部署人脸检测器模型:https://www.tensorflow.org/serving/。
  • 在 Tensorflow Serving 中,有一个名为 --enable_batching 的命令行选项。这会导致模型服务器自动批处理请求以最大化吞吐量。我希望启用它。
  • 我的模型接收一组图像(称为图像),这是一个形状为 (batch_size, 640, 480, 3) 的张量。
  • 该模型有两个输出:(number_of_faces, 4) 和 (number_of_faces,)。第一个输出将称为faces。最后一个输出,我们可以称之为 partitions 是原始批次中对应人脸的索引。例如,如果我传入一批 4 个 images 并获得 7 个 faces,那么我可能会将这个张量设为 [0, 0, 1, 2, 2, 2, 3]。前两张脸对应第一张图片,第三张脸对应第二张图片,第三张图片有3张脸,以此类推

我的问题是这样的:

  • 为了使--enable_batching 标志起作用,我的模型的输出需要具有与输入相同的第 0 维。也就是说,我需要一个具有以下形状的张量:(batch_size, ...)。我想这是为了让模型服务器可以知道将批处理中的每个输出发送到哪个 grpc 连接。
  • 我想做的是将面部检测器的输出张量从这个形状(number_of_faces, 4) 转换成这个形状(batch_size, None, 4)。也就是说,一个批次数组,其中每个批次可以有可变数量的面孔(例如,批次中的一个图像可能没有面孔,而另一个可能有 3 个)。

我尝试了什么:

  • tf.dynamic_partition。从表面上看,这个功能看起来很完美。但是,在意识到num_partitions 参数不能是张量,只能是整数后,我遇到了困难:

    tensorflow_serving_output = tf.dynamic_partition(faces, partitions, batch_size)

如果tf.dynamic_partition 函数接受num_partition 的张量值,那么我的问题似乎就解决了。但是,我回到第一方,因为情况并非如此。

感谢大家的帮助!如果有什么不清楚的地方请告诉我

附:这是预期过程的可视化表示:

【问题讨论】:

    标签: tensorflow tensorflow-serving


    【解决方案1】:

    我最终找到了使用TensorArray 和tf.while_loop 的解决方案:

    def batch_reconstructor(tensor, partitions, batch_size):
        """
        Take a tensor of shape (batch_size, 4) and a 1-D partitions tensor as well as the scalar batch_size
        And reconstruct a TensorArray that preserves the original batching
    
        From the partitions, we can get the maximum amount of tensors within a batch. This will inform the padding we need to use.
        Params:
            - tensor: The tensor to convert to a batch
            - partitions: A list of batch indices. The tensor at position i corresponds to batch # partitions[i]
        """
        tfarr = tf.TensorArray(tf.int32, size=batch_size, infer_shape=False)
    
        _, _, count = tf.unique_with_counts(partitions)
        maximum_tensor_size = tf.cast(tf.reduce_max(count), tf.int32)
    
        padding_tensor_index = tf.cast(tf.gather(tf.shape(tensor), 0), tf.int32)
    
        padding_tensor = tf.expand_dims(tf.cast(tf.fill([4], -1), tf.float32), axis=0) # fill with [-1, -1, -1, -1]
        tensor = tf.concat([tensor, padding_tensor], axis=0)
    
        def cond(i, acc):
            return tf.less(i, batch_size)
    
        def body(i, acc):
            partition_indices = tf.reshape(tf.cast(tf.where(tf.equal(partitions, i)), tf.int32), [-1])
    
            partition_size = tf.gather(tf.shape(partition_indices), 0)
    
            # concat the partition_indices with padding_size * padding_tensor_index
            padding_size = tf.subtract(maximum_tensor_size, partition_size)
            padding_indices = tf.reshape(tf.fill([padding_size], padding_tensor_index), [-1])
    
            partition_indices = tf.concat([partition_indices, padding_indices], axis=0)
    
            return (tf.add(i, 1), acc.write(i, tf.gather(tensor, partition_indices)))
    
        _, reconstructed = tf.while_loop(
            cond,
            body,
            (tf.constant(0), tfarr),
            name='batch_reconstructor'
        )
    
        reconstructed = reconstructed.stack()
        return reconstructed
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-17
      • 2018-12-13
      • 1970-01-01
      • 2016-12-12
      • 1970-01-01
      • 2019-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多