webentwicklung-frage-antwort-db.com.de

Exportieren Sie ein mit MATLAB trainiertes neuronales Netzwerk in andere Programmiersprachen

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:

Diagram representing the Neural Network

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?

15
Vito Gentile

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]:

A scheme of Neural Network

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]:

All neurons are connected with all inputs

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:

  • Erzwingen Sie, dass die Anzahl der Anfangsgewichte mit der Länge des Eingabearrays übereinstimmt
  • Verwenden Sie die Gewichte, um das neuronale Netzwerk zu implementieren und zu verwenden, das gerade in anderen Programmiersprachen trainiert wurde

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:

  • ein MATLAB-Netzwerkobjekt, das das erstellte neuronale Netzwerk darstellt
  • das zum Trainieren des Netzwerks verwendete Eingabearray
  • das Ziel-Array, das zum Trainieren des Netzwerks verwendet wird

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:

The nprtool GUI to export data and generate the M-code

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.

14
Vito Gentile

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

3
Sangeun Chi

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!

3
Gabrer

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.

0
beniroquai

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.

  • Angenommen, Sie haben eine trainierte Ann (Netzwerkobjekt), die Sie exportieren möchten
  • Angenommen, der Name der trainierten Ann ist training_ann

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
0
fermat4214