之前说过要转深度学习这块的,今天给大家介绍一本Python神经网络编程,今年4月份出版的:
第一章 神经网络如何工作
Github源码地址:https://github.com/hzka/PythonNetworkBook 《Python神经网络编程》的PDF链接:链接: https://pan.baidu.com/s/1k0j-u-W-Y6Sov7ZqCW_CVw 提取码: jdgf
1.1尺有所短 寸有所长
有些任务,对于传统计算机而言很容易,对人类而言却很难,例如,对数百万个数字进行乘法运算。另一方面,有些任务对传统计算机来说很难,对人类反而很容易,例如,从一堆人中识别出面孔。我们的目的是设计新算法新方法去让计算机在求解相对困难的问题时让人觉得是智能在起作用而非人。
1.2一台简单的预测机
普通机器:输入->流程(计算)->输出;eg:输入是4*3;计算是4+4+4;输出是12。
假设一台机器要将千米转换为英里,已知两者关系是线性的(英里=千米*C,但C未知)和一些正确的千米和公里的样本示例(100km,62.137英里)。
机器假设参数C为0.5,机器得到50英里答案,有误差值12.137,增加C可以增加输出。增加到0.6会有明显进步(使用误差值来指导如何改变C的值),使用0.7会出现较大误差,所有0.6更好。尝试0.61.
需要说明的是,输出值越接近正确答案,误差越来越小。而神经网络学习核心过程就是:训练机器使其输出值越发接近正确的值,迭代:持续的一点一点接近答案。
本节关键点:
1.所有计算机系统只有一个输入和输出。在输入和输出之间进行某种类型计算,神经网络也是如此;
2.当我们不能精确知道一些事情如何运作时,我们可以尝试模型来估计其运作方式,在模型中,包括我们可以调整的参数。如果我们不知道如何将千米转换为公里,我们可以使用线性函数作为模型,使用可调节的梯度值作为参数;
3.改进模型的一种好方法是基于模型和已知真实示例之间进行比较,得到模型偏移的误差值,调整参数。
1.3分类器与预测器并无太大差别
假设花园中只有两种小虫子,毛虫细而长,瓢虫宽而短,构建直角坐标系,横坐标是宽度,纵坐标是长度。使用同样的方法对两者进行分类。如果直线可以将两者区分,那么两者就可以根据测量值分类了。调节斜率以达到效果(假设斜率为1)。构建好简单分类器后,机器手臂抓一只小虫,测量宽长,使用上述分界线,可以将其正确归类。(此为使用线性函数对未知数据进行分类)
而在这一过程中,我们忽略了如何得到正确斜率及能不能改进优化小虫分界线呢,这是神经网络的核心地带,下一节讲。
1.4训练简单的分类器
本节我们讲如何调整分界线斜率使其能够基于小虫的宽度和长度将两组点划分开来。
解决方案:
两组数据(瓢虫,宽度3.0,长度1.0;毛虫,宽度1.0,长度3.0);在这里我们假设也有一个调整了参数的线性函数。这是一个分界线,一台分类器而非转换(假设为y=aX)。
假设随机选择参数为0.25,宽度为3,长度为0.75,训练数据告诉我们这至少是1,根据误差值(误差值E等于期望目标值1.1减去实际输出值0.75)调整参数,尽可能使所有瓢虫的点在下方。我们假设这里有一个微小的增量△A。△A与E的关系是△A=E/X,倘若我们要调整到1.1,1.E=1-0.75=0.35.X=3;则△A为0.1167,则斜率从0.25增加至0.3667.
代入宽度1.0,长度3.0,y=aX=1*0.3667=0.3667,与3差距较大。目标值设为2.9,2.5333/1.0+0.3667=2.9。所以最终调整斜率便为2.9。但这样效果并不好。
我们应该采用适度改进策略。改进不能太过激烈,采用△A的几分之几作为一个变化值。小心谨慎的调节参数。可以有效抑制错误和噪声,引入了调节系数L。△A=L(E/X)。调节系数也被称为学习率。假设L=0.5。初始值A=0.25,y=0.25*3.0=0.75,期望值为1.1,得到误差0.35,△A=L(E/X)=0.5*0.35/3.0=0.0583,更新后的A值为0.25+0.0583=0.3083。这时使用第二个样本值将A更新为1.6042。我们可以通过两个参数加之L计算出最后更新的值为1.6042.结果不错。我们已经实现了自动化的学习方法。
关键点:
1.我们使用简单的数学,理解了线性分类器输出误差值和可调节斜率参数之间的关系,换句话说,在何种程度上调整斜率,可以消除输出误差值;
2.使用朴素的调整方法会出现一个问题,即改进后的模型只与最后一次训练样本最匹配,“有效地”忽略了所有以前训练的样本,解决这一问题的一个方法是使用学习率,调整改进学习率,这样单一的训练样本无法主导学习过程;
3.来自真实世界的训练样本充满噪声或包含错误,适度更新有助于限制这些错误样本的影响。
1.5 有时候一个分类器不足以求解问题
线性分类器有局限性,这里以布尔逻辑函数为例来说明问题。
使用线性分类器可以学习到布尔AND运算和布尔OR运算(当AB输入均为真时,AND函数才为真,当只要有一个为真时,OR才为真。)。但如果出现的是由XOR(两者同真同假时,其为假)函数支配的训练数据,那么一个简单的线性分类器无法学习到布尔XOR函数。(主要限制:若不能用一条直线把根本性问题划分开来,那么简单线性分类器就是无用的)
因此我们需要神经网络去解决。神经网络的核心思想是使用多分类器一起工作。这样才可以解决XOR分类问题。
关键点:
1.如果数据本身不是单一线性过程支配,那么一个简单的线性分类器不能对数据进行划分,例如逻辑XOR运算符支配的数据说明了这一点;
2.解决方案很容易,使用多个线性分类器来划分由单一直线无法分离的数据。
1.6神经元—大自然的计算器
计算机处理速度快但能力不如大脑。这是因为架构不同:传统计算机串行,不存在不确定性;动物大脑并行,模糊性式计算的特征。
让我们观察大脑中的神经元,神经元分为树突、轴突和终端,电信号沿着轴突从树突传到树突。人脑有1000亿神经元,连线虫都有302神经元。观察表明:神经元不会立即反应,而是会抑制输入,直至输入增强,强大到可以触发输出。只有输入超过了阈值,足够接通电路,才会产生输出信号。神经元并不希望传递微小的噪声信号。数学上提供了许多激活阶跃函数可以实现简单的阶跃。换句话说:输入达到阈值,神经元就被激发了。
S函数相对于阶跃函数相对平滑、更接近自然、现实。S函数又被称为逻辑函数y=1/(1+e^-x),e=2.71828。
那么如何建模人工神经?
多个输入a,b,c,采用最终输入的总和和适用阈值的思路。将三者之后(x=a+b+c)作为S阈值函数(s=f(x))的输入。最终S函数输出y。若一个足够大,其他较小,也可以激发神经元。单个一般大,但之和大于阈值也可以激发神经元。类比到神经元,树突收集电信号,若足够大超过阈值,神经元发射信号,沿着轴突。传到终端,将信号传递给下一个神经元。每个神经元接受多个神经元的输入。
构建多层神经元,每一层中的神经元都与在其前后层的神经元互相连接。文章给了一个三层神经元示例(主要是神经元和神经元之间的连接)。针对训练样本,哪一部分执行学习功能呢?针对训练样本,我们应该如何调整作出反应呢?
1.调整节点之间的连接强度(即调整输入总和和S阈值函数的形状)2.给每个连接赋上权重(较小权重弱化信号,较大权重放大信号)。
随着神经网络学习过程的进行,神经网络通过调整优化网络内部的链接权重改进输出,一些权重可能变为零或接近零,为零意思就是断开了。
关键点:
1.虽然比起现代计算机,生物大脑看起来存储空间少,运行速度慢,但却可以执行复杂任务。譬如飞行、寻食、学习语言等。
2.相比于传统的计算机系统,生物大脑对损坏和不完善信号具有难以置信的弹性;
3.由相互连接的神经元组成的生物大脑是人工神经网络的灵感来源。
1.7 在神经网络中追踪信号
我们尝试使用两层神经元、每层有两个较小的神经元(共四个链接)来说明神经网络是如何运行的?
两个输入分别是1.0和0.5,S激活函数:y=1/(1+e^-x)将输入变为输出。神经元总输入信号为x,输出为y。权重随机分别为W1,1 = 0.9;W1,2=0.2;W2,1=0.3;W2,2=0.8;通过学习样本对随机数值进行改进。
开始计算:第一层是输入层,输入节点不对输入值应用激活函数;第二层开始计算,组合输入,此处组合所连接的前一层的原始输出,但这些输出得到了链接权重的调节。对于第二层的节点一而言:x=(第一个点的输出*链接权重)+(第二个点的输出*链接权重);x=1.0*0.9+0.5*0.3=1.05.权重是神经网络学习的内容,对这些权重持续优化,得到越来越好的结果。使用激活函数得到y=1/(1+e^-1.05)=0.7408.得到该神经网络的一个实际输出。面对多层、多个节点的神经网络,我们可以使用矩阵的方法来计算出所有的输出值。
1.8 凭心而论,矩阵乘法大有用途
矩阵压缩计算,能够允许压缩运算,进行缩写;而且计算机可以高效高速完成矩阵计算。矩阵仅仅简单是数字表格、矩形网络而已。矩阵可以是数字,也可以是表示数值的变量。
简单的矩阵相乘(大家应该都会,就不介绍了,自行百度)。需要注意的是:第一个矩阵的列数等于第二个矩阵的行数目。那么这有什么用呢?
见证奇迹的时刻。第一个矩阵是包含两层节点之间的权重,第二个矩阵是包含第一层输入层的信号。第一个2*2矩阵是(W1,1 W2,1 W1,2 W2,2);第二个是(input_1,input_2),两者相乘我们惊奇的发现可以得到与刚才计算相同的结果。X=W*I,W为权重矩阵,I为输入矩阵。X为调节后的信号。激活函数较为简单,无需矩阵乘法。对矩阵X的每个单独元素应用S函数。激活函数只是简单应用阈值,是反应变得更像是在生物神经元中观察到的行为。第二层的最终输出为O=sigmoid(X),O代表神经网络中最后一层的所有输出。X=W.I适用于前后层之间的运算。
关键点:
1.通过神经网络向前馈送信号所需的大量运算可以表示为矩阵乘法;
2.不管神经网络的规模如何,将输入输出表达为矩阵乘法,使得我们可以更为简洁的书写。
3.更重要的是,计算机编程语言理解矩阵运算,致使其可以高效的执行。
1.9使用矩阵乘法的三层神经网络示例
作者建立了3层,每层有3个节点的神经网络示例。3层中第一层为输入层,最后一层为输出层,中间层称为隐藏层(只是因为没有明显输出)。Winput_hidden是输入层和隐藏层之间的权重矩阵,Whidden_output指的是隐藏层和输出层之间的权重矩阵。那么中间层的输入是Xhidden=Winput_hidden*I;中间层的输出是Ohideen=sigmoid(Xhidden),因为S的值域在0和1之间,所以所有的值都在这个区间内。第三层与第二层原理一样,将Ohidden作为第三层的输入。需要注意的是,不管多少层神经网络,我们都一视同仁,即组合输入信号,应用权重对其调节,应用激活函数,最终生成这些层的输出信号。
下一步我们需要将神经网络的输出值与训练样本的输入值进行比较,计算误差,我们需要使用这个误差值来调整神经网络本身,进而改进神经网络的输出值。
1.10学习来自多个节点的权重
因为输出和误差是多个节点共同作用的结果,如何更新权重?
(1)在所有造成误差的节点中平分误差。将输出误差平分至上两个节点。
(2)不等分误差,给较大链接权重分配更多误差,根据比例进行误差的分配。
权重的使用:
第一件事情,在神经网络中,我们使用权重将信号从输入向前传播到输出层;第二件事情,使用权重,将误差从输出向后传播至网络中,这种方法称为反向传播。
1.11多个输出节点反向传播误差
我们将第一个输出节点的误差标记为e1,e1等于训练数据t1所提供的期望值与实际输出值O1之间的差,按照权重比例w1,1和w2,1分割误差e1。w1,1和w2,1分别为6和3,用于更新w1,1的e1部分是2/3。
使用误差指导在网络内部如何调整一些参数,在这里也就是链接权重。那么若是神经网络大于二层,会如何更新权重呢?
1.12反向传播误差到更多层
三层神经网络。假设输出的误差标记为eoutput,将在输出层和隐藏层之间的链接权重标记为who,通过误差按照权重比例分割,我们计算每条链接相关的特定误差值。核心在于我们只知道最终输出的节点是多少,而不知道中间其它层的节点输出应该是多少?
可以使用看到的误差反向传播,为链接重组分割的误差。因此第一个隐藏层节点的误差是与这个节点前向连接中分割误差的和。
ehidden,1=链接W1,1和链接W1,2的分割误差之和
=eoutput,1 * w1,1 /(w1,1+w2,1)+=eoutput,2 * w1,2 /(w1,2+w2,2)
=0.8*2/(2+3)+0.5*1/(1+4)
=0.42
关键点:
1.神经网络通过调整链接权重进行学习,这种方法由误差引导,误差就是训练数据所给出正确答案和实际输出之间的差值。
2.输出节点处的误差等于所需值与实际值之间的差值
3.内部节点相关联的误差并不是显而易见的,按照链路权重的比例来分割来分割输出层的误差,再在每个内部节点处重组这些误差。
1.13使用矩阵乘法来进行反向传播误差
将过程矢量化。计算起点是输出层所出现的误差。由上面的分析可知:
更新矩阵乘法以代替。第一个矩阵其实是一个转置后的矩阵。
所以最终的结果为:
切除归一化因子相对于之前复杂的方法依然有效。反馈过大过小依然可以自行纠正。链接权重的强度给出了共享误差最好的提示。
关键点:
1.反向传播误差可以表示为矩阵乘法
2.无论网络规模大小,这是我们能够简洁表达反向传播误差,同时计算机处理矩阵运算会比较快。
3.前向馈送信号和反向传播误差都可以使用矩阵计算而变得高效。
有时候一篇文章太长也不是好事,容易让人觉得看的很累,那么下一章再讲如何更新权重、更新权重的示例以及神经网络的准备布局。
安卓开发交流群:651325026,欢迎大家入群交流。