如何在MATLAB中将训练神经网络编译为独立应用程序?

3
我想将使用神经网络的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

因此,在编译应用程序时,如果我们的代码中有像newffpatternnet或其他训练函数,我们将会得到错误。

我知道这是MATLAB编译器的一种限制,我已经搜索了几个月的解决方案,但没有找到任何变通方法或替代方法。

显然,较新版本的MATLAB添加了一个功能,用于在MATLAB编译器中使用已训练的神经网络:Deploy Neural Network Functions


非常感谢您的帮助,不仅没有给我负面声誉评分 :-)。 - Eghbal
谢谢您的回答。我们能在MATLAB中运行Octave代码吗? - Eghbal
如果我们在MATLAB中拥有所有神经网络的替代包(免费或商业),那就太好了。 - Eghbal
@QED。在您推荐的包中,我们有一些##符号,MATLAB无法读取。问题出在哪里? - Eghbal
显示剩余4条评论
3个回答

10

总之,MATLAB Compiler仅支持部署预训练神经网络。

神经网络工具箱

可编译:

  • 预训练网络命令行函数

不可编译:

  • 所有其他命令行功能
  • 应用程序和用户界面
  • Simulink块
  • gensim

这意味着您无法mcc-编译具有训练功能的函数(任何包含TRAINADAPT等内容的函数),您只能部署评估/模拟已经训练过的网络对象的函数(如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编译器mcc(编译为支持的目标之一)以及MATLAB Codercodegen(转换为独立的C/C++代码)完全兼容。

% generate standalone M-function from the trained net
genFunction(net, 'simulateStandaloneNet.m', 'MatrixOnly','yes', 'ShowLinks','no')

这是生成函数的代码:

simulateStandaloneNet.m

3) 手动模拟预训练网络

对于简单的静态神经网络(如前馈网络等),评估预训练网络并模拟其输出相对容易(难点在于训练它们!)。

我已经在previous answers中展示了如何做到这一点。你基本上需要从网络中提取学习到的权重,然后将这些数字插入到转移函数中,输入数据,计算传播输出(逐层计算)。你需要注意对数据进行任何预处理/后处理,并在每个层中使用相同的转移函数。

事实上,这基本上就是上一种方法中genFunction所做的,只不过是自动化的,可以处理所有情况(适用于各种神经网络,而不仅仅是前馈人工神经网络)。

以下是上述训练网络的一个示例:

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++应用程序。将神经网络编译成Simulink块是在R2010b中引入的。

我不是Simulink专家,所以我会留给你去探索这种方法

gensim(net)

在上述每种方法中(前三种),其思想是将simulate函数编译为MATLAB Compiler支持的目标之一(独立可执行文件,共享库,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

顺便提一下,如果您尝试编译一个包含TRAIN和SIM的函数,它将会成功完成,但是当您调用已编译的函数时,它会抛出一个错误。这里是我尝试过的一个例子:http://pastebin.com/YnEZeAFg - Amro
感谢您详细的回答。正如您所说,在独立应用程序中使用预训练神经网络是一个很大的限制,这在实际工作中是不可避免的。我们应该找到一种方法来摆脱这个限制。可以使用MATLAB或其他替代代码来解决这个问题。 - Eghbal

2
很遗憾,您不能通过deploytool(即使用matlab编译器)创建一个独立的神经网络程序。
以下是一些替代方案: 1. 您可以先训练一个网络,然后构建独立的程序,但这似乎不符合您的要求。 2. 您可以尝试使用matlab coder;这是从matlab创建程序的“另一种方式”。我没有找到它是否支持神经网络,但如果您考虑此选项,可以联系mathworks咨询。 3. 根据您的需求,可以考虑不创建独立的程序。例如,您可以从不同的程序或命令行中调用matlab来完成其工作。

是的,这是真的。在MATLAB编码器中我们也有同样的限制。我正在寻找其他的替代工具箱(第三方)用于神经网络。例如,我们有libsvm作为MATLAB SVM工具箱的免费替代工具箱。 - Eghbal
@user2991243 我认为matlab文件交换是你最好的选择。不幸的是,我无法判断它是否包含你所需的内容。 - Dennis Jaheruddin
非常感谢您的帮助。 - Eghbal

2
无法使用部署产品(MATLAB编译器,MATLAB Builder产品)或代码生成产品(MATLAB Coder等)来部署神经网络工具箱的网络训练功能。
您可以考虑使用第三方神经网络工具箱,例如Netlab。Netlab不包括神经网络工具箱的所有功能,但它包括大多数常用功能,以及由统计工具箱更好地覆盖的一些额外方法,例如K-means聚类。
我不知道在部署Netlab功能方面是否存在任何技术问题,而且我相信它是在BSD开放源代码许可下授权的,因此您应该能够将其包含和重新分发到您的项目中而没有问题。
编辑:从R2016b版本开始,现在可以编译来自神经网络工具箱(或现在称为深度学习工具箱)的网络训练功能。

感谢您的回答,Sam。这很令人困惑。为什么我们有像Libsvm这样的开源支持向量机库,它有着强大的支持和更新,但是却没有任何好的替代神经网络库供MATLAB使用!直到现在我还没有找到任何商业神经网络包供MATLAB使用! - Eghbal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接