Tensorflow中把稀疏的数字类别标签转为向量类型并计算loss和accuracy(附对mnist的损失函数值cross_entropy的理解)

本文探讨了在深度学习中如何处理稀疏标签,并详细解释了两种计算交叉熵的方法:一是使用稀疏标签直接计算;二是将稀疏标签转换为one-hot向量后再计算。此外,还介绍了这两种方法在TensorFlow中的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于N个类别,我们的数据中的标签一般是0,1,2,3,4,..n-1这样的数字
而官方的mnist中的标签是向量类型,比如有5类,那么五个标签分别是:
[ 1 , 0 , 0 , 0 , 0]
[ 0 , 1 , 0 , 0 , 0]
[ 0 , 0 , 1 , 0 , 0]
[ 0 , 0 , 0 , 1 , 0]
[ 0 , 0 , 0 , 0 , 1] 
mnist中,最后经过10个神经元的输出输入到softmax层中,输出10维的向量,每一维分别代表那个类别的概率
因此mnist最后计算cross_entropy的时候是这样的: 
cross_entropy = tf.reduce_mean( -tf.reduce_sum( ys * tf.log(prediction),
                                               reduction_indices=[1]) )
ys和prediction的维度都是 batch_size * num_classes (mnist中num_classes就是10了)
ys * tf.log(prediction) 是对两个矩阵的对应位置的元素进行运算,假设结果为result,因此result的维度还是 batch_size * num_classes
通过 tf.reduce_sum( result ,reduction_indices=[1]) ) 这个reduction_indices=[1]在这里的意思是对列进行压缩,
整个的意思就是对 result 每一行的所有元素进行求和,所以经过 tf.reduce_sum() 运算后,结果的维度为 batch_size * 1,注意外面有个 '-' 负号, 
即每行一个值,表示那个样本的cross_entropy

 上面 tf.reduce_mean() 没有指定操作维度,意思就是对所有样本的cross_entropy取求和取平均,作为最终的loss

 

 

 那么对于0,1,2,3,4,..n-1这样的稀疏的数字标签怎么做?
假设输入数据如下:
    crop_shape = [ 42,42,4 ] #忽略这个,我直接从我的code中copy出来的
    ......
    xs = tf.placeholder(tf.float32, [None, crop_shape[0],crop_shape[1],crop_shape[2]])
    ys = tf.placeholder(tf.int64, [None,])
    keep_prob = tf.placeholder(tf.float32)
网络(模型)的输出:
    logits = naive_net(xs,NUM_CLASSES,keep_prob) #注意logits是全连接层的输出,没有经过softmax
    prediction = tf.nn.softmax( logits )
一、直接用稀疏的数字标签来计算


    ##计算loss
    loss = tf.nn.sparse_softmax_cross_entropy_with_logits( logits=logits,labels= ys )
    loss = tf.reduce_mean(loss) #avg loss
    ##计算accuracy
    correct_prediction = tf.equal( tf.argmax( prediction,1 ), ys ) 
    accuracy = tf.reduce_mean( tf.cast(correct_prediction,tf.float32) )


二、转为类似mnist的向量形式dense_labels,再计算


    # 以下是把稀疏标签ys转为向量形式shape [batch_size, NUM_CLASSES].注意,需要把上面ys的int64替换为int32
    batch_size = train_batch_size #样本个数,假设是100
    sparse_labels = tf.reshape(ys, [batch_size, 1]) 
    print(np.shape(sparse_labels)) #[100*1]
    indices = tf.reshape(tf.range(batch_size), [batch_size, 1]) #生成样本的索引
    print(np.shape(indices)) #[100*1]
    concated = tf.concat( [indices, sparse_labels], 1 )
    print(np.shape(concated)) #[100*2]
    dense_labels = tf.sparse_to_dense(concated,
                                [batch_size, NUM_CLASSES],
                                1.0, 0.0) #[100*7], 这里NUM_CLASSES = 7
    # 转换完成
    #对应的计算loss:
    loss = tf.nn.softmax_cross_entropy_with_logits( logits=logits,labels= dense_labels )
    loss = tf.reduce_mean(loss) #avg loss
    #计算accuracy:
    correct_prediction = tf.equal( tf.argmax( prediction,1 ), tf.argmax( dense_labels,1 ) ) 
    accuracy = tf.reduce_mean( tf.cast(correct_prediction,tf.float32) )


总结:
以上有两个函数需要注意
1.  tf.nn.sparse_softmax_cross_entropy_with_logits( logits=logits,labels= ys )
直接输入稀疏数字标签来计算cross_entropy损失
2. tf.nn.softmax_cross_entropy_with_logits( logits=logits,labels= dense_labels )
直接输入向量形式标签计算cross_entropy损失
二者的不同点:labels类型不一样
二者的共同点:要求输入的数据值必须是没有经过softmax归一化的
所以,联系到开始的mnist的cross_entropy:
    cross_entropy = tf.reduce_mean( -tf.reduce_sum( ys * tf.log(prediction),
                                               reduction_indices=[1]) )
这里的prediction是经过softmax的,即
    prediction = tf.nn.softmax( logits )
其实这个softmax只是起到了归一化的作用,具体可以参考:http://www.jianshu.com/p/fb119d0ff6a6


那么问题来了:如果输入都正确的话,这三个是不是等价呢.....嫌麻烦,还没试过-_-|||

System.ArgumentException HResult=0x80070057 Message=Tensor must have 0 dimensions in order to convert to scalar Source=Tensorflow.Binding StackTrace: 在 Tensorflow.Tensor.EnsureScalar(Tensor tensor)Tensorflow.Tensor.op_Explicit(Tensor tensor) 在 DNN_Keras.Program.Main() 在 D:\编程软件系列\VS2022社区版\文件\DNN_Keras\Program.cs 中: 第 151 行 foreach (var (step, (batch_x, batch_y)) in enumerate(dataset1, 1)) { //调用 run_optimization 方法,将当前批次的输入数据 batch_x 标签数据 batch_y 作为参数传入。这个方法的主要功能是执行一次优化步骤,也就是依据当前批次的数据计算梯度,然后更新神经网络的参数Wb的。 run_optimization(batch_x, batch_y); //条件判断语句, step 是当前批次的序号, display_step=100 是一个预设的整数,表示每隔多少步输出一次训练信息。当 step 是 display_step 的整数倍时,就执行下面的代码块。 if (step % 100 == 0) { //调用 model 对象的 Apply 方法,把当前批次的输入数据 batch_x 作为输入, training: true 表明当前处于训练模式。该方法会让输入数据通过神经网络,得到预测结果 pred 。 var pred = model.Apply(batch_x, training: true); //调用 cross_entropy_loss 方法,将预测结果 pred 真实标签 batch_y 作为参数传入,计算交叉熵损失。交叉熵损失是分类问题里常用的损失函数,用于衡量预测结果真实标签之间的差异。 var loss = cross_entropy_loss(pred, batch_y); //调用 accuracy 方法,将预测结果 pred 真实标签 batch_y 作为参数传入,计算准确率。准确率表示预测正确的样本数占总样本数的比例。 var acc = accuracy(pred, batch_y); //输出当前批次的序号、损失准确率。 (float)loss (float)acc 是将 loss acc 转换为 float 类型,方便输出。 print($"step: {step}, loss: {(float)loss}, accuracy: {(float)acc}"); } }
最新发布
06-24
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值