前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >神经网络模型解决分类问题的思考方式

神经网络模型解决分类问题的思考方式

原创
作者头像
人工智能的秘密
发布2017-12-25 20:17:20
2.2K0
发布2017-12-25 20:17:20
举报

回顾

昨天介绍了神经网络的基本模型结构,可分类为前向传播神经网络,循环神经网络(RNN);介绍了神经网络中,梯度下降的原理推导,以小球下坡作为实例阐述梯度下降;分析了神经网络模型解决机器学习问题,与传统的机器学习算法的异同;并初步介绍了手写字分类的背景知识,欢迎参考:

深度学习|神经网络模型简介和梯度下降求解

下面,通过经典的手写字数据集来进一步认识神经网络模型解决分类问题的思考方式,原理,代码实现,通过这篇您学到如下重要的知识,这些是入门深度学习必须要掌握的理论和工具:

  1. 拿到一个分类任务后,通过神经网络模型求解的思维方式
  2. 神经网络前向传播原理
  3. SGD 的实现原理(包括代码)
  4. 反向传播的代码实现(接下来几天详细推送反向传播的原理)
  5. 评估分类结果精确度的方法
  6. 如何设定与某个问题相关的特定神经网络

神经网络模型求解手写字分类的核心代码

2.1?手写字分类问题解决步骤

手写字分类可以分解为2类子问题,第一,把图像分解为连续的按位分开的单个数字图像,例如,将图像

分解为如下的6个图像:

然后,接下来对每个小图像,建立神经网络模型学习,建立的NN模型如下,先初步解释下为什么是这样,因为每个小图像的像素为:28 by 28 = 784,共784个像素点,每个像素点看做一个特征,对应一个输入神经元,至于中间的隐含层的个数,为15个,至于如何构造隐含层,隐含层的意义是什么,会在接下来谈,输出层为10个神经元,是因为0~9共10个数字。

2.2 训练神经网络

训练神经网络的过程,就是求解所有神经元的权重参数,每层网络的偏置量,这样就可以进行手写字的分类预测了,输入小图像5后,经过这套网络,可以得出数字分类为5吗?

2.3 梯度下降求权重参数和偏置量

昨天推导了梯度下降求权重参数和偏置量的过程,接下来,看看神经网络模型,求解手写字分类的详细过程。

2.4 代码实现

模块实现SGD的前向神经网络的学习算法,主函数为 SGD,里面涉及到后向传播求梯度的技术,详细研究这些代码对于深刻理解神经网络模型做分类任务有重大帮助。

下面写的这些代码,带有详细的注释,建立 Network 类,里面的方法用深蓝色字体加粗,注释用红色字体标注。

import random

import numpy as np

class Network(object):

? ? ?def __init__(self, sizes):

? ? ? ? """

? ? ? ? 参数,sizes : 神经网络的结构尺寸,是tuple,比如(3,2,1),

? ? ? ? 输入层为3个神经元,

? ? ? ? 中间层为2个神经元,

? ? ? ? 输出层为1个神经元

? ? ? ? 类内全局:sizes

? ? ? ? biases:隐含层,输出层的偏置量

? ? ? ? weights:各个神经元的权重参数,[[15 by 784],[10 by 15]]

? ? ? ? """

? ? ? ? self.num_layers = len(sizes)

? ? ? ? self.sizes = sizes

? ? ? ? self.biases = [np.random.randn(y, 1) for y in sizes[1:]]

? ? ? ? self.weights = [np.random.randn(y, x)

? ? ? ? ? ? ? ? ? ? ? ? for x, y in zip(sizes[:-1], sizes[1:])]

? ? def feedforward(self, a):

"""

? ? ? ?前向传播

? ? ? ? a 是输入

? ? ? ? 返回神经网络的输出: sigmoid(w*a + b)

? ? ? ? """

? ? ? ? for b, w in zip(self.biases, self.weights):

? ? ? ? ? ? a = sigmoid(np.dot(w, a)+b)

? ? ? ? return a

? ? def SGD(self, training_data, epochs, mini_batch_size, eta,

? ? ? ? ? ? test_data=None):? ? ??

"""

? ? ? ? 采用 mini-batch SGD 训练神经网络

? ? ? ? training_data : [(x,y)],x 代表训练的输入, y 代表输出

? ? ? ? epochs:比如,迭代100次为一波

? ? ? ? mini_batch_size:批梯度下降,一次迭代,采用的样本个数,比如为10个样本

? ? ? ? eta : 学习率

? ? ? ? """

? ? ? ? if test_data: n_test = len(test_data)

? ? ? ? n = len(training_data)

? ? ? ? for j in range(epochs):

? ? ? ? ? ? random.shuffle(training_data)

? ? ? ? ? ? mini_batches = [

? ? ? ? ? ? ? ? training_data[k:k+mini_batch_size]

? ? ? ? ? ? ? ? for k in xrange(0, n, mini_batch_size)]

? ? ? ? ? ? for mini_batch in mini_batches:

? ? ? ? ? ? ? ? self.update_mini_batch(mini_batch, eta)

? ? ? ? ? ? if test_data:

? ? ? ? ? ? ? ? print ("Epoch {0}: {1} / {2}".format(

? ? ? ? ? ? ? ? ? ? j, self.evaluate(test_data), n_test))

? ? ? ? ? ? else:

? ? ? ? ? ? ? ? print ("Epoch {0} complete".format(j))

? ? def update_mini_batch(self, mini_batch, eta):

"""

? ? ? ? 更新神经网络的权重(类内全局参数weights)和偏置量(类内全局参数:biases),

? ? ? ? 使用后传播的梯度下降方法,这个方法的核心是后传播算法backprop

? ? ? ? mini_batch:[(x,y)],x是输入,y是输出

? ? ? ? """?

? ? ? ? nabla_b = [np.zeros(b.shape) for b in self.biases]

? ? ? ? nabla_w = [np.zeros(w.shape) for w in self.weights]

? ? ? ? for x, y in mini_batch:

? ? ? ? ? ? delta_nabla_b, delta_nabla_w = self.backprop(x, y)

? ? ? ? ? ? nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]

? ? ? ? ? ? nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]

? ? ? ? self.weights = [w-(eta/len(mini_batch))*nw

? ? ? ? ? ? ? ? ? ? ? ? for w, nw in zip(self.weights, nabla_w)]

? ? ? ? self.biases = [b-(eta/len(mini_batch))*nb

? ? ? ? ? ? ? ? ? ? ? ?for b, nb in zip(self.biases, nabla_b)]

? ? def backprop(self, x, y): """ 通过后向传播得出偏置量和权重参数的梯度方向, ? ? ? ? 返回值 ,biases:每层的偏置量的梯度 ? ? ? ? weights:每层神经元的权重参数 ? ? ? ? """ ? ? ? ? nabla_b = [np.zeros(b.shape) for b in self.biases] ? ? ? ? nabla_w = [np.zeros(w.shape) for w in self.weights] # 前向传播 ? ? ? ? activation = x ? ? ? ? activations = [x] # 分层存储每层的激活节点 ? ? ? ? zs = [] # 分层存储每层的 Z 向量 ? ? ? ? for b, w in zip(self.biases, self.weights): ? ? ? ? ? ? z = np.dot(w, activation)+b ? ? ? ? ? ? zs.append(z) ? ? ? ? ? ? activation = sigmoid(z) ? ? ? ? ? ? activations.append(activation) # 后向传播 ? ? ? ? delta = self.cost_derivative(activations[-1], y) * \ ? ? ? ? ? ? sigmoid_prime(zs[-1]) ? ? ? ? nabla_b[-1] = delta ? ? ? ? nabla_w[-1] = np.dot(delta, activations[-2].transpose()) # L = 1 表示最后一层神经元, L = 2 倒数第二层神经元 ? ? ? ? for layer in range(2, self.num_layers): ? ? ? ? ? ? z = zs[-layer] ? ? ? ? ? ? sp = sigmoid_prime(z) ? ? ? ? ? ? delta = np.dot(self.weights[-layer+1].transpose(), delta) * sp ? ? ? ? ? ? nabla_b[-layer] = delta ? ? ? ? ? ? nabla_w[-layer] = np.dot(delta, activations[-layer-1].transpose()) ? ? ? ? return (nabla_b, nabla_w)

? ? def evaluate(self, test_data):

"""

? ? ? ? 输出层中,输出值最大的神经元对应的索引为分类,比如神经元5的激活值

? ? ? ? 最大,则认为输入的图像为5?

? ? ? ? """

? ? ? ? test_results = [(np.argmax(self.feedforward(x)), y)

? ? ? ? ? ? ? ? ? ? ? ? for (x, y) in test_data]

? ? ? ? return sum(int(x == y) for (x, y) in test_results)

? ? def cost_derivative(self, output_activations, y):

? ? ? ? """

? ? ? ? 成本函数的导数

? ? ? ? """?

? ? ? ? return (output_activations-y)

def sigmoid(z):

"""The sigmoid 函数."""

? ? return 1.0/(1.0+np.exp(-z))

def sigmoid_prime(z):

"""sigmoid 函数的导数"""

? ? return sigmoid(z)*(1-sigmoid(z))

以上就是前向神经网络的后向传播梯度下降求解的完整代码。

附:

手写字的数据集下载,请参考:http://yann.lecun.com/exdb/mnist/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com