我想将使用神经网络的MATLAB应用程序编译为独立应用程序,但是正如您所知,MATLAB不能将训练神经网络编译为独立的,只能编译已经训练的神经网络。
我的应用程序的核心包括在导入的数据上训练神经网络。我该怎么做呢?有别的办法吗?我的MATLAB版本是R2014a。
我尝试使用deploytool
编译,但根据MATLAB编译器文档:
THIS CAN BE COMPILED
* Pre-trained network
* command line functions
THIS CANNOT BE COMPILED
* All other command line functionality
* All GUIs provided with toolbox
* Simulink blocks
* gensim
因此,如果我们在代码中有newff
或patternnet
或其他训练函数,则在编译应用程序后会出现错误。
我知道这是MATLAB编译器的限制,我搜索了几个月的解决方案,但我没有找到任何变通方法或替代方法。
显然,在MATLAB的新版本中增加了一个函数,用于在MATLAB编译器中使用训练好的神经网络:部署神经网络函数。
最重要的是MATLAB Compiler只支持部署预训练的神经网络。
神经网络工具箱
可以编译:
- 预训练的网络命令行函数
不能编译:
- 所有其他命令行功能
- Apps and ui
<- 模型块/gh>
gensim
这意味着你不能mcc
编译函数与训练功能(任何包含TRAIN, ADAPT等…),你只能部署函数评估/模拟一个已经训练的网络对象(SIM函数等)。
对于支持的场景(部署预训练的网络),有几种方法可以实现:
1)保存/加载预训练的网络对象到mat文件
在正常的MATLAB会话中,加载您拥有的训练数据,然后使用所需的设置创建和训练神经网络(不断调整网络参数,直到您对结果满意为止)。最后将网络对象保存到磁盘(在mat文件中作为变量导出)。
% sample regression dataset
[x,y] = simplefit_dataset();
% feed-forward neural network (one hidden layer with 4 neurons)
net = fitnet(4);
net = configure(net, x, y); % configure net to match data
net.trainParam.showWindow = false; % dont show training GUI
net.trainParam.showCommandLine = true; % display output in command line
net.trainParam.show = 1; % display output every iteration
% train networks (data is divided into train/validation/test sets)
net = init(net); % initialize network weights
[net,tr] = train(net, x, y);
% save pre-trained network to MAT-file
save('pretrained_network.mat', 'net')
接下来创建一个可部署的函数,该函数加载保存的网络,并使用它来预测给定一些测试数据的输出(注意使用%#function
pragma行):
simulateSavedNet.m
function y_hat = simulateSavedNet(x)
% this is a special pragma for MATLAB Compiler
% used to declare "network" class as dependency in deployed mode
%#function network
% load pre-trained network
S = load('pretrained_network.mat', 'net');
net = S.net;
% predict outcome given input data
%y_hat = net(x);
y_hat = sim(net, x);
end
2)从预训练的网络
生成一个独立的m函数您可以使用genFunction
从预训练的网络对象生成独立的MATLAB函数,然后可以使用该函数来模拟网络输出。此功能已在MATLAB R2013b中引入。
它基本上将硬编码网络设置,结构和权重都在一个m函数中。生成的函数与MATLAB Compiler mcc
(编译成支持的目标之一)以及MATLAB Coder codegen
(转换为独立的C/c++代码)完全兼容。
% generate standalone M-function from the trained net
genFunction(net, 'simulateStandaloneNet.m', 'MatrixOnly','yes', 'ShowLinks','no')
下面是生成函数的代码:
3)手动模拟预训练网络simulateStandaloneNet.m
对于简单的静态神经网络(前馈等),评估预训练的网络并模拟其输出相对容易(困难的部分是训练它们!)。
我已经在前面的回答中展示了如何做到这一点。基本上,您可以从网络中提取学习到的权重,然后将这些数字插入传递函数,为其提供输入,并计算传播输出(一次一层)。你必须注意对数据进行任何预处理/后处理,并在每一层使用相同的传递函数。
事实上,这基本上就是genFunction
在前面的方法中所做的,只是它是自动化的,并且处理所有情况(适用于各种神经网络,而不仅仅是前馈ann)。
下面是上面训练的网络的一个例子:
simulateManualNet.m
function y_hat = simulateManualNet(x)
% pre-trained feed-forward neural network
% contains one hidden layer with 4 neurons, 1D input, 1D output
% We assume the default transfer functions, preprocessing, etc..
% The following hardcoded values were obtained
% from net.IW, net.LW, net.b properties using MAT2STR
% hidden layer weights/biases
b1 = [6.0358701949521; 2.72569392497815; 0.584267717191459; -5.1615078566383];
W1 = [-14.0019194910639; 4.90641117353245; -15.2282807645331; -5.26420794868803];
% output layer weights/biases
b2 = -0.756207251486408;
W2 = [0.548462643231606 -0.435802343861239 -0.085111261420613 -1.13679228253379];
% scale input
in = mapFcn(x);
% hidden layer
hid = hiddenLayerTransferFcn(bsxfun(@plus, W1*in, b1));
% output layer
out = outputLayerTransferFcn(W2*hid + b2);
% inverse scale output
y_hat = mapInverseFcn(out);
end
function xx = mapFcn(x)
% linear mapping from [mn,mx] to [-1,1]
mn = 0; mx = 9.97628374728129;
xx = (x - mn)*2 / (mx - mn) - 1;
end
function x = mapInverseFcn(xx)
% inverse linear mapping from [-1,1] to [mn,mx]
mn = 0; mx = 10;
x = (xx + 1) * (mx - mn)/2 + mn;
end
function out = hiddenLayerTransferFcn(in)
% Hyperbolic tangent sigmoid transfer function
out = tanh(in);
end
function out = outputLayerTransferFcn(in)
% Linear transfer function
out = in;
end
4)从预训练的网络生成Simulink块,并使用Simulink Coder进行转换
这里的想法是使用gensim
从预训练的网络生成一个Simulink块,然后使用Simulink Coder(以前称为Real-Time Workshop)将生成的块转换为独立的C/c++应用程序。R2010b中介绍了将神经网络编译为Simulink块。
我不是一个Simulink专家,所以我把它留给你去探索这个方法:
gensim(net)
在上述每种方法中(无论如何前三种),其思想是将simulate
函数编译成MATLAB编译器(独立可执行文件,共享库,Java包,. net汇编)支持的目标之一,然后部署生成的组件。
(实际上方法#2和#3也可以使用MATLAB Coder codegen
转换为C/c++源代码)。
下面是如何使用mcc
命令将每个库编译成一个共享库(如果你喜欢,你可以使用deploytool
):
% 1) saved network
mcc -v -W cpplib:libANN -T link:lib -N -p nnet simulateSavedNet.m -a pretrained_network.mat
% 2) standalone simulation function (genFunction)
mcc -v -W cpplib:libANN -T link:lib -N simulateStandaloneNet
% 3) standalone simulation function (manual)
mcc -v -W cpplib:libANN -T link:lib -N simulateManualNet
为了检查生成的dll,下面是一个c++测试程序,它链接到生成的共享库:
% 1)
mbuild -output test_savedNet -DSIMFCN=simulateSavedNet -I. test_net.cpp libANN.lib
% 2)
mbuild -output test_standaloneNet -DSIMFCN=simulateStandaloneNet -I. test_net.cpp libANN.lib
% 3)
mbuild -output test_manualNet -DSIMFCN=simulateManualNet -I. test_net.cpp libANN.lib
测试程序的代码:
test_net.cpp
#include <cstdlib>
#include <iostream>
#include "libANN.h"
// choose one!
//#define SIMFCN simulateSavedeNet
//#define SIMFCN simulateStandaloneNet
//#define SIMFCN simulateManualNet
int main()
{
// initialize MCR and lib
if (!mclInitializeApplication(NULL,0)) {
std::cerr << "could not initialize the application" << std::endl;
return EXIT_FAILURE;
}
if(!libANNInitialize()) {
std::cerr << "Could not initialize the library" << std::endl;
return EXIT_FAILURE;
}
try {
// create input data (1x5 vector)
double x[] = {1.0, 3.0, 5.0, 7.0, 9.0};
mwArray in(1, 5, mxDOUBLE_CLASS, mxREAL);
in.SetData(x, 5);
// predict network output by simulating network
mwArray out;
SIMFCN(1, out, in);
double y[5];
out.GetData(y, 5);
// show result
std::cout << "y = net(x)" << std::endl;
std::cout << "y = n" << out << std::endl;
} catch (const mwException& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
} catch (...) {
std::cerr << "Unexpected error thrown" << std::endl;
return EXIT_FAILURE;
}
// cleanup
libANNTerminate();
mclTerminateApplication();
return EXIT_SUCCESS;
}
下面是结果程序的输出,与原始网络对象和源m函数进行比较:
>> net([1 3 5 7 9])
ans =
9.5620 7.7851 7.2716 6.1647 2.4073
>> simulateSavedNet([1 3 5 7 9])
ans =
9.5620 7.7851 7.2716 6.1647 2.4073
>> simulateStandaloneNet([1 3 5 7 9])
ans =
9.5620 7.7851 7.2716 6.1647 2.4073
>> simulateManualNet([1 3 5 7 9])
ans =
9.5620 7.7851 7.2716 6.1647 2.4073
>> !test_savedNet.exe
y = net(x)
y =
9.5620 7.7851 7.2716 6.1647 2.4073
>> !test_standaloneNet.exe
y = net(x)
y =
9.5620 7.7851 7.2716 6.1647 2.4073
>> !test_manualNet.exe
y = net(x)
y =
9.5620 7.7851 7.2716 6.1647 2.4073
这是一个很长的帖子,但我想涵盖这个问题和未来的所有可能的情况:)HTH
不幸的是,您无法通过deploytool(因此使用matlab编译器)创建独立的神经网络程序。
替代:
- 你可以先训练一个网络,然后构建独立的程序,但似乎你想在它创建后进行训练。
- 您可以查看matlab编码器;这基本上是从matlab创建程序的"另一种方式"。我还不能找到它是否支持神经网络,但如果你正在考虑这个选项,你可以联系mathworks。
- 考虑不要制作独立的程序。例如,根据您的需要,您可以从不同的程序或从命令行调用matlab来完成其工作。
使用部署产品(MATLAB Compiler, MATLAB Builder产品)或代码生成产品(MATLAB Coder等)都不可能部署Neural network Toolbox的网络训练功能。
你可以考虑使用第三方的神经网络工具箱,比如Netlab。Netlab不包括neural network Toolbox的所有神经网络功能,但它包括大多数常用的功能,以及Statistics Toolbox更好地涵盖的一些额外方法,例如K-means聚类。
我不知道部署Netlab功能有任何技术问题,我相信它是在BSD开源许可证下许可的,所以你应该能够在你的项目中包含和重新发布它,没有问题。
编辑:从R2016b开始,现在可以从神经网络工具箱(或现在已知的深度学习工具箱)编译网络训练功能。