c语言设计注释,BP算法的C语言实现(注释详解)

如有错漏,欢迎大佬指出并进行探讨

#include

#include

#include

#define ETA 1//学习率,步长

#define PRECISION 0.00001//精度要求

typedef struct Neuron//神经元结构体,output=sigmoid[for(weight*output)]

{

double input;//输入

double output;//输出

double* weights;//权重

double Error;//误差

} NEURON;

typedef struct Layer//层结构体

{

int numberOfNeurons;//神经元个数

NEURON *neurons;//第一个神经元头指针,数组

} LAYER;

typedef struct NNet //网络结构体

{

int numberOfLayers;//神经层数

LAYER *layers;//第一层神经层头指针,数组

} NNET;

double sigmoid(double v)//S形,初始rule函数

{

return 1 / (1 + exp(-v));

}

double randomWeight()//随机权重值

{

return ((int)rand() % 100000) / (float)100000 - 1;

}

void createNetWorks(NNET *nnet, int NumberOfLayers, int* NumberOfNeurons)

//构造网络,参数为网络头指针、神经层数、神经元个数

{

nnet->numberOfLayers = NumberOfLayers;//将神经层数赋值给网络结构体的层数元素

nnet->layers = (LAYER*)malloc(NumberOfLayers * sizeof(LAYER));//构造得到一个神经层头指针

for (int i = 0; i < NumberOfLayers; i++)//神经层和神经元都是连续数组结构

{

nnet->layers[i].numberOfNeurons = NumberOfNeurons[i];//将神经元个数一一赋值代入具体元素

nnet->layers[i].neurons = (NEURON*)malloc(NumberOfNeurons[i] * sizeof(NEURON));//构造得到每一层的神经元头指针

}

}

void init(NNET *nnet, double * inputs) //神经网络初始化,参数为神经网络指针,输入参数

{

for (int i = 0; i < nnet->layers[0].numberOfNeurons; i++) //遍历网络第一层的所有神经元

{

nnet->layers[0].neurons[i].output = inputs[i];//将输入序列依次赋值给网络第一层各个神经元的输出元素

}

for (int i = 1; i < nnet->numberOfLayers; i++) //遍历网络的所有层

{

for (int j = 0; j < nnet->layers[i].numberOfNeurons; j++)

//遍历每层的所有神经元,由于i从1开始,因此这里从第二层开始遍历

{

nnet->layers[i].neurons[j].weights = (double*)malloc(nnet->layers[i - 1].numberOfNeurons * sizeof(double));

//为每个神经元的权值参数申请一个双精度的存储空间,个数为上一层神经元个数

//因为权重值是与上一层的输出进行结合计算的

//且本层每一个神经元都默认与上一层的每个输出进行计算,因此是神经元里的权重数组

//因此个数应为上一层的神经元个数,且第一层只有输入作为输出,不用权重处理

double input = 0;//初定义输入为0

for (int kk = 0; kk < nnet->layers[i - 1].numberOfNeurons; kk++)

//当kk小于上一层的神经元个数时进行循环(因为从第二层开始遍历)

{

double weight = randomWeight();//定义一个权重数进行随机赋值

nnet->layers[i].neurons[j].weights[kk] = weight;//将这个随机数赋值给权重数组的依次位

input += nnet->layers[i - 1].neurons[kk].output*weight;//将权重值和上一层对应的神经元的输出进行乘积计算并累加

}

nnet->layers[i].neurons[j].input = input;//将输入累加值赋值为此神经元的输入值

nnet->layers[i].neurons[j].output = sigmoid(input);//用rule函数对输入值进行计算得到本神经元的输出值

}

}

}

void feedforward(NNET *nnet) //前向网络

{

for (int i = 1; i < nnet->numberOfLayers; i++) //遍历每层,从第二层开始

{

for (int j = 0; j < nnet->layers[i].numberOfNeurons; j++) //遍历每个神经元,从第一个开始

{

double input = 0;//输入初始为0

for (int kk = 0; kk < nnet->layers[i - 1].numberOfNeurons; kk++) //根据上一层的神经元个数配置权重数组

{

double weight = nnet->layers[i].neurons[j].weights[kk];

input += nnet->layers[i - 1].neurons[kk].output*weight;

}

nnet->layers[i].neurons[j].input = input;//累加为函数输入

nnet->layers[i].neurons[j].output = sigmoid(input);//用rule函数求输出

}

}

}

void feedforwardWithiInput(NNET *nnet, double* input) //带有初始输入的前向网络

{

for (int i = 0; i < nnet->layers[0].numberOfNeurons; i++) //遍历第一层的神经元

{

nnet->layers[0].neurons[i].output = input[i];//将输入作为第一层神经元输出

}

for (int i = 1; i < nnet->numberOfLayers; i++) //从第二层开始遍历神经层,类似地,进行参数配置

{

for (int j = 0; j < nnet->layers[i].numberOfNeurons; j++)

{

double input = 0;

for (int kk = 0; kk < nnet->layers[i - 1].numberOfNeurons; kk++)

{

double weight = nnet->layers[i].neurons[j].weights[kk];

input += nnet->layers[i - 1].neurons[kk].output*weight;

}

nnet->layers[i].neurons[j].input = input;

nnet->layers[i].neurons[j].output = sigmoid(input);

}

}

}

void backprop(NNET *nnet, double* targets) //后向反馈调节,参数为网络头指针和目标值数组

{

//double **Errors= (double**)malloc(nnet->numberOfLayers * sizeof(double*));

int num = nnet->layers[nnet->numberOfLayers - 1].numberOfNeurons;//定义最后一层的神经元个数

//Errors[nnet->numberOfLayers - 1]=(double*)malloc((num+1)*sizeof(double));

for (int i = 0; i < num; i++)//遍历最后一层的神经元

{

double out = nnet->layers[nnet->numberOfLayers - 1].neurons[i].output;//取出out进行赋值

nnet->layers[nnet->numberOfLayers - 1].neurons[i].Error = out*(1 - out)*(targets[i] - out);//误差计算

}

for (int i = nnet->numberOfLayers - 1; i >= 0;)

//从最后一层遍历神经层,直到第一层则停止操作,因为没有更前层用来调节

{

if (i != 0)//只要不是第一层

{

// Errors[i - 1] = (double*)malloc(nnet->layers[i - 1].numberOfNeurons * sizeof(double));

for (int jj = 0; jj < nnet->layers[i - 1].numberOfNeurons; jj++)

//前一层的神经元数量,逐个用上一层的神经元对本层所有神经元进行权值调整

{

double temp = 0;//用temp将权值*误差进行累加

for (int kk = 0; kk < nnet->layers[i].numberOfNeurons; kk++)//本层神经元数量

{

temp += nnet->layers[i].neurons[kk].weights[jj] * nnet->layers[i].neurons[kk].Error;

nnet->layers[i].neurons[kk].weights[jj] = nnet->layers[i].neurons[kk].weights[jj] + ETA * nnet->layers[i].neurons[kk].Error *nnet->layers[i - 1].neurons[jj].output;

//将学习率*当次本神经元的误差 *本神经元的误差所对应的上层神经元的输出 所得值加在权值进行调节;

}

double out = nnet->layers[i - 1].neurons[jj].output;

//用上层一个神经元对一层权值进行了调整之后,取出上一层用来调节的神经元的output

nnet->layers[i - 1].neurons[jj].Error = out * (1 - out)*temp;//非末层的误差计算公式不一样

}

}

i--;

}

}

int main()

{

NNET* net = (NNET*)malloc(sizeof(NNET));//建立网络头指针

int num = 3;

int a[4] = { 3, 3, 1 };

createNetWorks(net, num, a);//建立网络,3层网络,神经元个数分别为3、3、1

double input0[4] = { 1, 1, 1 };

double input1[4] = { 1, 0, 1 };

double input2[4] = { 1, 1, 0 };

double input3[4] = { 0, 1, 1 };//4种输入,3个元素因为第一层有3个神经元

double target0[1] = { 0.8 };

double target1[1] = { 0.7 };

double target2[1] = { 0.5 };

double target3[1] = { 0.3 };//4种输出,一个元素因为最后一层只有1个神经元

init(net, input0);//用第一个输入进行初始化,不能省,

printf("\n");

int alpha = 0;

int flag = 0;

while (1)

{

//训练过程

feedforwardWithiInput(net, input0);//前向一次,后向一次,四个输入输出轮一回

backprop(net, target0);

feedforwardWithiInput(net, input1);

backprop(net, target1);

feedforwardWithiInput(net, input2);

backprop(net, target2);

feedforwardWithiInput(net, input3);

backprop(net, target3);

alpha++;//迭代次数计数

//测试过程

feedforwardWithiInput(net, input0);

if (fabs(net->layers[2].neurons[0].output - target0[0]) >= PRECISION)//精度要求0.00001

{

//flag = 1;

continue;

}

feedforwardWithiInput(net, input1);

if (fabs(net->layers[2].neurons[0].output - target1[0]) >= PRECISION)

{

//flag = 1;

continue;

}

feedforwardWithiInput(net, input2);

if (fabs(net->layers[2].neurons[0].output - target2[0]) >= PRECISION)

{

//flag = 1;

continue;

}

feedforwardWithiInput(net, input3);

if (fabs(net->layers[2].neurons[0].output - target3[0]) >= PRECISION)

{

//flag = 1;

continue;

}

break;

}

//输出结果

printf("\n");

printf("Numbers of iteration : %d", alpha);

printf("\n");

//再次前向计算并输出

feedforwardWithiInput(net, input0);

printf(" %f \n", net->layers[2].neurons[0].output);

feedforwardWithiInput(net, input1);

printf(" %f \n", net->layers[2].neurons[0].output);

feedforwardWithiInput(net, input2);

printf(" %f \n", net->layers[2].neurons[0].output);

feedforwardWithiInput(net, input3);

printf(" %f \n", net->layers[2].neurons[0].output);

getchar();

return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值