Ich habe ein neuronales Netzwerk mit der MATLAB Neural Network Toolbox und insbesondere mit dem Befehl nprtool
trainiert, der eine einfache Benutzeroberfläche zur Nutzung der Toolbox-Funktionen und zum Exportieren eines net
-Objekts mit den Informationen über den generierten NN bietet.
Auf diese Weise habe ich ein funktionierendes neuronales Netzwerk erstellt, das ich als Klassifikator verwenden kann, und ein Diagramm, das dies darstellt, sieht folgendermaßen aus:
Es gibt 200 Eingänge, 20 Neuronen in der ersten verborgenen Schicht und 2 Neuronen in der letzten Schicht, die eine zweidimensionale Ausgabe liefern.
Ich möchte das Netzwerk in einer anderen Programmiersprache (C #, Java, ...) verwenden.
Um dieses Problem zu lösen, versuche ich, den folgenden Code in MATLAB zu verwenden:
y1 = tansig(net.IW{1} * input + net.b{1});
Results = tansig(net.LW{2} * y1 + net.b{2});
Angenommen, input
ist ein eindimensionales Array von 200 Elementen, dann würde der vorherige Code funktionieren, wenn net.IW{1}
eine 20x200-Matrix (20 Neuronen, 200 Gewichte) ist.
Das Problem ist, dass ich festgestellt habe, dass size(net.IW{1})
unerwartete Werte zurückgibt:
>> size(net.IW{1})
ans =
20 199
Ich habe das gleiche Problem mit einem Netzwerk mit 10000 Eingängen. In diesem Fall war das Ergebnis nicht 20x10000, sondern etwa 20x9384 (ich erinnere mich nicht an den genauen Wert).
Die Frage ist also: Wie kann ich die Gewichte der einzelnen Neuronen ermitteln? Und kann mir danach jemand erklären, wie ich mit ihnen die gleiche Ausgabe von MATLAB erzeugen kann?
Ich habe die oben beschriebenen Probleme gelöst und finde es nützlich, das Gelernte mitzuteilen.
Räumlichkeiten
Zunächst brauchen wir einige Definitionen. Betrachten wir das folgende Bild aus [1]:
In der obigen Abbildung stehtIWfür anfängliche Gewichte: Sie stellen die Gewichte der Neuronen auf der Ebene 1 dar , von denen jedes mit jedem Eingang verbunden ist , wie das folgende Bild zeigt [1]:
Alle anderen Gewichte werden als Ebenengewichte (LWin der ersten Abbildung) bezeichnet und sind ebenfalls mit jedem Ausgang der vorherigen Ebene verbunden. In unserem Fall verwenden wir ein Netzwerk mit nur zwei Schichten, sodass wir nur ein LW-Array verwenden, um unsere Probleme zu lösen.
Lösung des Problems
Nach der obigen Einführung können wir das Problem in zwei Schritte unterteilen:
A - Erzwinge, dass die Anzahl der anfänglichen Gewichte mit der Länge des Eingabearrays übereinstimmt
Mit der nprtool
können wir unser Netzwerk trainieren und am Ende des Prozesses können wir auch einige Informationen über den gesamten Trainingsprozess in den Arbeitsbereich exportieren. Insbesondere müssen wir exportieren:
Außerdem müssen wir eine M-Datei generieren, die den von MATLAB zum Erstellen des neuronalen Netzwerks verwendeten Code enthält, da wir ihn ändern und einige Trainingsoptionen ändern müssen.
Das folgende Bild zeigt, wie diese Vorgänge ausgeführt werden:
Der generierte M-Code ähnelt dem folgenden:
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)
Bevor wir mit dem Training beginnen, müssen wir alle Vorverarbeitungs- und Nachverarbeitungsfunktionen entfernen die MATLAB auf Ein- und Ausgängen ausführt. Dies kann durch Hinzufügen der folgenden Zeilen unmittelbar vor den Zeilen % Train and Apply Network
erfolgen:
net.inputs{1}.processFcns = {};
net.outputs{2}.processFcns = {};
Nach diesen Änderungen an der Funktion create_pr_net()
können wir sie einfach verwenden, um unser endgültiges neuronales Netzwerk zu erstellen:
net = create_pr_net(input, target);
dabei sind input
und target
die Werte, die wir über nprtool
exportiert haben.
Auf diese Weise stellen wir sicher, dass die Anzahl der Gewichtungen der Länge des Eingabearrays entspricht. Dieser Vorgang ist auch nützlich, um die Portierung auf andere Programmiersprachen zu vereinfachen.
B - Implementieren und verwenden Sie das neuronale Netzwerk, das gerade in anderen Programmiersprachen geschult wurde
Mit diesen Änderungen können wir eine Funktion wie folgt definieren:
function [ Results ] = classify( net, input )
y1 = tansig(net.IW{1} * input + net.b{1});
Results = tansig(net.LW{2} * y1 + net.b{2});
end
In diesem Code verwenden wir die oben erwähnten IW- und LW-Arrays, aber auch die Verzerrungen b, die von der nprtool
im Netzwerkschema verwendet werden. In diesem Zusammenhang ist uns die Rolle von Vorurteilen egal; einfach müssen wir sie verwenden, weil nprtool
es tut.
Jetzt können wir die oben definierte Funktion classify()
oder die Funktion sim()
gleichermaßen verwenden und die gleichen Ergebnisse erzielen, wie im folgenden Beispiel gezeigt:
>> sim(net, input(:, 1))
ans =
0.9759
-0.1867
-0.1891
>> classify(net, input(:, 1))
ans =
0.9759
-0.1867
-0.1891
Offensichtlich kann die Funktion classify()
als Pseudocode interpretiert und dann in allen Programmiersprachen implementiert werden, in denen die Funktion MATLAB tansig()
[2] und die grundlegenden Operationen zwischen Arrays definiert werden können.
Referenzen
[1] Howard Demuth, Mark Beale und Martin Hagan: Neural Network Toolbox 6 - Benutzerhandbuch, MATLAB
[2] Mathworks, tansig - Hyperbolic Tangent Sigmoid Transfer Function, MATLAB Documentation Center
Zusätzliche Hinweise
Werfen Sie einen Blick auf die Antwort von robott und die Antwort von Sangeun Chi für weitere Einzelheiten.
Dank der Antworten von VitoShadow und robott kann ich die Werte des neuronalen Netzwerks von Matlab in andere Anwendungen exportieren.
Ich schätze sie sehr, aber ich habe einige unbedeutende Fehler in ihren Codes gefunden und möchte sie korrigieren.
1) In den VitoShadow-Codes
Results = tansig(net.LW{2} * y1 + net.b{2});
-> Results = net.LW{2} * y1 + net.b{2};
2) In den Vorverarbeitungscodes von robott ist es einfacher, xmax und xmin aus der Nettovariablen zu extrahieren, als sie zu berechnen.
xmax = net.inputs{1}.processSettings{1}.xmax
xmin = net.inputs{1}.processSettings{1}.xmin
3) In den robott Nachbearbeitungscodes
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;
Sie können die Werte wie folgt manuell überprüfen und bestätigen:
p2 = mapminmax('apply', net(:, 1), net.inputs{1}.processSettings{1})
-> vorverarbeitete Daten
y1 = purelin ( net.LW{2} * tansig(net.iw{1}* p2 + net.b{1}) + net.b{2})
-> Verarbeitete Daten des Neuronalen Netzes
y2 = mapminmax( 'reverse' , y1, net.outputs{2}.processSettings{1})
-> nachbearbeitete Daten
Referenz: http://www.mathworks.com/matlabcentral/answers/14517-processing-of-i-p-data
Dies ist eine kleine Verbesserung der Antwort des großen Vito Gentile.
Wenn Sie die Vorverarbeitung und Nachverarbeitung ' mapminmax ' verwenden möchten, müssen Sie darauf achten, dass 'mapminmax' in Matlab nach ROW und nicht nach Spalte normalisiert wird!
Dies ist, was Sie zur oberen "Klassifizierungs" -Funktion hinzufügen müssen, um eine kohärente Vor-/Nachbearbeitung zu gewährleisten:
[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
Und das am Ende der Funktion:
ymax = 1;
ymin = 0;
xmax = 1;
xmin = -1;
Results = (ymax-ymin)*(Results-xmin)/(xmax-xmin) + ymin;
Dies ist Matlab-Code, der jedoch leicht als Pseudocode gelesen werden kann. Hoffe das wird hilfreich sein!
Ich habe versucht, ein einfaches 2-Layer-NN in C++ mit OpenCV zu implementieren und dann die Gewichte nach Android exportiert, was recht gut funktionierte. Ich habe ein kleines Skript geschrieben, das eine Header-Datei mit den erlernten Gewichten generiert und dies wird im folgenden Code abgeschnitten.
// 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;
}
ein Beispiel für eine Verzerrung im Header könnte sein:
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}};
Mit der Veröffentlichung von Tensorflow durch Google wurde dies hinfällig.
Daher wird die Lösung (nach Korrektur aller Teile)
Hier gebe ich eine Lösung in Matlab, aber wenn Sie tanh () -Funktion haben, können Sie es leicht in jede Programmiersprache konvertieren. Hier werden nur die Felder des Netzwerkobjekts und die von Ihnen benötigten Vorgänge angezeigt.
Hier ist das Skript zum Exportieren und Testen. Das Testskript vergleicht das ursprüngliche Netzwerkergebnis mit dem Ergebnis von 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')';
wo Sie die folgenden zwei Funktionen benötigen
Erster 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
Zweite 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