Tensorflow二维直方图



我正试图在tensorflow中创建一个2D直方图,用于tensorflow的自定义损失函数。更普遍地说,我认为人们可以从使用神经元的共同激活中受益,这需要类似的结构。

以下是我要做的具体操作:

给定一个Nx2张量,其中N是一些样本数量,我想创建一个共激活的(装箱(直方图。例如,在input=[0,0.01],[0,0.99],[0.5,0.5]]的简单情况下,总共有10000个bin,我想生成一个100x100张量,除(0,0.01(、(0,0.99(和(0.5,0.5(处的3个条目外,其余均为0,其中值为1/3(缩放很容易,所以我可以用1代替(。

我可以使用标准的numpy或数组操作轻松做到这一点

neuron1 = data[:, 1]
neuron2 = data[:, 2]
hist_2d = np.zeros((100, 100))
for neuron1_output in neuron1:
for neuron2_output in neuron2:
hist_2d[int(100 * neuron1_output), int(100 * neuron2_output)] += 1

不过,如果我想在Tensorflow中使用hist_2d作为损失函数的一部分,看起来我不能进行这种迭代。

有人知道生成我想要的二维直方图的好方法吗?我很高兴找到tf.histogram_fixed_width((,但它只生成1d个直方图。我已经开始研究tf.wile_loop((和tf.map_fn((,但我对Tensorflow还很陌生,所以我不确定哪种途径最有前景。

发布一个我发现的"答案",更像是一个变通方法。

我想创建2D直方图的全部原因是我想计算两个神经元激活的联合分布的熵。我已经在将激活的值离散化到仓中,所以如果我打乱分布也没关系,因为这不会修改熵值。

考虑到这一点,我做了以下工作:我创建了一个1D直方图,其中包含一个平方数的二进制数,并简单地滑动这些值,使数字的前半部分对应于神经元1的激活,后半部分对应于神经2的激活。在python中:

# Calculate the entropy of a 1D tensor, fuzzing the edges with epsilon to keep numbers
# clean.
def calculate_entropy(y, epsilon):
clipped = tf.clip_by_value(y, epsilon, 1 - epsilon)
return -tf.cast(tf.reduce_sum(clipped * tf.log(clipped)), dtype=tf.float32)

# Sandbox for developing calculating the entropies of y
def tf_entropies(y, epsilon, nbins):
# Create histograms for the activations in the batch.
value_range = [0.0, 1.0]
# For prototype, only consider first two features.
neuron1 = y[:, 0]
neuron2 = y[:, 1]
hist1 = tf.histogram_fixed_width(neuron1, value_range, nbins=nbins)
hist2 = tf.histogram_fixed_width(neuron2, value_range, nbins=nbins)
# Normalize
count = tf.cast(tf.count_nonzero(hist1), tf.int32)
dist1 = tf.divide(hist1, count)
dist2 = tf.divide(hist2, count)
neuron1_entropy = calculate_entropy(dist1, epsilon)
neuron2_entropy = calculate_entropy(dist2, epsilon)
# Calculate the joint distribution and then get the entropy
recast_n1 = tf.cast(tf.divide(tf.cast(nbins * neuron1, tf.int32), nbins), tf.float32)
meshed = recast_n1 + tf.divide(neuron2, nbins)  # Shift over the numbers for neuron2
joint_hist = tf.histogram_fixed_width(meshed, value_range, nbins=nbins * nbins)
joint_dist = tf.divide(joint_hist, count)
joint_entropy = calculate_entropy(joint_dist, epsilon)
return neuron1_entropy, neuron2_entropy, joint_entropy, joint_dist

一旦我得到了联合直方图,我就可以使用正常程序得到联合熵。通过使用正常的numpy操作实现相同的逻辑,我验证了我得到了正确的结果。熵计算结果相匹配。

如果其他人遇到类似的问题,我希望这能帮助他们。

也许这个片段会对你有所帮助。

import tensorflow as tf
@tf.function
def get2dHistogram(x, y,
value_range,
nbins=100,
dtype=tf.dtypes.int32):
"""
Bins x, y coordinates of points onto simple square 2d histogram

Given the tensor x and y:
x: x coordinates of points
y: y coordinates of points
this operation returns a rank 2 `Tensor` 
representing the indices of a histogram into which each element
of `values` would be binned. The bins are equal width and
determined by the arguments `value_range` and `nbins`.


Args:
x:  Numeric `Tensor`.
y: Numeric `Tensor`.
value_range[0] lims for x
value_range[1] lims for y

nbins:  Scalar `int32 Tensor`.  Number of histogram bins.
dtype:  dtype for returned histogram.



"""
x_range = value_range[0]
y_range = value_range[1]
histy_bins = tf.histogram_fixed_width_bins(y, y_range, nbins=nbins, dtype=dtype)

H = tf.map_fn(lambda i: tf.histogram_fixed_width(x[histy_bins == i], x_range, nbins=nbins),
tf.range(nbins))
return H # Matrix!

用tensorflow 2.0编写,但你肯定可以管理它。

最新更新