ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

轻量级C++神经网络应用库CreativeLus:2、分类问题,代码案例:平面点2分类。

2020-01-30 17:44:26  阅读:258  来源: 互联网

标签:误差 CreativeLus 样本 0.000000 分类 bp 多线程 轻量级 size


案例2:平面点2分类问题

本章将介绍以下几个新的使用方法:
1、对样本数据的保存及读取,对训练好的模型的保存及读取;
2、启动多线程支持,加速你的训练模型;
3、动态的实时输出训练时的图形结果;(按每一训练周期做一次输出更新的方式)
4、将图形和曲线结果保存到外部Bitmap图形文件中;
5、将模型的计算内核和训练扩展脱开,释放训练扩展占用的内存,仅保留预测部分。

问题介绍:

我们在三位空间中 x y z方向中取x,y在0,1之间,z取0,取一定数量的随机三维点,保证全部落在0,1的xy平面内。在该[0,1]xy平面范围内构造两个多段线封闭区域R1和R2(该区域是任意定义的,他们之间可能存在交集),若点ptx属于R1则对应的分类标记记作1,反之为0,则对每一个点ptx={x,y,z},他存在一个唯一的2分类标记集T={t1,t2}。以此构建数据映射样本集和测试集。
R1={ {0.1,0.1,0},{0.32,0.1,0},{0.56,0.55,0},{0.25,0.25,0},{0.29,0.88,0},{0.1,0.76,0} };
R2={ {0.38,0.13,0},{0.66,0.13,0},{0.66,0.90,0},{0.15,0.90,0}, {0.15,0.65,0},{0.65,0.38,0} };
分类区域如下:(由图像可知,这仍然是一个非线性问题)
在这里插入图片描述

测试代码:

#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include "CreativeLus.h"
#include "CreativeLusExTools.h"

using namespace cl;

int main() {
	printf("\n案例2:平面区域分类 \n\n");
	string pathTag = ("D:\\Documents\\Desktop\\example_01_classify\\"); //输出目录

	//第一步:构造数据样本集------------------------
	//空间点坐标定义域范围在 [ 0 , 1 ] 内
	const Float r1 = 0, r2 = 1; 
	//构造平面分类区域。(CLSpace::Polygon定义在 CreativeLusExTools.h 中)
	CLSpace::Polygon R1 = { {0.1,0.1,0},{0.32,0.1,0},{0.56,0.55,0},{0.25,0.25,0},{0.29,0.88,0},{0.1,0.76,0} };
	CLSpace::Polygon R2= { {0.38,0.13,0},{0.66,0.13,0},{0.66,0.90,0},{0.15,0.90,0}, {0.15,0.65,0},{0.65,0.38,0} };

	//构造逻辑:采用3输入,2输出样本对,表示空间3维点是否属于两个平面区域poly或poly2,若属于,则对应的分类为1,否则为0,将所有点的z置0,转化为平面点
	Float x = 0, y = 0, z = 0, t1 = 0, t2 = 0;
	BpnnSamSets sams, tags;
	size_t si = 10000;//训练样本数
	for (size_t i = 0; i < si; i++)
	{
		// CLSpace::pointIsInPolygon()方法判断某个点是否在一个多段线封闭范围内
#define INPUT_DATA_CLASSIFY \
			x = rand_f_a_b(r1, r2), y = rand_f_a_b(r1, r2), z = 0;\
			t1 = CLSpace::pointIsInPolygon({ x,y,z }, R1) ? (1.0) : (0.0);\
			t2 = CLSpace::pointIsInPolygon({ x,y,z }, R2) ? (1.0) : (0.0);
		INPUT_DATA_CLASSIFY;
		sams.addSample({ x,y,z }, { t1,t2 });
		INPUT_DATA_CLASSIFY;
		tags.addSample({ x,y,z }, { t1,t2 });
	}
	//样本数据,保存到外部文件,第二个参数标明保存的文件形式:二进制文件 或 文本文件
	sams.writeToFile((pathTag + "\\sams.txt").c_str(), true); //保存为二进制文件,会自动修改扩展名为特定格式
	tags.writeToFile((pathTag + "\\tags.txt").c_str(), false);//保存为文本文件

	//第二部:构造网络------------------------------
	Bpnn bp;
	bp.setName("区域分类");
	bp.setSampSets(sams);
	bp.setCorrectRateEvaluationModel( //正确率评价模式
		0.975, //正确率目标97.5%
		&tags, //测试集设为tags
		2000, //测试集只取用其中2000对数据(测试集总计10000个数据)
		true, //这2000对数据是从集合中随机抽样的
		CRT_MeanSquareLoss //采用均方差评价方式,即误差评价方式,详情见,附录2
	); 
	bp.setLayer(3, 12);//构造3隐层,每层12个神经元的,全连接网络结构
	bp.setTransFunc(TF_Sigmoid, TF_Sigmoid);//分类目标值值域为0或1,输出层函数可选用S函数
	bp.setSampleBatchCounts(
		0,   //参数1 = 0 表示单一次拟合训练中同时采用的样本数为全部样本,这能增加拟合能力
		true //参数2 = true 表示样本采用随机抽取,本例采用了全部样本数据,所以采用随机抽取并无意义,该参数将被忽略
	);  	
	bp.setParam(0.003, 0.005, 0.8);    //特别注意:由于采用的一批次样本数为全部样本数,所以应该设置一个较小的学习率,否则梯度爆炸
	bp.setLossFunc(LS_MeanSquareLoss); //目前支持均方差损失函数(默认)。后续详解:通过构造网络结构,实现自定义的其他损失函数和分类器,例如softmax分类器。
	bp.setMultiThreadSupport(true);	   //采用一批次样本为全部样本数,计算量较大,开启多线程支持,让训练加速。(CPU要求最低为4核)
	bp.setMaxTimes(sams.size());
	bp.openGraphFlag(true);
	Bpnn::CallBackExample bk;
	BPNN_CALLBACK_MAKE(vcb2, Bpnn::CallBackExample::print);//构造监控回调函数指针
	bp.buildNet(vcb2, &bk);
	bp.exportGraphNetStruct((pathTag + "/NnStruct.bmp").c_str());//输出网络结构到一张bmp图片文件


	CLTick tick, tick2, tick3; //计时器CLTick类代码详见,案例1,附录。
	bool rt = false; Int epoch = 0;
	while (!rt) {
		rt = bp.train(0, 0, 0, vcb2, &bk);
		printf(("\nEpoch %d:总耗时:%gs,本次:%gs,CorrectRate = %.2f %%, Er = %g \n"), ++epoch, tick.getSpendTime(), tick2.getSpendTime(true),
			bp.getSavedCorrectRate() * 100.0, bp.getEr());
		if (epoch == 1 || rt == true || tick3.getSpendTime() > 10.0) {
			bp.showGraphParam(5 * sams.size()); //参数指定仅保留并显示最近不高于5倍样本数的个数的结果值,当为0显示全部数据
			bp.showGraphNetStruct(true, 800, 1);
			tick3.timingStart();
		}
	};
	if (rt) { //将训练完成的模型输出
		bp.writeBpnnToFile((pathTag + "/Nn.txt").c_str()); //保存为二进制,会自动修改扩展名为特定格式
		bp.writeBpnnToFile((pathTag + "/Nn.txt").c_str(), false); // 保存为文本
	}
	bp.exportGraphNetStruct((pathTag + "/NnStructDetail.bmp").c_str(), true); // 保存带权重的网络结构图
	bp.exportGraphEa((pathTag + "/NnEa.bmp").c_str()); // 输出保存损失曲线图

	bp.detachExtend();//计算内核和训练扩展脱开,用于发布网络产品(在此仅作演示)
	VLF threadBuf;
	//为模型构建线程独享的独立运行时数据区,作用是:可以实现在多线程运行中,使用同一个成品网络对象而无需复制多个模型副本,节约内存,保证预测无关性。
	bp.makeIndependentDataBuf(threadBuf);
	for (size_t i = 0; i < 10; i++)
	{
		INPUT_DATA_CLASSIFY;
		VLF vIn = { x,y,z }; VLF vtag = { t1,t2 }; VLF vout;
		Float Er = bp.predictWithIndependentData(threadBuf.data(), vIn, &vout, &vtag);//采用独立数据区,做数据预测
		printf("   \n输入值 = { ");
		for (size_t i = 0; i < vIn.size(); i++)
			printf("%f, ", vIn[i]);
		printf(" } \n预测值 = { ");
		for (size_t i = 0; i < vout.size(); i++)
			printf("%f, ", vout[i]);
		printf(" } \n真实值 = { ");
		for (size_t i = 0; i < vtag.size(); i++)
			printf("%f, ", vtag[i]);
		printf(" } \n误差   =   %f \n\n", Er);
	}
	return system("pause");
}

运行结果:

案例2:平面区域分类

Net construct completed. Neurons: 38, layers: 4.
Net training epoch completed.

Epoch 1:总耗时:37.3914s,本次:37.3914s,CorrectRate = 92.85 %, Er = 0.00584912
Net training epoch completed.

Epoch 2:总耗时:74.3549s,本次:36.9635s,CorrectRate = 95.50 %, Er = 0.00420637
Net training epoch completed.

Epoch 3:总耗时:112.808s,本次:38.4528s,CorrectRate = 96.65 %, Er = 0.00254209
Net training epoch completed with achieve accuracy. CorrectRate(97.55%) >= TagCorrectRate(97.50%)

Epoch 4:总耗时:123.166s,本次:10.3582s,CorrectRate = 97.55 %, Er = 0.00292503

输入值 = { 0.517881, 0.132116, 0.000000,  }
预测值 = { 0.000000, 0.743129,  }
真实值 = { 0.000000, 1.000000,  }
误差   =   0.032991


输入值 = { 0.462613, 0.364779, 0.000000,  }
预测值 = { 0.076051, 0.000000,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.002892


输入值 = { 0.667225, 0.318124, 0.000000,  }
预测值 = { 0.000000, 0.000012,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.000000


输入值 = { 0.928136, 0.928764, 0.000000,  }
预测值 = { 0.000000, 0.000000,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.000000


输入值 = { 0.047767, 0.979304, 0.000000,  }
预测值 = { 0.000000, 0.000000,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.000000


输入值 = { 0.331989, 0.474740, 0.000000,  }
预测值 = { 0.000009, 0.000000,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.000000


输入值 = { 0.804383, 0.490540, 0.000000,  }
预测值 = { 0.000000, 0.000000,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.000000


输入值 = { 0.571966, 0.122691, 0.000000,  }
预测值 = { 0.000000, 0.000001,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.000000


输入值 = { 0.690587, 0.090982, 0.000000,  }
预测值 = { 0.000000, 0.012756,  }
真实值 = { 0.000000, 0.000000,  }
误差   =   0.000081


输入值 = { 0.274573, 0.264051, 0.000000,  }
预测值 = { 0.995739, 0.000000,  }
真实值 = { 1.000000, 0.000000,  }
误差   =   0.000009

请按任意键继续. . .

结论:评价10次随机预测,预测值于真实值误差都小于精度要求,模型预测正确。

图形结果:

1、带权重的网络结构:

观察网络结构可看出,这是一个3输入2输出,4层38神经元的全连接网络。因为输入节点3(即z)被常置为0,该维度数据对模型结果不会产生影响,经过训练,该节点的所有链接权重全部被调整为0,该节点因子被预测模型完全抛弃,这反映了神经网络自适应的条件选择过程。
在这里插入图片描述

2、误差曲线:

通过设置同一批次训练拟合所采用的样本数量为1扩充至整个训练集(即训练采用的样本数相当于maxTimes x batchSize = 10000 x 10000次),模型在开始很短的训练步数内,误差就下降到一个很低的值,加速了收敛,模型波动相对单样本更稳定。但这却大大增加了的计算量。(因此,我们打开多线程支持,此处采用了1型多线程方案,大大加速了训练计算,当你拥有一块16线程、32线程或更多线程的CPU时,你将感受到速度的飞跃)【1型多线程类型:样本批次划分多线程方案,详见本章附录1。】
在这里插入图片描述

3、正确率曲线:

关于正确率的评价标准,CL分为2种,一种为误差型评价(一般用于相对精确的拟合过程),一种为维度位置型评价(一般用于只关注主类别的多分类过程)。【关于正确率的评价准则,详见本章附录2】
在这里插入图片描述


上一篇:【 轻量级C++神经网络应用库CreativeLus:1、介绍及应用,代码案例:sin函数逼近。
下一篇:【 轻量级C++神经网络应用库CreativeLus:3、逼近问题,代码案例:混合函数逼近。


本章附录:

附 1:多线程支持类型

CL支持1型多线程和2型多线程。该技术细节,对于对神经网络计算效率不关心的用户可以不用关注,因为只要启动多线程加速,模型会根据具体的训练情况,区分使用1型还是2型多线程,无需用户自行处理。

1)型多线程【样本多线程】:表示采用一批次样本数量大于cpu核数时,将一批次样本分配到多个cpu核内独立计算,相互无交叉,没有控制线程和工作线程的平凡切换的性能消耗,理论上有多少个cpu核,就能提高多少倍的计算速度。所以在必要时,用户应该组装满足1型多线程的模型训练条件,加速收敛并充分的发掘你的多核计算机的运算能力。

2)型多线程【结构多线程】:表示结构模型前向运算和反向传递过程中,对每一层的各个神经元分配到不同cpu核内计算,下一层的计算必须等待上一层的所有线程全部运行完毕,再由主控线程重新分配下层执行任务,由于CL采用多线程非阻塞轮询策略(而非自旋或沉睡策略),所以就算是采用了分层多线程方案也能保证较高的执行效率,没有较大的切换开销。该方案将在除1型多线程之外的所有其他需要用到多线程支持的地方。

附 2:所谓的正确率评价类型

所谓正确率:即测试集合中单个样本输入向量通过预测计算,其结果与真实值对比计算(例如通过损失函数计算均方差)结果值达到目标(此处的目标是广义的,可以是误差小于误差精度,也可以是某一维度的值为极大值且该值大于评价阈值),达到目标即为预测正确,则:预测正确的次数 / 总的预测次数 = 正确率。

1)误差型评价:即样本输入通过预测得到的结果值与真实值计算均方差(定义为损失),该值小于设定的误差精度Er,即视为该样本预测正确;

2)位置型评价:即样本输入通过预测得到的结果向量中,出现极大值的维度位置与真实值向量的极值位置相同且该极值绝对值大于真实向量极值的绝对值(一般用于多分类问题),即视为该样本预测正确。由于该方式忽略了非极值维度的输出数据,所以他是不完全的。他只能用在主分类评价等情况。而误差评价会对整个输出向量与目标向量做均方差,每一个分量数据都会参与计算并考量,所以误差型评价所包含的信息是全面的。

注:这也是为什么,在案例2中,本来是分类问题却使用误差型评价的原因,案例2的分类类别虽然相对较少,为2,但案例2需要精确的区分是在哪个区域(虽然只有2类,但却有4种可能,他们必须被全部区分出来),所以输出向量的每一维数据都是不可忽略的,因此采用更精确的误差型评价。

夜雨清狂 发布了8 篇原创文章 · 获赞 1 · 访问量 471 私信 关注

标签:误差,CreativeLus,样本,0.000000,分类,bp,多线程,轻量级,size
来源: https://blog.csdn.net/carlclouder/article/details/104114736

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有