神经网络有两个重要工作

1.网络的构建

2、网络的训练,一般训练的方法采用BP算法

这里我采用全链接的方式,当然这样的效率会受到影响

训练的方法为BP算法,其实现并不想当初想象的那么复杂

另外在训练的时候,各个神经元的输入权值初始化的值应该是随机的,如果都是一样的值(缺省值,0,1)效果奇差

另外发现,并不是层数越多越好,也不是每一层的神经元越多越好,这要看具体情况,实验确定

另外发现,在训练的时候,对训练集上每一个数据训练一次,参数调整一次,然后再对下一个数据进行训练,这为一轮,而不是将每一个数据训练到误差限再训练下一个数据 ,这样没有效果。

神经网络头文件 

#ifndef NeuronNet_H
#define NeuronNet_H
typedef struct neuron {
    double *weight;//所有输入信号的权重
    double inputsNumb;//输入信号的数量
    double out;//输出结果
    double error;//目标与输出之间的误差 
    int layerID;
    int ID;
} Neuron;
typedef struct neuronLayer {
    Neuron *neurons;//所有的神经元 
    double bias;//偏置 
    int neuronsNumb;//神经元的数目 
    int layerID;
} NeuronLayer;
typedef struct neuronNet {
    int inputsNumb;//输入节点数
    int outputsNumb;//输出节点数
    int layersNumb;//神经网络层数
    NeuronLayer* layers;
} NeuronNet;
//@@brief:根据指定参数创建神经网络
//@@param: nets   表示神经网络的结构,每一元素表示每一层的神经元的数量、
//        元素的个数表示神经网络的个数
//        其第一个元素应该与输入信号数组inputs元素个数相同
//@@param: layers  神经网络的参数,应该与nets元素个数相同
//@@return: 神经网络的结构指针
NeuronNet* createNeuronNet(const int *nets,const int layers);
NeuronNet* createNeuronNetFromFile(const char *fileName);
//@@brief:释放神经网络所占空间
//@@param:net神经网络的结构指针
//@@return:无
void releaseNeuronNet(NeuronNet* net);
//@@brief:更新神经网络数据
//@@param:net神经网络的结构指针
//@@param:input神经网络的输入数据组
//@@param:isShow神经网络的结果是否显示
//@@return:无
void updateNeuronNet(NeuronNet *net,double *inputs,int isShow);
//@@brief:训练神经网络数据
//@@param:net神经网络的结构指针
//@@param:setIn神经网络的训练输入数据组
//@@param:setOut神经网络的对应训练输入数据组的输出
//@@param:setLength训练数据的长度
//@@param:learningRate训练的学习率
//@@param:setLength训练精度
//@@return:无
void ModelTrainning(NeuronNet *net,double *setIn,double *setOut,int setLength,double learningRate,double accuracy);
void NeuronNetDisplay(NeuronNet *net);
#endif

神经网络的源文件 

#include"NeuronNet.h"
#include<malloc.h>
#include<math.h>
#include <time.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
//#define NULL 0
static double sigmoid(double a,double p) {
	return 1/(1+exp(-a/p));
}
//@@brief:
//@@param:
//@@param:
//@@return:
NeuronNet* createNeuronNet(const int *nets,const int layers) {
	int i,j,k;
	srand(time(NULL));
	NeuronNet* result=(NeuronNet*)malloc(sizeof(NeuronNet));
	//initial the neuronNet
	result->layers=(NeuronLayer*)malloc(layers*sizeof(NeuronLayer));
	result->inputsNumb=nets[0];
	result->outputsNumb=nets[layers-1];
	result->layersNumb=layers;

	NeuronLayer *neuronLayer=NULL;
	Neuron    *neuron=NULL;
	//initial the inputLayer
	neuronLayer=result->layers;
	neuronLayer->neurons=(Neuron*)malloc((nets[0])*sizeof(Neuron));
	neuronLayer->neuronsNumb=nets[0];
	neuronLayer->bias=1;
	neuronLayer->layerID=0;
	for(i=0; i<neuronLayer->neuronsNumb; i++) {
		neuron=neuronLayer->neurons+i;
		neuron->weight=NULL;
		//*(neuron->weight)=1;
		neuron->inputsNumb=1;
		neuron->out=1;
		neuron->layerID=0;
		neuron->ID=i;
	}
	//initial the others layer
	for(i=1; i<layers; i++) {
		neuronLayer=result->layers+i;
		neuronLayer->neurons=(Neuron*)malloc(nets[i]*sizeof(Neuron));
		neuronLayer->neuronsNumb=nets[i];
		neuronLayer->bias=1;
		neuronLayer->layerID=i;
		for(j=0; j<nets[i]; j++) {
			//initial every neuron
			neuron=neuronLayer->neurons+j;
			neuron->inputsNumb=nets[i-1];
			neuron->layerID=i;
			neuron->ID=j;
			neuron->weight=(double*)malloc((nets[i-1]+1)*sizeof(double));//plus bias weight

			for(k=0; k<nets[i-1]+1; k++) { //plus bias weight
				neuron->weight[k]=rand()*1.0/32768;
			}
		}
	}

	return result;
}
//@@brief:
//@@param:
//@@param:
//@@return:
void releaseNeuronNet(NeuronNet*net) {
	int i,j;
	NeuronLayer* neuronLayer=NULL;
	Neuron *neuron=NULL;
	for(i=0; i<net->layersNumb; i++) {
		neuronLayer=net->layers+i;
		for(j=0; j<neuronLayer->neuronsNumb; j++) {
			neuron=neuronLayer->neurons+j;
			if(neuron->weight)free(neuron->weight);
		}
		free(neuronLayer->neurons);
	}
	free(net->layers);
	free(net);
	net=NULL;
}
//@@brief:
//@@param:
//@@param:
//@@return:
void updateNeuronNet(NeuronNet *net,double *inputs,int isShow) {

	int i,j,k;
	double sum=0;
	NeuronLayer *preLayer=NULL,*curLayer=NULL;
	Neuron       *neuron=NULL;
	//update inputLayer data
	curLayer=net->layers;
	neuron=curLayer->neurons;
	if(isShow)printf("@@inputLayer:\n");
	for(i=0; i<net->inputsNumb; i++) {
		(neuron+i)->out=inputs[i];
		if(isShow)printf("%19.16f\t",(neuron+i)->out);
	}
	if(isShow)printf("\n");
	//update hideLayer&outputLlayer data
	for(i=1; i<net->layersNumb-1; i++) {
		//	if(isShow)printf("//hiddenLayer %4d:\n",i);
		preLayer=net->layers+(i-1);
		curLayer=net->layers+i;
		//update one layer data
		for(j=0; j<curLayer->neuronsNumb; j++) {
			sum=0;
			//update one neuron data
			neuron=curLayer->neurons+j;
			for(k=0; k<preLayer->neuronsNumb; k++) {
				sum+=preLayer->neurons[k].out*neuron->weight[k];
			}
			sum+=preLayer->bias*neuron->weight[k];
			neuron->out=sigmoid(sum,1);
			//if(isShow)printf("%19.16f\t",neuron->out);//neuron->out
		}
		//	if(isShow)printf("\n");
	}
	if(isShow)printf("//outputLayer:\n");
	preLayer=curLayer;
	curLayer=curLayer+1;
	for(j=0; j<curLayer->neuronsNumb; j++) {
		sum=0;
		//update one neuron data
		neuron=curLayer->neurons+j;
		for(k=0; k<preLayer->neuronsNumb; k++) {
			sum+=preLayer->neurons[k].out*neuron->weight[k];
		}
		sum+=preLayer->bias*neuron->weight[k];
		neuron->out=neuron->out=sigmoid(sum,1);
		if(isShow)printf("%19.16f\t",neuron->out);
	}
	if(isShow)printf("\n\n");

}
double  backPropagation(NeuronNet *net,double *in,double *out,double learningRate) {
	int i=0,j=0,k=0;
	NeuronLayer *curLayer=net->layers+(net->layersNumb-1);
	NeuronLayer *nextLayer=NULL,*preLayer=curLayer-1;
	Neuron *neuron=curLayer->neurons;
	Neuron *nextLayerNeuron=NULL;
	updateNeuronNet(net,in,0);
	//update outputLayer errors & adjust outLayer weight
	double totalError=0;
	for(i=0; i<curLayer->neuronsNumb; i++) {
		neuron+=i;
		//update errors
		neuron->error=(out[i]-neuron->out)*(neuron->out)*(1-neuron->out);
		//adjust  weight
		for(j=0; j<neuron->inputsNumb; j++) {
			*(neuron->weight+j)+=learningRate*(neuron->error)*((preLayer->neurons+j)->out);
		}
		*(neuron->weight+j)+=learningRate*(neuron->error)*1;//bias

		totalError+=(out[i]-neuron->out)*(out[i]-neuron->out)/2;
	}

	//adjust hiddenLayer weight
	double sum=0;

	for(i=net->layersNumb-2; i>0; i--) {//
		preLayer=net->layers+(i-1);
		curLayer=net->layers+(i);
		nextLayer=net->layers+(i+1);
		for(j=0; j<curLayer->neuronsNumb; j++) {
			//update current layer's curent neuron error:
			//E(i,j)=O(i,j)*(1-O(i,j)*sum{E(i+1,k)*w(i+1,k,j)}
			sum=0;
			neuron=curLayer->neurons+j;

			for(k=0; k<nextLayer->neuronsNumb; k++) {
				nextLayerNeuron=(nextLayer->neurons)+k;
				sum+=(nextLayerNeuron->error)*(nextLayerNeuron->weight[j]);
			}
			neuron->error=neuron->out*(1-neuron->out)*sum;

			//adjust weight:previous layer neurons and current neuron
			for(k=0; k<neuron->inputsNumb; k++) {
				*(neuron->weight+k)+=learningRate*(neuron->error)*(preLayer->neurons[k].out);
			}
			//adjust the weight of previous layer's bias
			*(neuron->weight+k)+=learningRate*(neuron->error)*1;//bias
		}


	}
//	printf("the total error is %20.16f\n",totalError);
	//limit the total error

	return totalError;
}

void ModelTrainning(NeuronNet *net,double *setIn,double *setOut,int setLength,double learningRate,double accuracy) {
	int i=0,j=0;
	int inputsNumb=net->inputsNumb;
	int outputsNumb=net->outputsNumb;
	double result=0;
	for(i=0; i<1500000; i++) {
		result=0;
		for(j=0; j<setLength; j++) {
			result+=backPropagation(net,setIn+j*inputsNumb,setOut+j*outputsNumb,learningRate);
		}
#if 0
		if((result/setLength)<accuracy) {
			printf("time=%d\n",i);
			break;
		}
#endif

	}
	printf("total Error is %20.16f\n",result);
}
void NeuronNetDisplay(NeuronNet *net) {
	int layers=net->layersNumb;
	NeuronLayer *layer=NULL;
	Neuron      *neuron=NULL;
	int i,j,k;
//display inputLayer
	printf("--input layer.\n");
	//display hiddenLayers
	printf("--hiddenLayers & outputLayer\n");
	for(i=1; i<=net->layersNumb-1; i++) {
		layer=net->layers+i;
		printf("layer:%d\n",i);
		for(j=0; j<layer->neuronsNumb; j++) {
			printf("\t:%d\n",j);
			neuron=layer->neurons+j;
			for(k=0; k<neuron->inputsNumb+1; k++) {
				printf("%15.10f\t",*(neuron->weight+k));
			}
			printf("\n");
		}
	}
	//displayer outputLayer
}
NeuronNet* createNeuronNetFromFile(const char *fileName) {
	return NULL;
}

 下面是测试例程:

主要是测试神经网络实现异或功能

//神经网络异或功能测试
//0,0->0
//0,1->1
//1,0->1
//1,1->0
#include <stdio.h>
#include <time.h>
#include<math.h>
#include"neuronNet.h"

void test2() {

        //网络结构为输入层2个神经元,中间层2个神经元,输出层1个
	int net[]= {2,2,1};
        //训练集,输入
	double setIn[]= {0,1,0,0};
        //训练集,输出
	double setOut[]= {1,0,0,1};
        /测试集
        double  testSet={1,1,1,0};
	int len=4;
//创建神经网络
	printf("start create neuron...\n");
	NeuronNet *neuronNet=createNeuronNet(net,sizeof(net)/sizeof(int));
	printf("NeuronNet has been created.\n");
//显示神经网络的结构
	NeuronNetDisplay(neuronNet);
	//double inputs[]={3,2,1};
	//updateNeuronNet(neuronNet,inputs,1);
	updateNeuronNet(neuronNet,setIn,1);
	ModelTrainning(neuronNet,setIn,setOut,len,1.5,1e-12);

	printf("_________________Trainning is Over_____________________\n");
	NeuronNetDisplay(neuronNet);
	printf("\n");

	updateNeuronNet(neuronNet,setIn,1);
	updateNeuronNet(neuronNet,setIn+2,1);
	updateNeuronNet(neuronNet,setIn+4,1);
	updateNeuronNet(neuronNet,setIn+6,1);
	/*	*/
	releaseNeuronNet(neuronNet);
}
int main(int argc, char** argv) {
	test2();
}

很久以前就看过神经网络了,也知道BP算法但是一直感觉比较复杂和不靠谱,今天终于编写出来了且用它进行了异或分类操作,正成功了,开心。主程序中还包括一个生成两个半月环的随机数的功能,可以有来测试Rosenblatt感知器的,这也是用来进行分类的,没有试验。

机器学习方法主要是两类:监督学习和无监督学习。监督学习主要学习的样本是有明确的输入和输出结果的,或者是有标签,通过构造一个系统(一般要求构造系统的输出与样本的输出的方差达到最小),然后用验证集样本进行参数优化,并用测试集对系统进行测试。吴恩达认为三者一般比例(60:10:30)。无监督学习一般是样本无标签,或没有所谓的输入和输出关系(比如说分类),设计一个代价函数,使得代价最小(如K聚类分析),或设计一个惩罚函数,机器自己调整参数,如机器排雷游戏。

获得两条经验:

1.初始化的权重应该是随机数,不能是相同的

2.训练的数据不能一个一个的训练达到精度要求,应该将数据批量地训练

看了几天的吴恩达的机器学习的课程,有一些想法:

1.机器学习中的很多算法是一起就有的,不过现在大家将其进行理论化的归类,总结,有好多的东西是在很多年以前我在计算方法(数值计算)课程,优化方法课程中学习的。

2.看了卷积网络后,我的想法是我们从输入中其实已经可以识别出很多特征,这些特征我们以往常常用来识别对象,实际上这些特征对我们的最终结果可能都会有影响,而以往我们设计的算法一般仅仅考虑单一因素或几个因素,而且一般是将识别出的特征以线性关系考虑,但是识别出的这些特征如何影响最终的结果其实可能是非常复杂的,而神经网络就是比较擅长与分析其中的复杂的、非线性的关系。

通过卷积网络,我们加速了对特征的识别,然后由神经网络来分析计算这些特征之间的关系。我们在识别物体时,其颜色、形状和其他周边物体的关系都会影响我们的识别,仅仅一项特征可能难以决定。在之前的物体识别中我们往往用形状特征、纹理特征等,在特定的情况下很有效,但是如果这些信息不全呢?(李飞飞:露出一个头的猫用形状能识别吗?看不到尾巴,爪子)。进一步想到我现在学习的操控行为控制,在多操控行为的时候各个操控力的大小如何设定呢?现在是设定参数进行调节,但是这是一个个试验出来的系数,要看经验。能否用机器学习的方法设定呢?我看是可行的。