BP算法代码学习

目录

概念

结构

举例初始化三层网络

正向处理

反向修正

正向、反向反复计算

代码


概念

Sigmoid:S型生长曲线,将变量映射到0,1之间。

 

 

结构

每一层的每个节点包含如下

输入:只有1个。(可以>1)

输出:只有1个,并且该节点的输出=sigmoid(该节点输入)。

ERR:只有1个,初始值赋值给最后1个网络节点,值为Output*(1-Output)*(target-ouput), output为本网络输出,target为外部指定目标。

权重:有多个,个数取决于上层网络节点个数;初次为随机数<1,后续由反向来修正(受到前1层网络的输出和本网络的ERR影响)。

举例初始化三层网络

1、设置第1层初始输入input均为1, output=input

2、随机第2层的weight, weight=((int)rand() % 100000) / (float)100000 - 1;

3、计算第2层的input,output=sigmoid(input); 按照此方法输出第3层的input和output。

  • 正向处理

类似第三步,区别是weight不是随机值,其他基本相同。

 

  • 反向修正

1、计算ERR

计算第3层Err,Err=output*(1-output)*(target-output);

第2层计算方法,

2、修正权重

3、重复赋值Err、修正weight

 

  • 正向、反向反复计算

  1. 第1组输入正向、第1组目标反向;下一步第2步
  2. 第2组输入正向、第2组目标反向;下一步第3步
  3. 第3组输入正向、第3组目标反向;下一步第4步
  4. 第4组输入正向、第4组目标反向;下一步第5步
  5. 第1组输入正向,判断输出目标与第1组目标误差是否小于0.00001,是第6步,否则返回第1步。
  6. 第2组输入正向,判断输出目标与第2组目标误差是否小于0.00001,是第7步,否则返回第1步。
  7. 第3组输入正向,判断输出目标与第3组目标误差是否小于0.00001,是第8步,否则返回第1步。
  8. 第4组输入正向,判断输出目标与第4组目标误差是否小于0.00001,是第9步,否则返回第1步。
  9. 训练完成。

代码

源自:https://blog.csdn.net/weixin_36408040/article/details/79138444

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#define ETA 1//Learning_rate
#define PRECISION 0.00001
 
typedef struct Neuron
{
	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;
/function

double sigmoid(double v)
{
	return 1 / (1 + exp(-v));
}
 
double randomWeight()  //random weight generator between -0.5 ~ 0.5 
{
	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++) {
			nnet->layers[i].neurons[j].weights = (double*)malloc(nnet->layers[i - 1].numberOfNeurons * sizeof(double));
			double input = 0;
			for (int kk = 0; kk < nnet->layers[i - 1].numberOfNeurons; 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);
		
		}
	}
}

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;
		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;
				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;
				
				nnet->layers[i-1].neurons[jj].Error= out * (1 - out)*temp;
				
			
			}
		}
		i--;
		
	}
	
}
 
int _tmain(int argc, _TCHAR* argv[])
{
	
	NNET* net=(NNET*)malloc(sizeof(NNET));
	int num = 3;
	int a[4] = { 3,3,1 };
	createNetWorks(net, num, a);
	double input[4] = { 1,2,2 };
	double input1[4] = { 1,0,1 };
	double input2[4] = { 1,1,0 };
	double input3[4] = { 0,0,1 };

	double target0[1] = { 0.9 };
	double target1[1] = { 0.7 };
	double target2[1] = { 0.5 };
 
	double target3[1] = { 0.3 };
	init(net,input);
	printf("\n");
	int alpha = 0;
	int flag = 0;
	while (1) {
 
		feedforwardWithiInput(net, input);
		backprop(net, target0);
 
		feedforwardWithiInput(net, input1);
		backprop(net, target1);
 
		feedforwardWithiInput(net, input2);
		backprop(net, target2);
 
		feedforwardWithiInput(net, input3);
		backprop(net, target3);
 
		alpha++;
		feedforwardWithiInput(net, input);
		if (fabs(net->layers[2].neurons[0].output - target0[0]) >= PRECISION) {
			//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, input);
	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;
}
Algorithms   本次README修订为算法仓库Algorithms的第100次commit,首先我们庆祝自2016年8月4日本仓库建立以来Dev-XYS在算法学习方面取得的显著进步!   这里有各种算法的C++代码,任何人可以在自己的任何程序中使用,欢迎大家指出代码中的错误以及有待改进的地方。   本仓库内所有代码的授权方式为Unlicense,大家如果使用我的代码开发自己的软件挣了大钱,或是参考我的代码在NOI中得了金牌,我都会很高兴的。使用这里的代码之后,你可以自主选择是否公开源代码。总而言之,你可以把这里的代码当作你自己写的一样,无论怎样使用都是被允许的。但是,我不对本仓库内代码的正确性负责。大家要是使用我的代码开发软件而导致程序崩溃,或是参考我的代码在考试时出错,请不要向我抱怨。如果你愿意,遇到问题可以在Issues中提出来,我们共同解决。我们不赞成Pull Request,因为本仓库主要储存作者已经学习的算法,全部代码均由作者本人负责维护与更新。   以下索引提供了本仓库内算法的中文名,方便大家查找。更新可能有很长时间的延迟,不保证所有算法的名称都在列表中出现。 Index --------------------------Contents-------------------------- --------------------------FileName-------------------------- AC自动机 Aho-Corasick-Automation 单源最短路径(SPFA) Bellman-Ford(Queue-Optimised) 单源最短路径(Bellman-Ford) Bellman-Ford 使用Edmonds-Karp进行二分图匹配 Bigrpah-Matching(Edmonds-Karp) 普通的二叉搜索树 Binary-Search-Tree 广度优先搜索 Breadth-First-Search 冒泡排序 Bubble-Sort 桶排序 Bucket-Sort 组合数的递推求解 Combination(Recursion) 枚举组合 Combination 基本的复数类 Complex-Number 割点 Cut-Vertex 深度优先搜索 Depth-First-Search 堆优化的Dijkstra算法 Dijkstra(Heap-Optimised) 并查集 Disjoint-Set-Union 最大流Edmonds-Karp算法 Edmonds-Karp 欧拉函数 Euler's-Totient-Function 有向图的欧拉回路 Eulerian-Tour(Digraph) 拓展欧几里得算法 Extended-Euclid 简单的快速幂 Fast-Exponentiation 树状数组 Fenwick-Tree 所有结点对之间的最短路径(Floyd) Floyd-Warshall 凸包算法(Graham扫描法) Graham-Scan 辗转相除法求最大公约数 Greatest-Common-Divisor 堆排序 Heap-Sort ISAP算法 Improved-Shortest-Augmenting-Path(Naive) 插入排序 Insertion-Sort 字符串匹配(KMP) Knuth-Morris-Pratt 最小生成树(Kruskal) Kruskal 最近公共祖先(Tarjan) Least-Common-Ancestor(Tarjan) 使用后缀数组求解最长公共子串 Longest-Common-Substring 最长上升子序列(n·log(n)) Longest-Increasing-Subsequence(n·log(n)) 倍增法求最近公共祖先 Lowest-Common-Ancestor(Doubling) 朴素的矩阵乘法 Matrix-Multiplication(Naive) 归并排序 Merge-Sort 最小堆 Min-Heap 乘法逆元 Modular-Multiplicative-Inverse 仅支持单点修改的可持久化线段树(维护区间和值) Persistent-Segment-Tree(Sum) 试除法素数测试 Prime-Check(Naive) 线性的素数筛法 Prime-Sieve(Linear) 队列的基本操作 Queue 快速排序的优化版本 Quick-Sort(Extra-Optimised) 快速排序的随机化版本 Quick-Sort(Randomized) 快速排序 Quick-Sort 使用向量叉积判断两个有向线段的时针关系 Segment-Direction 线段树维护区间最大值 Segment-Tree(Maximum) 线段树维护区间最小值 Segment-Tree(Minimum) 线段树维护区间和值 Segment-Tree(Sum) 普通的选择算法 Selection Eratosthenes素数筛法 Sieve-of-Erotosthenes 指针版的单向链表 Singly-Linked-List(Pointer) 跳表 Skip-List ST表 Sparse-Table 伸展树 Splay 博弈论SG函数 Sprague-Grundy 栈的基本操作 Stack 递推法求解无符号第一类斯特林数 Stirling-Number(Cycle,Unsigned,Recursion) 递推法求解第二类斯特林数 Stirling-Number(Subset,Recursion) 倍增法求解后缀数组 Suffix-Array(Doubling) 倍增法求解后缀数组(附带Height数组) Suffix-Array-with-Height(Doubling) 使用Tarjan算法求解强连通分量 Tarjan(Strongly-Connected-Components) 数组版的字典树 Trie(Array) 指针版的字典树 Trie(Pointer)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值