在TensorFlow中更改张量的比例

23

对于标题可能的错误,我很抱歉,我不知道该怎样措辞。无论如何,我有一个包含值集合的张量,但我想确保张量中的每个元素都具有从0-255的范围(或者从0-1也可以)。然而,我不想像使用softmax一样将所有值相加得到1或255,我只想降低值的比例。

有没有方法可以做到这一点?

谢谢!

6个回答

43

您正在尝试规范化数据。 经典的规范化公式如下:

normalize_value = (value − min_value) / (max_value − min_value)

在tensorflow中的实现将如下所示:

tensor = tf.div(
   tf.subtract(
      tensor, 
      tf.reduce_min(tensor)
   ), 
   tf.subtract(
      tf.reduce_max(tensor), 
      tf.reduce_min(tensor)
   )
)

张量的所有值都将在0和1之间。

重要提示:确保张量具有float / double值,否则输出张量将只有零和一。如果您有一个整数张量,请先调用此函数:

tensor = tf.to_float(tensor)

更新:从tensorflow 2开始,tf.to_float()已被弃用,应使用tf.cast()代替:

tensor = tf.cast(tensor, dtype=tf.float32) # or any other tf.dtype, that is precise enough

2
还要确保取小值(即 epsilon=1e-12)和分母的最大值,以避免除零错误。(val - min_val) / max((max_val - min_val), epsilon) - JYun
3
当val等于最大值和最小值时,将epsilon添加到分子,将2倍的epsilon添加到分母,以使结果为0.5。翻译后的表达式为:(val - min_val + epsilon) / max((max_val - min_val), 2*epsilon) - THN
然而,如果你的训练数据的最大像素为254,而测试或实际数据的最大像素为255,那么规范化会有所偏差(希望不会有太大变化)。因此,对于图像,你可以只使用你了解的最大值和最小值。 - user12582392

6
根据维基百科中有关特征缩放的介绍,您也可以尝试使用单位长度缩放:

enter image description here

代码示例如下所示:

In [3]: a = tf.constant([2.0, 4.0, 6.0, 1.0, 0])                                                                                                                                                                     
In [4]: b = a / tf.norm(a)
In [5]: b.eval()
Out[5]: array([ 0.26490647,  0.52981293,  0.79471946,  0.13245323,  0.        ], dtype=float32)

只是补充一下,这个范数的实现被称为L2范数。它被计算为平方向量值之和的平方根。 - Mandias

5

sigmoid(tensor) * 255应该可以解决问题。


3

让输入为

X = tf.constant([[0.65,0.61, 0.59, 0.62, 0.6 ],[0.25,0.31, 0.89, 0.52, 0.6 ]])

我们可以定义一个缩放函数。
def rescale(X, a=0, b=1):
  repeat = X.shape[1]
  xmin = tf.repeat(tf.reshape(tf.math.reduce_min(X, axis=1), shape=[-1,1]), repeats=repeat, axis=1)
  xmax = tf.repeat(tf.reshape(tf.math.reduce_max(X, axis=1), shape=[-1,1]), repeats=repeat, axis=1)
  X = (X - xmin) / (xmax-xmin)
  return X * (b - a) + a

这将在范围 [0,1] 内输出 X。

>>rescale(X)

<tf.Tensor: shape=(2, 5), dtype=float32, numpy=
array([[1.        , 0.333334  , 0.        , 0.5000005 , 0.16666749],
       [0.        , 0.09375001, 1.        , 0.42187497, 0.54687506]],
      dtype=float32)>

将其缩放到范围 [0, 255]

>> rescale(X, 0, 255) 
<tf.Tensor: shape=(2, 5), dtype=float32, numpy=
array([[255.      ,  85.00017 ,   0.      , 127.50012 ,  42.50021 ],
       [  0.      ,  23.906252, 255.      , 107.57812 , 139.45314 ]],
      dtype=float32)>


1
在某些情况下,您需要单独对每个图像进行归一化处理 - 例如对抗数据集,其中每个图像都带有噪声。以下内容根据每个图像的最小值和最大值进行归一化处理,假设输入具有典型的大小 Batch x YDim x XDim x Channels:
    cast_input = tf.cast(inputs,dtype=tf.float32)     # e.g. MNIST is integer
    input_min = tf.reduce_min(cast_input,axis=[1,2])  # result B x C
    input_max = tf.reduce_max(cast_input,axis=[1,2])
    ex_min = tf.expand_dims(input_min,axis=1)         #  put back inner dimensions
    ex_max = tf.expand_dims(input_max,axis=1)
    ex_min = tf.expand_dims(ex_min,axis=1)            # one at a time - better way?
    ex_max = tf.expand_dims(ex_max,axis=1)            # Now Bx1x1xC
    input_range = tf.subtract(ex_max, ex_min)
    floored = tf.subtract(cast_input,ex_min)          # broadcast
    scale_input = tf.divide(floored,input_range)

我希望能够像在Numpy中那样通过一行代码扩展维度,但是tf.expand_dims似乎只能一次接受一个维度 - 在此开放建议。谢谢!


0
如果您希望最大值成为0-1范围的有效上限,并且存在有意义的零,则可以使用以下内容:
import tensorflow as tf
tensor = tf.constant([0, 1, 5, 10])
tensor = tf.divide(tensor, tf.reduce_max(tensor))
tf.print(tensor)

将导致:

[0 0.1 0.5 1]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接