tensorflow histogram_fixed_width()是否支持反向传播?

3pmvbmvn  于 2022-11-25  发布在  其他
关注(0)|答案(3)|浏览(163)

我想用CNN输出的直方图来计算损失,不知道tf.histogram_fixed_width()是否支持梯度流回原来的图层,只有这样,我才能在计算直方图后添加一个损失图层。

eeq64g8w

eeq64g8w1#

tf.histogram_fixed_width()不支持自动梯度功能,因为直方图不是连续微分函数。您可以查看以下返回梯度None的示例。

import keras.backend as K
import tensorflow as tf

value_range = [0.0, 5.0]
a = np.array([-1.0, 0.0, 1.5, 2.0, 5.0, 15])

x = K.variable(a)
hist = tf.histogram_fixed_width(x, value_range, nbins=5, dtype=tf.float32)
gradient = K.gradients(hist, x)

# output is [None]
tyg4sfes

tyg4sfes2#

我也遇到过类似的问题。有两种方法可以尝试:1.在输出层之后,添加额外的层以产生直方图; 2.使用tf.RegisterGradienttf.custom_gradient之类的命令定义您自己的操作梯度。

rryofs0p

rryofs0p3#

如果有人正在寻找解决方案:
正如Stephen提到的,直方图不是连续函数(甚至大部分是连续的),所以它是不可微的。然而,你可能正在寻找的实际上是强度分布的密度估计。你可以使用核密度估计来计算它类似于直方图,除了对强度值进行插值以使得强度的连续变化将对应于密度估计的连续变化之外。
目前在Tensorflow中最简单的方法是使用Tensorflow Probability。在他们的原始paper中有一个例子(参见5.1节):

f = lambda x: tfd.Independent(tfd.Normal( loc=x, scale=1.))
n = x.shape[0].value
kde = tfd.MixtureSameFamily(
mixture_distribution=tfd.Categorical( probs=[1 / n] * n),
components_distribution=f(x))

注意,你必须安装tensorflow_probability(pip works)并将tensorflow_probability作为tfp导入和/或将tensorflow_probability. distribution作为tfd导入。
你也可以自己滚动,尽管不写自定义操作就想办法实现有点棘手。对于1D直方图/分布,只需要第二项)。
我的(轻微测试)努力:

import tensorflow as tf

def cubicSplineFunction(arg):
    """ Applies the cubic spline basis function to the argument """
    absX = tf.math.abs(arg)
    sqrX = tf.math.square(arg)
    coef1 = (4.0 - 6.0*sqrX + 3.0*sqrX*absX) / 6.0              # |arg| < 1.0
    coef2 = (8.0 - 12.0*absX + 6.0*sqrX - sqrX*absX) / 6.0      # |arg| < 2.0
    lt1 = tf.cast(tf.where(absX <= 1,1,0),tf.float32)
    lt2 = tf.cast(tf.where(absX < 2,1,0),tf.float32) * (1-lt1)
    out = coef1 * lt1 + coef2 * lt2
    return out
    
def bincountWithWeights(h,bins,weights):
    """ Adds weights[i] into h[bins[i]] for all i"""
    return tf.tensor_scatter_nd_add(h,tf.reshape(tf.cast(bins,tf.int32),[-1,1]),weights)

def parzenDensityEstimate(x,histN):
    """ Returns a cubic spline interpolated probability density estimate for x """
    padding = 2
    minOb = tf.reduce_min(x)-1e-4; maxOb = tf.reduce_max(x)+1e-4; 
    delta = (maxOb-minOb) / (histN-2*padding)
    min = minOb / delta - padding
    max = maxOb / delta + padding
    xs = tf.range(minOb-2*delta,maxOb+2*delta,delta)
    h = tf.zeros_like(xs)
    xn = x/delta - min
    xb = tf.math.floor(xn,tf.int32)
    for offset in range(-2,3):
        splineArg = (xb+offset)-xn+0.5        # 0.5 is to find the distance from the bin centre
        v = cubicSplineFunction(splineArg)
        h = bincountWithWeights(h=h,bins=xb+offset,weights=v)
    h = h / tf.reduce_sum(h)
    return h,xs

density, bins = parzenDensityEstimate([0.,10.,10.,10.,20.],histN=20)

相关问题