本文将Matlab训练好的神经网络参数导出,在Visual Studio中导入,对数据重新计算。本文的方法可以用于C++调用离线训练好的神经网络。作为神经网络学习之路的一个小小记录
Matlab训练神经网络
首先在Matlab中训练神经网络,本文使用了Matlab的神经网络工具箱中的House Pricing
示例模型。
在Matlab命令行界面中键入nnstart
进入神经网络工具箱,导入数据,默认隐含层有10个神经元,一路next到这里,导出矩阵参数的神经网络匹配函数
得到myNeuralNetworkFunction
函数,例如下面这个:
可见里面有很多的数据矩阵,那些就是神经网络的权值和偏置参数
写一小段代码,用于测试生成的神经网络,例如:
i=1:15;
predict = myNeuralNetworkFunction(houseInputs(:,i))
result = houseTargets(i);
plot(predict,'b');hold on;
plot(result,'g');
该代码用了生成的神经网络重新计算前15组输入数据,并与真实结果plot
在同一幅图像中,可见该神经网络还是比较令人满意的
导出Matlab的神经网络参数
上文生成的神经网络函数中包含了很多的网络权值和偏移参数,下面将这些参数矩阵导出供Visual Studio读取
- 在
myNeuralNetworkFunction
退出的地方放置一个断点,让程序跑到这里停止,方便导出数据 - 将结构体中的矩阵分别复制出来
x1_xoffset = x1_step1.xoffset
x1_gain = x1_step1.gain
%...方法类似,在此不赘述
- 将矩阵保存到文件中
save('x1_gain.txt','x1_gain','-ascii')
save('x1_xoffset.txt','x1_xoffset','-ascii')
%...方法类似,不赘述
注意保存的时候要使用-ascii
参数
- 可见,Matlab的工作目录中生成了一系列的文件,里面就是响应的矩阵数据,将他们复制到Visual Studio工程目录中
此处我新建了一个data
文件夹以免混乱
Visual Studio工程中调用参数
参考本博客文章Visual Studio使用Armadillo线性代数运算库添加Armadillo
线性代数库,新建工程,编写代码
注意:貌似LAPACK和BLAS库有点问题,因此到Armadillo的
config.hpp
中注释掉#define ARMA_USE_LAPACK #define ARMA_USE_BLAS
这两句,调试阶段,牺牲一点速度吧
代码中矩阵的初始化使用load
方法读取文件,如下:
layer1.bias.load("data\\b1.txt", raw_ascii);
layer1.weight.load("data\\IW1_1.txt", raw_ascii);
测试代码
OffLineNeuralNet.hpp
#pragma once
#ifndef _OFFLINE_NEURAL_
#define _OFFLINE_NEURAL_
#include "stdafx.h"
#include <armadillo>
using namespace arma;
using namespace std;
enum Method method;
class Setting
{
public:
mat xoffset;
mat gain;
mat ymin;
};
class Layer
{
public:
mat bias;
mat weight;
};
mat mapminmax_apply(mat x, Setting setting)
{
mat y;
mat temp = x;
y = x - setting.xoffset;
y = y % setting.gain;
temp.fill(setting.ymin(0, 0));
y = y + temp;
return y;
}
mat tansig_apply(mat n)
{
mat a;
a = 2 / (1 + exp(-2 * n)) - 1;
return a;
}
mat mapminmax_reverse(mat y, Setting setting)
{
mat x;
mat temp = y;
temp.fill(setting.ymin(0, 0));
x = y - temp;
temp.fill(setting.gain(0, 0));
x = x / temp;
temp.fill(setting.xoffset(0, 0));
x = x + setting.xoffset;
return x;
}
#endif // !_OFFLINE_NEURAL_
main.cpp
// HousePrizeModel.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <armadillo>
#include "OffLineNeuralNet.h"
#define TOTAL_TEST 15
using namespace arma;
const mat x1_ymin = { -1 };
const mat y1_ymin = { -1 };
const mat y1_gain = { 0.0444444444444444 };
const mat y1_xoffset = { 5 };
const mat layer2_b = { 0.91848175916311114 };
int main()
{
Setting x1_step1, y1_step1;
Layer layer1, layer2;
x1_step1.xoffset.load("data\\x1_xoffset.txt", raw_ascii);
x1_step1.gain.load("data\\x1_gain.txt", raw_ascii);
x1_step1.ymin = x1_ymin;
y1_step1.ymin = y1_ymin;
y1_step1.gain = y1_gain;
y1_step1.xoffset = y1_xoffset;
layer1.bias.load("data\\b1.txt", raw_ascii);
layer1.weight.load("data\\IW1_1.txt", raw_ascii);
layer2.bias = layer2_b;
layer2.weight.load("data\\LW2_1.txt", raw_ascii);
mat houseInputs;
vec result(TOTAL_TEST);
houseInputs.load("data\\houseInputs.txt", raw_ascii);
for (int i = 0; i < TOTAL_TEST; i++)
{
mat x1 = houseInputs.col(i);
mat xp1 = mapminmax_apply(x1, x1_step1);
mat a1 = tansig_apply(layer1.bias + layer1.weight * xp1);
mat a2 = layer2.bias + layer2.weight*a1;
double result_temp = mapminmax_reverse(a2, y1_step1)(0);
result.at(i) = result_temp;
}
result.print("Target = ");
system("pause");
return 0;
}
同样测试了数据集的前15组数据,结果如下: