搜尋
一、前文回顾
神经网络的基本知识已经全部介绍完了。主要包括了以下几个:
①激活函数
②softmax函数
③损失函数
④批处理
⑤梯度
⑥梯度下降法
今天就把这些都归纳起来,然后完整的实现神经网络的自主学习过程。
二、神经网络的自主学习流程
以前也有提到过,神经网络所谓的自主学习,其实就是一个寻找最佳权重参数值的过程。或者说寻找损失函数最小值的过程。归纳起来的话主要是以下几个步骤。
①随机选取样品从大量的训练数据中随机选择一部分进行训练。
②求梯度为了获取损失函数的最小值,求出权重参数的梯度。
③更新权重参数沿着梯度方向对权重参数进行一次细微的调整。
④重复上面①②③
三、实现神经网络
1.先定义一个神经网络类。
# 定义神经网络类
class DeepVisionZeroNet:
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
# 权重初期化
# 初始化参数W1(形状为input_size行,hidden_size列,大小在0-1之间并且符合高斯分布的数组)
# 初始化参数W2(形状为hidden_size行,output_size列,大小在0-1之间并且符合高斯分布的数组)
self.params = {'W1': weight_init_std * np.random.randn(input_size, hidden_size), 'b1': np.zeros(hidden_size),
'W2': weight_init_std * np.random.randn(hidden_size, output_size), 'b2': np.zeros(output_size)}
# 推理
def predict(self, x):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1 # W1*x+b1
z1 = sigmoid(a1) # 1 / (1 + np.exp(-a1)) 激活函数
a2 = np.dot(z1, W2) + b2 # z1*W2+b2
y = softmax(a2) # softmax函数
return y
# 求损失函数值
# x:样本数据
# t:标签(正确答案)
def loss(self, x, t):
# 先推理
y = self.predict(x)
# 求出推理值和正确值之间的差距:损失函数值
return cross_entropy_error(y, t)
# 计算神经网络的识别准确率
# 样本识别正确数/样本总数
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
#
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
# 求梯度
def numerical_gradient(self, x, t):
# 设定损失函数
loss_W = lambda W: self.loss(x, t)
# 求出每一个参数的梯度
grads = {'W1': numerical_gradient(loss_W, self.params['W1']),
'b1': numerical_gradient(loss_W, self.params['b1']),
'W2': numerical_gradient(loss_W, self.params['W2']),
'b2': numerical_gradient(loss_W, self.params['b2'])}
return grads
# 保存权重参数
def save_params(self, file_name="params_two_layer.pkl"):
params = {}
for key, val in self.params.items():
params[key] = val
with open(file_name, 'wb') as f:
pickle.dump(params, f)
2.实现神经网络学习过程。
if __name__ == "__main__":
# 读取MNIST手写数字集(详细参考第七弹)
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
print("x_train:", x_train.shape)
print("t_train:", t_train.shape)
print("x_test:", x_test.shape)
print("t_test:", t_test.shape)
# 实例化神经网络
network = DeepVisionZeroNet(input_size=784, hidden_size=50, output_size=10)
step_num = 10000 # 设定梯度下降法的步数
train_size = x_train.shape[0]
batch_size = 100 # 批处理数
learning_rate = 0.1 # 设定梯度下降法的步长(学习率)
# 记录损失函数值
train_loss_list = []
# 记录训练精度
train_acc_list = []
# 记录测试精度
test_acc_list = []
# 每iter_per_epoch次保存一次训练精度和测试精度
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(step_num):
# 随机选取batch_size个样品
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 计算梯度
grad = network.numerical_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(i, " train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "Number of steps completed:", i)
# 保存最终的权重参数
network.save_params()
# 把训练精度和损失精度用图标表示出来
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
四、总结
虽然我们实现了神经网络的学习过程,但是很遗憾,我自己的电脑运行起来的话,每一步大概需要45秒,10000步(step_num)的话大概需要125小时,这是一个很漫长的过程。一个最简单的神经网络却需要花费这么多时间,那要是几十层的神经网络岂不是得几十年了,显然这很不现实。下节就要来说说为什么这么慢,以及怎么解决。
Comments