一 、基本原理
分类器
形如y=ax+b
的简单线性分类器
误差值 = (期望目标值 - 实际输出值)
E=t-y
E=(ΔA)x
ΔA是斜率差
ΔA=L(E/x)
L为调节系数,称为学习率
激活函数
神经元是输出超过了阈值(threshold)才会产生输出信号,可以通过激活函数完成。阶跃函数就是一种激活函数。阶跃函数变得平滑一些更符合实际,称为S函数(Sigmoid function),信号函数。
S函数有时也称为逻辑函数:
输入值及输出值计算
如果神经网络有多层,则x为组合调节后的信号,表示:
W是权重矩阵,I是输入矩阵。神经网络层输出:O=sigmoid(X)
,O代表输出矩阵
以隐藏层组合调节输入值为例,X看做Xhidden
对应两个输入的矩阵如下:
其中I
为上一层输入,W
为隐藏层权重
矩阵相乘,第一个矩阵的列数应该等于第二个矩阵的行数。矩阵乘法又称为点乘(dot product)或内积(inner product)
每层输出都需要应用激活函数,例如:
反向误差传播
输出节点的误差等于所需值与实际值的差值。但是内部节点的误差并不显而易见,一种方法就是按照链路权重比例分割输出层的误差,然后在每个内部节点充足这些误差。隐藏层误差公式:
隐藏层矩阵误差表示如下:
这些分数的分母是归一化因子,如果我们忽略因子,仅仅失去后馈误差的大小。我们可以通过e1*w1,1 代替e1 * w1,1/(w1,1+w2,1)
那么隐藏层矩阵误差表示如下:
我们可以发现这个W矩阵是组合调节后的信号公式中W矩阵的转置,故此处可以通过wT表示该处的矩阵。
权重更新
二、数字识别神经网络
神经网络分为三部分
- 神经网络初始化
- 训练神经网络
- 调用神经网络
下面展示了最简单数字识别神经网络
import numpy
import scipy.special
# 该神经网络有三层,输入层、隐藏层和输出层
class NeuralNetwork:
# 初始化神经网络
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
# 设置每层节点数量
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
# 学习率
self.lr = learningrate
# 权重形式
# w11 w21
# w21 w22 etc,故对于W_input_hidden来说列数为inodes,行数为hnodes
# self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5
# self.who = numpy.random.rand(self.onodes, self.hnodes) - 0.5
# 采用正太分布优化权重取值,标准差为1/(传入连接数目的0.5次方)
self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes))
# 激活函数
self.activation_function = lambda x: scipy.special.expit(x)
pass
# 根据正确的输入值和目标值训练神经网络,找到更合适的权重
def train(self, inputs_list, targets_list):
inputs = numpy.array(inputs_list, ndmin=2).T; # 列表转化为二维数组
targets = numpy.array(targets_list, ndmin=2).T;
hidden_inputs = numpy.dot(self.wih, inputs)
hidden_outputs = self.activation_function(hidden_inputs)
final_inputs = numpy.dot(self.who, hidden_outputs)
final_outputs = self.activation_function(final_inputs)
output_errors = targets - final_outputs;
# errors_hidden = W_hidden_output.T error_output
hidden_errors = numpy.dot(self.who.T, output_errors)
self.who += self.lr * numpy.dot(output_errors * final_outputs * (1.0 - final_outputs),
numpy.transpose(hidden_outputs))
self.wih += self.lr * numpy.dot(hidden_errors * hidden_outputs * (1.0 - hidden_outputs),
numpy.transpose(inputs))
# 根据输入求输出
def query(self, inputs_list):
inputs = numpy.array(inputs_list, ndmin=2).T
# X_hidden = W_input_hidden I
hidden_inputs = numpy.dot(self.wih, inputs)
# O_hidden = sigmoid(X_hidden)
hidden_outputs = self.activation_function(hidden_inputs)
# 输出层计算
final_inputs = numpy.dot(self.who, hidden_outputs)
final_outputs = self.activation_function(final_inputs)
return final_outputs
训练神经网络
input_nodes = 784 # 数字的像素为28x28,故输入节点为784个
hidden_nodes = 100
output_nodes = 10 # 表示0~9,10个数字
learning_rate = 0.3
n = NeuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
training_data_file = open("mnist_dataset/mnist_train.csv", 'r') # 训练数据
training_data_list = training_data_file.readlines()
training_data_file.close()
for record in training_data_list:
all_values = record.split(',')
inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 # 输入数据要在[0.01,1]之内
targets = numpy.zeros(output_nodes) + 0.01 # 初始10个为0.01的列表
targets[int(all_values[0])] = 0.99 # 目标值为0.99
n.train(inputs, targets) # 调用神经网络进行训练
测试神经网络
test_data_file = open('mnist_dataset/mnist_test.csv', 'r') # 测试数据
test_data_list = test_data_file.readlines()
test_data_file.close()
scorecard = []
for record in test_data_list:
all_values = record.split(',')
correct_label = int(all_values[0])
# print('correct_label={0}'.format(correct_label))
inputs_list = numpy.asfarray(all_values[1:])/255.0 * 0.99 + 0.01
outputs = n.query(inputs_list)
label = numpy.argmax(outputs) # 找到输出数组中最大值的索引,其对应的就是实际识别的数字
# print("network's answer={0}",label)
if(label == correct_label) : # 数字识别正确加1,否则加0
scorecard.append(1)
else :
scorecard.append(0)
scorecard_array = numpy.asarray(scorecard)
print('performance = ', scorecard_array.sum()/scorecard_array.size)
最终识别率在94.7%
一些改进
-
调整学习率
性能与学习率关系
学习要选取合适,并不是越大越好,也不能偏小,可以根据多次实验选取最佳学习率,该例学习率为0.2时,性能更好为95.13%
-
多次运行
训练一次称为1个世代,看看同样的训练数据是否会改善性能
性能和世代关系
在7个世代性能高达96.28%
在提高世代时调低学习率也会有一定改善
学习率分别为0.1,和0.2,学习率为0.1时,世代为5时性能最高,达96.89%
-
改变网络形状
输入和输出不能改变,但隐藏层节点个数可以调整。
性能和隐藏层节点个数关系
整体看来隐藏层节点越大,性能越高,前100个节点性能增长非常快,在到达200个节点时性能已经基本没有改善,为了神经网络的执行时间更短,我们可以选择节点200。
网友评论