神经网络有两个重要工作
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.看了卷积网络后,我的想法是我们从输入中其实已经可以识别出很多特征,这些特征我们以往常常用来识别对象,实际上这些特征对我们的最终结果可能都会有影响,而以往我们设计的算法一般仅仅考虑单一因素或几个因素,而且一般是将识别出的特征以线性关系考虑,但是识别出的这些特征如何影响最终的结果其实可能是非常复杂的,而神经网络就是比较擅长与分析其中的复杂的、非线性的关系。
通过卷积网络,我们加速了对特征的识别,然后由神经网络来分析计算这些特征之间的关系。我们在识别物体时,其颜色、形状和其他周边物体的关系都会影响我们的识别,仅仅一项特征可能难以决定。在之前的物体识别中我们往往用形状特征、纹理特征等,在特定的情况下很有效,但是如果这些信息不全呢?(李飞飞:露出一个头的猫用形状能识别吗?看不到尾巴,爪子)。进一步想到我现在学习的操控行为控制,在多操控行为的时候各个操控力的大小如何设定呢?现在是设定参数进行调节,但是这是一个个试验出来的系数,要看经验。能否用机器学习的方法设定呢?我看是可行的。