说明:通过计算图,人们可以直观地把握整个计算过程,计算图的节点是由局部构成的,局部计算构成全局计算。建议自己动手手推BP(反向传播)神经网络!注:以下代码和内容都是学习《深度学习入门》一书的学习笔记。
import numpy as np
class Addlayer:#加法层
def __init__(self):
pass
def forward(self,x,y):
out=x+y
return out
def backward(self,dout):
dx=dout*1
dy=dout*1
return dx,dy
class Mulayer:#乘法层
def __init__(self):
self.x=None
self.y=None
def forward(self,x,y):
self.x=x
self.y=y
out =x*y
return out
def backward(self,dout):
dx=dout*self.y
dy=dout*self.x
return dx,dy
熟悉上面这个过程之后,以后就只要关注下面这个输入和输出就OK了。
以下为python代码实现方式
class Sigmoid:
def __init__(self):
self.out = None
def forward(self, x):
out = sigmoid(x)
self.out = out
return out
def backward(self, dout):
dx = dout * (1.0 - self.out) * self.out
return dx
class Affine:
def __init__(self,W,b):
self.W=W
self.b=b
self.X = None
self.dW=None
self.db=None
def forward(self,x):
self.x=x
out=np.dot(x,self.W)+self.b
return out
def backward(self,dout):
self.dx = np.dot(dout , self.W.T)
self.dW=np.dot(self.x.T,dout)
self.db=np.sum(dout,axis=0)#为什么是求和?
return dx
问题:为什么Affine层反向传播过程中,db是对dout的列求和?
参见损失值对b的梯度
class SoftmaxWithLoss:
def __init__(self):
self.loss = None
self.y = None # softmax的输出
self.t = None # 监督数据
def forward(self, x, t):
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
def backward(self, dout=1):
batch_size = self.t.shape[0]
if self.t.size == self.y.size: # 监督数据是one-hot-vector的情况
# test=self.y - self.t
dx = (self.y - self.t) / batch_size
else:
dx = self.y.copy()
dx[np.arange(batch_size), self.t] -= 1
dx = dx / batch_size#为什么要除以batch_size的大小?
return dx
# coding: utf-8
import sys, os
sys.path.append(os.pardir)
import timejiqiao
import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
from common.util import smooth_curve
import matplotlib.pyplot as plt
start = time.time()
# 读入数据
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_sizejiqiao=10)
iters_num = 10000#迭代次数
train_size = x_train.shape[0]
batch_size = 100jiqiao
learning_rate = 0.1jiqiao
jiqiao
train_loss_list = []
train_acc_list = []
test_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(iters_num):
batch_mask = np.random.choice(train_size, batch_size)#随机选择了100组数据
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 梯度
# grad = network.numerical_gradient(x_batch, t_batch)
grad = network.gradient(x_batch, t_batch)
# 更新
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
print(train_acc, test_acc)
print(len(train_loss_list))
x=np.arange(iters_num)
plt.plot(x, smooth_curve(train_loss_list))
plt.xlabel("iterations")
plt.ylabel("loss")
plt.title("gradient")
# plt.title("numerical_gradient")
# plt.legend()
plt.show()
end = time.time()
print("time: ",str(end-start)+"s ")
w = np.random.randn(node_num, node_num) * 1
从上图中可以看出大多数数据会偏向0和1的情况,所以随着学习的不断进行,反向传播的值会不断减小,最终会消失,这个就叫做梯度消失?->怎么样解决梯度消失,更换激活函数或者更改权重的标准差
若改变上面语句为
w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num)
实验结果就为如下图所示,这里做了仅仅是将权重的初始值使用标准差为1/(根号n)的高斯分布进行初始化。
下面,这里展示基于std=0.01,Xavier初始值、he初始值(激活函数使用ReLU函数、标准差为根号2/n)的训练数据比较。
训练集的数量级和模型的复杂度不匹配。训练集的数量级要小于模型的复杂度;
训练集和测试集特征分布不一致;
样本里的噪音数据干扰过大,大到模型过分记住了噪音特征,反而忽略了真实的输入输出间的关系;
权值学习迭代次数足够多(Overtraining),拟合了训练数据中的噪声和训练样例中没有代表性的特征
方法-> 权值衰减(在学习的过程中对打的权重进行惩罚)
通过前六章的学习,大致明白了神经网络的学习层次,以及各种优化的方法,最后得出一个结论是应该多动手去算,最底层就是数学推导的过程,多想想为什么?换一种方式可不 可以?