使用神经网络识别手写数字

使用MNIST数据集训练神经网络模型。训练数据由28*28的手写数字的图像组成,输入层包含784=28*28个神经元。输入像素是灰度级的,值为0.0表示白色,值为1.0表示黑色,中间数值表示逐渐暗淡的灰色。

intro.png

Algorithm

algorithm.png

神经网络快速入门

Codes

mnist_loader.py: 加载数据

import numpy as np
import pickle
import gzip

def load_data():
    f = gzip.open('data/mnist.pkl.gz', 'rb')
    training_data, validation_data, test_data = pickle.load(f, encoding="latin1")
    f.close()
    return (training_data, validation_data, test_data)

def load_data_wrapper():
    tr_d, va_d, te_d = load_data()
    # tr_d[0]: x; 1*784
    # tr_d[1]: y; 0-9
    training_inputs = [np.reshape(x, (784, 1)) for x in tr_d[0]]
    training_results = [vectorized_result(y) for y in tr_d[1]]
    training_data = zip(training_inputs, training_results)
    validation_inputs = [np.reshape(x, (784, 1)) for x in va_d[0]]
    validation_data = zip(validation_inputs, va_d[1])
    test_inputs = [np.reshape(x, (784, 1)) for x in te_d[0]]
    test_data = zip(test_inputs, te_d[1])
    return (training_data, validation_data, test_data)

def vectorized_result(j):
    v = np.zeros((10, 1))
    v[j] = 1.0
    return v

network.py: 算法,包括小批量梯度下降、反向传播算法

import numpy as np
import random

class Network(object):
    
    def __init__(self, sizes):
        """初始化权重和偏置
        
        :param sizes: 每一层神经元数量,类型为list
        
        weights:权重
        biases:偏置
        """
        
        self.sizes = sizes
        self.num_layers = len(sizes)
        self.weights = np.array([np.random.randn(x, y) for x, y in zip(sizes[1:], sizes[:-1])])
        self.biases = np.array([np.random.randn(y, 1) for y in sizes[1:]])
        
    
    def feedforward(self, a):
        """对一组样本x进行预测,然后输出"""
        
        for w, b in zip(self.weights, self.biases):
            a = sigmoid(np.dot(w, a) + b)
        return a
        
    
    def gradient_descent(self, training_data, epochs, mini_batch_size, alpha, test_data=None):
        """MBGD,运行一个或者几个batch时更新一次
        
        :param training_data: 训练数据,每一个样本包括(x, y),类型为zip
        :epochs: 迭代次数
        :mini_batch_size:每一个小批量数据的数量
        :alpha: 学习率
        :test_data: 测试数据
        """
        
        training_data = list(training_data)
        n = len(training_data)
        if test_data: 
            test_data = list(test_data)
            n_test = len(list(test_data))
        for i in range(epochs):
            random.shuffle(training_data)
            mini_batches = [training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)]
            for mini_batch in mini_batches:
                init_ws_derivative = np.array([np.zeros(w.shape) for w in self.weights])
                init_bs_derivative = np.array([np.zeros(b.shape) for b in self.biases])
                for x, y in mini_batch:
                    activations, zs = self.forwardprop(x) #前向传播
                    delta = self.cost_deviation(activations[-1], zs[-1], y) #计算最后一层误差
                    ws_derivative, bs_derivative = self.backprop(activations, zs, delta) #反向传播,cost func对w和b求偏导
                    init_ws_derivative = init_ws_derivative + ws_derivative
                    init_bs_derivative = init_bs_derivative + bs_derivative
                self.weights = self.weights - alpha / len(mini_batch) * init_ws_derivative
                self.biases = self.biases - alpha / len(mini_batch) * init_bs_derivative
            if test_data:
                print("Epoch {} : {} / {}".format(i, self.evaluate(test_data), n_test)) #识别准确数量/测试数据集总数量
            else:
                print("Epoch {} complete".format(i))


    def forwardprop(self, x):
        """前向传播"""
        
        activation = x
        activations = [x]
        zs = []
        for w, b in zip(self.weights, self.biases):
            z = np.dot(w, activation) + b
            zs.append(z)
            activation = sigmoid(z)
            activations.append(activation)
        return (activations, zs)


    def cost_deviation(self, output, z, y):
        """计算最后一层误差"""
    
        return (output - y) * sigmoid_derivative(z)
    
    
    def backprop(self, activations, zs, delta):
        """反向传播"""
        
        ws_derivative = np.array([np.zeros(w.shape) for w in self.weights])
        bs_derivative = np.array([np.zeros(b.shape) for b in self.biases])
        ws_derivative[-1] = np.dot(delta, activations[-2].transpose())
        bs_derivative[-1] = delta
        
        for l in range(2, self.num_layers):
            z = zs[-l]
            delta = np.dot((self.weights[-l+1]).transpose(), delta) * sigmoid_derivative(z)
            ws_derivative[-l] = np.dot(delta, activations[-l-1].transpose())
            bs_derivative[-l] = delta
        
        return (ws_derivative, bs_derivative)
     
        
    def evaluate(self, test_data):
        """评估"""
        
        test_results = [(np.argmax(self.feedforward(x)), y) for (x, y) in test_data]
        return sum(int(output == y) for (output, y) in test_results)
    

def sigmoid(z):
    return 1.0 / (1.0 + np.exp(-z))


def sigmoid_derivative(z):
    """sigmoid函数偏导"""
    
    return sigmoid(z) * (1 - sigmoid(z))

run.py: 运行,训练一个三层(1个输入层、1个隐藏层、1个输出层)的神经网络模型

import mnist_loader
import network

if __name__ == '__main__':
    training_data, validation_data, test_data = mnist_loader.load_data_wrapper()
    net = network.Network([784, 30, 10]) #28*28
    net.gradient_descent(training_data, 30, 10, 3.0, test_data=test_data)

MNIST数据集及源码下载


更多内容:Github个人博客
备注:本文发表于 https://cnyangkui.github.io/2018/10/07/ML-NeuralNetwork/

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

推荐阅读更多精彩内容