深度学习之BP神经网络识别手写数字(五)

本节使用MNIST数据集作为输入数据。

根据MNIST数据集的特性:
每张图片为28*28,其中大约有60000个手写字体训练样本。因为是对数字的识别,所以输出的范围为0~9。这就类似于一个10分类的问题。

构建神经网络

输入层需要28*28个节点,输出成需要10个节点。对于隐藏层的层数以及节点数的判定是一个技术活。不过对于全连接网络来说,一般隐藏层不要超过三层,当然如果层数越多,计算的难度肯定是越大。本次只设定一个隐藏层。
而隐藏层的节点数目的确定,有几个公式:


image.png

当然也没有特定的确定方式,一般就是哪个效果好使用哪个。
本次隐藏层节点定为:300
所以网络结构为:

Tables Cool
输入层 784
隐藏层 300
输出层 10

接着只需要将MNIST的训练数据按照节点一个个数据就可以了。

废话不多说 看代码。

代码

getImage.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import struct
from bp import *
from datetime import datetime
import matplotlib.pyplot as plt

# 数据加载器基类
class Loader(object):
    def __init__(self, path, count):
        '''
        初始化加载器
        path: 数据文件路径
        count: 文件中的样本个数
        '''
        self.path = path
        self.count = count
    def get_file_content(self):
        '''
        读取文件内容
        '''
        f = open(self.path, 'rb')
        content = f.read()
        f.close()
        return content
    def to_int(self, byte):
        '''
        将unsigned byte字符转换为整数
        '''
        return struct.unpack('B', byte)[0]
# 图像数据加载器
class ImageLoader(Loader):
    def get_picture(self, content, index):
        '''
        内部函数,从文件中获取图像
        '''
        ##从偏移量位置开始读取有效数据
        start = index * 28 * 28 + 16

        picture = []
        for i in range(28):
            picture.append([])
            for j in range(28): 
                picture[i].append(
                    self.to_int(content[start + i * 28 + j]))
        #picture 结构 二位数组 28*28
        return picture
    def get_one_sample(self, picture):
        '''
        内部函数,将图像转化为样本的输入向量
        '''
        sample = []
        for i in range(28):
            for j in range(28):
                sample.append(picture[i][j])
        #将样本
        return sample
    def load(self):
        '''
        加载数据文件,获得全部样本的输入向量
        '''
        #读取所有的图片样本
        content = self.get_file_content()
        data_set = []
        for index in range(self.count):
            data_set.append(
                self.get_one_sample(
                    self.get_picture(content, index)))
        return data_set
# 标签数据加载器
class LabelLoader(Loader):
    def load(self):
        '''
        加载数据文件,获得全部样本的标签向量
        '''
        content = self.get_file_content()
        labels = []
        for index in range(self.count):
            labels.append(self.norm(content[index + 8]))
        return labels
    def norm(self, label):
        '''
        内部函数,将一个值转换为10维标签向量
        '''
        label_vec = []
        label_value = self.to_int(label)
        for i in range(10):
            if i == label_value:
                label_vec.append(0.9)
            else:
                label_vec.append(0.1)
        return label_vec

def get_training_data_set():
    '''
    获得训练数据集
    '''
    image_loader = ImageLoader('train-images.idx3-ubyte', 60000)
    label_loader = LabelLoader('train-labels.idx1-ubyte', 60000)
    return image_loader.load(), label_loader.load()

def get_test_data_set():
    '''
    获得测试数据集
    '''
    image_loader = ImageLoader('t10k-images.idx3-ubyte', 10000)
    label_loader = LabelLoader('t10k-labels.idx1-ubyte', 10000)
    return image_loader.load(), label_loader.load()

netWork.py

# coding=utf-8
import numpy as np
import getImage as gim
#全连接神经网络层类
class BPLayer(object):
    def __init__(self, input_size, output_size, activator):
        '''
        input_siez:本层输入向量维度
        output_size:本层输出向量维度
        activator:本层激活函数
        '''
        self.input_size = input_size;
        self.output_size = output_size;
        self.activator = activator;
        #权值数组(范围-0.1~0.1)
        self.W = (np.random.rand(output_size, input_size)-0.5)*2;
        #偏执项
        self.B = np.zeros((output_size, 1));
        #输出向量
        self.output = np.zeros((output_size, 1));
        return;

    def forward(self, input_array):
        '''
        向前运算
        '''
        self.input = input_array;
        self.output = self.activator.forward(np.dot(self.W, self.input)+self.B);
        return;

    def backward(self, detal_array):
        '''
        向后运算
        '''
        self.detal = self.activator.backward(self.input)*np.dot(self.W.T, detal_array);
        self.W_grad = np.dot(detal_array, self.input.T);
        self.B_grad = detal_array;
        return;

    def update(self, learning_rate):
        '''
        更新权重
        '''
        self.W +=learning_rate*self.W_grad;
        self.B +=learning_rate*self.B_grad;
        return;

#激活函数类
class SigmoidActivator(object):
    def forward(self, x):
        return 1/(1+np.exp(-x));

    def backward(self, x):
        return x*(1-x);

#BP神经网络类
class BPNetWork(object):
    def __init__(self, layers):
        self.layers = [];
        for i in range(len(layers)-1):
            self.layers.append(BPLayer(layers[i], layers[i+1], SigmoidActivator()));

    def predict(self, sample):
        '''
        预测实现
        '''
        output = sample;
        for layer in self.layers:
            layer.forward(output);
            output = layer.output;
        return output;

    def train(self, labels, data_set, rate, epoch):
        '''
        训练网络
        '''
        for i in range(epoch):
            for d in range(len(data_set)):
                #按照矩阵乘的结构具状数据 W [300行*784列]  input[1行*784列]
                self.train_one_sample(np.array([labels[d]]).T, np.array([data_set[d]]).T, rate);
##              self.train_one_sample(labels[d], data_set[d], rate);
        return;

    def train_one_sample(self, label, date, rate):
        self.predict(date);
        self.calc_gradient(label);
        self.update_w(rate);
        return;

    def calc_gradient(self, label):
        detal = self.layers[-1].activator.backward(self.layers[-1].output)*(label - self.layers[-1].output);
        for layer in self.layers[::-1]:
            layer.backward(detal);
            detal = layer.detal;
        return;

    def update_w(self, rate):
        for layer in self.layers:
            layer.update(rate);
        return;

def get_result(vec):
    max_value_index = 0;
    max_value = 0;
    for i in range(len(vec)):
        if vec[i] > max_value:
            max_value = vec[i];
            max_value_index = i;

    return max_value_index;

def evaluate(network, test_data_set, test_labels):
    error = 0;
    total = len(test_data_set);
    for index in range(total):
        label = get_result(test_labels[index]);
        predict = get_result(network.predict(np.array([test_data_set[index]]).T));
        if label != predict:
            error += 1;
    return float(error)/float(total);

def  train_and_evaluate():
    last_error_ratio = 1.0;
    epoch = 0;
    x_train,y_train = gim.get_training_data_set();
    x_test,y_test = gim.get_test_data_set();
    
    layers=[784,300,10];
    bpNet = BPNetWork(layers);

    while True:
        epoch += 1;

        bpNet.train(y_train, x_train, 0.3, 1);
        print 'epoch %d finished' % (epoch);

        if epoch % 3 == 0:
            error_ratio = evaluate(bpNet, x_test, y_test);
            print 'after epoch %d , error ratio is %f' % (epoch, error_ratio);

            if error_ratio > last_error_ratio:
                break;
            else:
                last_error_ratio = error_ratio;
    


if __name__ == '__main__':
    train_and_evaluate();

运行结果

image.png

训练的效果很慢,目前也就达到这个水平。偷下懒O(∩_∩)O哈哈~

参考

零基础入门深度学习(3) - 神经网络和反向传播算法
https://www.zybuluo.com/hanbingtao/note/476663

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容

  • 原文地址:http://www.cnblogs.com/subconscious/p/5058741.html 神...
    Albert陈凯阅读 5,447评论 0 48
  • 文章主要分为:一、深度学习概念;二、国内外研究现状;三、深度学习模型结构;四、深度学习训练算法;五、深度学习的优点...
    艾剪疏阅读 21,834评论 0 58
  • 改进神经网络的学习方法(下) 权重初始化 创建了神经网络后,我们需要进行权重和偏差的初始化。到现在,我们一直是根据...
    nightwish夜愿阅读 1,866评论 0 0
  • 自打从事新媒体写作以来,我就发现之前那种有灵感再写作的方法,已经跟不上日更的步伐了。 现实逼得我不得不思考如何进行...
    辣妈思维阅读 577评论 0 1
  • 你在繁华的都市中畅快淋漓, 我在寂静的郊野里幕天席地。 梦想与现实像是一对性格不合的男女, 一个爱在巴黎,另一个向...
    可乐薄荷丶阅读 178评论 0 1