深度学习与计算机视觉:基于Python的神经网络的实现
在前面两篇文章介绍了深度学习的一些基本概念,本文则使用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。 这是将神经元的偏置和权值统一的放到了权值矩阵里面。
\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]
\]
可以将上式写成齐次的形式
\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\)
        error = A[-1] - y # 输出层的误差,均值方差作为损失函数
        D = [error * self.sigmoid_deriv(A[-1])]
得到输出层的误差D后,根据\(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\)计算权值矩阵和偏置的导数
\]
\]
        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的神经网络的实现的更多相关文章
- 学习《深度学习入门:基于Python的理论与实现》高清中文版PDF+源代码
		
入门神经网络深度学习,推荐学习<深度学习入门:基于Python的理论与实现>,这本书不来虚的,一上来就是手把手教你一步步搭建出一个神经网络,还能把每一步的出处讲明白.理解神经网络,很容易就 ...
 - [高清·非影印] 深度学习入门:基于Python的理论与实现 + 源代码
		
------ 郑重声明 --------- 资源来自网络,纯粹共享交流, 如果喜欢,请您务必支持正版!! --------------------------------------------- 下 ...
 - 深度学习与计算机视觉教程(15) | 视觉模型可视化与可解释性(CV通关指南·完结)
		
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/37 本文地址:http://www.showmeai.tech/article-det ...
 - 深度学习与计算机视觉(12)_tensorflow实现基于深度学习的图像补全
		
深度学习与计算机视觉(12)_tensorflow实现基于深度学习的图像补全 原文地址:Image Completion with Deep Learning in TensorFlow by Bra ...
 - 深度学习与计算机视觉(11)_基于deep learning的快速图像检索系统
		
深度学习与计算机视觉(11)_基于deep learning的快速图像检索系统 作者:寒小阳 时间:2016年3月. 出处:http://blog.csdn.net/han_xiaoyang/arti ...
 - 30个深度学习库:按Python、C++、Java、JavaScript、R等10种语言分类
		
30个深度学习库:按Python.C++.Java.JavaScript.R等10种语言分类 包括 Python.C++.Java.JavaScript.R.Haskell等在内的一系列编程语言的深度 ...
 - Python深度学习 deep learning with Python
		
内容简介 本书由Keras之父.现任Google人工智能研究员的弗朗索瓦•肖莱(François Chollet)执笔,详尽介绍了用Python和Keras进行深度学习的探索实践,涉及计算机视觉.自然 ...
 - 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV
		
这次博客园的排版彻底残了..高清版请移步: https://zhuanlan.zhihu.com/p/24425116 本篇是前面两篇教程: 给深度学习入门者的Python快速教程 - 基础篇 给深度 ...
 - 给深度学习入门者的Python快速教程 - 基础篇
		
实在搞不定博客园的排版,排版更佳的版本在: https://zhuanlan.zhihu.com/p/24162430 Life is short, you need Python 人生苦短,我用Py ...
 
随机推荐
- 15.linux基础
			
1.目录 /:根目录,一般根目录下只存放目录,在Linux下有且只有一个根目录.所有的东西都是从这里开始.当你在终端里输入“/home”,你其实是在告诉电脑,先从/(根目录)开始,再进入到home目录 ...
 - Oracle数据库逻辑迁移之数据泵的注意事项
			
环境:数据迁移,版本 11.2.0.4 -> 12.2.0.1 思考: 对于DBA而言,常用物理方式的迁移,物理迁移的优势不必多说,使用这种方式不必担心对象前后不一致的情况,而这往往也解决了不懂 ...
 - Hibernate Session总结
			
现在我们可以在 IDEA 下新建一个 Hibernate 项目,接着上次内容这次主要总结一下 Hibernate 的 Session,及其核心方法. Session 概述 Session 接口是 Hi ...
 - https://doc.opensuse.org/projects/kiwi/doc/
			
KIWI 是用于创建操作系统映像的系统.映像是带有一个文件的目录,该文件包含操作系统.其应用程序与配置.操作系统的文件系统结构.可能的附加元数据,以及(取决于映像类型)磁盘几何属性和分区表数据.通过 ...
 - java项目中通过添加filter过滤器解决ajax跨域问题
			
1.在web.xml添加filter <filter> <filter-name>contextfilter</filter-name> <filter-cl ...
 - 微信小程序基于第三方websocket的服务器端部署
			
微信小程序后台请求越来越严格 1.request要求用https 2.websocket要求用wss 3.测试后发现websocket只能走433端口 作为.net开发,websocket又是使用的第 ...
 - Ueditor  专题
			
https://github.com/xwjie/SpringBootUeditor 提交表单提交表单设置按照部署编辑器的教程,完成编辑器加载 把容器放到form表单里面,设置好要提交的路径,如下面代 ...
 - SQL查询中用到的函数
			
数据库表 students id name sex age address 101 张汉 男 14 杭州 102 欧阳钦 男 13 杭州 103 吴昊 男 14 北京 104 钱进进 男 ...
 - 按钮组,导航条选中其中一个后添加Class突出元素
			
$(document).on("click",".modalnavtop",function(e){ $(".modalnavtop").e ...
 - python 简单的信息管理系统
			
#!/usr/bin/python #coding=utf-8 import io import os import time FileRead = io.open('callingcard','r' ...