首页 文章

将张量组织成批量动态形状的张量

提问于
浏览
1

我有以下情况:

  • 我想使用Tensorflow服务部署面部检测器模型:https://www.tensorflow.org/serving/ .

  • 在Tensorflow服务中,有一个名为 --enable_batching 的命令行选项 . 这会导致模型服务器自动批处理请求以最大化吞吐量 . 我想要启用它 .

  • 我的模型接受一组图像(称为 images ),这是一个形状的张量 (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 的张量值,那么似乎我的问题将得到解决 . 但是,我回到原点,因为事实并非如此 .

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

附:以下是预期过程的直观表示:

Image batch to prediction batch

1 回答

  • 1

    我最终使用 TensorArraytf.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
    

相关问题