行直方图

时间:2017-01-20 12:53:33

标签: tensorflow

给定二维张量t,计算张量t'的最快方法是什么

t'[i, :] = tf.histogram_fixed_width(t[i, :], vals, nbins)

即。每行调用tf.histogram_fixed_width

似乎tf.histogram_fixed_width缺少axis参数,其效果类似于tf.reduce_sum的{​​{1}}参数。

4 个答案:

答案 0 :(得分:3)

tf.histogram_fixed_width确实适用于整个张量。您必须显式循环遍历行以计算每行直方图。以下是使用TensorFlow tf.while_loop构造的完整工作示例:

import tensorflow as tf

t = tf.random_uniform([2, 2])

i = 0
hist = tf.constant(0, shape=[0, 5], dtype=tf.int32)

def loop_body(i, hist):
  h = tf.histogram_fixed_width(t[i, :], [0.0, 1.0], nbins=5)
  return i+1, tf.concat_v2([hist, tf.expand_dims(h, 0)], axis=0)

i, hist = tf.while_loop(
              lambda i, _: i < 2, loop_body, [i, hist],
              shape_invariants=[tf.TensorShape([]), tf.TensorShape([None, 5])])

sess = tf.InteractiveSession()
print(hist.eval())

答案 1 :(得分:1)

受到keveman的回答的启发,并且因为,的行数固定且相当小,我选择使用t的组合来拆分行和tf.gather加入行。它看起来简单而有效,会看它是否有效......

tf.pack

答案 2 :(得分:0)

我想提出另一个实施方案。 此实现还可以处理多轴和未知尺寸(批处理)。

def histogram(tensor, nbins=10, axis=None):
    value_range = [tf.reduce_min(tensor), tf.reduce_max(tensor)]

    if axis is None:
        return tf.histogram_fixed_width(tensor, value_range, nbins=nbins)
    else:
        if not hasattr(axis, "__len__"):
            axis = [axis]

        other_axis = [x for x in range(0, len(tensor.shape)) if x not in axis]
        swap = tf.transpose(tensor, [*other_axis, *axis])
        flat = tf.reshape(swap, [-1, *np.take(tensor.shape.as_list(), axis)])

        count = tf.map_fn(lambda x: tf.histogram_fixed_width(x, value_range, nbins=nbins), flat, dtype=(tf.int32))

        return tf.reshape(count, [*np.take([-1 if a is None else a for a in tensor.shape.as_list()], other_axis), nbins])

这里唯一慢的部分是tf.map_fn,但它仍然比提到的其他解决方案快。

如果有人知道更快的实现方式,请发表评论,因为此操作仍然非常昂贵。

答案 3 :(得分:0)

上面的

答案在GPU中运行仍然很慢。在这里,我给出了另一个选择,它更快(至少在我运行的环境中),但是它限制为0〜1(您可以先将值标准化)。可以预先定义一次train_equal_mask_nbin

def histogram_v3_nomask(tensor, nbins, row_num, col_num):
    #init mask
    equal_mask_list = []
    for i in range(nbins):
        equal_mask_list.append(tf.ones([row_num, col_num], dtype=tf.int32) * i)
    #[nbins, row, col]
    #[0, row, col] is tensor of shape [row, col] with all value 0
    #[1, row, col] is tensor of shape [row, col] with all value 1
    #....
    train_equal_mask_nbin = tf.stack(equal_mask_list, axis=0)

    #[inst, doc_len] float to int(equaly seg float in bins)
    int_input = tf.cast(tensor * (nbins), dtype=tf.int32)
    #input [row,col] -> copy N times, [nbins, row_num, col_num]
    int_input_nbin_copy = tf.reshape(tf.tile(int_input, [nbins, 1]), [nbins, row_num, col_num])
    #calculate histogram
    histogram = tf.transpose(tf.count_nonzero(tf.equal(train_equal_mask_nbin, int_input_nbin_copy), axis=2))
    return histogram