文 号

823740

9 回复 / 1864 浏览


116059967810 个月前 -2016-07-31 17:28823740

零、前言

神经网络是我这半年来研究的重点,它的接近完美的非线性非类能力和广泛的运用前景是我所期待的(要不然为什么研究那么久)。 于是乎,来给大家讲一讲几种主要的的神经网络结构。

可能大家会问神经网络到底是什么? 综合神经网络的来源、特点和各种解释,它可简单地表述为:人工神经网络是一种旨在模仿人脑结构及其功能的信息处理系统 [1] 。 嗯,有点教科书的古板,但讲的如此简洁、清楚。

一、M-P模型

知道神经网络到底是什么之后,可以来讲一讲它的历史了。 开始的时候,大家只是建立了一个很简单的数学模型,就是下图的M-P模型(神经元的阀值模型),由McCulloch W.S.和 Pitts W.A.在1943年提出。 267877
这是一个模型很简陋,只能展现一个神经元,而且还没有训练方法(在当时,W[权值]是固定的,由人来调节),但以此模型的提出为标志,神经网络拉开了研究的序幕。 它的公式为: $$y_j=f(\sum_{i}(w_{ij}*x_{i}+\theta_j))$$ 其中 $$f(x)=1/[1+exp(-x)]$$ 当然,这个函数是后来人们才提出来的,最初的时候,当x大于0时,f(x)取1,反之为-1。 这种结构使得人工神经网络成为具有学习能力的系统,可以发展知识,以至超过设计者原有的知识水平。[2]

二、Hebb 规则

四十年代末,D. O. Hebb 首先提出了一种神经网络学习算法,称为 Hebb 规则。 这种规则使得神经网络具有了学习的能力。 输出表示为: $$y_j=f(\sum_{i}(w_{ij}*x_{i}))$$ 权值调整: $$w_{ij}(t+1)=w_{ij}(t)+ \eta * y_j * x_i$$ 其中Eta是学习率,取值随环境而定。

下面是代码(很粗暴):

class hebb{
public:
	double w[10][10];
	double tran_c;
	double o[10];

	void tran(double *X_in,double *Y_in)
	{
		int i,j;
		for (i=0;i<10;i++)
		{
			for(j=0;j<10;j++)
			{
				w[i][j]=tran_c*w[i][j]+X_in[i]*Y_in[j];
			}
		}
	}

	void rest(){
		int i,j;
		for (i=0;i<10;i++)
		{
			for(j=0;j<10;j++)
			{
				w[i][j]=0;
			}
		}
	}

	void run(double *X_in)
	{
		int k,l;
		for (k=0;k<10;k++)
		{
			o[k]=0;
			for(l=0;l<10;l++)
			{
				o[k]+=w[l][k]*X_in[i][l];
			}
		}
	}
};

参考文献:

[1] 董军,胡上序。混沌神经网络研究进展和展望。信息与控制,1997,26(5):360-368。 [2]朱大奇,史慧编著。人工神经网络原理及应用。北京:科学出版社,2006

[修改于 10 个月前 - 2016-07-31 18:18:55]

+1  学术分    虎哥   2016-08-04   系统的阐述神经网络的基础知识。

116059967810 个月前 -2016-07-31 18:51823742

神经网络的学习方法还有很多,但Hebb具有标志性的意义,误差反传神经网络之前的只讲这一种,如果大家有兴趣可以参考

这本书进行进一步的了解。

误差反传(BP)神经网络

下图是误差反传神经网络的结构示意图(来源,侵删) 267890
如图所示,误差反传神经网络由输入层、输出层和中间层(或称隐层)组成。(和图上不一样的是,隐层通常是多层) 它的输出计算公式可以表示为:

267889
267891
误差反传神经网络是用一种叫梯度下降的方法进行训练的,关于梯度下降法可以参考:梯度下降是门手艺活…… - 无痛的机器学习 - 知乎专栏,本文将不会展开讲述。 使用梯度下降法后,权值调整公式如下: 267892
其中: 267893
同时阈值调整公式可以表示为: 267895
关于误差反传神经网络的公式的推导,可以参考段首提供的文献。

讲了这么多公(fei)式(hua),误差反传神经网络的特点是什么呢?

误差反传神经网络作为一个多层的神经网络,它有非线性分类的能力(单层神经网络发展受约束的原因),而且和多层感知器不同的是,它具备良好和学习能力(这是第一个多层神经网络的学习算法)。这两个特点和它的易用性使得它成为现在使用最多的神经网络。

不过它还有许多缺点:样本需求量过大,易陷入局部最优······

但无论如何,它始终是这个领域最经典的算法(没有之一),带领神经网络的研究从低迷走向辉煌(在它之前,神经网络的前景并不被人看好,因为没有多层神经网络的训练方法),在这里向它的提出者们:由Rumelhart和McCelland为首的科学家小组致敬。

本人的BPNN实现:GitHub - mwsht/BPNN: Back Propagation Neural Network

PS:代码会溢出(在使用class指针数组时)大家可以帮忙检查一下。

[修改于 10 个月前 - 2016-07-31 19:12:04]


Cirno10 个月前 -2016-08-01 11:49823760

科创Neural Network第一帖! 感谢为机器学习版块添砖加瓦,内容很严谨充实。

提一点小建议:

  1. 学习NN尽量参考2012年以后的资料,因为在这之后出现了很多重要的算法和思路,比如楼主位提到的 sigmoid activation function,现在已经广泛被ReLu所代替,同时引入了dropout layer来增加网络的稀疏性,另外还有针对图像数据的CNN等等,很大程度上改变了NN的结构和性能。
  2. 粗略看了下github的代码,像是一个multi-layer perceptron,你提到的数据溢出的问题很有可能出在这里:
double sigmoid(double x)
{
    return (1.0/(1.0+exp(x)));
}

计算sigmoid时,在未对exp运算做特殊处理的情况下,数据溢出几乎是100%会发生的,因为cpp里double最大只能到1.7e307,此时对应的log只有710左右。关于解决这个问题的思路,可以参考这个blog。欢迎多多交流

[修改于 10 个月前 - 2016-08-01 12:11:47]


116059967810 个月前 -2016-08-01 20:20823813
引用 琪露诺:
科创Neural Network第一帖! 感谢为机器学习版块添砖加瓦,内容很严谨充实。

提一点小建议:
1. 学习NN尽量参考2012年以后的资料,因为在这之后出现了很多重要的算法和思路,比如楼主位……


感谢评论
1.比较忙,还没写完,以后会介绍径向基函数(RBF)神经网络、限制波尔兹曼机(RBM)、卷积神经网络(CNN)、深度置信神经网络(DBN),还会拓展讲一下CNN的变种:深度卷积神经网络(DCNN)、区域卷积神经网络(R-CNN),以及中科院计算所的“寒武纪”神经网络处理器。其他的太多了,如果大家对哪方面感兴趣,我可以讲一下。
2.程序的问题是报c0000005,是内部变量指针越界的问题。
3.学习资料方面,只有本层之前以及径向基函数(RBF)神经网络的文献是图书(没去找论文),后面的文献都是论文(而且除限制波尔兹曼机用的是中文论文,其他的都是E文的)。

[修改于 10 个月前 - 2016-08-02 12:48:46]


Cirno10 个月前 -2016-08-01 21:23823819
引用 1160599678:
感谢评论
1.比较忙,还没写完,以后会介绍径向基函数(RBF)神经网络、限制波尔兹曼机(RBM)、卷积神经网络(CNN)、深度置信神经网络(DBN),还会拓展讲一下CNN的变种:深度卷积神经网络(
期待

116059967810 个月前 -2016-08-01 22:05823823

限制波尔次曼机(RBM)

中文论文见层尾

限制波尔次曼机是一种无监督单层神经网络。

无监督和监督的区别在于无监督不需要在训练的时候提供输出层数据,因为无监督神经网络可以“自主学习”:即可以自行抽取出输入数据的特征,对不同的输入数据进行分类(输出不同的结果),同时也具有较良好的泛化能力(指对新鲜样本的适应能力)。

如图,RBM有n个可见单元和m个隐单元,用向量V和H表示,W是RBM的连接权值矩阵,向量A、B分别表示可见单元、隐单元的偏置(oh,前面忘记讲了,就是M-P模型中的theta,用来修正神经元的输出)。 268033

在RBM里,大家可能对能量状态和激活概率感到陌生。

能量函数参考文献[1],这里做简单说明:能量函数代表神经网络的稳定程度,值越小代表神经网络越稳定,分类性能最好,在监督学习中,能量函数通常与输出层数据与期望值之间的误差有关,而在RBM中则与两个层的数据分布概率有关: $$E(v,h|\theta)=-\ln P(v,h|\theta) + const$$ 注:\(\theta\)是指神经网络的配置,包括W、A和B。

而整个神经网络的值函数是各个数据的值函数的累加。 $$E(\theta)=\sum_{v,h}E(v,h|\theta)$$ 由此可见,数据分布越平均,值函数越小,而整个神经网络就越稳定。 RBM的数据分布概率定义为: $$E(v,h|\theta)=\sum_{i, j} W_{ij} v_{i} h_{j} + \sum_{i} a_{i} v_{i} + \sum_{j} b_{j} h_{j}$$ 以此为基础,我们可以计算出它的联合概率分布: 268057

在这里值得大家注意的是,我们所关注的数据分布概率是可见层v的分布\(P (v|θ) \),即即联合概率分布\(P (v,h|θ)\) 的边际分布。

268056

激活概率可以理解为神经元的的输出,因为: 268050
268051
眼熟?没错,这就是神经元的输出,只不过在可见层和隐层的计算中,权值是对称的。

这里RBM使用一种基于对比散度的训练方法,各参数的更新准则为: $$ \Delta W_{ij}=\eta (<v_i h_j>_{data} - <v_i h_j> _{recon} ) $$

$$ \Delta a_{i}=\eta (< v_i > _{ data } - < v_i > _{ recon } ) $$

$$ \Delta b_{j}=\eta (< h_j > _{ data } - < h_j > _{ recon } ) $$

\(<·> _{ data } \)表示初始的数据分布, \(<·> _{ recon } \)表示一次重构后模型的数据分布。

简单来说,我们输入\(v1\)得到\(h1\),从而用\(v2\)和\(h2\)计算出分布 \(<·> _{ data } \),但还没结束,我们要用对称的权值从\(h1\)计算出\(v2\)(重构后的可见层),计算出\(h2\)(重构后的隐层),然后用\(v2\)和\(h2\)计算出的分布是\(<·> _{ recon } \)。

详细的公式: 268058

下面贴论文和代码。

RBM.h:

#include <stdlib.h>
#include <math.h>
namespace MWS{
	
	//********************************** 
	//函数描述:返回符合正态分布的随机值 
	//********************************** 
	double R(){
		return sqrt(-2*log(rand()/(RAND_MAX+1.0)))*cos(2*3.14159265*rand()/(RAND_MAX+1.0));
	}
	
	//********************************** 
	//函数描述:返回从0到1的随机值 
	//**********************************
	double r(){
		return rand()/(RAND_MAX+1.0);
	}
	
	//********************************** 
	//函数描述:S型函数 
	//********************************** 
	double sigmoid(double x)
	{
		return (1.0/(1.0+exp(x)));
	}
	
	//****************************************************
	//类:受限波尔兹曼机
	//作者:黄涛
	//日期:2016年7月29日
	//描述:受限波尔兹曼机是一类具有两层结构、对称连接且无
	//自反馈的随机神经网络模型,层间全连接,层内无连接。
	//备注:深度信念网络测试用
	//****************************************************
	class RBM{
	public:
		double eta;
		//eta:学习率
		double *v,*h;
		//v:可见层(n) 
		//h:隐层 (m)
		double **W,*a,*b;
		//W:权值(n*m)
		//a:可见层偏置(n) 
		//b:隐层偏置(m)
		int m,n;			
		//m:隐层单元个数
		//n:可见层单元个数
		
		//**************************
		//函数描述:类初始化 
		//**************************
		RBM(
		int m_in,
		//m_in:隐层单元个数输入 
		int n_in,
		//n_in:可见层单元个数输入 
		double eta_in=0.95
		//eta_in:学习率输入
		){
			eta=eta_in;
			m=m_in;
			n=n_in;
			v=new double[n];
			h=new double[m];
			W=new double*[n];
			a=new double[n];
			b=new double[m];
			for(int i=0;i<n;i++){
				a[i]=R();
				W[i]=new double[m];
				for(int j=0;j<m;j++)
				{
					W[i][j]=R();
				}
			}
			for(int i=0;i<m;i++){
				b[i]=R();
			}
			//W,a,b初始化时均为符合正态分布的随机值 
		}
		
		//**************************
		//函数描述:训练 
		//**************************
		void tran(
		double *x0,
		//x0:训练样本(n)
		int T
		//T:最大训练周期
		){
			double *v1=x0;
			double h1[m];
			double v2[n];
			double P_h1[m];
			double P_v2[n];
			double P_h2[m];
			for(int t=0;t<T;t++){
				//计算概率
				for(int j=0;j<m;j++){
					double E=0;
					for(int i=0;i<n;i++){
						E+=v1[i]*W[i][j];
					}
					P_h1[j]=sigmoid(b[j]+E);
					if (r()<=P_h1[j]){
						h1[j]=1;
					}else{
						h1[j]=0;
					}
				}
				for(int i=0;i<n;i++){
					double E=0;
					for(int j=0;j<m;j++){
						E+=h1[j]*W[i][j];
					}
					P_v2[i]=sigmoid(a[i]+E);
					if (r()<=P_v2[i]){
						v2[i]=1;
					}else{
						v2[i]=0;
					}
				}
				for(int j=0;j<m;j++){
					double E=0;
					for(int i=0;i<n;i++){
						E+=v2[i]*W[i][j];
					}
					P_h2[j]=sigmoid(b[j]+E);
				}
				//更新权值
				//W
				for(int i=0;i<n;i++){
					for(int j=0;j<m;j++){
						W[i][j]+=eta*(P_h1[j]*v1[i]-P_h2[j]*v2[i]);
					}
				}
				//a
				for(int i=0;i<n;i++){
					a[i]+=eta*(v1[i]-v2[i]);
				}
				//b
				for(int j=0;j<m;j++){
					b[j]+=eta*(P_h1[j]-P_h2[j]);
				}
			}
		}
		
		//**************************
		//函数描述:计算 
		//**************************
		void calculate(
		double *x
		//x:输入(n)
		){
			for(int j=0;j<m;j++){
				double E=0;
				for(int i=0;i<n;i++){
					E+=x[i]*W[i][j];
				}
				h[j]=sigmoid(b[j]+E);
			}
		}
	};
} 

RBM.cpp:

#include <stdio.h>
#include <time.h>
#include "RBM.h"

MWS::RBM test(4,10);

double x0[10][10]=
{
{1,2,3,4,5,6,7,8,9,0},
{2,3,4,5,6,7,8,9,0,1},
{3,4,5,6,7,8,9,0,1,2},
{4,5,6,7,8,9,0,1,2,3},
{5,6,7,8,9,0,1,2,3,4},
{6,7,8,9,0,1,2,3,4,5},
{7,8,9,0,1,2,3,4,5,6},
{8,9,0,1,2,3,4,5,6,7},
{9,0,1,2,3,4,5,6,7,8},
{0,1,2,3,4,5,6,7,8,9}
};

double result[10][4];

int main(){
	srand(time(NULL));
	for (int i=0;i<100;i++){
		for (int j=0;j<10;j++){
			test.tran(x0[j],10);
		}
	}
	for (int i=0;i<10;i++){
		test.calculate(x0[i]);
		for (int j=0;j<4;j++){
			result[i][j]=test.h[j];
			printf("%f,",result[i][j]);
		}
		printf("\n");
	}
	return 0;
}

这个cpp没有太大意义,只是测试RBM的特征抽取能力,下图是结果(不同的颜色代表不同的维度,序号表示输入样本编号,高度代表输出值的大小) 268059

输出的.csv结果下载:

E文论文:

神奇的文件大小显示:-(

参考文献:

  • [1]:章毅, 王平安. 关于神经网络的能量函数[J]. 计算机研究与发展, 1999, 36(07):794-799.
  • 下载:

[修改于 10 个月前 - 2016-08-02 12:47:39]


Cirno10 个月前 -2016-08-01 23:03823827
引用 1160599678:
### 限制波尔次曼机(RBM)
> 中文论文见层尾

限制波尔次曼机是一种无监督单层神经网络。

无监督和监督的区别在于无监督不需要在训练的时候提供输出层数据,因为无监督神经网络可以“自主学习”……
Nice code,最好能附上程序输出结果

116059967810 个月前 -2016-08-02 16:24823884

先吐槽一下: 268062

深度置信神经网络(DBN)

恩,先贴论文吧:

还有一个PPT: 这是G. Hinton 提出的一种无监督学习神经网络,以RBM为基础(这就是为什么先讲RBM)。 下图是DBN的结构(这是一个图像识别的应用,不过这里识别的是脸部的倾斜角度LOL): 268064
注GP: Gaussian processes(高斯过程),这个东西不属于DBN。 从图中可以看出,DBN由多层神经元构成,每层神经元之间用RBM进行训练,从 \( (v,h_1) \) 到 \((h_{n-1},h_n)\)一层层构建起来(先用所有样本训练\( (v,h_1) \),然后用训练出的结果\( h_1 \)作为样本训练\( (h_1,h_2) \),一直到\((h_{n-1},h_n)\))。

没错,原理就是辣么简单。

但这还不够,因为单纯地用RBM只是无监督网络,但这样的网络不具备分类的能力(输出没有规律),所以要做到半监督,而要做到半监督,必须要进行监督学习,而上述的DBN架构并不能进行监督学习(没有输出层),于是我们再在\(h_n\)上方加上一个输出层\( y \),把\(v\)看作输入层,然后对整个神经网络使用梯度下降法进行优化,对于普通的结构,直接用BP算法即可。

这种半监督训练方法中,样本分为无标签和有标签两种,无标签样本指的是没有输出层数据,只有输入层数据的样本,有标签样本则是具有输入层和输出层的数据的样本,在训练时,无标签样本只参加无监督训练,有标签样本参加无监督训练(不需要输出层数据)和监督训练。这种训练的好处在于,无监督训练可以以一种较快的训练速度训练权值以适应输入数据,而监督训练则可以优化输出,减小输出误差。这种模型相对于普通的BP神经网络来说,它不再依赖超级大量的数据(在BP神经网络中,我们通常要用到连接权值总数的 5~10 倍的训练数据,而RBM则可以很快地逼近一个分类能力较好的权值,并且减小模型走向局部最优的几率),而且可以以一种更快的速度进行学习(RBM的构建会比BP快很多)。

于是乎,DBN成为2006年以来很火很火的神经网络架构,成为了神经网络的一个标杆。


116059967810 个月前 -2016-08-03 14:30823947

卷积神经网络(CNN)

268275

终于讲到卷积神经网络了,RBF神经网络先暂时先不讲,因为用途不是很广(现在主要是机械控制),而且网上讲的不错:这里

卷积是一个数学操作,用两个函数得到第三个函数,用公式可以表示为: $$h(x)=\int_{-\infty}^{+\infty}f(\tau )*g(x-\tau )d\tau $$ 但说实话,这个公式对于我们理解卷积神经网络没有太大帮助,因为我们这里用的是广义上的卷积,我们最好用一张动态图像来表示(未找到来源,侵删) 268273
$$x_j^{\ell}=f(\sum_{i\in M_j}x_{i}^{\ell -1}*k_{ij}^{\ell}+b_j^{\ell})$$ 其中,\(M_j\)是一个输入集合,代表\(x_j^{\ell}\)的输入来源,通常包含上一层中的若干个特征图像,\(k_{ij}\)是权值,\(b_j\)是偏置。 在[2]中的LeNet-5 (结构见图6)中,输入集合是如下表示的: 269644

当然,卷积神经网络还有二次抽样层(池化层): 268276
图中所示的是一种叫做最大池化的一种池化技术。 同时,卷积神经网络还有一种全连接层,这种层的结构与反向传播神经网络是一样的,它的作用是对提取出来的特征进行分类。 卷积神经网络通常有两部分,一部分是卷积层和池化层交替的特征提取部分,还有一部分是全连接层组成的分类部分。 由于卷积神经网络的卷积及池化操作符合人脑的图像处理中枢的部分特征,再加上卷积操作本身减少了不必要的权值并且取消了原本的神经网络的数据区域独立,使得图像的特征得以较好地提取,故其成为现在图像识别领域重要模型。

参考文献: [1]:

[2]:

[修改于 9 个月前 - 2016-09-11 12:28:38]


更多·卷积神经网络
11605996789 个月前 -2016-09-11 12:30825476
269645

图中的深层卷积神经网络是一种较深层级的卷积神经网络,使用两台NVIDIA GTX 580 3GB GPU进行计算和训练(上下的层分别代表两显卡中不同的层),它验证了卷积神经网络在高层数方面的适用性及其优越性,在ILSVRC-2012 数据集中获得了37.5% 17.0%的Top-1 Top-5误差,可以说它运算速度快、分类能力好,具有极强的发展潜力。
269646

图中的神经网络类型按照名字来说应该是深度神经网络(Multi-column Deep Neural Networks),但是http://yann.lecun.com/exdb/mnist/上却将其分类为卷积神经网络,故在此处介绍。
输入图像被分成多个小块(Pn)然后这些图像块被输入深度神经网络,然后再对深度神经网络的输出进行处理,成为最终输出结果。
该神经网络可以说是非常优秀的,0.23的MINST数据集错误率(最低),以及NIST SD 19、CASIA 、GTSRB、CIFAR 10、NORB数据集的优秀成绩。
269647

这是一个具有残差项的神经网络,某个层的输出会被当作残差项传递到几层后参与运算,残差项的优点是可以较好地减少梯度消失(当神经网络层数过多时,由于其输出函数的特性,输入数据对输出数据的影响会过小,造成误差增大)带来的影响,可以做到152层左右,误差如下图所示(虚线是训练误差,实线是测试误差),可见深层级可以带来较好的效果,但过深层还是会受到梯度下降的影响。
269648

该神经网络在ILSVRC2015比赛中取得第一名。

返回 机器学习/自控仿真
返回 本页顶部

想参与大家的讨论?现在就 登陆 或者 注册


nkc Development Server https://github.com/lovetheory/nkc2

科创研究院 (c)2005-2016

蜀ICP备11004945号-2 川公网安备51010802000058号