轻量级C++神经网络应用库CreativeLus:1、库介绍。案例:简单sin函数逼近。

编程 同时被 3 个专栏收录
16 篇文章 0 订阅
9 篇文章 0 订阅

github资源地址:[Release-x86/x64]

下一篇:轻量级C++神经网络应用库CreativeLus:2、分类问题。案例:空间点在平面上2分类。


轻量级C++神经网络应用库CreativeLus:介绍及应用!

1.CL库介绍:

CreativeLus库,又名“创造性逻辑元”,简称CL,是基于反馈式神经网络(BP网络)模型理论基础开发的C++神经网络库。希望在尽可能的丰富功能前提下,让使用者付出极低的代价。尤其是学生、研究人员或小型应用,在机器学习,深度学习,神经网络应用等领域能有一种快速的应用可选方案。

作为超轻量级应用库,它区别于TensorFlow、PyTorch等强大而复杂的系统工具或库,但它同样简单易用,而且有效。能处理常规逼近,分类问题,还能构建自定义的各类网络模型,包括:复杂节点网络,卷积网络(cnn),残差网络(ResNet),循环网络(RNN)等等,用于解决实际的诸如图像识别,语义识别等问题。它的小范围可视化输出,能让神经网络初学者在理论学习中,有对神经网络工作原理的感官认知,具有一定启发性。

由于开发力量有限,所以目前这个库只用于Windows平台,并在不断成长中,由衷希望得到大家的支持和宝贵的意见!

2.特点介绍:

序号内容
1Windows平台,基于C++语言的,面向对象神经网络库。
2多线程支持,让你的多核CPU飞起来。(GPU加速暂不支持,完善中)
3拒绝臃肿,作为轻量级的库,代码简洁易于使用。适用于学习,科研,和部分小型化产品。
4快速的可视化输出,过程监控及网络结构呈献。可加深对神经网络的理解。
5具有灵活自如的,快捷的,创造性的多种建模方式。发挥你的创造力。
6对象是由内核(用于发布)和训练层(用于训练)组成,他们相互独立。节约内存。

3.获取及使用:

  • 1、支持Windows平台 .
  • 2、开发环境Microsoft Visual Studio 2019 (v142),其他IDE支持情况暂未验证,使用中若出现问题请留言或更改IDE尝试
  • 3、编译语言C++11

3.1 文件组成

该工具库在Windows平台下以静态链编dll方式使用,包含三个部分文件:

  • 1、C++头文件(.h):CreativeLus.h
  • 2、windows静态链接库(.lib):CreativeLus_x64.lib,CreativeLus_x86.lib
  • 3、windows动态链接库(.dll):CreativeLus_x64.dll,CreativeLus_x86.dll

头文件会根据版本不同,连同lib和dll文件一同发布。
从_x64或_x86文件后缀可看出,你需要根据你的系统是64位或32位选择对应的库文件,暂时未提供debug版本的库文件。

3.2 库的使用

1.首先,在任何需要调用该类库中对象的源文件中引入头文件

#include "CreativeLus.h"

2.其次,项目在编译时链接静态库lib文件,方法有两种。
第一种:通过显示的在源文件代码中申明编译器链接静态库

#ifdef _WIN64
#pragma comment(lib,"CreativeLus_x64.lib") //文件路径自行调整修改
#else
#pragma comment(lib,"CreativeLus_x86.lib")
#endif

第二种:将CreativeLus_x64.dll,CreativeLus_x86.dll文件放入生成的应用程序目录,或系统目录,或到IDE(开发环境)的链接库搜索目录下面,这要根据你使用IDE情况而定。具体方法自行百度.。

3.最后,将CreativeLus_x64.dll,CreativeLus_x86.dll文件放入生成的应用程序所在的同目录下,或Windows系统目录C:\Windows\System32下,或环境变量指定的搜索目录下。

3.2 库的获取

github资源地址:[Release-x86/x64]

4.应用案例:

千言万语不如代码来得真实!首先我们就以一个最朴实无华的例子,sin函数逼近,借助代码我们徐徐展开,看看他能做些什么!

案例1:Sin函数逼近

问题:我们在x轴,取定义域[-Π,Π]之间的随机输入,通过y=f(x)=sin(x),得到一定数量的训练样本对和测试样本对。通过构建的bp神经网络,在一定次数的训练后,若达到任务目标(即误差精度达到目标或测试集样本带入模型预测正确率满足目标要求),则模型训练完成,此时,随机生成(也可人为指定)多个单点测试输入数据,加入模型预测,观察结果与真实结果之间的差距(是否满足精度要求或是正确分类),评价模型的有效性(即预测能力)。

代码如下:

#include <stdio.h>
#include <math.h>
#include <vector>
#include "CreativeLus.h"

#ifdef _WIN64
#pragma comment(lib,"CreativeLus_x64.lib")
#else
#pragma comment(lib,"CreativeLus_x86.lib")
#endif

using namespace cl;

int main() {

	printf("\nCL控件信息:\n"); //只是做一个控件信息显示,不是必须的步骤
	for (auto& i : getBpnnToolInfo())cout << i.first << " = " << i.second << endl;

	printf("\n\n//案例1:sin函数逼近测试");

	printf("\n\n//第一步:以下生成原始数据集---------------------------------------\n");
	const Float rangA = -ConstPi * 1.0, rangB = ConstPi * 1.0; //
	Float x1, y1;
#define XData x1 = rand_f_a_b(rangA,rangB) // rand_f_a_b是一个生成a,b之间范围随机数的Api,精度远高于rand()
#define YData y1 = ::sin(x1)
#define LDataIn x1
#define LDataOut y1
	BpnnSamSets trainData;//定义训练数据集
	BpnnSamSets checkData;//定义测试数据集
	size_t nPtSi = 2020;  //样本数量2020(至于为什么设2020,纪念一下今年抗战医务一线战士们)
	for (size_t i = 0; i < nPtSi; i++) {
		XData; YData; trainData.addSample({ LDataIn }, { LDataOut });
		//取1/4数量的测试集数据
		if (i < nPtSi / 4) { XData; YData; checkData.addSample({ LDataIn }, { LDataOut }); }
	}

	printf("\n\n//第二步:以下构造神经网络---------------------------------------\n");
	Bpnn::CallBackExample bpnnMonitor;//生成一个过程监控器
	BPNN_CALLBACK_MAKE(pMonitCbFunc, Bpnn::CallBackExample::print);//用其中的成员函数作为外显回调函数
	Float learnRate = 0.1, tagEr = 0.0005, movment = 0.8;
	Bpnn bp;
	bp.setName("sin函数逼近")  //给网络取个中文名(可省略)
		.setLayer(2, 5) //设置2隐藏层,每次5个神经元。(输出层神经元无需设置,由传入的训练样本维度确定)
		.setParam(learnRate, tagEr, movment) //设置 学习率,误差精度,动量惯性系数(一个避免陷入局部极小值的设定,也可增加训练过程稳定性)
		.setTransFunc(TF_Sigmoid, TF_PRelu) //隐藏层采用S函数,为保证输出域是正负无穷,输出层采用PRelu函数
		.setSampSets(trainData) //设置训练集到网络
		.setCorrectRateEvaluationModel(0.999, &checkData) //设置网络目标要求正确率99.9%,测试数据集,0表示采用测试集全部数据
		.setSampleBatchCounts(1, false) //设置每一步训练时,样本采用的批次数量(可省略)
		.buildNet(pMonitCbFunc, &bpnnMonitor); //构建网络,不需要监控可以传入nullptr

	printf("\n\n//第三步:以下开始训练网络---------------------------------------\n");
	CLTick tick, tick2;//CLTick类源码详文章末尾代码,此处计算耗时的代码不是必须的,可自行调整修改或删掉
	Bool rt = false;
	bp.openGraphFlag(true); //打开训练数据流记录
	do { //此处采用循环,保证模型训练持续,直到收敛为止
		rt = bp.setMaxTimes(trainData.size() * 10).train(nullptr, nullptr, nullptr, pMonitCbFunc, &bpnnMonitor);
		printf(("总耗时:%g秒,本次:%g秒,正确率 = %.2f %%, 当前误差 = %g\n"),
			tick.getSpendTime(), tick2.getSpendTime(true), bp.getSavedCorrectRate() * 100.0, bp.getEr());
		bp.showGraphParam();  //显示训练结果曲线(前面必须先打开训练数据流记录开关)
		bp.showGraphNetStruct(true, 800, 1); //显示网络结构,参数为true表示权值结构图一起显示
	} while (rt == false);


	printf("\n\n//第四步:以下做随机测试,验证网络预测能力---------------------------------------\n");
	const size_t checkTimes = 5;  //做5次随机检测,检查模型有效性
	for (size_t i = 0; i < checkTimes; i++)
	{
		XData; YData;
		VLF vIn = { LDataIn };
		VLF vtag = { LDataOut };
		VLF vout;
		auto Er = bp.predict(vIn, &vout, &vtag);
		printf_s("   \n输入值 = { ");
		for (size_t i = 0; i < vIn.size(); i++)
			printf_s(("%f, "), vIn[i]);
		printf_s(" } \n预测值 = { ");
		for (size_t i = 0; i < vout.size(); i++)
			printf_s(("%f, "), vout[i]);
		printf_s(" } \n真实值 = { ");
		for (size_t i = 0; i < vtag.size(); i++)
			printf_s(("%f, "), vtag[i]);
		printf_s(" } \n损失   =   %f, < %g %s\n\n", Er, tagEr,Er < tagEr ? "         预测正确!":"         结果错误!");
	}
	getchar();
	return 1;
}

网络模型结构图:这是一个有3层11个神经元的网络结构(2隐藏层,每层5个神经元),由于y=sin(x),即输入输出维度均为1。
在这里插入图片描述
网络各节点链接及权重分布:颜色越重,越粗表示该节点的链接权重绝对值越大。可以直观的观察网络。
带连接权重的网络结构图
误差曲线:随着训练次数的增加,模型误差在逐渐减小,模型开始收敛。模型在运行71988次训练后达到训练目标。
在这里插入图片描述
正确率曲线:随着训练次数的增加,模型误差减小同时,模型对传入的测试数据正确率开始逐渐提高。模型在运行71988次训练后达到训练目标,正确率达到100%。
在这里插入图片描述

输出信息:

CL控件信息:
Author                 = Cailuo
CharacterSet           = gbk
CharacterWidth         = MuiltChar/Ascii
Company                = Cailuo
CompileDate            = Jan 30 2020
CompileEnvironment     = Microsoft Visual Studio 2019 (v142)
CompileLanguage        = C++17
CompileTime            = 02:22:06
Country                = China
Debug                  = Release
IsDoublePrecision      = false
Language               = Chinese
Level                  = 0
OriginalExtensionName  = dll
OriginalFilename       = CreativeLus_x64
Platform               = x64
Region                 = Shenzhen
RuntimeLib             = MT
SupportGpuAcceleration = false
SupportMultiThreading  = true
System                 = Windows
SystemMinimumSupport   = Windows Nt
Version                = 1.0.2

//案例1:sin函数逼近测试

//第一步:以下生成原始数据集---------------------------------------

//第二步:以下构造神经网络---------------------------------------
Net construct completed. Neurons: 11, layers: 3.

//第三步:以下开始训练网络---------------------------------------
Net training epoch completed.
总耗时:0.162917秒,本次:0.162916秒,正确率 = 24.00 %, 当前误差 = 0.00131303
Net training epoch completed.
总耗时:0.493067秒,本次:0.330151秒,正确率 = 97.00 %, 当前误差 = 2.78476e-05
Net training epoch completed.
总耗时:1.57773秒,本次:1.08466秒,正确率 = 99.80 %, 当前误差 = 1.23399e-05
Net training epoch completed with achieve accuracy. CorrectRate(100.00%) >= TagCorrectRate(99.90%)
总耗时:2.49737秒,本次:0.919643秒,正确率 = 100.00 %, 当前误差 = 3.94404e-06

//第四步:以下做随机测试,验证网络预测能力---------------------------------------
输入值 = { 0.950780,  }
预测值 = { 0.822401,  }
真实值 = { 0.813869,  }
损失   =   0.000036, < 0.0005          预测正确!
输入值 = { -0.023569,  }
预测值 = { -0.044516,  }
真实值 = { -0.023567,  }
损失   =   0.000219, < 0.0005          预测正确!
输入值 = { -2.826877,  }
预测值 = { -0.312865,  }
真实值 = { -0.309546,  }
损失   =   0.000006, < 0.0005          预测正确!
输入值 = { -0.262898,  }
预测值 = { -0.250678,  }
真实值 = { -0.259880,  }
损失   =   0.000042, < 0.0005          预测正确!
输入值 = { -1.556672,  }
预测值 = { -1.006636,  }
真实值 = { -0.999900,  }
损失   =   0.000023, < 0.0005          预测正确!
请按任意键继续. . .

案例1:sin逼近,发散性问题

1 模型采用了学习率ls为0.1,调整学习率分别为1、0.01、0.001观察对模型的影响?
设置不同的学习率,观察模型及训练结果表现.。
2 输出层采用PRelu函数目的,替换成Sigmod函数或者PureLin函数是否可行?
由于sin的值域在[-1,1],采用sigmod函数其值域只在[0,1]将导致模型永远不会收敛。
3 调整网络隐藏层数和神经元数量,对模型的影响?
模型深度越深(即层数越多)模型对问题的非线性(拆解)解释能力越强,每层神经元越多(即模型越宽)则同一非线性复杂维度平面下可拆解的线性无关要素越多.,为后续层提供非线性拆解的输入要素就越多,模型越容易被描述。当神经元数量,多余问题本身的描述因子个数时候,继续增加神经元不会显著提示模型精度。
4 调整每一步训练时,同一批次拟合训练使用的样本数量,对模型的影响?
通过 bp.setSampleBatchCounts(100, true); 方法调整每一批次样本采用100个,每一次样本均采用训练集中随机抽取的。此方法可有效降低模型训练波动(误差曲线更平滑),提高训练收敛速度(训练所需总步数更少),提高泛化能力。但是增加了计算机内存使用和计算时间。结果如下:
在这里插入图片描述 在这里插入图片描述

下一篇:轻量级C++神经网络应用库CreativeLus:2、分类问题。案例:空间点在平面上2分类。


本章附录:

附 1:高精度的计时器类CLTick实现
#include "windows.h"
#ifndef __CL_TICK_DEF__
#define __CL_TICK_DEF__
//高精度计时器类
class CLTick {
protected:
	LARGE_INTEGER lis;
	LARGE_INTEGER lie;
	LARGE_INTEGER Freg;
public:
	CLTick() {
		timingStart();
	}
	//开始计时
	CLTick& timingStart() {
		QueryPerformanceFrequency(&Freg);
		QueryPerformanceCounter(&lis);
		return *this;
	}
	//取得从计时开始到当前的时间
	double getSpendTime(bool saveToStart = false) {
		QueryPerformanceCounter(&lie);
		double rt = double(lie.QuadPart - lis.QuadPart) / double(Freg.QuadPart);
		if (saveToStart)lis = lie;
		return rt;
	}
};
#endif`
  • 3
    点赞
  • 5
    评论
  • 9
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值