创富东方的官方站勒索病毒会不会传染有病毒,是不是正规的?

机器学习入门——浅谈神经网络_人工智能吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:53,371贴子:
机器学习入门——浅谈神经网络收藏
一楼献给度娘
先从回归(Regression)问题说起。我在本吧已经看到不少人提到如果想实现强AI,就必须让机器学会观察并总结规律的言论。具体地说,要让机器观察什么是圆的,什么是方的,区分各种颜色和形状,然后根据这些特征对某种事物进行分类或预测。其实这就是回归问题。 如何解决回归问题?我们用眼睛看到某样东西,可以一下子看出它的一些基本特征。可是计算机呢?它看到的只是一堆数字而已,因此要让机器从事物的特征中找到规律,其实是一个如何在数字中找规律的问题。 例:假如有一串数字,已知前六个是1、3、5、7,9,11,请问第七个是几?你一眼能看出来,是13。对,这串数字之间有明显的数学规律,都是奇数,而且是按顺序排列的。那么这个呢?前六个是0.14、0.57、1.29、2.29、3.57、5.14,请问第七个是几?这个就不那么容易看出来了吧!我们把这几个数字在坐标轴上标识一下,可以看到如下图形:用曲线连接这几个点,延着曲线的走势,可以推算出第七个数字——7。由此可见,回归问题其实是个曲线拟合(Curve Fitting)问题。那么究竟该如何拟合?机器不可能像你一样,凭感觉随手画一下就拟合了,它必须要通过某种算法才行。
假设有一堆按一定规律分布的样本点,下面我以拟合直线为例,说说这种算法的原理。
其实很简单,先随意画一条直线,然后不断旋转它。每转一下,就分别计算一下每个样本点和直线上对应点的距离(误差),求出所有点的误差之和。这样不断旋转,当误差之和达到最小时,停止旋转。说得再复杂点,在旋转的过程中,还要不断平移这条直线,这样不断调整,直到误差最小时为止。这种方法就是著名的梯度下降法(Gradient Descent)。为什么是梯度下降呢?在旋转的过程中,当误差越来越小时,旋转或移动的量也跟着逐渐变小,当误差小于某个很小的数,例如0.0001时,我们就可以收工(收敛, Converge)了。啰嗦一句,如果随便转,转过头了再往回转,那就不是梯度下降法。 我们知道,直线的公式是y=kx+b,k代表斜率,b代表偏移值(y轴上的截距)。也就是说,k可以控制直线的旋转角度,b可以控制直线的移动。强调一下,梯度下降法的实质是不断的修改k、b这两个参数值,使最终的误差达到最小。 求误差时使用 累加(直线点-样本点)^2,这样比直接求差距 累加(直线点-样本点) 的效果要好。这种利用最小化误差的平方和来解决回归问题的方法叫最小二乘法(Least Square Method)。 问题到此使似乎就已经解决了,可是我们需要一种适应于各种曲线拟合的方法,所以还需要继续深入研究。 我们根据拟合直线不断旋转的角度(斜率)和拟合的误差画一条函数曲线,如图:
从图中可以看出,误差的函数曲线是个二次曲线,凸函数(下凸, Convex),像个碗的形状,最小值位于碗的最下端。如果在曲线的最底端画一条切线,那么这条切线一定是水平的,在图中可以把横坐标轴看成是这条切线。如果能求出曲线上每个点的切线,就能得到切线位于水平状态时,即切线斜率等于0时的坐标值,这个坐标值就是我们要求的误差最小值和最终的拟合直线的最终斜率。 这样,梯度下降的问题集中到了切线的旋转上。切线旋转至水平时,切线斜率=0,误差降至最小值。
切线每次旋转的幅度叫做学习率(Learning Rate),加大学习率会加快拟合速度,但是如果调得太大会导致切线旋转过度而无法收敛。
注意:对于凹凸不平的误差函数曲线,梯度下降时有可能陷入局部最优解。下图的曲线中有两个坑,切线有可能在第一个坑的最底部趋于水平。
微分就是专门求曲线切线的工具,求出的切线斜率叫做导数(Derivative),用dy/dx或f'(x)表示。扩展到多变量的应用,如果要同时求多个曲线的切线,那么其中某个切线的斜率就叫偏导数(Partial Derivative),用∂y/∂x表示,∂读“偏(partial)”。由于实际应用中,我们一般都是对多变量进行处理,我在后面提到的导数也都是指偏导数。
以上是线性回归(Linear Regression)的基本内容,以此方法为基础,把直线公式改为曲线公式,还可以扩展出二次回归、三次回归、多项式回归等多种曲线回归。下图是Excel的回归分析功能。在多数情况下,曲线回归会比直线回归更精确,但它也增加了拟合的复杂程度。直线方程y=kx+b改为二次曲线方程y=ax^2+bx+c时,参数(Parameter)由2个(分别是k、b)变为3个(分别是a、b、c),特征(Feature)由1个(x)变为2个(x^2和x)。三次曲线和复杂的多项式回归会增加更多的参数和特征。前面讲的是总结一串数字的规律,现实生活中我们往往要根据多个特征(多串数字)来分析一件事情,每个原始特征我们都看作是一个维度(Dimension)。例如一个学生的学习成绩好坏要根据语文、数学、英语等多门课程的分数来综合判断,这里每门课程都是一个维度。当使用二次曲线和多变量(多维)拟合的情况下,特征的数量会剧增,特征数=维度^2/2 这个公式可以大概计算出特征增加的情况,例如一个100维的数据,二次多项式拟合后,特征会增加到100*100/2=5000个。下面是一张50*50像素的灰度图片,如果用二次多项式拟合的话,它有多少个特征呢?——大约有3百万!它的维度是50*50=2500,特征数==3,125,000。如果是彩色图片,维度会增加到原来的3倍,那么特征数将增加到接近3千万了!这么小的一张图片,就有这么巨大的特征量,可以想像一下我们的数码相机拍下来的照片会有多大的特征量!而我们要做的是从十万乃至亿万张这样的图片中找规律,这可能吗?很显然,前面的那些回归方法已经不够用了,我们急需找到一种数学模型,能够在此基础上不断减少特征,降低维度。于是,“人工神经网络(ANN, Artificial Neural Network)”就在这样苛刻的条件下粉墨登场了,神经科学的研究成果为机器学习领域开辟了广阔的道路。
神经元有一种假说:“智能来源于单一的算法(One Learning Algorithm)”。如果这一假说成立,那么利用单一的算法(神经网络)处理世界上千变万化的问题就成为可能。我们不必对万事万物进行编程,只需采用以不变应万变的策略即可。有越来越多的证据证明这种假说,例如人类大脑发育初期,每一部分的职责分工是不确定的,也就是说,人脑中负责处理声音的部分其实也可以处理视觉影像。下图是单个神经元(Neuron),或者说一个脑细胞的生理结构:下面是单个神经元的数学模型,可以看出它是生理结构的简化版,模仿的还挺像:解释一下:+1代表偏移值(偏置项, Bias Units);X1,X2,X2代表初始特征;w0,w1,w2,w3代表权重(Weight),即参数,是特征的缩放倍数;特征经过缩放和偏移后全部累加起来,此后还要经过一次激活运算然后再输出。激活函数有很多种,后面将会详细说明。举例说明:X1*w1+X2*w2+...+Xn*wn这种计算方法称为加权求和(Weighted Sum)法,此方法在线性代数里极为常用。加权求和的标准数学符号是,不过为了简化,我在教程里使用女巫布莱尔的符号表示,刚好是一个加号和一个乘号的组合。
这个数学模型有什么意义呢?下面我对照前面那个 y=kx+b 直线拟合的例子来说明一下。这时我们把激活函数改为Purelin(45度直线),Purelin就是y=x,代表保持原来的值不变。这样输出值就成了 Y直线点 = b + X直线点*k,即y=kx+b。看到了吧,只是换了个马甲而已,还认的出来吗?下一步,对于每个点都进行这种运算,利用Y直线点和Y样本点计算误差,把误差累加起来,不断地更新b、k的值,由此不断地移动和旋转直线,直到误差变得很小时停住(收敛)。这个过程完全就是前面讲过的梯度下降的线性回归。一般直线拟合的精确度要比曲线差很多,那么使用神经网络我们将如何使用曲线拟合?答案是使用非线性的激活函数即可,最常见的激活函数是Sigmoid(S形曲线),Sigmoid有时也称为逻辑回归(Logistic Regression),简称logsig。logsig曲线的公式如下:还有一种S形曲线也很常见到,叫双曲正切函数(tanh),或称tansig,可以替代logsig。下面是它们的函数图形,从图中可以看出logsig的数值范围是0~1,而tansig的数值范围是-1~1。
自然常数e公式中的e叫自然常数,也叫欧拉数,e=2.71828...。e是个很神秘的数字,它是“自然律”的精髓,其中暗藏着自然增长的奥秘,它的图形表达是旋涡形的螺线。融入了e的螺旋线,在不断循环缩放的过程中,可以完全保持它原有的弯曲度不变,就像一个无底的黑洞,吸进再多的东西也可以保持原来的形状。这一点至关重要!它可以让我们的数据在经历了多重的Sigmoid变换后仍维持原先的比例关系。e是怎么来的?e = 1 + 1/1! + 1/2! + 1/3! + 1/4! + 1/5! + 1/6! + 1/7! + ... = 1 + 1 + 1/2 + 1/6 + 1/24 + 1/120+ ... ≈ 2.71828 (!代表阶乘,3!=1*2*3=6)再举个通俗点的例子:从前有个财主,他特别贪财,喜欢放债。放出去的债年利率为100%,也就是说借1块钱,一年后要还给他2块钱。有一天,他想了个坏主意,要一年算两次利息,上半年50%,下半年50%,这样上半年就有1块5了,下半年按1块5的50%来算,就有1.5/2=0.75元,加起来一年是:上半年1.5+下半年0.75=2.25元。用公式描述,就是(1+50%)(1+50%)=(1+1/2)^2=2.25元。可是他又想,如果按季度算,一年算4次,那岂不是更赚?那就是(1+1/4)^4=2.44141,果然更多了。他很高兴,于是又想,那干脆每天都算吧,这样一年下来就是(1+1/365)^365=2.71457。然后他还想每秒都算,结果他的管家把他拉住了,说要再算下去别人都会疯掉了。不过财主还是不死心,算了很多年终于算出来了,当x趋于无限大的时候,e=(1+1/x)^x≈ 2.71828,结果他成了数学家。e在微积分领域非常重要,e^x的导数依然是e^x,自己的导数恰好是它自己,这种巧合在实数范围内绝无仅有。一些不同的称呼:e^x和e^-x的图形是对称的;ln(x)是e^x的逆函数,它们呈45度对称。
神经网络好了,前面花了不少篇幅来介绍激活函数中那个暗藏玄机的e,下面可以正式介绍神经元的网络形式了。下图是几种比较常见的网络形式:- 左边蓝色的圆圈叫“输入层”,中间橙色的不管有多少层都叫“隐藏层”,右边绿色的是“输出层”。- 每个圆圈,都代表一个神经元,也叫节点(Node)。- 输出层可以有多个节点,多节点输出常常用于分类问题。- 理论证明,任何多层网络可以用三层网络近似地表示。- 一般凭经验来确定隐藏层到底应该有多少个节点,在测试的过程中也可以不断调整节点数以取得最佳效果。计算方法:- 虽然图中未标识,但必须注意每一个箭头指向的连线上,都要有一个权重(缩放)值。- 输入层的每个节点,都要与的隐藏层每个节点做点对点的计算,计算的方法是加权求和+激活,前面已经介绍过了。(图中的红色箭头指示出某个节点的运算关系)- 利用隐藏层计算出的每个值,再用相同的方法,和输出层进行计算。- 隐藏层用都是用Sigmoid作激活函数,而输出层用的是Purelin。这是因为Purelin可以保持之前任意范围的数值缩放,便于和样本值作比较,而Sigmoid的数值范围只能在0~1之间。- 起初输入层的数值通过网络计算分别传播到隐藏层,再以相同的方式传播到输出层,最终的输出值和样本值作比较,计算出误差,这个过程叫前向传播(Forward Propagation)。
前面讲过,使用梯度下降的方法,要不断的修改k、b两个参数值,使最终的误差达到最小。神经网络可不只k、b两个参数,事实上,网络的每条连接线上都有一个权重参数,如何有效的修改这些参数,使误差最小化,成为一个很棘手的问题。从人工神经网络诞生的60年代,人们就一直在不断尝试各种方法来解决这个问题。直到80年代,误差反向传播算法(BP算法)的提出,才提供了真正有效的解决方案,使神经网络的研究绝处逢生。BP算法是一种计算偏导数的有效方法,它的基本原理是:利用前向传播最后输出的结果来计算误差的偏导数,再用这个偏导数和前面的隐藏层进行加权求和,如此一层一层的向后传下去,直到输入层(不计算输入层),最后利用每个节点求出的偏导数来更新权重。为了便于理解,后面我一律用“残差(error term)”这个词来表示误差的偏导数。输出层→隐藏层:残差 = -(输出值-样本值) * 激活函数的导数隐藏层→隐藏层:残差 = (右层每个节点的残差加权求和)* 激活函数的导数如果输出层用Purelin作激活函数,Purelin的导数是1,输出层→隐藏层:残差 = -(输出值-样本值)如果用Sigmoid(logsig)作激活函数,那么:Sigmoid导数 = Sigmoid*(1-Sigmoid)输出层→隐藏层:残差 = -(Sigmoid输出值-样本值) * Sigmoid*(1-Sigmoid) = -(输出值-样本值)*输出值*(1-输出值)隐藏层→隐藏层:残差 = (右层每个节点的残差加权求和)* 当前节点的Sigmoid*(1-当前节点的Sigmoid)如果用tansig作激活函数,那么:tansig导数 = 1 - tansig^2残差全部计算好后,就可以更新权重了:输入层:权重增加 = 当前节点的Sigmoid * 右层对应节点的残差 * 学习率隐藏层:权重增加 = 输入值 * 右层对应节点的残差 * 学习率偏移值的权重增加 = 右层对应节点的残差 * 学习率学习率前面介绍过,学习率是一个预先设置好的参数,用于控制每次更新的幅度。此后,对全部数据都反复进行这样的计算,直到输出的误差达到一个很小的值为止。以上介绍的是目前最常见的神经网络类型,称为前馈神经网络(FeedForward Neural Network),由于它一般是要向后传递误差的,所以也叫BP神经网络(Back Propagation Neural Network)。
BP神经网络的特点和局限:- BP神经网络可以用作分类、聚类、预测等。需要有一定量的历史数据,通过历史数据的训练,网络可以学习到数据中隐含的知识。在你的问题中,首先要找到某些问题的一些特征,以及对应的评价数据,用这些数据来训练神经网络。- BP神经网络主要是在实践的基础上逐步完善起来的系统,并不完全是建立在仿生学上的。从这个角度讲,实用性 & 生理相似性。- BP神经网络中的某些算法,例如如何选择初始值、如何确定隐藏层的节点个数、使用何种激活函数等问题,并没有确凿的理论依据,只有一些根据实践经验总结出的有效方法或经验公式。- BP神经网络虽然是一种非常有效的计算方法,但它也以计算超复杂、计算速度超慢、容易陷入局部最优解等多项弱点著称,因此人们提出了大量有效的改进方案,一些新的神经网络形式也层出不穷。
文字的公式看上去有点绕,下面我发一个详细的计算过程图。参考这个: 我做了整理
这里介绍的是计算完一条记录,就马上更新权重,以后每计算完一条都即时更新权重。实际上批量更新的效果会更好,方法是在不更新权重的情况下,把记录集的每条记录都算过一遍,把要更新的增值全部累加起来求平均值,然后利用这个平均值来更新一次权重,然后利用更新后的权重进行下一轮的计算,这种方法叫批量梯度下降(Batch Gradient Descent)。
推荐的入门级学习资源:Andrew Ng的《机器学习》公开课: Coursera公开课笔记中文版(神经网络的表示): 公开课笔记-斯坦福大学机器学习第八课-神经网络的表示-neural-networks-representationCoursera公开课视频(神经网络的学习): 公开课视频-斯坦福大学机器学习第九课-神经网络的学习-neural-networks-learning斯坦福深度学习中文版: 教程
谢谢大家的支持。今天先发个实际编程操作教程,介绍一下Matlab神经网络工具箱的用法,后面有空再加些深入点的知识。
关于Matlab的入门教程,参看这个帖子:例1:我们都知道,面积=长*宽,假如我们有一组数测量据如下:我们利用这组数据来训练神经网络。(在Matlab中输入以下的代码,按回车即可执行)p = [2 5; 3 6; 12 2; 1 6; 9 2; 8 12; 4 7; 7 9]'; % 特征数据X1,X2t = [10 18 24 6 18 96 28 63]; % 样本值net = newff(p, t, 20); % 创建一个BP神经网络 ff=FeedForwardnet = train(net, p, t); % 用p,t数据来训练这个网络出现如下的信息,根据蓝线的显示,可以看出最后收敛时,误差已小于10^-20。你也许会问,计算机难道这样就能学会乘法规则吗?不用背乘法口诀表了?先随便选几个数字,试试看:s = [3 7; 6 9; 4 5; 5 7]'; % 准备一组新的数据用于测试y = sim(net, s) % 模拟一下,看看效果% 结果是:25.1029
37.5879看到了吧,预测结果和实际结果还是有差距的。不过从中也能看出,预测的数据不是瞎蒙的,至少还是有那么一点靠谱。如果训练集中的数据再多一些的话,预测的准确率还会大幅度提高。你测试的结果也许和我的不同,这是因为初始化的权重参数是随机的,可能会陷入局部最优解,所以有时预测的结果会很不理想。
例2:下面测试一下拟合正弦曲线,这次我们随机生成一些点来做样本。p = rand(1,50)*7 % 生成1行50个0~7之间的随机数t = sin(p) % 计算正弦曲线s = [0:0.1:7]; % 生成0~7的一组数据,间隔0.1,用于模拟测试plot(p, t, 'x') % 画散点图net = newff(p, t, 20);
% 创建神经网络net = train(net, p, t); % 开始训练y = sim(net, s); % 模拟plot(s, y, 'x')
% 画散点图从图中看出,这次的预测结果显然是不理想的,我们需要设置一些参数来调整。
下面的设置是一种标准的批量梯度下降法的配置。% 创建3层神经网络 [隐藏层10个节点-&logsig, 输出层1个节点-&purelin] traingd代表梯度下降法net = newff(p, t, 10, {'logsig' 'purelin'}, 'traingd'); % 10不能写成[10 1]% 设置训练参数net.trainparam.show = 50; % 显示训练结果(训练50次显示一次)net.trainparam.epochs = 500; % 总训练次数net.trainparam.goal = 0.01;
% 训练目标:误差&0.01net.trainParam.lr = 0.01; % 学习率(learning rate)net = train(net, p, t); % 开始训练注意:newff的第三个参数10不能写成[10 1],否则就是4层网络,两个隐藏层,分别是10个和1个节点。这个很容易弄错。(输出层的节点数程序会自动根据t的维度自动判断,所以不用指定)y = sim(net, s); % 模拟plot(s, y, 'x')
% 画散点图这时的效果显然更差了。把精度调高一点看看。训练次数加到9999,误差&0.001;学习率调到0.06,希望能加快点速度。% 创建2层神经网络 [隐藏层10个节点-&logsig, 输出层1个节点-&purelin] traingd代表梯度下降法net = newff(p, t, 10, {'logsig' 'purelin'}, 'traingd');% 设置训练参数net.trainparam.show = 50; % 每间隔50次显示一次训练结果net.trainparam.epochs = 9999; % 总训练次数net.trainparam.goal = 0.001;
% 训练目标:误差&0.001net.trainParam.lr = 0.06; % 学习率(learning rate)net = train(net, p, t); % 开始训练标准的批量梯度下降法的速度确实够慢,这次计算花了一分多钟。y = sim(net, s); % 模拟plot(s, y, 'x')
% 画散点图效果比上次稍好一点。不过这条曲线显得坑坑洼洼的很难看,这是一种过拟合(Overfitting)现象,与之相反的是欠拟合(Underfitting)。
先来解决速度问题,把traingd改为trainlm即可。trainlm使用LM算法,是介于牛顿法和梯度下降法之间的一种非线性优化方法,不但会加快训练速度,还会减小陷入局部最小值的可能性,是Matlab的默认值。net = newff(p, t, 10, {'logsig' 'purelin'}, 'trainlm');... 后面的代码不变这个速度比较惊叹了,1秒钟之内完成,只做了6轮计算,效果也好了一些。不过,LM算法也有弱点,它占用的内存非常大,所以没把其它算法给淘汰掉。 下面解决过拟合问题,把隐藏层的节点数目设少一点就行了。net = newff(p, t, 3, {'logsig' 'purelin'}, 'trainlm');... 后面的代码不变这回终于达到满意的效果了。(有时会出现局部最优解,可以多试几次)
如果节点数目太少,会出现欠拟合的情况。关于隐藏层的节点个数,一般是要凭感觉去调的。如果训练集的维数比较多,调节起来比较耗时间,这时可以根据经验公式上下浮动地去调整。下面给出几个经验公式供参考:
如果把输出层改为logsig激活会是什么样子呢?net = newff(p, t, 3, {'logsig' 'logsig'}); % 创建神经网络net = train(net, p, t); % 开始训练y = sim(net, s); % 模拟plot(s, y, 'x') % 画散点图 可以看出,-1~0范围之间的点都变为0了。使用logsig输出时要想得到完整数值范围的效果,必须先对数据进行归一化才行。 归一化(Normalization),也叫标准化,就是把一堆数字按比例缩放到0~1或-1~1的范围。虽然用Purelin输出可以不必归一化,但归一化能在一定程度上加快收敛速度,因此被许多教程定为训练前的必须步骤。公式为:归一值 = (当前值x-最小值min)/(最大值max-最小值min)如果限定了范围,公式为:y = (ymax-ymin)*(x-xmin)/(xmax-xmin) +0.1~0.9的范围:(0.9-0.1)*(x-min)/(max-min)*(0.9-0.1)+0.1把5, 2, 6, 3这四个数归一化: Matlab的归一化命令为:mapminmax注:网上的不少教程里用premnmx命令来归一化,要注意Matlab版本R2007b和R2008b,premnmx在处理单列数据时有bug,Matlab已给出了警告,R2009a版才修正。因此推荐使用mapminmax。mapminmax的输入输出值和premnmx是行列颠倒的,使用时要注意代码中是否添加转置符号。a = [5, 2, 6, 3];b = mapminmax(a, 0, 1) % 归一化到0~1之间% b = 0..0c = mapminmax(a) % 归一化到-1~1之间% c = 0.0 1.0 反归一化(Denormalization)就是按归一化时的比例还原数值。a = [5, 2, 6, 3];[c,PS] = mapminmax(a); % PS记录归一化时的比例mapminmax('reverse', c, PS) % 利用PS反归一化% ans = 5 2 6 3 神经网络的归一化(0~1范围)代码:p = rand(1,50)*7; % 特征数据t = sin(p); % 样本值s = [0:0.1:7]; % 测试数据[pn, ps] = mapminmax(p, 0, 1); % 特征数据归一化[tn, ts] = mapminmax(t, 0, 1); % 样本值归一化sn = mapminmax('apply', s, ps); % 测试数据,按ps比例缩放net = newff(pn, tn, [5 1], {'logsig' 'logsig'}); % 创建神经网络net = train(net, pn, tn); % 开始训练yn = sim(net, sn); % 模拟y = mapminmax('reverse', yn, ts); % 按ps的比例还原plot(s, y, 'x') % 画散点图
神经网络工具箱还有一个UI图形操作界面,执行nntool就可以打开。我觉得不如写代码方便,所以不怎么用。我提供一个相关的教程链接,有兴趣的可以看一下:matlab神经网络工具箱创建神经网络 - 新浪./s/blog_0vxtv.html
(新浪替换成sina)
关于Sigmoid的由来,中文的网站上很少有提及的。下面简单讲一下,希望能给大家拓展一下思路。PS: 这里的公式我都给出了求解过程,但如今这个年头,用手工解题的人越来越少了,一般的方程用软件来解就行了。例如解Sigmoid微分方程,可以用Matlab去解:dsolve('Dx=x*(1-x)')% ans = 1/(1+exp(-t)*C1) 如果想得到求解的步骤或更详细的信息,推荐使用Wolfram:在Wolfram的搜索框输入 x'=x(1-x) 即可。
logsigSigmoid函数(S形函数,Logistic Function)是受统计学模型的启发而产生的激活函数。基于生物学的神经元激活函数是这样的:参看:实践证明了基于统计学的Sigmoid函数激活效果要比基于生物学的模型好,而且计算起来很方便,所以说不能以机器和人的相似度为标准来判断AI算法的好坏。Sigmoid函数原先是个描述人口增长的数学模型,1838提出,给出的是导数形式(概率密度)。人口增长规律:起初阶段大致是指数增长;然后逐渐开始变得饱和,增长变慢;达到成熟时几乎停止增长;整个过程形如一条S型曲线。
导数的形式知道了,那么它的原函数是什么样子呢?已知导数求原函数,用统计学的话来讲,即根据概率密度函数(PDF)求累积分布函数(CDF),不定积分(Indefinite Integral)就是专门用来做这个的工具。根据不定积分的知识可知,由于常数项是可变的,所以存在无数个原函数的可能。让我们先用图解法看一下:既然导数是函数曲线的斜率,那么可以把一定数值范围内的斜率,都画成一根根的短斜线,组成斜率场(Slope Fields, Direction Fields),然后根据这些斜线的走势,画出积分曲线。Matlab可以用quiver命令来画斜率场。从上图中可以看出,在y轴的0~1之间是个分水岭,0和1处的方向趋于水平。下面放大0~1的范围看看是什么样子的。看到了吧,我们要的Logistic Sigmoid就在这里呢。下面给出符号求解的过程:
tansig双曲正切函数(双极S形函数, tanh, Hyperbolic Tangent),读tanch,18世纪就已经出现了。它的定义是:tanh(x)=sinh(x)/cosh(x),可以由著名的欧拉公式(Euler's formula)推导出来。用tanh作激活函数,收敛比较快,效果比Logistic函数还要好。欧拉公式:
i是虚数(Imaginary Number)单位,它的定义是:
(即i^2 = -1)题外话:根据上面的公式变换,可以得出史上最美的数学公式: ,数学中最神秘的5个符号e、i、π、1和0,全包含在里面了。求tanh的导数:logsig和tansig的关系:
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或BP神经网络原理及python实现-爱编程
BP神经网络原理及python实现
【废话外传】:终于要讲神经网络了,这个让我踏进机器学习大门,让我读研,改变我人生命运的四个字!话说那么一天,我在乱点百度,看到了这样的内容:
看到这么高大上,这么牛逼的定义,怎么能不让我这个技术宅男心向往之?现在入坑之后就是下面的表情:
好了好了,玩笑就开到这里,其实我是真的很喜欢这门学科,要不喜欢,老子早考公务员,找事业单位去了,还在这里陪你们牛逼打诨?写博客,吹逼?
1神经网络历史(本章来自维基百科,看过的自行跳过)
和·皮茨(1943)[基于数学和一种称为阈值逻辑的算法创造了一种神经网络的计算模型。这种模型使得神经网络的研究分裂为两种不同研究思路。一种主要关注大脑中的生物学过程,另一种主要关注神经网络在人工智能里的应用。
赫布型学习
二十世纪40年代后期,心理学家·赫布根据神经可塑性的机制创造了一种对学习的假说,现在称作。赫布型学习被认为是一种典型的规则,它后来的变种是的早期模型。从1948年开始,研究人员将这种计算模型的思想应用到B型图灵机上。
法利和·A·克拉克(1954)[3]首次使用计算机,当时称作计算器,在MIT模拟了一个赫布网络。
弗兰克·罗森布拉特(1956)[4]创造了感知机。这是一种模式识别算法,用简单的加减法实现了两层的计算机学习网络。罗森布拉特也用数学符号描述了基本感知机里没有的回路,例如异或回路。这种回路一直无法被神经网络处理,直到Paul Werbos(1975)创造了。
在·明斯基和·帕尔特(1969)发表了一项关于机器学习的研究以后,神经网络的研究停滞不前。他们发现了神经网络的两个关键问题。第一是基本感知机无法处理异或回路。第二个重要的问题是电脑没有足够的能力来处理大型神经网络所需要的很长的计算时间。直到计算机具有更强的计算能力之前,神经网络的研究进展缓慢。
反向传播算法与复兴[编辑]
后来出现的一个关键的进展是(Werbos 1975)。这个算法有效地解决了异或的问题,还有更普遍的训练多层神经网络的问题。
在二十世纪80年代中期,(当时称作)流行起来。David E. Rumelhart和James McClelland(1986)的教材对于联结主义在计算机模拟神经活动中的应用提供了全面的论述。
神经网络传统上被认为是大脑中的神经活动的简化模型,虽然这个模型和大脑的生理结构之间的关联存在争议。人们不清楚人工神经网络能多大程度地反映大脑的功能。
和其他更简单的方法(例如)在机器学习领域的流行度逐渐超过了神经网络,但是在2000年代后期出现的重新激发了人们对神经网络的兴趣。
2006年之后的进展[编辑]
人们用CMOS创造了用于生物物理模拟和神经形态计算的计算装置。最新的研究显示了用于大型和的纳米装置[5]具有良好的前景。如果成功的话,这会创造出一种新的神经计算装置[6],因为它依赖于学习而不是编程,并且它从根本上就是的而不是的,虽然它的第一个实例可能是数字化的CMOS装置。
在2009到2012年之间,Jürgen Schmidhuber在Swiss AI Lab IDSIA的研究小组研发的和深前馈神经网络赢得了8项关于模式识别和机器学习的国际比赛。[7]例如,Alex Graves et al.的双向、多维的LSTM赢得了2009年ICDAR的3项关于连笔字识别的比赛,而且之前并不知道关于将要学习的3种语言的信息。[9]
IDSIA的Dan Ciresan和同事根据这个方法编写的基于GPU的实现赢得了多项模式识别的比赛,包括IJCNN 2011交通标志识别比赛等等。[13]他们的神经网络也是第一个在重要的基准测试中(例如IJCNN 2012交通标志识别和NYU的·勒丘恩(Yann LeCun)的MNIST手写数字问题)能达到或超过人类水平的人工模式识别器。
类似1980年Kunihiko Fukushima发明的neocognitron和视觉标准结构[16](由David H. Hubel和Torsten Wiesel在初级视皮层中发现的那些简单而又复杂的细胞启发)那样有深度的、高度非线性的神经结构可以被多伦多大学杰夫·辛顿实验室的非监督式学习方法所训练
现在的发展:
谷歌阿法狗战胜李世石,深度学习火的不要不要的。
二 神经网络的原理
1 人工神经元与神经元
众所周知,人是靠神经元控制身体的运转的。例如下图:
你看这边大头的,就是我们的输入,经过处理,后面的就是我们的输出,这个输出有可能又接着其他的输入,最后形成这样:
然后信息就这样被传播下去了,人体是这样传播的,那我们的人造神经网络是什么样的呢,当然也和这个差不多了。
现在人们提出的神经元模型有很多,其中最早提出并且影响最多的是1943年心理学家
McCullocl和数学家W.Pitts在分析总结神经元基本特性的基础上首先提出的MP模型。该
模型经过不断改进后,形成现在广泛应用的BP神经元模型(朱人奇提出,2006)。人工神经元模型是由大量处理单元广泛互连而成的网络,是人脑的抽象、简化、模拟,反映人脑的基
本特性。一般来说,作为人工神经元模型应具各三个要素:
每个神经元的输入有一个权重wi用来表示第i个神经元神经元的连接权重。
各个信号信息乘以权重得到的信号累加器,θ表示阀值。
激励函数。(这个我后面讲)
有了上述三个要素,来看看人造神经元:
其中为神经元的初始输入,为神经元的组合输入,即:,θ为阀值,vi为组合输入与阀值计算之后的输入,。
f(x)为激励函数,激活函数,挤压函数都可以。yi是这个神经元最后的输出,
作用:数值上挤压,几何上变形。
类似于这样:我们要用一条直线把下面的点区分开来:
这个很容易,但是要是这样的呢?:
龟龟,这样一条直线是不是就很难分开了啊,但是要想分开,我们可以这样:把他改成非线性的不就ok了?例如先画个圆?
还有一种方法是把点投影到一个直线上,也是可以解决的。我们暂且不说。
2.1激活函数的种类
1:阀值函数
比如有时候要把很大很大的数挤压到(0,1)的范围,理想情况应该是这样:图1(本图片来自百度,反正大家都用这图)
但是这个函数有个缺点只输出(0,1)是不是就降低了神经元的功效了?这就是MP模型,可以用来表示神经元的激活与非激活状态。
2 sigmoid函数
Sigmoid函数又称为s形函数,等等我好像在logistic回归中讲过这个函数,看来这个函数还是很牛逼的啊。
我们可以通过改变a来改变函数的斜率。当斜率趋向于无穷大时候,那么这就是一个阶跃函数。Sigmoid函数可微分,但是阶跃函数却不是的。
三 BP神经网络
1 BP的基本思想
BP算法的基本思想是:学习过程由信号的正向传播与误差的反向传播两个过程组成。正向传播时,输入样本从输入层传入,经各隐含层处理后,传向输出层,若输出层的实际输出与期望的输出不符合要求,则转入误差的反向传播阶段。误差反向传播是将输出误差以某种形式通过隐含层向输入层逐层反向传播,并将误差分摊给各层的所有单元,从而获得各层单元的误差信号,此误差信号即作为修正各单元的依据。这种信号正向传播与误差反向传播的各层权值调整过程,是周而复始地进行的。权值不断调整的过程,也就是网络的学习训练过程。此过程一直进行到网络输出的误差减少到可接受的程度或进行到预先设定的学习次数为止。
其实就是我们小时候去给老师检查作业:老师说,不合格,拿回去修改,修改过程就是调节权重的过程,一般这个过程结束就只有,(假设老师的忍耐系数是10次)你把老师惹烦了,老师懒得理你了,就说你过了,第二种就是你达到了老师的要求了。。。你就过了,哈哈。
2 BP的结构
就很多神经元结合在一起,得到最后的输出,这个应该很好理解。我就不多说了。
3 BP的公式推导
以上图为例子:
训练样本集:
对任意样本集:
实际输出:
期望输出:
正向传播:
初始输入—》I层:
I层—》J层:
J层—》P层:
那么预测输出:
定义误差能量为:,(感觉就是方差有木有)那么神经元的误差总和:
正向过程是信号向前传播的过程,那么得到这个误差是不是就要想方设法地让误差最小,要是0才好呢。但这是不可能的,因为只要是估计预测总会有误差,就好像你去医院用B超查男女孩,也是会有误差的。所以要想更新误差就要反向传播误差信号。
反向传播过程:
隐层J与输出层P之间的修正量,BP算法中权重的修正量与误差的权重的偏微分成正比,即:
梯度为(梯度下降算法的梯度?其实本质上就是了,估计我后面写的大家也猜到了):
根据激励函数为:
那么修正量就可以表示为:
所以可得迭代公式为:
隐层I到J的权值修正值为(和上面照葫芦画葫芦,我就不说了):
M层与I层:
现在BP的推导过程到这里就结束了。
4 BP的类型
BP网络的权值调整有两种模式:增量模式和批量模式。前者是指在每输入一个样本后,都回传误差一次并调整权值,后者是在所有的样本输入之后,计算网络的误差E(n),然后根据总误差计算各层信号并调整权值。由于批量模式遵循了以减小全局误差为目标的"集体主义"原则,因而可以保证总误差向减小方向变化。在样本数较多时,批量模式比增黄模式的收敛速度快。图2-7给出了批量模式的流程图。
四 BP的代码实现
1 python代码
# Back-Propagation Neural Networks#&# Written in Python. &See http://www.python.org/# Placed in the public domain.# Neil Schemenauer &&import mathimport randomimport stringrandom.seed(0)# calculate a random number where: &a &= rand & bdef rand(a, b):& & return (b-a)*random.random() + a# Make a matrix (we could use NumPy to speed this up)def makeMatrix(I, J, fill=0.0):& & m = []& & for i in range(I):& & & & m.append([fill]*J)& & return m# our sigmoid function, tanh is a little nicer than the standard 1/(1+e^-x)def sigmoid(x):& & return math.tanh(x)# derivative of our sigmoid function, in terms of the output (i.e. y)-derivative of tanhdef dsigmoid(y):& & return 1.0 - y**2class CBPNNClass:& & def __init__(self, ni, nh, no):& & & & # number of input, hidden, and output nodes& & & & self.ni = ni + 1 # +1 for bias node& & & & self.nh = nh& & & & self.no = no& & & & # activations for nodes& & & & self.ai = [1.0]*self.ni& & & & self.ah = [1.0]*self.nh& & & & self.ao = [1.0]*self.no& & & &&& & & & # create weights& & & & self.wi = makeMatrix(self.ni, self.nh)& & & & self.wo = makeMatrix(self.nh, self.no)& & & & # set them to random vaules& & & & for i in range(self.ni):& & & & & & for j in range(self.nh):& & & & & & & & self.wi[i][j] = rand(-0.2, 0.2)& & & & for j in range(self.nh):& & & & & & for k in range(self.no):& & & & & & & & self.wo[j][k] = rand(-2.0, 2.0)& & & & # last change in weights for momentum &&& & & & self.ci = makeMatrix(self.ni, self.nh)& & & & self.co = makeMatrix(self.nh, self.no)& & def update(self, inputs):& & & & if len(inputs) != self.ni-1:& & & & & & raise ValueError('wrong number of inputs')& & & & # input activations& & & & for i in range(self.ni-1):& & & & & & #self.ai[i] = sigmoid(inputs[i])& & & & & & self.ai[i] = inputs[i]& & & & # hidden activations& & & & for j in range(self.nh):& & & & & & sum = 0.0& & & & & & for i in range(self.ni):& & & & & & & & sum = sum + self.ai[i] * self.wi[i][j]& & & & & & self.ah[j] = sigmoid(sum)& & & & # output activations& & & & for k in range(self.no):& & & & & & sum = 0.0& & & & & & for j in range(self.nh):& & & & & & & & sum = sum + self.ah[j] * self.wo[j][k]& & & & & & self.ao[k] = sigmoid(sum)& & & & return self.ao[:]& & def backPropagate(self, targets, N, M):& & & & if len(targets) != self.no:& & & & & & raise ValueError('wrong number of target values')& & & & # calculate error terms for output& & & & output_deltas = [0.0] * self.no& & & & for k in range(self.no):& & & & & & error = targets[k]-self.ao[k]& & & & & & output_deltas[k] = dsigmoid(self.ao[k]) * error& & & & # calculate error terms for hidden& & & & hidden_deltas = [0.0] * self.nh& & & & for j in range(self.nh):& & & & & & error = 0.0& & & & & & for k in range(self.no):& & & & & & & & error = error + output_deltas[k]*self.wo[j][k]& & & & & & hidden_deltas[j] = dsigmoid(self.ah[j]) * error& & & & # update output weights& & & & for j in range(self.nh):& & & & & & for k in range(self.no):& & & & & & & & change = output_deltas[k]*self.ah[j]& & & & & & & & self.wo[j][k] = self.wo[j][k] + N*change + M*self.co[j][k]& & & & & & & & self.co[j][k] = change& & & & & & & & #print N*change, M*self.co[j][k]& & & & # update input weights& & & & for i in range(self.ni):& & & & & & for j in range(self.nh):& & & & & & & & change = hidden_deltas[j]*self.ai[i]& & & & & & & & self.wi[i][j] = self.wi[i][j] + N*change + M*self.ci[i][j]& & & & & & & & self.ci[i][j] = change& & & & # calculate error& & & & error = 0.0& & & & for k in range(len(targets)):& & & & & & error = error + 0.5*(targets[k]-self.ao[k])**2& & & & return error& & def test(self, patterns):& & & & for p in patterns:& & & & & & print(p[0], '-&', self.update(p[0]))& & def weights(self):& & & & print('Input weights:')& & & & for i in range(self.ni):& & & & & & print(self.wi[i])& & & & print()& & & & print('Output weights:')& & & & for j in range(self.nh):& & & & & & print(self.wo[j])& & def train(self, patterns, iterations=1000, N=0.5, M=0.1):& & & & # N: learning rate& & & & # M: momentum factor& & & & for i in range(iterations):& & & & & & error = 0.0& & & & & & for p in patterns:& & & & & & & & inputs = p[0]& & & & & & & & targets = p[1]& & & & & & & & self.update(inputs)& & & & & & & & error = error + self.backPropagate(targets, N, M)& & & & & & if i % 100 == 0:& & & & & & & & print('error %-.5f' % error)def demo():& & # Teach network XOR function& & pat = [& & & & [[0,0], [0]],& & & & [[0,1], [1]],& & & & [[1,0], [1]],& & & & [[1,1], [0]]& & ]& & # create a network with two input, two hidden, and one output nodes& & n = CBPNNClass(2, 2, 1)& & # train it with some patterns& & n.train(pat)& & # test it& & n.test(pat)if __name__ == '__main__':& & demo()
五 BP的缺点
(1 ) BP学习算法采用梯度下降法来收敛实际输出与期望输出之间误差。因为误差是高
维权向量的复杂非线性函数,故易陷入局部极小值;
(2)网络在学习过程收敛速度慢;
(3)在网络训练过程中容易发生振荡,导致网络无法收敛;
(4)网络的结构难以确定(包括隐层数及各隐层节点数的确定);
(5)在学习新样本时有遗忘以学过样本的趋势,因为每输入一个样本,网络的权值就
要修改一次。
(6)学习样本的数量和质量影响学习效果(主要是泛化能力)和学习速度。
正是因为BP网络白身的缺陷使得其在应用过程中存在一些棘手的问题,从而极大地影响了BP网络的进一步发展和应用。在上面的儿点中,前四点都是BP网络存在的最引人
注目的问题,第五点也是很有研究价值的一个内容。其实现在还有很多的发展,但是这个毕竟是最经典的算法,我就拿来说说。
六 后续总结
为什么我不说现在火的深度学习呢。。。。因为我感觉深度学习属于大样本事件,而且无GPU不DP。而且DP之间的参数联系我不懂,也就是说DP对于我们来说就是一个黑盒子,没人知道里面是什么。。。等我有空了,我在慢慢抽出两个月好好研究DP的paper来和大家研究。
再一次说一下,能不能点个关注????
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。

我要回帖

更多关于 勒索病毒会不会传染 的文章

 

随机推荐