【深度学习】神经网络的Python代码实现
作者:[美]霍布森·莱恩,科尔·霍华德
在学习神经网络之前,我们需要对神经网络底层先做一个基本的了解。我们将在本节介绍感知机、反向传播算法以及多种梯度下降法以给大家一个全面的认识。
一、感知机
数字感知机的本质是从数据集中选取一个样本(example),并将其展示给算法,然后让算法判断“是”或“不是”。一般而言,把单个特征表示为xi,其中i是整数。所有特征的集合表示为,表示一个向量:,
类似地,每个特征的权重表示为 其中 对应于与该权重关联的特征的下标,所有权重可统一表示为 一个向量:
这里有一个缺少的部分是是否激活神经元的阈值。一旦加权和超过某个阈值,感知机就输出1,否则输出0。我们可以使用一个简单的阶跃函数(在图5-2中标记为“激活函数”)来表示这个阈值。
一般而言我们还需要给上面的阈值表达式添加一个偏置项以确保神经元对全0的输入具有弹性,否则网络在输入全为0的情况下输出仍然为0。
注:所有神经网络的基本单位都是神经元,基本感知机是广义神经元的一个特例,从现在开始,我们将感知机称为一个神经元。
二、反向传播算法
2.1 代价函数
很多数据值之间的关系不是线性的,也没有好的线性回归或线性方程能够描述这些关系。许多数据集不能用直线或平面来线性分割。比如下图中左图为线性可分的数据,而右图为线性不可分的数据:
在这个线性可分数据集上对两类点做切分得到的误差可以收敛于0,而对于线性不可分的数据点集,我们无法做出一条直线使得两类点被完美分开,因此我们任意做一条分割线,可以认为在这里误差不为0,因此我们需要一个衡量误差的函数,通常称之为代价函数:
而我们训练神经网络(感知机)的目标是最小化所有输入样本数据的代价函数
2.2 反向传播
权重通过下一层的权重()和()来影响误差,因此我们需要一种方法来计算对误差的贡献,这个方法就是反向传播。
下图中展示的是一个全连接网络,图中没有展示出所有的连接,在全连接网络中,每个输入元素都与下一层的各个神经元相连,每个连接都有相应的权重。因此,在一个以四维向量为输入、有5个神经元的全连接神经网络中,一共有20个权重(5个神经元各连接4个权重)。
感知机的每个输入都有一个权重,第二层神经元的权重不是分配给原始输入的,而是分配给来自第一层的各个输出。从这里我们可以看到计算第一层权重对总体误差的影响的难度。第一层权重对误差的影响并不是只来自某个单独权重,而是通过下一层中每个神经元的权重来产生的。反向传播的推导过程较为复杂,这里仅简单展示其结果:
如果该层是输出层,借助于可微的激活函数,权重的更新比较简单, 对于第 个输出,误差的导数如下
如果要更新隐藏层的权重,则会稍微复杂一点儿:
函数表示实际结果向量,表示该向量第个位置上的值,,是倒数第二层第个节点和输出第个节点的输出,连接这两个节点的权重为,误差代价函数对求导的结果相当于用(学习率)乘以前一层的输出再乘以后一层代价函数的导数。公式中表示层第个节点上的误差项,前一层第个节点到层所有的节点进行加权求和。
2.3 多种梯度下降法
到目前为止,我们一直是把所有训练样本的误差聚合起来然后再做梯度下降,这种训练方法称为批量学习(batch learning)。一批是训练数据的一个子集。但是在批量学习中误差曲面对于整个批是静态的,如果从一个随机的起始点开始,得到的很可能是某个局部极小值,从而无法看到其他的权重值的更优解。这里有两种方法来避开这个陷阱。
第一种方法是随机梯度下降法。在随机梯度下降中,不用去查看所有的训练样本,而是在输入每个训练样本后就去更新网络权重。在这个过程中,每次都会重新排列训练样本的顺序,这样将为每个样本重新绘制误差曲面,由于每个相异的输入都可能有不同的预期答案,因此大多数样本的误差曲面都不一样。对每个样本来说,仍然使用梯度下降法来调整权重。不过不用像之前那样在每个训练周期结束后聚合所有误差再做权重调整,而是针对每个样本都会去更新一次权重。其中的关键点是,每一步都在向假定的极小值前进(不是所有路径都通往假定的极小值)。
使用正确的数据和超参数,在向这个波动误差曲面的各个最小值前进时,可以更容易地得到全局极小值。如果模型没有进行适当的调优,或者训练数据不一致,将导致原地踏步,模型无法收敛,也学不会任何东西。不过在实际应用中,随机梯度下降法在大多数情况下都能有效地避免局部极小值。这种方法的缺点是计算速度比较慢。计算前向传播和反向传播,然后针对每个样本进行权重更新,这在本来已经很慢的计算过程的基础上又增加了很多时间开销。
第二种方法,也是更常见的方法,是小批量学习。在小批量学习中,会传入训练集的一个小的子集,并按照批量学习中的误差聚合方法对这个子集对应的误差进行聚合。然后对每个子集按批将其误差进行反向传播并更新权重。下一批会重复这个过程,直到训练集处理完成为止,这就重新构成了一个训练周期。这是一种折中的办法,它同时具有批量学习(快速)和随机梯度下降(具有弹性)的优点。
三、Keras:用Python实现神经网络
用原生Python来编写神经网络是一个非常有趣的尝试,而且可以帮助大家理解神经网络中的各种概念,但是Python在计算速度上有明显缺陷,即使对于中等规模的网络,计算量也会变得非常棘手。不过有许多Python库可以用来提高运算速度,包括PyTorch、Theano、TensorFlow和Lasagne等。本书中的例子使用Keras。
Keras是一个高级封装器,封装了面向Python的API。API接口可以与3个不同的后端库相兼容:Theano、谷歌的TensorFlow和微软的CNTK。这几个库都在底层实现了基本的神经网络单元和高度优化的线性代数库,可以用于处理点积,以支持高效的神经网络矩阵乘法运算。
我们以简单的异或问题为例,看看如何用Keras来训练这个网络。
import numpy as np
from keras.models import Sequential # Kera的基础模型类
from keras.layers import Dense, Activation # Dense是神经元的全连接层
from keras.optimizers import SGD # 随机梯度下降,Keras中还有一些其他优化器
# Our examples for an exclusive OR.
x_train = np.array([[0, 0],[0, 1],[1, 0],[1, 1]]) # x_train是二维特征向量表示的训练样本列表
y_train = np.array([[0],[1],[1],[0]]) # y_train是每个特征向量样本对应的目标输出值
model = Sequential()
num_neurons = 10 # 全连接隐藏层包含10个神经元
model.add(Dense(num_neurons, input_dim=2)) # input_dim仅在第一层中使用,后面的其他层会自动计算前一层输出的形状,这个例子中输入的XOR样本是二维特征向量,因此input_dim设置为2
model.add(Activation('tanh'))
model.add(Dense(1)) # 输出层包含一个神经元,输出结果是二分类值(0或1)
model.add(Activation('sigmoid'))
model.summary()
可以看到模型的结构为:
Layer (type) Output Shape Param
=================================================================
dense_18 (Dense) (None, 10) 30
_________________________________________________________________
activation_6 (Activation) (None, 10) 0
_________________________________________________________________
dense_19 (Dense) (None, 1) 11
_________________________________________________________________
activation_7 (Activation) (None, 1) 0
=================================================================
Total params: 41.0
Trainable params: 41.0
Non-trainable params: 0.0
model.summary()
提供了网络参数及各阶段权重数(Param \#
)的概览。我们可以快速计算一下:10个神经元,每个神经元有3个权重,其中有两个是输入向量的权重(输入向量中的每个值对应一个权重),还有一个是偏置对应的权重,所以一共有30个权重需要学习。输出层中有10个权重,分别与第一层的10个神经元一一对应,再加上1个偏置权重,所以该层共有11个权重。
下面的代码可能有点儿不容易理解:
sgd = SGD(lr=0.1)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
SGD是之前导入的随机梯度下降优化器,模型用它来最小化误差或者损失。lr
是学习速率,与每个权重的误差的导数结合使用,数值越大模型的学习速度越快,但可能会使模型无法找到全局极小值,数值越小越精确,但会增加训练时间,并使模型更容易陷入局部极小值。损失函数本身也定义为一个参数,在这里用的是binary_crossentropy
。metrics
参数是训练过程中输出流的选项列表。用compile
方法进行编译,此时还未开始训练模型,只对权重进行了初始化,大家也可以尝试一下用这个随机初始状态来预测,当然得到的结果只是随机猜测:
model.predict(x_train)
[[ 0.5 ][ 0.43494844][ 0.50295198][ 0.42517585]]
predict
方法将给出最后一层的原始输出,在这个例子中是由sigmoid
函数生成的。
之后再没什么好写的了,但是这里还没有关于答案的任何知识,它只是对输入使用了随机权重。接下来可以试着进行训练。
model.fit(x_train, y_train, epochs=100) # 从这里开始训练模型
Epoch 1/100
4/4 [==============================] - 0s - loss: 0.6917 - acc: 0.7500
Epoch 2/100
4/4 [==============================] - 0s - loss: 0.6911 - acc: 0.5000
Epoch 3/100
4/4 [==============================] - 0s - loss: 0.6906 - acc: 0.5000
...
Epoch 100/100
4/4 [==============================] - 0s - loss: 0.6661 - acc: 1.0000
提示
在第一次训练时网络可能不会收敛。第一次编译可能以随机分布的参数结束,导致难以或者不能得到全局极小值。如果遇到这种情况,可以用相同的参数再次调用model.fit
,或者添加更多训练周期,看看网络能否收敛。或者也可以用不同的随机起始点来重新初始化网络,然后再次尝试fit
。如果使用后面这种方法,请确保没有设置随机种子,否则只会不断重复同样的实验结果。
当网络一遍又一遍地学习这个小数据集时,它终于弄明白了这是怎么回事。它从样本中“学会”了什么是异或!这就是神经网络的神奇之处。
model.predict_classes(x_train)
4/4 [==============================] - 0s
[[0][1][1][0]]
model.predict(x_train)
4/4 [==============================] - 0s
[[ 0.0035659 ][ 0.99123639][ 0.99285167][ 0.00907462]]
在这个经过训练的模型上再次调用predict
(和predict_classes
)会产生更好的结果。它在这个小数据集上获得了 100%的精确度。当然,精确率并不是评估预测模型的最佳标准,但对这个小例子来说完全可以说明问题。接下来展示了如何保存这个异或模型:
import h5py
model_structure = model.to_json() # 用Keras的辅助方法将网络结构导出为JSON blob类型以备后用with open("basic_model.json", "w") as json_file:json_file.write(model_structure)model.save_weights("basic_weights.h5") # 训练好的权重必须被单独保存。第一部分只保存网络结构。在后面重新加载网络结构时必须对其重新实例化
同样也有对应的方法来重新实例化模型,这样做预测时不必再去重新训练模型。虽然运行这个模型只需要几秒,但是在后面的章节中,模型的运行时间将会快速增长到以分钟、小时甚至天为单位,这取决于硬件性能和模型的复杂度,所以请准备好!
本文内容经出版社授权发布,节选自《自然语言处理实战》一书,由霍布森·莱恩,科尔·霍华德所著。理论与实战结合,有具体的代码可以参考,对于理解算法过程很有帮助。
往期精彩回顾适合初学者入门人工智能的路线及资料下载机器学习及深度学习笔记等资料打印机器学习在线手册深度学习笔记专辑《统计学习方法》的代码复现专辑
AI基础下载机器学习的数学基础专辑
获取本站知识星球优惠券,复制链接直接打开:
https://t.zsxq.com/qFiUFMV
本站qq群704220115。加入微信群请扫码:
【深度学习】神经网络的Python代码实现相关推荐
- 利用python深度学习神经网络预测五年内糖尿病的发生(全代码)
各位朋友大家好,今天我们做一个深度学习神经网络的项目,预测五年内糖尿病的发生.神经网络但凡入门数据科学的人都知道,我觉得叫神经网络是从仿生学角度的命名,从数据科学角度我更喜欢称它为多层感知机(mult ...
- MINIST深度学习识别:python全连接神经网络和pytorch LeNet CNN网络训练实现及比较(三)...
版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com 在前两篇文章MINIST深度学习识别:python全连接神经网络和pytorch LeNet CNN网 ...
- 从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具
从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具 文章目录 1. 神经网络数据预处理 1.1 常规预测情景 1.2 文本预测场景 2.全连接神经网络 ...
- 深度学习 + OpenCV,Python实现实时视频目标检测
选自PyimageSearch 机器之心编译 参与:路雪.李泽南 使用 OpenCV 和 Python 对实时视频流进行深度学习目标检测是非常简单的,我们只需要组合一些合适的代码,接入实时视频,随后加 ...
- 《深度学习入门——基于Python的理论与实现》笔记
PS:写这篇博客主要是记录下自己认为重要的部分以及阅读中遇到的些问题,加深自己的印象. 附上电子书及源代码: 链接:https://pan.baidu.com/s/1f2VFcnXSSK-u3wuvg ...
- DL:深度学习(神经网络)的简介、基础知识(神经元/感知机、训练策略、预测原理)、算法分类、经典案例应用之详细攻略
DL:深度学习(神经网络)的简介.基础知识(神经元/感知机.训练策略.预测原理).算法分类.经典案例应用之详细攻略 目录 深度学习(神经网络)的简介 1.深度学习浪潮兴起的三大因素 深度学习(神经网络 ...
- 深度学习 自组织映射网络 ——python实现SOM(用于聚类)
深度学习 自组织映射网络 --python实现SOM(用于聚类) 摘要 python实现代码 计算实例 摘要 SOM(Self Organizing Maps ) 的目标是用低维目标空间的点来表示高维 ...
- 10 年深度学习顶级论文和代码精选,请务必收藏!
点击上方"AI有道",选择"星标"公众号 重磅干货,第一时间送达 你是否经常花费时间或苦于寻找深度学习相关的顶会优秀论文极其相对应的代码?今天给大家介绍一个超赞 ...
- 深度学习之编程语言Python(Ⅰ)
深度学习之编程语言Python 编程语言Python 什么是编程语言? 编程语言(Programming Language)就是人与计算机之间交互的方式.简单来说,就是人与计算机都可以理解的一种语言. ...
- 实现Linux服务器配置深度学习环境并跑代码完整步骤
实现Linux服务器配置深度学习环境并跑代码完整步骤 目录 实现Linux服务器配置深度学习环境并跑代码完整步骤 安装pytorch 第一步 安装anaconda创建虚拟环境 1.下载安装包 2.安装 ...
最新文章
- HDU 6889 Graph Theory Class(CCPC网络赛)
- 【Python】PyCharm新建PythonPackage呈现出普通Dictionary的样式的解决方法
- jquery实现输入框动态增减
- JDK8新特性(六)之Stream流的forEach()方法
- 大战设计模式【19】—— 享元模式
- 呕心沥血博一文--MySQL主从异步复制
- Win10/Win8快速启动失效/卡logo 的解决方法汇总
- 计算机维修需要工具,小200个电脑维护工具,都能去开个维修店了
- 微软服务器打补丁步骤,自己手动制作 Windows 系统补丁包全过程
- android 字符串 声波,识别成功率100%的声波配网,看完你也可以实现一个
- 墨卡托投影参数设置_[转载]MRT投影参数设置及原理
- winpe读取linux硬盘数据恢复,如何在WinPE环境下完成文件恢复
- 谢孟媛初级文法28 课地方副词时间副词和程度副词
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- i春秋——“百度杯”CTF比赛 十月场——Vld(Vulcan Logic Dumper 、php opcode、sql 报错注入)...
- 介绍谱聚类(spectral clustering)
- untiy实现文本滚动
- 【shaderforge学习笔记】 UVTile节点
- 快速批量查询快递物流数据的工具,51Tracking可同时多种快递物流信息跟踪查件
- 51单片机——单片机基础知识