学习神经网络算法(python复现)
参考
- 学习神经网络算法时,发现了一份很好的帖子,重复进行了相关实验:https://juejin.im/post/6844903798704455694
环境搭建
- 安装virtualenv,进入虚拟环境进行相应配置;
- 安装 jupyter matplotlib numpy scipy;
#安装virtualenv
pip3 install virtualenv
#创建虚拟环境
virtualenv env
#windows下启动虚拟环境
env\Scripts\activate
#安装依赖
pip3 install --upgrade matplotlib jupyter numpy scipy
#启动jupyter
jupyter notebook
算法实现
搭建神经网络,简单勾勒出神经网络的样子,需要3个函数:
- 初始化函数-设定输入层,隐含层,输出层,随机生成权重
- 训练,学习相关样本,调整权重
- 查询,根据给定的权重,获取预测结果
code
# 引入依赖库
import numpy as np
import scipy.special
import matplotlib.pyplot
# 神经网络类定义
class neuralNetwork:
def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate):
"""初始化神经网络"""
#设置输入层,隐藏层,输出层结点的数量
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
#连接权重,随机生成输入层到隐藏层和隐藏层到输出层的权重
# rand()生成指定维度矩阵的0-1范围的随机数,减去0.5后权重值位于-0.5-0.5之间
self.wih = np.random.rand(self.hnodes, self.inodes) - 0.5
self.who = np.random.rand(self.onodes,self.hnodes) - 0.5
#学习率
self.lr = learningrate
#将激活函数设置为sigmoid函数
self.activation_function = lambda x: scipy.special.expit(x)
pass
def query(self,inputs_list):
"""查询神经网络"""
#将输入的数组转化为1个二维数组,第二个输出参数表示维度(并转置)
inputs = np.array(inputs_list,ndmin=2).T
#计算输入数据与权重的点积
hidden_inputs = np.dot(self.wih,inputs)
#经过激活函数到隐藏层数据
hidden_outputs = self.activation_function(hidden_inputs)
#计算隐藏层数据与权重的点积
final_inputs = np.dot(self.who,hidden_outputs)
final_outputs = self.activation_function(final_inputs)
return final_outputs
def train(self, inputs_list, targets_list):
"""训练神经网络"""
#将输入数据与目标数据转换为二维数组
inputs = np.array(inputs_list, ndmin=2).T
targets = np.array(targets_list,ndmin=2).T
#通过矩阵点积与激活函数得到隐藏层的输出
hidden_inputs = np.dot(self.wih,inputs)
hidden_outputs = self.activation_function(hidden_inputs)
#通过矩阵点积与激活函数得到最终输出
final_inputs = np.dot(self.who, hidden_outputs)
final_outputs = self.activation_function(final_inputs)
#获取目标值与实际值的差值
output_errors = targets - final_outputs
#反向传播差值
hidden_errors = np.dot(self.who.T , output_errors)
#通过梯度下降法更新隐藏层到输出层的权重
self.who += self.lr * np.dot(
(output_errors * final_outputs * (1.0 - final_outputs)),
np.transpose(hidden_outputs)
)
#通过梯度下降法更新输入层到隐藏等的权重
self.wih += self.lr * np.dot(
(hidden_errors * hidden_outputs * (1.0 - hidden_outputs)),
np.transpose(inputs)
)
pass
# 进行训练
# 设置每一层的结点数量
input_nodes = 784
hidden_nodes = 100
output_nodes = 10
# 学习率
learning_rate = 0.1
# 创建神经网络模型
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
#加载训练数据 1000个
training_data_file = open("./dataset/mnist_train_100.csv",'r')
training_data_lists = training_data_file.readlines()
training_data_file.close()
# 训练神经网络
# epochs 表示训练次数
epochs = 10
for e in range(epochs):
# 遍历所有数据进行训练
for record in training_data_lists:
# 数据通过","分割,变成一个数组
all_values = record.split(',')
# 分离出图片的像素点到一个单独的数组
inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# 创建目标输出至(0-9出现的概率,默认全部是0.01)
targets = np.zeros(output_nodes) + 0.01
# all_values[0] 表示手写数字的真实值,将该数字的概率设为0.99
targets[int(all_values[0])] = 0.99
n.train(inputs,targets)
pass
pass
# 训练完毕
print('done')
#加载测试数据
test_data_file = open("./dataset/mnist_test_10.csv",'r')
test_data_list = test_data_file.readlines()
test_data_file.close()
# 测试神经网络
# 记录所有训练值,正确存1,错误存0
scorecard = []
# 遍历所有数据进行测试
for record in test_data_list:
#数据通过','分割变成1个数组
all_values = record.split(',')
#第一个数字为标签(正确答案)
correct_label = int(all_values[0])
#取出测试的数据并进行归一化处理
inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# 查询神经网络
outputs = n.query(inputs)
# 取出输出最大值作为预测输出
label = np.argmax(outputs)
# 打印出真实值与查询值
print('act: ', correct_label, 'pre: ',label)
if(label == correct_label):
#神经网络查询结果与真实值匹配,记录数组存入1
scorecard.append(1)
else:
#神经网络查询结果与真实值不匹配,记录数组存入0
scorecard.append(0)
pass
pass
#计算神经网络训练成功率
scorecard_array = np.asarray(scorecard)
print("performance = ", scorecard_array.sum() / scorecard_array.size)
思考
-
神经网络结点反向计算得到每个点的误差后,通过梯度下降法对权重进行更新,更新的公式参考西瓜书的章节如下,梯度下降法迭代公式的实现如下图:
-
计算神经网络隐层的反向误差时,使用权重矩阵的转置进行计算:
-
神经网络的权值矩阵初始化至0.5~-0.5之间;
-
神经网络输入的数据需要进行归一化处理,处理至合适范围;
-
输入结点x有h个,隐层结点n个,则输入层到隐藏的权重矩阵为 n × \times × h(n行h列) , 隐藏结点n个,输出层结点k个,则隐层到输出层的权重矩阵为k × \times ×h,从误差(实际值与输出预测值之差)反向计算隐藏误差时,误差左乘权重矩阵的转置即可获得相应的结果;