终于弄懂tf.reduce_sum()函数和tf.reduce_mean()函数

参考博客:

1.https://www.zhihu.com/question/51325408/answer/125426642

2.https://www.w3cschool.cn/tensorflow_python/tensorflow_python-5y4d2i2n.html

3.https://blog.csdn.net/dcrmg/article/details/79797826

在学习搭建神经网络的时候,照着敲别人的代码,有一句代码一直搞不清楚,就是下面这句了

loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction), reduction_indices=[1]))

刚开始照着up主写的代码是这样滴:

loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction)))

然后就出现了这样的结果:

709758.1
nan
nan
nan
nan
nan
nan
nan
nan
nan
nan

怎么肥事,对于萌新小白首先想到的就是找度娘,结果找到的方法都不行,然后开始查函数,终于发现了原因,问题就出在reduce_sum()函数上,哈哈哈,然后小白又叕叕叕开始找博客学习reduce_sum()顺带学下reduce_mean(),结果看了好几篇,还是脑袋一片浆糊,为啥用reduction_indices=[1],不用reduction_indices=[0]或者干脆不用,费了九牛二虎之力终于让我给弄懂了,赶紧记录下来!!
-----------------------------------------------------------------------分割线----------------------------------------------------------------------------------
1.tf.reduce_mean 函数用于计算张量tensor沿着指定的数轴(tensor的某一维度)上的的平均值,主要用作降维或者计算tensor(图像)的平均值。

reduce_mean(input_tensor,
                axis=None,
                keep_dims=False,
                name=None,
                reduction_indices=None)
  • 第一个参数input_tensor: 输入的待降维的tensor;
  • 第二个参数axis: 指定的轴,如果不指定,则计算所有元素的均值;
  • 第三个参数keep_dims:是否降维度,设置为True,输出的结果保持输入tensor的形状,设置为False,输出结果会降低维度;
  • 第四个参数name: 操作的名称;
  • 第五个参数 reduction_indices:在以前版本中用来指定轴,已弃用;
    2.tf.reduce_sum函数计算一个张量的各个维度上元素的总和,一般只需设置两个参数
reduce_sum ( 
    input_tensor , 
    axis = None , 
    keep_dims = False , 
    name = None , 
    reduction_indices = None
 )
  • 第一个参数input_tensor: 输入的tensor
  • 第二个参数 reduction_indices:指定沿哪个维度计算元素的总和

最难的就是维度问题,反正本小白看了好几个博客都没弄太懂,最后还是按自己的理解,直接上例子

  • reduce_sum()
tf.reduce_sum
matrix1 = [[1.,2.,3.],            #二维,元素为列表
          [4.,5.,6.]]
matrix2 = [[[1.,2.],[3.,4.]],      #三维,元素为矩阵
           [[5.,6.],[7.,8.]]]

res_2 = tf.reduce_sum(matrix1)
res_3 = tf.reduce_sum(matrix2)
res1_2 = tf.reduce_sum(matrix1,reduction_indices=[0])
res1_3 = tf.reduce_sum(matrix2,reduction_indices=[0])
res2_2 = tf.reduce_sum(matrix1,reduction_indices=[1])
res2_3 = tf.reduce_sum(matrix2,reduction_indices=[1])

sess = tf.Session()
print("reduction_indices=None:res_2={},res_3={}".format(sess.run(res_2),sess.run(res_3)))
print("reduction_indices=[0]:res1_2={},res1_3={}".format(sess.run(res1_2),sess.run(res1_3)))
print("reduction_indices=[1]:res2_2={},res2_3={}".format(sess.run(res2_2),sess.run(res2_3)))

结果如下:

axis=None:res_2=21.0,res_3=36.0
axis=[0]:res1_2=[5. 7. 9.],res1_3=[[ 6.  8.]
                                    [10. 12.]]
axis=[1]:res2_2=[ 6. 15.],res2_3=[[ 4.  6.]
                                   [12. 14.]]
  • tf.reduce_mean
    只需要把上面代码的reduce_sum部分换成renduce_mean即可
res_2 = tf.reduce_mean(matrix1)
res_3 = tf.reduce_mean(matrix2)
res1_2 = tf.reduce_mean(matrix1,axis=[0])
res1_3 = tf.reduce_mean(matrix2,axis=[0])
res2_2 = tf.reduce_mean(matrix1,axis=[1])
res2_3 = tf.reduce_mean(matrix2,axis=[1])

结果如下:

axis=None:res_2=3.5,res_3=4.5
axis=[0]:res1_2=[2.5 3.5 4.5],res1_3=[[3. 4.]
                                       [5. 6.]]
axis=[1]:res2_2=[2. 5.],res2_3=[[2. 3.]
                                 [6. 7.]]

可以看到,reduction_indices和axis其实都是代表维度,当为None时,reduce_sum和reduce_mean对所有元素进行操作,当为[0]时,其实就是按行操作,当为[1]时,就是按列操作,对于三维情况,把最里面的括号当成是一个数,这样就可以用二维的情况代替,最后得到的结果都是在原来的基础上降一维,下面按专业的方法讲解:

对于一个多维的array,最外层的括号里的元素的axis为0,然后每减一层括号,axis就加1,直到最后的元素为单个数字

如上例中的matrix1 = [[1., 2., 3.], [4., 5., 6.]]:

axis=0时,所包含的元素有:[1., 2., 3.]、[4., 5., 6.]
axis=1时,所包含的元素有:1.、2.、3.、4.、5.、6.
所以当reduction_indices/axis=[0],应对axis=0上的元素进行操作,故reduce_sum()得到的结果为[5. 7. 9.],即把两个数组对应元素相加;当reduction_indices/axis=[1],应对axis=1上的元素进行操作,故reduce_sum()得到的结果为[ 6. 15.],即把每个数组里的元素相加。reduce_mean()同理。

不难看出对于三维情况也是同样的思路,如上例中的matrix2 = [[[1,2],[3,4]], [[5,6],[7,8]]]:

axis=0时,所包含的元素有:[[1., 2.],[3., 4.]]、[[5., 6.],[7., 8.]]
axis=1时,所包含的元素有:[1., 2.]、[3., 4.]、[5., 6.]、[7., 8.]
axis=2时,所包含的的元素有:1.、2.、3.、4.、5.、6.、7.、8.
当reduction_indices/axis=[0],reduce_sum()得到的结果应为[[ 6. 8.], [10. 12.]],即把两个矩阵对应位置元素相加;当reduction_indices/axis=[1],reduce_sum()得到的结果应为[[ 4. 6.], [12. 14.]],即把数组对应元素相加。reduce_mean()同理。

一句话就是对哪一维操作,计算完后外面的括号就去掉,相当于降维。

那么问题来了,当reduction_indices/axis=[2]时呢???

  • 对于二维情况,当然是报错了,因为axis最大为1
ValueError: Invalid reduction dimension 2 for input with 2 dimensions. for 'Sum_4' (op: 'Sum') with input shapes: [2,3], [1] and with computed input tensors: input[1] = <2>.
  • 对于三维情况,reduce_sum()得到的结果为:[[ 3. 7.], [11. 15.]],即对最内层括号里的元素求和。

-----------------------------------------------------------------------分割线----------------------------------------------------------------------------------

回到最开始自己的问题,为什么只有设置参数reduction_indices=[1],loss才不为Nan

loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),reduction_indices=[1]))
本程序构建的是一个3层神经网络,输入层只有1个神经元,输入数据为100个样本点,即shape为(100,1)的列向量,隐藏层有10个神经元,输出层同样只有1个神经元,故最后输出数据的shape也为(100,1)的列向量,那么reduce_sum的参数即为一个二维数组。

  • 若reduction_indices=[0],最后得到的是只有一个元素的数组,即[n]
  • 若reduction_indices=[1],最后得到的是有100个元素的数组,即[n1,n2…n100]
  • 若reduction_indices=None,最后得到的则是一个数

那么再使用reduce_mean()求平均时,想要得到的结果是sum/100,这时就只有reduce_sum()传入参数reduction_indices=[1],才能实现想要的效果了。

完美解决!!!

猜你喜欢

转载自blog.csdn.net/weixin_42149550/article/details/98759006