二分类问题中,大量的负样本会影响到网络的训练吗?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_38145317/article/details/100536017

在分类问题中,比如我们训练一个网络,让它识别出这张照片是否为人,我们的数据集假设有张1000张,其中100张为人,900张不是人(里面包含了车,飞机,花朵等乱七八糟的图片),可以看到这个数据集出现了负样本远大于正样本的情况.现在假设我们把这1000张图片一次性送入网络进行训练,那么得到的损失值如何计算?负样本对损失值有贡献吗?

答案:

(1)损失值loss计算公式:

假设真实标签值y_true=[y1,y2,y3,...yn]

预测值y_pred=[z1,z2,z3,...zn]

loss=-\frac{y_1*logz_1+y_2*logz_2+y_3*logz_3...+y_n*logz_n}{n}      (1)

(2) 负样本对损失值有贡献,主要体现到上面的loss计算上,虽然负样本标签值=0,分子中遇到负样本0,y_i*log(z_i)=0, 但是在分母中,n的值是正负样本样本的总数量,所以负样本对损失值是有贡献的,特别当正负样本比例失衡,负样本远大于正样本时,会造成训练进行不下去.

还是用一段程序来证明吧

import tensorflow as tf
y_true=[[0], [0],[0],[0],[1], [1]]#真实标签
y_pre=[[0.9],[0.9],[0.9],[0.9],[0.6],[0.5]]#预测值
cross_entropy=-tf.reduce_mean(y_true*tf.log(tf.clip_by_value(y_pre,1e-10,1.0)))#-ylogp
a=-tf.log(0.6)-tf.log(0.5)#就算所有样本的损失和,可以看出这里负样本因为标签值=0,所以无论预测值是多少,对损失和是没有影响的
with tf.Session() as sess:
    print(sess.run(a))#1.20397
    print(sess.run(a / 2))#0.601986
    print(sess.run(a / 6))#0.200662
    print(sess.run(cross_entropy))#0.200662#这里可以看出经过reduce_mean之后,这个是按照所有的样本数量来求平均值的,虽然前面正样本只有2个,
    # 但是算平均损失的话,这里是除以样本总数的,所以随着负样本的增多,当其数量远远大于正样本数量时,无论网络对于正样本是否预测正确,最后的总的损失值会很小,
    #即由负样本主导了损失函数值,造成损失函数值非常小,无法反向传播,训练失败

完整例子,来源于tensorflow实战google深度学习框架

import tensorflow as tf
from numpy.random import RandomState
batch_size=8
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))#第一个权重矩阵
#tf.randdom_normal(shape,mean=0.0,stddev=1.0,dtype=tf.float32,seed=None,name=None)
#shape:输出张量的形状,必选,mean正态分布的均值,默认=0,stddev标准差,默认=1,dtype,输出的类型,默认=tf.float32
#seed随机数种子,是一个整数,当设置之后,每次生成的随机数都一样,name操作的名称
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))#生成3行1列矩阵

x=tf.placeholder(tf.float32,shape=(None,2),name='x-input')#训练样本,?x2的矩阵
y_=tf.placeholder(tf.float32,shape=(None,1),name='y-input')#训练样本的标签,?x1的矩阵
a=tf.matmul(x,w1)#计算x*w1,[?,2]*[2,3]=[?,3]
y=tf.matmul(a,w2)#计算a*w2=x*w1*w2,[?,2]*[2,3]*[3,1=[?,3]*[3,1]=[?,1]
cross_entropy=-tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))#-ylogp
#tf.reduce_mean(input_tensor,axis=None,)函数用于计算张量tensor沿着指定的数轴tensor的某一维度)上的平均值,主要用作将维或者计算tensor
# (图像)的平均值,
#第一个参数input_tensor:输入的待降维的tensor
#axis: 指定的轴,如果不指定,则计算所有元素的均值
train_step=tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
rdm=RandomState(1)#因为这里固定了随机数种子,所以每次运行程序,生成的训练样本都是一样的
dataset_size=3
X=rdm.rand(dataset_size,2)#生成128x2的训练样本
Y=[[int(x1+x2<1)] for (x1,x2) in X]#对训练样本生成标签,值=0或1

with tf.Session() as sess:
 init_op=tf.initialize_all_variables()
 sess.run(init_op)
 print(sess.run(w1))
 print(sess.run(w2))
 # print('x', sess.run(X))
 # print('y', sess.run(Y))
 steps=5000
 for i in range(steps):
  start=(i*batch_size)%dataset_size
  end=min(start+batch_size,dataset_size)
  sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
  if i%1000==0:
   total_cross_entropy=sess.run(cross_entropy,feed_dict={x:X,y_:Y})
   print('after %d training steps, cross entropy on all data is %g'%(i,total_cross_entropy))#%g啥意思?
 print(sess.run(w1))
 print(sess.run(w2))


解决方案:

挖坑1: 从等式(1)可以看出负样本对损失函数值的影响主要体现在分母上,那我干脆对于y_true, 多加一列,标记一下其是负样本,这样我就不把它统计到样本总量中不久可以了吗?

  具体操作:把y_true中值=1的个数统计出来,假设=m,求均值时,分母=m即可.

挖坑2:在实际的应用场景中,做目标检测时,同一张图片中会出现多个目标,而且这多个目标可能属于不同的类别中,比如在一张图片中出现了一个人和一群狗,我们的网络任务为在这图片中找出人和狗,并识别出是狗还是人,所以这里我们对同一张图片,就会

后面问题不知道如何描述了,让我想想再写,2019-09-04

猜你喜欢

转载自blog.csdn.net/weixin_38145317/article/details/100536017
今日推荐