我使用MATLAB神经网络工具箱训练了一个神经网络,特别是使用命令nprtool
,它提供了一个简单的GUI来使用工具箱功能,并导出一个net
对象包含有关NN生成的信息。
通过这种方式,我创建了一个可以用作分类器的工作神经网络,并且代表它的图表如下:
第一个隐藏层有200个输入,20个神经元,最后一层有2个神经元提供二维输出。
我想要做的是以其他编程语言(C#,Java,...)使用网络。
为了解决这个问题,我尝试在MATLAB中使用以下代码:
y1 = tansig(net.IW{1} * input + net.b{1});
Results = tansig(net.LW{2} * y1 + net.b{2});
假设input
是一个包含200个元素的单维数组,如果net.IW{1}
是20x200矩阵(20个神经元,200个权重),则前面的代码将起作用。
问题是我注意到size(net.IW{1})
返回了意外的值:
>> size(net.IW{1})
ans =
20 199
我在使用10000输入的网络时遇到了同样的问题。在这种情况下,结果不是20x10000,而是像20x9384(我不记得确切的值)。
所以,问题是:我如何获得每个神经元的权重?之后,有人可以解释我如何使用它们来生成相同的MATLAB输出?
答案 0 :(得分:14)
我解决了上述问题,我认为分享我学到的东西很有用。
<强>处所强>
首先,我们需要一些定义。让我们考虑以下图像,取自[1]:
在上图中, IW 代表初始权重:它们代表第1层上的神经元权重,每个权重都是与每个输入相连,如下图所示:[1]:
所有其他权重称为图层权重(第一个图中的 LW ),它们也与前一层的每个输出相关联。在我们的研究中,我们使用只有两层的网络,因此我们将只使用一个LW阵列来解决我们的问题。
解决问题
在上述介绍之后,我们可以通过两个步骤来划分问题:
A - 强制初始权重的数量与输入数组长度相匹配
使用nprtool
,我们可以培训我们的网络,在流程结束时,我们还可以在工作区中导出有关整个培训流程的一些信息。特别是,我们需要出口:
此外,我们需要生成一个M文件,其中包含MATLAB用于创建神经网络的代码,因为我们需要修改它并更改一些培训选项。
下图显示了如何执行这些操作:
生成的M代码类似于以下代码:
function net = create_pr_net(inputs,targets)
%CREATE_PR_NET Creates and trains a pattern recognition neural network.
%
% NET = CREATE_PR_NET(INPUTS,TARGETS) takes these arguments:
% INPUTS - RxQ matrix of Q R-element input samples
% TARGETS - SxQ matrix of Q S-element associated target samples, where
% each column contains a single 1, with all other elements set to 0.
% and returns these results:
% NET - The trained neural network
%
% For example, to solve the Iris dataset problem with this function:
%
% load iris_dataset
% net = create_pr_net(irisInputs,irisTargets);
% irisOutputs = sim(net,irisInputs);
%
% To reproduce the results you obtained in NPRTOOL:
%
% net = create_pr_net(trainingSetInput,trainingSetOutput);
% Create Network
numHiddenNeurons = 20; % Adjust as desired
net = newpr(inputs,targets,numHiddenNeurons);
net.divideParam.trainRatio = 75/100; % Adjust as desired
net.divideParam.valRatio = 15/100; % Adjust as desired
net.divideParam.testRatio = 10/100; % Adjust as desired
% Train and Apply Network
[net,tr] = train(net,inputs,targets);
outputs = sim(net,inputs);
% Plot
plotperf(tr)
plotconfusion(targets,outputs)
在开始训练过程之前,我们需要删除MATLAB在输入和输出上执行的所有预处理和后处理功能。这可以在% Train and Apply Network
行之前添加以下行:
net.inputs{1}.processFcns = {};
net.outputs{2}.processFcns = {};
对create_pr_net()
函数进行这些更改后,我们可以使用它来创建最终的神经网络:
net = create_pr_net(input, target);
其中input
和target
是我们通过nprtool
导出的值。
这样,我们确定权重的数量等于输入数组的长度。此外,此过程对于简化到其他编程语言的移植非常有用。
B - 实施和使用刚刚使用其他编程语言培训的神经网络
通过这些更改,我们可以定义如下函数:
function [ Results ] = classify( net, input )
y1 = tansig(net.IW{1} * input + net.b{1});
Results = tansig(net.LW{2} * y1 + net.b{2});
end
在此代码中,我们使用上面提到的IW和LW数组,以及nprtool
在网络模式中使用的偏差 b。在这种情况下,我们不关心role of biases;简单地说,我们需要使用它们,因为nprtool
会这样做。
现在,我们可以使用上面定义的classify()
函数或sim()
函数,获得相同的结果,如下例所示:
>> sim(net, input(:, 1))
ans =
0.9759
-0.1867
-0.1891
>> classify(net, input(:, 1))
ans =
0.9759
-0.1867
-0.1891
显然,classify()
函数可以解释为伪代码,然后在每种编程语言中实现,其中可能定义MATLAB tansig()
函数[2]和数组之间的基本操作。
<强>参考强>
[1] Howard Demuth, Mark Beale, Martin Hagan: Neural Network Toolbox 6 - User Guide, MATLAB
[2] Mathworks, tansig - Hyperbolic tangent sigmoid transfer function, MATLAB Documentation center
附加说明
有关详细信息,请查看robott's answer和Sangeun Chi's answer。
答案 1 :(得分:3)
这对伟大的Vito Gentile的答案来说是一个小小的改进。
如果你想使用预处理和后处理' mapminmax '函数,你必须要注意,因为Matlab中的'mapminmax'通过ROW而不是列进行规范化!
这是您需要添加到上层“分类”功能,以保持连贯的前/后处理:
[m n] = size(input);
ymax = 1;
ymin = -1;
for i=1:m
xmax = max(input(i,:));
xmin = min(input(i,:));
for j=1:n
input(i,j) = (ymax-ymin)*(input(i,j)-xmin)/(xmax-xmin) + ymin;
end
end
这在函数的末尾:
ymax = 1;
ymin = 0;
xmax = 1;
xmin = -1;
Results = (ymax-ymin)*(Results-xmin)/(xmax-xmin) + ymin;
这是Matlab代码,但它可以很容易地读作伪代码。 希望这会有所帮助!
答案 2 :(得分:3)
感谢VitoShadow和robott的答案,我可以将Matlab神经网络值导出到其他应用程序。
我真的很感激他们,但我在他们的代码中发现了一些微不足道的错误并希望纠正它们。
1)在VitoShadow代码中,
Results = tansig(net.LW{2} * y1 + net.b{2});
-> Results = net.LW{2} * y1 + net.b{2};
2)在robott预处理代码中, 从净变量中提取xmax和xmin比计算它们更容易。
xmax = net.inputs{1}.processSettings{1}.xmax
xmin = net.inputs{1}.processSettings{1}.xmin
3)在robott后处理代码中,
xmax = net.outputs{2}.processSettings{1}.xmax
xmin = net.outputs{2}.processSettings{1}.xmin
Results = (ymax-ymin)*(Results-xmin)/(xmax-xmin) + ymin;
-> Results = (Results-ymin)*(xmax-xmin)/(ymax-ymin) + xmin;
您可以按如下方式手动检查和确认值:
p2 = mapminmax('apply', net(:, 1), net.inputs{1}.processSettings{1})
- &GT;预处理数据
y1 = purelin ( net.LW{2} * tansig(net.iw{1}* p2 + net.b{1}) + net.b{2})
- &GT;神经网络处理数据
y2 = mapminmax( 'reverse' , y1, net.outputs{2}.processSettings{1})
- &GT;后处理数据
参考: http://www.mathworks.com/matlabcentral/answers/14517-processing-of-i-p-data
答案 3 :(得分:0)
我尝试使用OpenCV在C ++中实现一个简单的2层NN,然后将权重导出到Android,安静得很好。我写了一个小脚本,它生成一个带有学习权重的头文件,这在下面的代码中使用了。
// Map Minimum and Maximum Input Processing Function
Mat mapminmax_apply(Mat x, Mat settings_gain, Mat settings_xoffset, double settings_ymin){
Mat y;
subtract(x, settings_xoffset, y);
multiply(y, settings_gain, y);
add(y, settings_ymin, y);
return y;
/* MATLAB CODE
y = x - settings_xoffset;
y = y .* settings_gain;
y = y + settings_ymin;
*/
}
// Sigmoid Symmetric Transfer Function
Mat transig_apply(Mat n){
Mat tempexp;
exp(-2*n, tempexp);
Mat transig_apply_result = 2 /(1 + tempexp) - 1;
return transig_apply_result;
}
// Map Minimum and Maximum Output Reverse-Processing Function
Mat mapminmax_reverse(Mat y, Mat settings_gain, Mat settings_xoffset, double settings_ymin){
Mat x;
subtract(y, settings_ymin, x);
divide(x, settings_gain, x);
add(x, settings_xoffset, x);
return x;
/* MATLAB CODE
function x = mapminmax_reverse(y,settings_gain,settings_xoffset,settings_ymin)
x = y - settings_ymin;
x = x ./ settings_gain;
x = x + settings_xoffset;
end
*/
}
Mat getNNParameter (Mat x1)
{
// convert double array to MAT
// input 1
Mat x1_step1_xoffsetM = Mat(1, 48, CV_64FC1, x1_step1_xoffset).t();
Mat x1_step1_gainM = Mat(1, 48, CV_64FC1, x1_step1_gain).t();
double x1_step1_ymin = -1;
// Layer 1
Mat b1M = Mat(1, 25, CV_64FC1, b1).t();
Mat IW1_1M = Mat(48, 25, CV_64FC1, IW1_1).t();
// Layer 2
Mat b2M = Mat(1, 48, CV_64FC1, b2).t();
Mat LW2_1M = Mat(25, 48, CV_64FC1, LW2_1).t();
// input 1
Mat y1_step1_gainM = Mat(1, 48, CV_64FC1, y1_step1_gain).t();
Mat y1_step1_xoffsetM = Mat(1, 48, CV_64FC1, y1_step1_xoffset).t();
double y1_step1_ymin = -1;
// ===== SIMULATION ========
// Input 1
Mat xp1 = mapminmax_apply(x1, x1_step1_gainM, x1_step1_xoffsetM, x1_step1_ymin);
Mat temp = b1M + IW1_1M*xp1;
// Layer 1
Mat a1M = transig_apply(temp);
// Layer 2
Mat a2M = b2M + LW2_1M*a1M;
// Output 1
Mat y1M = mapminmax_reverse(a2M, y1_step1_gainM, y1_step1_xoffsetM, y1_step1_ymin);
return y1M;
}
标题中偏差的示例可能是:
static double b2[1][48] = {
{-0.19879, 0.78254, -0.87674, -0.5827, -0.017464, 0.13143, -0.74361, 0.4645, 0.25262, 0.54249, -0.22292, -0.35605, -0.42747, 0.044744, -0.14827, -0.27354, 0.77793, -0.4511, 0.059346, 0.29589, -0.65137, -0.51788, 0.38366, -0.030243, -0.57632, 0.76785, -0.36374, 0.19446, 0.10383, -0.57989, -0.82931, 0.15301, -0.89212, -0.17296, -0.16356, 0.18946, -1.0032, 0.48846, -0.78148, 0.66608, 0.14946, 0.1972, -0.93501, 0.42523, -0.37773, -0.068266, -0.27003, 0.1196}};
现在,谷歌发布了Tensorflow,这已经过时了。
答案 4 :(得分:0)
因此解决方案变为(在纠正所有部分之后)
这里我给出了Matlab的解决方案,但是如果你有tanh()函数,你可以轻松地将它转换为任何编程语言。它只是显示来自网络对象的字段和您需要的操作。
以下是导出和测试的脚本。 测试脚本将原始网络结果与my_ann_evaluation()结果进行比较
% Export IT
exported_ann_structure = my_ann_exporter(trained_ann);
% Run and Compare
% Works only for single INPUT vector
% Please extend it to MATRIX version by yourself
input = [12 3 5 100];
res1 = trained_ann(input')';
res2 = my_ann_evaluation(exported_ann_structure, input')';
您需要以下两个功能
首先是my_ann_exporter :
function [ my_ann_structure ] = my_ann_exporter(trained_netw)
% Just for extracting as Structure object
my_ann_structure.input_ymax = trained_netw.inputs{1}.processSettings{1}.ymax;
my_ann_structure.input_ymin = trained_netw.inputs{1}.processSettings{1}.ymin;
my_ann_structure.input_xmax = trained_netw.inputs{1}.processSettings{1}.xmax;
my_ann_structure.input_xmin = trained_netw.inputs{1}.processSettings{1}.xmin;
my_ann_structure.IW = trained_netw.IW{1};
my_ann_structure.b1 = trained_netw.b{1};
my_ann_structure.LW = trained_netw.LW{2};
my_ann_structure.b2 = trained_netw.b{2};
my_ann_structure.output_ymax = trained_netw.outputs{2}.processSettings{1}.ymax;
my_ann_structure.output_ymin = trained_netw.outputs{2}.processSettings{1}.ymin;
my_ann_structure.output_xmax = trained_netw.outputs{2}.processSettings{1}.xmax;
my_ann_structure.output_xmin = trained_netw.outputs{2}.processSettings{1}.xmin;
end
第二次my_ann_evaluation:
function [ res ] = my_ann_evaluation(my_ann_structure, input)
% Works with only single INPUT vector
% Matrix version can be implemented
ymax = my_ann_structure.input_ymax;
ymin = my_ann_structure.input_ymin;
xmax = my_ann_structure.input_xmax;
xmin = my_ann_structure.input_xmin;
input_preprocessed = (ymax-ymin) * (input-xmin) ./ (xmax-xmin) + ymin;
% Pass it through the ANN matrix multiplication
y1 = tanh(my_ann_structure.IW * input_preprocessed + my_ann_structure.b1);
y2 = my_ann_structure.LW * y1 + my_ann_structure.b2;
ymax = my_ann_structure.output_ymax;
ymin = my_ann_structure.output_ymin;
xmax = my_ann_structure.output_xmax;
xmin = my_ann_structure.output_xmin;
res = (y2-ymin) .* (xmax-xmin) /(ymax-ymin) + xmin;
end