全连接神经网络识别手写数字
先放代码链接: https://github.com/EricEricEricJin/Written-Number-Recogonizice
目录
- 搭建神经网络
- 下载手写数字数据集
- 训练模块
- 读取和处理数据集
- 初始化神经网络类
- 训练
- 测试模块
- 导入 处理数据集(和前文的类似)
- 初始化和加载权重矩阵
- 测试
搭建神经网络
算法,实现 略
我参照了《Python神经网络编程》一书。书中的3层神经网络的示例代码:https://github.com/makeyourownneuralnetwork/makeyourownneuralnetwork/blob/master/part2_neural_network.ipynb
我在其基础上改为了多层,并增加了存储、加载权重矩阵的函数 SaveWeight
和 LoadWeight
。代码:https://github.com/EricEricEricJin/multi-layer-neuralnetwork
import numpy
import scipy.special
class neuralnetwork:
def __init__(self, nodes_list, learningrate, layer):
#变量初始化
self.weights_list = [] #i-1个
self.nodes_list = nodes_list #i个
self.lr = learningrate
self.layer = layer
#初始化权重
for i in range (self.layer - 1):
self.weights_list.append (numpy.random.rand(self.nodes_list[i + 1], self.nodes_list[i]) - 0.5)
#激活函数
self.activation_function = lambda x: scipy.special.expit(x)
def train(self, inputs, targets):
inputs_list = [] #i个
outputs_list = [] #i-1个
errors_list = [] #i-1个
#第0层的输入
inputs_list.append (numpy.array(inputs, ndmin = 2).T)
#目标
targets_list = numpy.array(targets, ndmin = 2).T
#输入输出计算
inputs_list.append (numpy.dot(self.weights_list[0], inputs_list[0]))
outputs_list.append (self.activation_function (inputs_list[1]))
for i in range (self.layer - 2):
inputs_list.append (numpy.dot(self.weights_list[i+1], outputs_list[i])) #
outputs_list.append (self.activation_function(inputs_list[i+2]))
#误差计算 从后往前
#error是反的!!!
errors_list.append (targets_list - outputs_list[self.layer - 2])
for i in range (self.layer - 2):
errors_list.append (numpy.dot(self.weights_list[self.layer - 2 - i].T, errors_list[i]))
#权重更新
for i in range (self.layer - 2):
self.weights_list[self.layer - 2 - i] += self.lr * numpy.dot((errors_list[i] * outputs_list[self.layer - 2 - i] * (1 - outputs_list[self.layer - 2 - i])), numpy.transpose(outputs_list[self.layer - 3 - i]))
self.weights_list[0] += self.lr * numpy.dot((errors_list[self.layer - 2] * outputs_list[0] * (1 - outputs_list[0])), numpy.transpose(inputs_list[0]))
def SaveWeight(self, filepath):
m = numpy.array(self.weights_list)
numpy.save(filepath, m)
def LoadWeight(self, filepath):
self.weights_list = numpy.load(filepath)
def query(self, inputs):
inputs_list = []
outputs_list = []
inputs_list.append (numpy.array(inputs, ndmin = 2).T)
inputs_list.append (numpy.dot(self.weights_list[0], inputs_list[0]))
outputs_list.append (self.activation_function(inputs_list[1]))
for i in range (self.layer - 2):
inputs_list.append (numpy.dot(self.weights_list[i + 1], outputs_list[i]))
outputs_list.append (self.activation_function(inputs_list[i+2]))
return outputs_list[self.layer - 2]
下载手写数字数据集
我用的阿里天池数据集 原链接忘记存了 可以从我的GitHub上下载:https://github.com/EricEricEricJin/Written-Number-Recogonizice/blob/master/train.zip
是个CSV文件 长这个样子:
训练模块
读取和处理数据集
使用python内置的csv
模块, 把数据集读为二维列表TrainingData
代码:
import csv
TrainFile = open("train.csv", "r")
TrainingData = []
Reading = csv.reader(TrainFile)
for row in Reading:
TrainingData.append(row)
对于每一条(也就是CSV里的一行)数据我们这样处理:
通过Label对应写Target(这里对应如下表),并且把TrainingData里的Input归一
Label | Target |
---|---|
0 | [1,0,0,0,0,0,0,0,0,0] |
1 | [0,1,0,0,0,0,0,0,0,0] |
2 | [0,0,1,0,0,0,0,0,0,0] |
3 | [0,0,0,1,0,0,0,0,0,0] |
4 | [0,0,0,0,1,0,0,0,0,0] |
… | … |
8 | [0,0,0,0,0,0,0,0,1,0] |
9 | [0,0,0,0,0,0,0,0,0,1] |
代码:
Targets = []
for i in range(len(TrainingData) - 1):
cond = int(TrainingData[i+1][0])
if cond == 0:
Targets.append([1,0,0,0,0,0,0,0,0,0])
elif cond == 1:
Targets.append([0,1,0,0,0,0,0,0,0,0])
elif cond == 2:
Targets.append([0,0,1,0,0,0,0,0,0,0])
elif cond == 3:
Targets.append([0,0,0,1,0,0,0,0,0,0])
elif cond == 4:
Targets.append([0,0,0,0,1,0,0,0,0,0])
elif cond == 5:
Targets.append([0,0,0,0,0,1,0,0,0,0])
elif cond == 6:
Targets.append([0,0,0,0,0,0,1,0,0,0])
elif cond == 7:
Targets.append([0,0,0,0,0,0,0,1,0,0])
elif cond == 8:
Targets.append([0,0,0,0,0,0,0,0,1,0])
elif cond == 9:
Targets.append([0,0,0,0,0,0,0,0,0,1])
for j in range(len(TrainingData[0]) - 1):
TrainingData[i+1][j+1] = int(TrainingData[i+1][j+1]) / 255
初始化神经网络类
文件头上要导入之前(<搭建神经网络>里)写的神经网络代码
NL = [len(TrainingData[1]) - 1, int((len(TrainingData[1]) - 1) / 1.5), int((len(TrainingData[1]) - 1)/2.5), 10]
LR = 0.1
L = len(NL)
ann = mla.neuralnetwork(NL, LR, L)
NL: Network Layer, 描述神经网络每层的节点数。如:[1,2,3]意为三层,第一层1个节点,第二层2个节点,第三层3个节点
LR: Learning Rate, 学习率 决定神经网络的学习速度
训练
有的时候我们可能需要在之前训练的权重的基础上再训练,所以这里我写了:
LW = input("load weight? yes/no")
if LW == "yes":
ann.LoadWeight("new_a.npy")
注意:如果放在服务器上不挂起的跑的话,无法接受键盘标准输入,是否加载权重要写死
然后开始训练:
for num in range(5): # 训练5次
for i in range(len(TrainingData) - 1):
ann.train(TrainingData[i+1][1:], Targets[i])
#print("---", num+1, "---", i+1, "---")
ann.SaveWeight("new_a.npy")
print("Training: time(s):", num+1)
这样你训练过的权重矩阵就被存到new_a.npy
里了。文件名根据个人喜好和规范设定, 扩展名.npy
是numpy数组的格式
测试模块
Good. 现在开始测试训练的模型的准确率。
导入 处理数据集 (和前文的差不多)
由于我用的test.csv里没有label(???鬼知道为什么),此处使用train.csv(之前用来训练的数据集)来测试(这样做是不正确的,可能会导致测试准确率偏高)
import csv
TrainFile = open("train.csv", "r")
TrainingData = []
Reading = csv.reader(TrainFile)
for row in Reading:
TrainingData.append(row)
for i in range(len(TrainingData) - 1):
TrainingData[i+1][0] = int(TrainingData[i+1][0])
for j in range(len(TrainingData[0]) - 1):
TrainingData[i+1][j+1] = int(TrainingData[i+1][j+1]) / 255
初始化神经网络和计数变量,并且加载之前训练好的权重矩阵 (和前文的差不多)
NL = [len(TrainingData[1]) - 1, int((len(TrainingData[1]) - 1) / 1.5), int((len(TrainingData[1]) - 1)/2.5), 10]
LR = 0.1
L = len(NL)
nn = mla.neuralnetwork(NL, LR, L)
nn.LoadWeight("new_a.npy")
right = 0
wrong = 0
测试
由于我们之前设置Targets的方法(可以回去康一眼),我们现在看输出列表中最大的数字的index就是图片里的数字。
for i in range(len(TrainingData) - 1):
output = nn.query(TrainingData[i + 1][1:])
output_index = 0
for j in range(10):
if (output[j] > output[output_index]):
output_index = j
if output_index == TrainingData[i + 1][0]:
right += 1
#print("#", i+1, " correct!")
else:
wrong += 1
#print("#", i+1, " wrong!")
#print("R: ", right, " W: ", wrong)
print("\n\nRate: ", right / (right + wrong))
打印出来的就是你的准确率了。