Matlab离线训练好的神经网络在Visual Studio中调用

本文将Matlab训练好的神经网络参数导出,在Visual Studio中导入,对数据重新计算。本文的方法可以用于C++调用离线训练好的神经网络。作为神经网络学习之路的一个小小记录,来自https://www.hsli.top

Matlab训练神经网络

首先在Matlab中训练神经网络,本文使用了Matlab的神经网络工具箱中的House Pricing示例模型。

在Matlab命令行界面中键入nnstart进入神经网络工具箱,导入数据,默认隐含层有10个神经元,一路next到这里,导出矩阵参数的神经网络匹配函数

这里写图片描述

得到myNeuralNetworkFunction函数,例如下面这个:

这里写图片描述

可见里面有很多的数据矩阵,那些就是神经网络的权值和偏置参数

写一小段代码,用于测试生成的神经网络,例如:

1
2
3
4
5
i=1:15;
predict = myNeuralNetworkFunction(houseInputs(:,i))
result = houseTargets(i);
plot(predict,'b');hold on;
plot(result,'g');

该代码用了生成的神经网络重新计算前15组输入数据,并与真实结果plot在同一幅图像中,可见该神经网络还是比较令人满意的

这里写图片描述

导出Matlab的神经网络参数

上文生成的神经网络函数中包含了很多的网络权值和偏移参数,下面将这些参数矩阵导出供Visual Studio读取

  1. myNeuralNetworkFunction退出的地方放置一个断点,让程序跑到这里停止,方便导出数据
    这里写图片描述

  2. 将结构体中的矩阵分别复制出来

    1
    2
    3
    x1_xoffset = x1_step1.xoffset
    x1_gain = x1_step1.gain
    %...方法类似,在此不赘述
  3. 将矩阵保存到文件中

    1
    2
    3
    save('x1_gain.txt','x1_gain','-ascii')
    save('x1_xoffset.txt','x1_xoffset','-ascii')
    %...方法类似,不赘述

    注意保存的时候要使用-ascii参数

  4. 可见,Matlab的工作目录中生成了一系列的文件,里面就是响应的矩阵数据,将他们复制到Visual Studio工程目录中

    这里写图片描述

    此处我新建了一个data文件夹以免混乱

Visual Studio工程中调用参数

参考本博客文章Visual Studio使用Armadillo线性代数运算库添加Armadillo线性代数库,新建工程,编写代码

注意:貌似LAPACK和BLAS库有点问题,因此到Armadillo的config.hpp中注释掉

1
2
#define ARMA_USE_LAPACK
#define ARMA_USE_BLAS

这两句,调试阶段,牺牲一点速度吧

代码中矩阵的初始化使用load方法读取文件,如下:

1
2
layer1.bias.load("data\\b1.txt", raw_ascii);
layer1.weight.load("data\\IW1_1.txt", raw_ascii);

测试代码

OffLineNeuralNet.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 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组数据,结果如下:

这里写图片描述

如果文章有用,请随意打赏