神经网络初识&MNIST数据集

《Python神经网络编程》 实践笔记,按照原书中 Chapter2 尝试复现了一个简单的识别手写数字的神经网络

神经网络代码框架

class neuralNetwork:
    def __init__():
    	pass

    def train():
        pass
        
    def query():
        pass

我们先填写简单的初始化部分:
我们只打算实现一个简单的三层神经网络模型,包括输入层,隐藏层,输出层。确定了神经网络的架构后就很容易能确定需要的参数了,输入节点的个数,隐藏层节点个数,输出层节点个数。同时还需要设置神经网络的学习率 (learning rate)

def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        self.lr = learningrate

重头戏是各传输链接权重,由于我们使用Sigmoid函数做激励函数以及梯度下降法更新权重,我们不希望初始权重值过大,这会使得输出值过大,激励函数的斜率趋于平坦,让神经网络学习能力下降,同样我们也不能将权重设置为0或者设定为相等的值(反向传播时不断平分误差)这里使用用书上推荐的方法设置初始权重:
在这里插入图片描述

		self.wih = np.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
        self.who = np.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))  # -1/sqrt(传入链接数) - 1/sqrt(传入链接数) 正态分布

W i h W_{ih} Wih为 input 层到 hidden 层的链接权重矩阵, W h o W_{ho} Who为 hidden 层到 output 层的链接权重矩阵,注意矩阵大小分别为 h n o d e s × i n o d e s hnodes\times inodes hnodes×inodes以及 o n o d e s × h n o d e s onodes\times hnodes onodes×hnodes

接着我们再做次简单的工作:query :
只需要将输入矩阵与各权重矩阵相乘最后返回输出层节点的输出即可,先导入Scipy高级科学计算库:

import scipy.special as sp

接着定义激励函数:

	def activation(self, x):       #Sigmoid(x)
        return sp.expit(x)

也可以在init函数中:

	self.activation = lambda x : sp.expit(x)

q u e r y query query函数:

	def query(self, inputs):
        hidden_inputs = np.dot(self.wih, inputs)
        hidden_outputs = self.activation(hidden_inputs)
        final_inputs = np.dot(self.who, hidden_outputs)
        return self.activation(final_inputs)

接下来是train函数,先捋一下思路,我们首先要计算出训练集每个输入的输出结果,然后与标准答案比对计算出误差,反向传播误差并更新各边权重,第一部分与 q u e r y query query函数一致:

	def train(self, inputs, std):
        inputs = np.array(inputs, ndmin = 2).T
        std = np.array(std, ndmin = 2).T                       #转换为矩阵并转置 3*1

        hidden_inputs = np.dot(self.wih, inputs)
        hidden_outputs = self.activation(hidden_inputs)
        final_inputs = np.dot(self.who, hidden_outputs)
        final_outputs = self.activation(final_inputs)          #计算outputs

回头看一下第一章推导出来的权重更新公式:
在这里插入图片描述
其中 ∗ * 代表正常对应元素乘法, ⋅ \cdot 代表矩阵乘法

		error = std - final_outputs                            #计算误差,准备反向传递
        hidden_err = self.who.T.dot(error)
        self.who += self.lr * np.dot(error * final_outputs * (1 - final_outputs), hidden_outputs.T)
        self.wih += self.lr * np.dot(hidden_err * hidden_outputs * (1 - hidden_outputs), inputs.T)

训练神经网络

至此这个简单的三层神经网络模型搭建完成,我们将要使用MNIST训练集训练这个简单的模型使其能够识别手写数字,访问这个网站可以直接得到两个数据集的csv格式文件

书上分别先给了两个小训练集以及测试集,我们先来热热身:

首先思考一下需要多少个各层节点,我们知道图片大小为28*28,共784个像素点,值处于(0,255)之间,故输入层节点设置为784个。考虑我们的神经网络的功能:神经网络需要判断这个图片对应是哪一个数字,数字一共10个(0到9),故我们设计10个输出层节点,输入图片对应数字为8时,第八个输出节点输出值最高,处于激发态,其余节点输出值均很低,处于抑制态。至于中间层节点,我们期待神经网络其能发现我们所发现不了的规律,所以设置的值小于784,但又不能太小,否则学不下所需的知识,先设置成100试试(实际上越大程序跑的越慢):

	N = neuralNetwork(28 * 28, 100, 10, 0.3)

读取文件:

	data_file = open("mnist_train_100.csv", "r") # "r" - 只读
    data_list = data_file.readlines()            # 读一行并全部存在内存里
    data_file.close()

我们还需要对数据进行处理,比如将数字之间的逗号去掉,将所有数值归一化使其值处于(0,1)中,同时将0替换成0.01等:
(传入train的只需要是数列即可,函数内部会将其转换为矩阵)

	for i in range(len(data_list)):
        val = data_list[i].split(',')
        val_arr = np.asfarray(val[1:])#.reshape(28, 28)

        #可视化数据
        #plt.imshow(val_arr, cmap="Greys")
        #plt.show()

        std_inputs = val_arr / 255 * 0.99 + 0.01              #归一化输入数据
        std_outputs = np.zeros(10) + 0.01                     #设置标准输出
        std_outputs[int(val[0])] = 0.99

        N.train(std_inputs, std_outputs)

也可以将上面代码注释段去掉,看看图片到底长啥样:
大致长这样
接下来就是激动人心的时刻辣,看看我们100次训练后的神经网络表现如何:

	test_file = open("mnist_test_10.csv", "r")
    test_list = test_file.readlines()
    test_file.close()

    for i in range(10):
        val = test_list[i].split(',')
        val_arr = np.asfarray(val[1:])
        
        print(val[0])
        img_arr = val_arr.reshape(28, 28)
        plt.imshow(img_arr, cmap = "Greys")

        print(N.query(val_arr))
        plt.show()

上面这个代码可以看到图片和输出的值,但是如果我们只关心哪几个对了哪几个错了:

	score = []
    for rec in test_list:
        rec_arr = rec.split(',')
        rec_arr = np.asfarray(rec_arr)

        std_ans = rec_arr[0]
        ans = np.argmax(N.query(rec_arr[1:]))
        if ans == std_ans:
            score.append(1)
        else:
            score.append(0)   
    print(score)
    print(sum(score))

输出:
[ 1 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ] [1, 0, 1, 1, 1, 1, 1, 0, 0, 0] [1,0,1,1,1,1,1,0,0,0]
6 6 6
正确率百分之60……勉强及格了吧

接下来试试全训练集以及全数据集吧:修改一下两次open的文件名即可(记得close)

data_file = open("mnist_train.csv", "r")
test_file = open("mnist_test.csv", "r")

输出:
9451 9451 9451
将近95%的准确率了,已经是相当不错的成绩了


关于MNIST数据集

Mnist数据集简介
如果想知道MNIST数据集格式以及查看方法可以看一下上面的博客,附我的代码:

import numpy as np
import struct
import matplotlib.pyplot as plt

with open('t10k-labels.idx1-ubyte', 'rb') as lbfile:
    labels_magic, labels_num = struct.unpack('>II', lbfile.read(8))
    labels = np.fromfile(lbfile, dtype=np.uint8)

with open('t10k-images.idx3-ubyte', 'rb') as imgfile:
    img_magic, img_num, img_row, img_column = struct.unpack('>IIII', imgfile.read(16))
    img = np.fromfile(imgfile, dtype=np.uint8).reshape(img_num, img_row * img_column)

#plt.imshow(img[1].reshape(28,28),cmap="Greys")
#plt.show();

data = []

for i in range(len(labels)):
    data.append(np.append(labels[i], img[i]))

np.save("test.npy", data)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值