在前面两篇文章介绍了深度学习的一些基本概念,本文则使用Python实现一个简单的深度神经网络,并使用MNIST数据库进行测试。

神经网络的实现,包括以下内容:

  • 神经网络权值的初始化
  • 正向传播
  • 误差评估
  • 反向传播
  • 更新权值

主要是根据反向传播的4个基本方程,利用Python实现神经网络的反向传播。

初始化

首先定义代表神经网络的类NeuralNetwork,

class NeuralNetwork:
def __init__(self,layers,alpha=0.1):
self.W = []
self.layers = layers
self.alpha = alpha

有三个属性,

  • W存储各个层之间的权值矩阵,也是神经网络要更新学习的
  • layers 神经网络的结构,例如: [2,2,1]表示输入层有2个神经元,隐藏层2个神经元,输出层只有1个神经元。
  • alpha 学习速率

接下来初始化各个层之间的权值矩阵

for i in np.arange(0,len(layers) - 2):
w = np.random.randn(layers[i] + 1,layers[i + 1] + 1)
self.W.append(w / np.sqrt(layers[i]))

注意上面生成权值矩阵的大小layers[i] + 1,layers[i + 1] + 1,都加了1。 这是将神经元的偏置和权值统一的放到了权值矩阵里面。

\[\left[
\begin{array}{c}w_{11} & w_{12} \\ w_{21} & w_{22}\end{array} \right] \cdot \left[\begin{array}{c}x_1 \\ x_2\end{array}\right] + \left[\begin{array}{c}b_1 \\ b_2\end{array}\right] = \left[\begin{array}{c}w_{11}x_1 + w{12}x_2 + b_1 \\ w_{21}x_1 + w_{22}x_2 + b_2 \end{array}\right]
\]

可以将上式写成齐次的形式

\[\left[
\begin{array}{c}w_{11} & w_{12} & b_1 \\ w_{21} & w_{22} &b_2 \end{array}
\right] \cdot \left[\begin{array}{c}x_1 \\ x_2 \\ 1\end{array}\right]
\]

使用统一的矩阵运算,在正向反向传播的时候更方便。

在输出层的神经元并没有偏置,所以要单独初始化输出层的权值矩阵

        w = np.random.randn(layers[-2] + 1,layers[-1])
self.W.append(w / np.sqrt(layers[-2]))

下面实现Python的magic function __repr__输出神经网络结构

    def __repr__(self):
return "NeuralNetWork:{}".format("-".join(str(l) for l in self.layers))

激活函数

在神经网络中使用sigmoid作为激活函数,实现sigmoid及其导数

    def sigmoid(self,x):
return 1.0 / (1 + np.exp(-x)) def sigmoid_deriv(self,x):
return x * (1 - x)

正向反向传播

这一部分是神经的网络的核心了。下面实现fit方法,在方法中完成神经网络权值更新(训练)的过程。

    def fit(self,X,y,epochs=1000,displayUpdate=100):
X = np.c_[X,np.ones((X.shape[0]))] for epoch in np.arange(0,epochs):
for(x,target) in zip(X,y):
self.fit_partial(x,target) # check to see if we should display a training update
if epoch == 0 or (epoch + 1) % displayUpdate == 0:
loss = self.calculate_loss(X,y)
print("[INFO] epoch={},loss={:.7f}".format(epoch + 1,loss))

该函数有4个参数:

  • X是输入的样本数据
  • y是样本的真是值
  • epochs训练的轮数
  • displayUpdate 输出训练的loss值。

X = np.c_[X,np.ones((X.shape[0]))]将输入训练的样本表示为齐次向量(也就是在末尾添1)。fit_partial是对输入的每个样本进行训练,包括正向传播,反向传播以及权值的更新。

    def fit_partial(self,x,y):
A = [np.atleast_2d(x)]
# 正向传播
# 层层之间的数据传递
for layer in np.arange(0,len(self.W)): # 输入经过加权以及偏置后的值
net = A[layer].dot(self.W[layer]) # 神经元的输出
out = self.sigmoid(net) # 保存下来,反向传播的时候使用
A.append(out)

上面完成了神经玩过的正向传播过程,下面根据反向传播的4个基本方程进行反向传播。

首先根据\(BP1\),

\[\delta^L = \frac{\partial e}{\partial a^L} \odot \sigma'(z^L) \tag{BP1}
\]

计算输出层的误差\(\delta^L\)

        error = A[-1] - y # 输出层的误差,均值方差作为损失函数

        D = [error * self.sigmoid_deriv(A[-1])]

得到输出层的误差D后,根据\(BP2\)计算各个层的误差

\[\delta^{L-1} = (W^L)^T\delta^L \odot \sigma'(z^{L-1}) \tag{BP2}
\]

        for layer in np.arange(len(A) - 2,0 ,-1):
delta = D[-1].dot(self.W[layer].T)
delta = delta * self.sigmoid_deriv(A[layer])
D.append(delta)
D = D[::-1]

D反转,和各个层的索引对应起来,下面根据\(BP3,BP4\)计算权值矩阵和偏置的导数

\[\frac{\partial e}{b_j^l} = \delta_j^l \tag{BP3}
\]

\[\frac{\partial e}{w_{jk}^l} = \delta_j^l a_k^{l-1} \tag{BP4}
\]

        for layer in np.arange(0,len(self.W)):
self.W[layer] += -self.alpha * A[layer].T.dot(D[layer])

首先求得权值和偏置的导数(权值和偏置统一到同一个矩阵中)A[layer].T.dot(D[layer],然后将梯度乘以学习速率alpha 每次权值减小的步长。

上述就完成利用反向传播算法更新权值的过程。 关于反向传播四个基本方程的推导过程,可以参考文章深度学习与计算机视觉: 搞懂反向传播算法的四个基本方程

误差评估

上面代码已经实现了深度学习的训练过程,下面实现predict输出使用训练好的模型预测的结果,calculate_loss评估训练后模型的评估

    def predict(self,X,addBias=True):
p = np.atleast_2d(X) if addBias:
p = np.c_[p,np.ones((p.shape[0]))] for layer in np.arange(0,len(self.W)):
p = self.sigmoid(np.dot(p,self.W[layer])) return p
def calculate_loss(self,X,targets): targets = np.atleast_2d(targets)
predictions = self.predict(X,addBias=False)
loss = 0.5 * np.sum((predictions - targets) ** 2) return loss

MNIST分类识别

使用上面实现的深度神经网络对MNIST手写体进行识别,首先导入必要的包

import NeuralNetwork
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn import datasets

需要使用sklearn包中的一些工具,进行数据的处理。

# load MNIST数据集,并使用min/max对数据进行归一化
digits = datasets.load_digits()
data = digits.data.astype("float")
data = (data - data.min()) / (data.max() - data.min()) print("[INFO] samples: {}, dim: {}".format(data.shape[0], data.shape[1]))

将数据拆分为训练集和测试集,并对MNIST的类别进行编码

(trainX, testX, trainY, testY) = train_test_split(data, digits.target, test_size=0.25)

# convert the labels from integers to vectors
trainY = LabelBinarizer().fit_transform(trainY)
testY = LabelBinarizer().fit_transform(testY)

下面构建神经网络结构,并使用训练集进行训练

nn = NeuralNetwork([data.shape[1], 32,16, 10])

print ("[INFO] {}".format(nn))

nn.fit(trainX, trainY, epochs=1000)

神经网络结构为:64-32-16-10,其中64为输入数据的大小,10输出类别的个数。

最后评估训练得到的模型

predictions = nn.predict(testX)

print(classification_report(testY.argmax(axis=1), predictions.argmax(axis=1)))

最终的输出结果:

[INFO] loading MNIST (sample) dataset...
[INFO] samples: 1797, dim: 64
[INFO] training network...
[INFO] NeuralNetWork:64-32-16-10
[INFO] epoch=1,loss=607.1711647
[INFO] epoch=100,loss=7.1082795
[INFO] epoch=200,loss=4.0731690
[INFO] epoch=300,loss=3.1401868
[INFO] epoch=400,loss=2.8801101
[INFO] epoch=500,loss=1.8738122
[INFO] epoch=600,loss=1.7461474
[INFO] epoch=700,loss=1.6624043
[INFO] epoch=800,loss=1.1852884
[INFO] epoch=900,loss=0.6710255
[INFO] epoch=1000,loss=0.6336826
[INFO] evaluating network...
precision recall f1-score support 0 1.00 0.95 0.97 39
1 0.84 1.00 0.92 38
2 1.00 0.98 0.99 41
3 0.93 0.98 0.95 52
4 0.91 0.97 0.94 40
5 0.98 0.98 0.98 41
6 1.00 0.96 0.98 51
7 1.00 0.98 0.99 48
8 0.98 0.89 0.93 55
9 0.98 0.93 0.95 45 micro avg 0.96 0.96 0.96 450
macro avg 0.96 0.96 0.96 450
weighted avg 0.96 0.96 0.96 450

如上测试结果,在测试集的上表现还算不错。

总结

本文使用Python简单的实现了一个神经网络。 主要是利用反向传播的4个基本方程,实现反向传播算法,更新各个神经元的权值。 最后使用该网络,对MNIST数据进行识别分类。

上面实现的神经网络只是“玩具”,用以加深对深度学习的训练过程以及反向传播算法的理解。后面将使用Keras和PyTorch来构建神经网络。

本文代码在git库 https://github.com/brookicv/machineLearningSample

深度学习与计算机视觉:基于Python的神经网络的实现的更多相关文章

  1. 学习《深度学习入门:基于Python的理论与实现》高清中文版PDF+源代码

    入门神经网络深度学习,推荐学习<深度学习入门:基于Python的理论与实现>,这本书不来虚的,一上来就是手把手教你一步步搭建出一个神经网络,还能把每一步的出处讲明白.理解神经网络,很容易就 ...

  2. [高清·非影印] 深度学习入门:基于Python的理论与实现 + 源代码

    ------ 郑重声明 --------- 资源来自网络,纯粹共享交流, 如果喜欢,请您务必支持正版!! --------------------------------------------- 下 ...

  3. 深度学习与计算机视觉教程(15) | 视觉模型可视化与可解释性(CV通关指南·完结)

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/37 本文地址:http://www.showmeai.tech/article-det ...

  4. 深度学习与计算机视觉(12)_tensorflow实现基于深度学习的图像补全

    深度学习与计算机视觉(12)_tensorflow实现基于深度学习的图像补全 原文地址:Image Completion with Deep Learning in TensorFlow by Bra ...

  5. 深度学习与计算机视觉(11)_基于deep learning的快速图像检索系统

    深度学习与计算机视觉(11)_基于deep learning的快速图像检索系统 作者:寒小阳 时间:2016年3月. 出处:http://blog.csdn.net/han_xiaoyang/arti ...

  6. 30个深度学习库:按Python、C++、Java、JavaScript、R等10种语言分类

    30个深度学习库:按Python.C++.Java.JavaScript.R等10种语言分类 包括 Python.C++.Java.JavaScript.R.Haskell等在内的一系列编程语言的深度 ...

  7. Python深度学习 deep learning with Python

    内容简介 本书由Keras之父.现任Google人工智能研究员的弗朗索瓦•肖莱(François Chollet)执笔,详尽介绍了用Python和Keras进行深度学习的探索实践,涉及计算机视觉.自然 ...

  8. 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV

    这次博客园的排版彻底残了..高清版请移步: https://zhuanlan.zhihu.com/p/24425116 本篇是前面两篇教程: 给深度学习入门者的Python快速教程 - 基础篇 给深度 ...

  9. 给深度学习入门者的Python快速教程 - 基础篇

    实在搞不定博客园的排版,排版更佳的版本在: https://zhuanlan.zhihu.com/p/24162430 Life is short, you need Python 人生苦短,我用Py ...

随机推荐

  1. ionic常见问题及解决方案

    1.Android SDK install设置代理服务器mirrors.neusoft.edu.cn80force http 2.ionic build android 2.1 gradle下载不了解 ...

  2. HTTP协议GET HEAD简单介绍

    一.HTTP协议简介 超文本传输协议(Hypertext Transfer Protocol,简称HTTP)是应用层协议,自 1990 年起,HTTP 就已经被应用于 WWW 全球信息服务系统. HT ...

  3. Java NIO SocketChannel套接字通道

    原文链接:http://tutorials.jenkov.com/java-nio/socketchannel.html 在Java NIO体系中,SocketChannel是用于TCP网络连接的套接 ...

  4. 关于Linux虚拟化技术KVM的科普 科普三(From OenHan)

    http://oenhan.com/archives,包括<KVM源代码分析1:基本工作原理>.<KVM源代码分析2:虚拟机的创建与运行>.<KVM源代码分析3:CPU虚 ...

  5. centos7搭建postfix邮件服务器

    在使用qq等邮件服务器厂商提供的邮件服务后,发现他们的邮件发送数量是有限制的,随着公司的业务的需求下,我们需要搭建一个邮件服务器,邮件服务器可以帮助我们在一些提醒方面和消息推送方面起到帮助. 理论性语 ...

  6. JavaWeb学习(一) ---- HTTP以及Tomcat的安装及使用

    HTTP 一.协议 双方在交互.通讯的时候,遵循的一种规范,一种规则. 二.HTTP协议 HTTP的全名是:Hypertext Transfer Protocol(超文本传输协议),针对网络上的客户端 ...

  7. 常见的web测试功能点测试思路

    常见的功能点的测试思路: . 新增 或 创建(Add or Create) ) 操作后的页面指向 )操作后所有绑定此数据源的控件数据更新,常见的排列顺序为栈Stack类型,后进先出 ) 取消操作是否成 ...

  8. 苹果通知推送服务(APNS)一些关键特性摘要

    http://ramosli.iteye.com/blog/1940843 前段时间,仔细研究了APNS的文档,把一些关键的地方记录了下来,弄懂这些对于理解APNS的规则,至关重要. 1. If AP ...

  9. 用Hyperledger Fabric(超级账本)来构建Java语言开发区块链的环境

    面向 Java 开发人员的链代码简介 您或许听说过区块链,但可能不确定它对 Java™ 开发人员有何用.本教程将帮助大家解惑.我将分步展示如何使用 Hyperledger Fabric v0.6 来构 ...

  10. linux下怎么样上传下载文件夹

    Linux下目录复制:本机->远程服务器 scp -r /home/shaoxiaohu/test1 zhidao@192.168.0.1:/home/test2 test1为源目录,test2 ...