关于深度学习中mini-batch里的y[np.arange(batch_size), t]


        今天在阅读深度学习入门鱼书的时候,读到4.2.4mini-batch版交叉熵误差的实现这一部分时,对其部分的代码有一点不解,虽然笔者有详细的解释,但是仍然存在一些问题不懂,在查阅了别人的解读后明白了,最后打算记录一下。

一、交叉熵损失是什么?

        在神经网络的训练过程中,我们使用损失函数用来判断模型的拟合效果。损失函数可以使用任意的函数,但是我们在深度学习中通常使用均方误差(Mean Squared Error, MSE)和交叉熵误差(Cross Entropy Error)。在分类问题中,通常我们选择交叉熵误差。本章的内容是基于MINSTS手写数字识别。交叉熵误差如下式所示:

                                E = -\sum_{k} t_klogy_k

二、使用步骤

数据部分(之前因为基础太差,在写书上代码的时候想自己写一组数据,但是老报错,所以引用了别人代码http://t.csdn.cn/t8AOe):

import numpy as np
y=np.array([[0,1,0.1,0,0,0,0,0,0,0],
            [0,0,0.2,0.8,0,0,0,0,0,0]])
t_onehot=np.array([[0,1,0,0,0,0,0,0,0,0],
                   [0,0,0,1,0,0,0,0,0,0]])#one-hot
t = t_onehot.argmax(axis=1)#非one-hot,这一步是将one—hot里为1的项的索引提出来
print(t)#[1 3]
batch_size = y.shape[0]
print(batch_size)#2
k=y[np.arange(batch_size), t] # [y[0,1] y[1,3]]
print(k)#[1.  0.8]
log=np.log(k)
print(log)#[ 0.         -0.22314355]
r=-np.sum(np.log(y[np.arange(batch_size), t] + 1e-7))/ batch_size
print(r)#0.11157166315711126

之后就是在读到 这一行代码的时候,虽然笔者说的很明了:(以下内容为书中原话)

np.arange(batch.size)会生成一个从0到batch_size-1的数组。比如当batch_size为5时,np.arange(batch.size)会生成一个NumPy数组[0,1,2,3,4]。因为t中标签是以[2,7,0,9,4]的形式存储的,所以y[np.arange(batch.size),t]能抽出各个数据的正确标签对应的神经网络的输出(在这个例子中,y[np.arange(batch.size),t]会生成NumPy数组y[0,2],y[1,7],y[2,0],y[3,9],y[4,4])。

-np.sum(np.log(y[np.arange(batch_size), t] + 1e-7))/ batch_size

 但是我在看到这句代码的时候仍然有很多疑问,就算生成了这些数组,那将这些数组放入log中,又有什么用呢?于是我查找了一些博客,了解了其中的原理(http://t.csdn.cn/w4ZVL):

        虽然在这里我们采用的监督数据为标签形式,但是我们仍然需要先写出他的独热编码(因为需要通过其中不为0的元素提取出索引,构成标签(0,1,2...,9))。如本文中的实例:

我们构建出了输出的数据,这里的batch_size为2,即代表可以识别两个数字的模型。可以看出第一组索引为‘1’的元素为1,第二组中索引为‘3’的的元素为0.8,我们可以知道其识别出的数字为1,3,但是我们要怎么提取出这个1,3呢?

我们采用argmax()函数将其索引提出来就可以啦

t = t_onehot.argmax(axis=1)

提取出来的结果就是[1  3]

最后我们再来说说这里的y[np.arange(batch_size), t]。正如书中所说,这一步骤是将生成的batch_size大小的数组和t拼接起来,所以这里生成的数组就是y[0,1],y[1,3]。我之前也因为基础的问题在这里犯了错误,其实这里就是很简单的在数组y中拿出第0行一列和第一行三列的的值

                                                                就是这里的1和0.8

然后对他们进行交叉熵损失求和就是最后的结果了。

但是在这里得到[1.  0.8]之后我之前还是看不懂log[1.  0.8]的意思。其实很简单的,numpy里的函数都是可以处理数组的,输入数组输出也是数组。最后的结果就是将他们相加然后处于batch_size求均值啦!

 

 

 


代码实现

最后在了解了相关函数后,我们用自己编写的数据实现书中的代码吧!

import numpy as np

y = np.array([[0.1,0.05,0.6,0.0,0.05,0.1,0.0,0.1,0.0,0.0],
              [0.8,0.1,0.0,0.0,0.05,0.0,0.0,0.05,0.0,0.0],
              [0.0,0.1,0.1,0.0,0.0,0.05,0.05,0.7,0.0,0.0],
              [1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0],
              [0.2,0.2,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.6]])

t_one_hot = np.array([[0,0,1,0,0,0,0,0,0,0],
                      [1,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,1,0,0],
                      [0,0,0,0,1,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,1]])  #one-hot

t = t_one_hot.argmax(axis=1)
print(t)

def cross_entropy_error_one_hot(y,t_one_hot):  #独热编码的交叉熵损失
    if y.ndim == 1:
        t_one_hot = t_one_hot.reshape(1, t_one_hot.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(t_one_hot * np.log(y + 1e-7)) / batch_size

def cross_entropy_error(y,t):           #标签形式的交叉熵损失
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size #y[0,2] y[1,0] y[2,7] y[3,4] y[4 9]

print("loss by one_hot= :" , cross_entropy_error_one_hot(y, t_one_hot))
print("loss = :" , cross_entropy_error(y, t))

这里的数据是我自己瞎想的,只要满足和为1就可以了嘛,因为要原原本本的复现MNIST,还需要下载数据集,我这里偷懒就不做了,最后我们得到的结果如图:

可以看到我们的结果是一样的! 

以上就是全部内容了,博主也只是刚入门深度学习的小萌新(可能连入门还算不上),一直都想有自己的方式记录学习的过程,以上内容也是我查阅别人的博客后自己写出来的一些感想吧,学习永远都没有捷径,只能一步步的来,虽然这只是一个非常简单的小问题,但是我还是决定记录一下,至少证明我们曾来过~

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值