我想用CNN输出的直方图来计算损失,不知道tf.histogram_fixed_width()是否支持梯度流回原来的图层,只有这样,我才能在计算直方图后添加一个损失图层。
tf.histogram_fixed_width()
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]
tyg4sfes2#
我也遇到过类似的问题。有两种方法可以尝试:1.在输出层之后,添加额外的层以产生直方图; 2.使用tf.RegisterGradient或tf.custom_gradient之类的命令定义您自己的操作梯度。
tf.RegisterGradient
tf.custom_gradient
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)
3条答案
按热度按时间eeq64g8w1#
tf.histogram_fixed_width()
不支持自动梯度功能,因为直方图不是连续微分函数。您可以查看以下返回梯度None的示例。tyg4sfes2#
我也遇到过类似的问题。有两种方法可以尝试:1.在输出层之后,添加额外的层以产生直方图; 2.使用
tf.RegisterGradient
或tf.custom_gradient
之类的命令定义您自己的操作梯度。rryofs0p3#
如果有人正在寻找解决方案:
正如Stephen提到的,直方图不是连续函数(甚至大部分是连续的),所以它是不可微的。然而,你可能正在寻找的实际上是强度分布的密度估计。你可以使用核密度估计来计算它类似于直方图,除了对强度值进行插值以使得强度的连续变化将对应于密度估计的连续变化之外。
目前在Tensorflow中最简单的方法是使用Tensorflow Probability。在他们的原始paper中有一个例子(参见5.1节):
注意,你必须安装tensorflow_probability(pip works)并将tensorflow_probability作为tfp导入和/或将tensorflow_probability. distribution作为tfd导入。
你也可以自己滚动,尽管不写自定义操作就想办法实现有点棘手。对于1D直方图/分布,只需要第二项)。
我的(轻微测试)努力: