动手实现深度神经网络2 增加批处理
在上一部分中,我们构造了一个简单的两层神将网络,上文中那个网络使用数值微分计算梯度,没有实现批处理,所以可以认为时不可用的。在着一部分中,批处理将会被实现
。
得益于numpy的广播属性,我们要实现批处理不难。简单来说,我们原来的网络中,每次输入都是一个有784个元素的二维矩阵,而加入我们每次输入一批数据(例如200条),那输入就是一个200*784的二维矩阵
。
那么我们来看看代码中有哪些地方需要为批处理的实现做修改
1.对神经网络类的修改
下面是原来实现的神经网络的主要代码
# 经过两层运算
def predict(self,x):
# 取出参数
w1,b1=self.params['w1'],self.params['b1']
w2,b2=self.params['w2'],self.params['b2']
a1=np.dot(x,w1)+b1
#一 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
z1=sigmoid(a1)
a2=np.dot(z1,w2)+b2
#一 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
y=softmax(a2)
return y
# 求损失函数值
def loss(self,x,t):
y=self.predict(x)
#二 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
return cross_entropy_error(y,t)
# 求个损失函数值关于各个参数的梯度
def gradient_numerical(self,x,t):
loss_W=lambda w:self.loss(x,t)
grads={
}
#三 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
grads['w1'] = numerical_gradient_2d(loss_W, self.params['w1'])
grads['b1'] = numerical_gradient_onenumber(loss_W, self.params['b1'])
grads['w2'] = numerical_gradient_2d(loss_W, self.params['w2'])
grads['b2'] = numerical_gradient_onenumber(loss_W, self.params['b2'])
return grads
# 计算准确率
def accuracy(self, x, t):
y = self.predict(x)
#四 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
y=np.argmax(y)
t=np.argmax(t)
return y==t
得益于numpy的广播机制,例如np.dot等操作就不需要修改了,可能需要修改的部分我都已经用感叹号
做了标注,接下来我们一个一个来看看。
1.1 sigmoid和softmax
我们先来看一下之前实现的sigmoid和softmax源代码
def sigmoid(x):
return 1 / (1 + np.exp(-x))
sigmoid只是简单的做矩阵运算,不管一维矩阵还是二维矩阵都不影响,所以sigmoid不需要修改。
def softmax(x):
# 这里就需要修改了
max = np.max(x)
x = x - max
return np.exp(x) / np.sum(np.exp(x))
**softmax中涉及到np.max操作这就需要修改了。**因为对二维矩阵做np.max操作只会返回最大的一个值,而我们需要的是每一条数据中的最大值。
幸好,np.max提供了 axis 参数
,具体来说就是对于二维矩阵np.max(x,axis=0)返回每列的最大值,np.max(x,axis=1)返回每行的最大值。
a_2d=np.array([[0.1,0.05,0.6,0.05,0.05,0.05,0.01,0.01,0.02,0.06],
[0.8,0.05,