Diskussion zum Artikel "Neuronale Netze leicht gemacht (Teil 5): Parallele Berechnungen mit OpenCL"
Der Artikel ist extrem kompliziert für jemanden, der sich nicht mit OpenCL beschäftigt, ich habe versucht, das Wesentliche zu verstehen, ich habe die Artikel gelesen, die Sie an Ihrer Stelle angegeben haben und ..... Ich habe nichts verstanden, oder besser gesagt, nur teilweise.
Ihr Artikel ist wahrscheinlich super, aber zu kompliziert, ich denke, Sie müssen sich mit den Grundlagen von OpenCL befassen und vielleicht mit eingebauten Bibliotheken wie OpenCL.mqh arbeiten, denn ohne sie wird es kein Verständnis geben, wie die fehlende Diskussion des Artikels zeigt. Ich verstehe Ihren Code nicht, weil er Verweise auf viele Bibliotheken enthält, von denen ich keine Ahnung habe.
Die zweite Frage, die ich nicht verstehe, ist, wie man OpenCL im Optimierungsmodus verwendet. Was wird passieren, wenn mehrere Instanzen von OpenCL gleichzeitig auf die Videokarte zugreifen????. Dann gibt es eine Menge Methoden, um Berechnungen von ein und derselben Sache in OpenCL zu beschleunigen. Zum Beispiel, double zugunsten von int loswerden. usw. .... Es gibt eine Vielzahl von Fragen.
Ich schlage vor, mit einem sehr einfachen Beispiel in einem Multithreading-Programmcode zu beginnen. Nehmen wir an, es gibt EIN Perzeptron, das n Eingänge hat, bzw. wir müssen einen einfachen Code für die Berechnung von Normalisierungsfunktionen im Bereich [-1,1] und die Berechnung des Wertes des Neurons durch tanh mit OpenCL schreiben. Und der Code selbst in OpenCL sollte kommentiert werden. Und betrachten Sie einen sehr einfachen Trading Expert Advisor mit Optimierung im Tester auf die Geschichte mit EINEM Indikator, und auch ein einfaches, d.h. geben nur einen Wert, wie RSI oder CCI. Das heißt, alles ist so einfach wie möglich, ohne Schnickschnack, einfach so einfach wie möglich. Ich denke, dass es in Zukunft kein Problem sein wird, dies auf viele Perceptrons auszuweiten und einen eigenen Expert Advisor zu schreiben.
Vielen Dank für den Artikel.
Der Artikel ist genau das, was Sie brauchen. Vielen Dank an den Autor. Ich habe parallele Berechnungen in Neuronen vom ersten Mal an verstanden. Ich muss nur noch "reifen".))
Nun, der eine ist nicht gereift, der andere ..... Aber ich denke, jeder will das.
Ich stimme zu, dass der Artikel notwendig ist
Ich gebe mir Mühe, ihn zu verstehen.
Vielleicht können Sie schreiben, was ich Sie gebeten habe zu schreiben, wenn es Ihnen so leicht fällt.Nun, eine ist nicht reif, die andere ist ..... und ich schätze, jeder will einen.
Ich stimme zu, dass dies ein guter Artikel ist.
Ich bemühe mich sehr, ihn zu verstehen.
Vielleicht können Sie schreiben, worum ich Sie gebeten habe, wenn es für Sie so einfach ist.All dies ist interessant, auch wenn ich es wahrscheinlich nicht wiederholen werde, aber die Frage, warum die 10-fache Steigerung, wenn nur ein weiterer Kern am Training beteiligt war, verwirrte mich.
Soweit ich weiß, werden beim Training mit OpenCL mehrere Indikatoren gleichzeitig berechnet.
All dies ist interessant, auch wenn ich es wahrscheinlich nicht wiederholen kann, aber die Frage, warum eine 10-fache Steigerung, wenn nur ein weiterer Kern für das Training verwendet wurde, verwirrte mich.
DerKernel ist kein physischer oder logischer Kern, sondern eine Firmware, die auf allen logischenKernen eines Prozessors oder einer Grafikkarte parallel ausgeführt wird.
Hier sind einige Punkte, die ich nicht verstehe
__kernel void FeedForward(__global double *matrix_w, __global double *matrix_i, __global double *matrix_o, int inputs, int activation) { int i=get_global_id(0); //Was bewirkt diese Zeile? double sum=0.0; double4 inp, weight; int shift=(inputs+1)*i; //Was bewirkt diese Zeile? for(int k=0; k<=inputs; k=k+4) { switch(inputs-k) { case 0: inp=(double4)(1,0,0,0); //Was bewirkt diese Zeile? weight=(double4)(matrix_w[shift+k],0,0,0); break; case 1: inp=(double4)(matrix_i[k],1,0,0); weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],0,0); break; case 2: inp=(double4)(matrix_i[k],matrix_i[k+1],1,0); weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],matrix_w[shift+k+2],0); break; case 3: inp=(double4)(matrix_i[k],matrix_i[k+1],matrix_i[k+2],1); weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],matrix_w[shift+k+2],matrix_w[shift+k+3]); break; default: inp=(double4)(matrix_i[k],matrix_i[k+1],matrix_i[k+2],matrix_i[k+3]); weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],matrix_w[shift+k+2],matrix_w[shift+k+3]); break; } sum+=dot(inp,weight); //Was bewirkt diese Zeile? } switch(activation) { case 0: sum=tanh(sum); break; case 1: sum=pow((1+exp(-sum)),-1); break; } matrix_o[i]=sum; }
Ich denke, es ist notwendig, sie für "entfernte" Leute zu erklären, und die Hauptsache ist, dass mir aus dem Code nicht klar ist, wo alles initialisiert wird und wo alles aufgerufen wird.
Hier sind einige Dinge, die ich nicht verstehe
Ich denke, es ist notwendig, sie für "entfernte" Leute zu erklären, und die Hauptsache ist, dass ich aus dem Code nicht verstehe, wo alles initialisiert wird und wo alles aufgerufen wird.
Guten Tag, Boris.
Sie haben den Kernel-Code beigefügt. Wie Maxim oben schrieb, handelt es sich um ein Mikroprogramm, das auf den Kernen des Mikroprozessors oder der Grafikkarte ausgeführt wird (je nach Initialisierungskontext). Der springende Punkt ist, dass mehrere solcher Programme auf einmal aufgerufen werden und parallel auf allen Kernen ausgeführt werden. Jedes Programm arbeitet mit seinen eigenen Daten.
int i=get_global_id(0); //Was bewirkt diese Zeile?
Diese Zeile holt sich einfach die Seriennummer des Mikroprogramms aus dem Pool der parallel laufenden Kopien. Im Code wird diese Nummer verwendet, um zu bestimmen, welches Datenpaket zur Verarbeitung übergeben werden soll. In diesem Fall entspricht sie der Anzahl der Neuronen in der Schicht.
Für eine noch stärkere Parallelisierung der Aktionen innerhalb des Mikroprogramms werden außerdem Vektorvariablen verwendet - das sind kleine Arrays fester Größe. In diesem Fall ist die Dimension der Vektoren 4, d.h. Arrays mit 4 Elementen.
double4 inp, weight;
Die Größe des Eingabefeldes ist jedoch nicht immer ein Vielfaches von 4. Um eine falsche Array-Referenz zu vermeiden, wird daher swith verwendet, und fehlende Werte werden mit "0" aufgefüllt. In diesem Fall ist für jedes Neuron die Dimensionalität des Gewichtsarrays um 1 Element größer als die Dimensionalität der Eingabeelemente, und dieses Element wird als Bayes'sche Verzerrung verwendet. Früher haben wir zu diesem Zweck ein zusätzliches Neuron verwendet, bei dem wir nur die Gewichte korrigierten und den Ausgangswert nicht neu berechneten, der immer gleich "1" blieb. Hier habe ich nicht ständig "1" zum Eingabefeld hinzugefügt, sondern es direkt in den Code geschrieben, und die Größe des Eingabefeldes ändert sich nicht.
inp=(double4)(1,0,0,0); //Was bewirkt diese Zeile? weight=(double4)(matrix_w[shift+k],0,0,0);
Die Dot-Funktion gibt das Skalarprodukt zweier Vektoren zurück, d.h. in unserem Fall zählen wir die Summe von 4 Produkten der Eingabewerte durch Gewichte in einer Zeile.
sum+=dot(inp,weight); //Was bewirkt diese Zeile?
EinKernel ist kein physischer oder logischer Kern, sondern eine Firmware, die auf allen logischenKernen eines Prozessors oder einer Grafikkarte parallel läuft
Es ist also keine Neuigkeit - es gab einen Kern und die Last lag auf ihm, und jetzt gibt es zwei Kerne, die Last ist halbiert.... Wahrscheinlich sind die Änderungen bedeutender und der Vergleich ist nicht korrekt.
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Neuer Artikel Neuronale Netze leicht gemacht (Teil 5): Parallele Berechnungen mit OpenCL :
Wir haben bereits einige Arten von Implementierungen neuronaler Netze besprochen. In den betrachteten Netzwerken werden die gleichen Operationen für jedes Neuron wiederholt. Ein logischer weiterer Schritt ist die Nutzung der parallelen Berechnung, die die moderne Technologie bietet, um den Lernprozess des neuronalen Netzwerks zu beschleunigen. Eine der möglichen Implementierungen wird in diesem Artikel beschrieben.
Wir haben die Technologie ausgewählt. Jetzt müssen wir über den Prozess der Aufteilung der Berechnungen in Threads entscheiden. Erinnern Sie sich an den Algorithmus des vollständig verbundenen Perceptrons bei einem feed-forward Durchlauf? Das Signal bewegt sich sequentiell von der Eingabeschicht zu den versteckten Schichten und dann zur Ausgabeschicht. Es macht keinen Sinn, für jede Schicht einen Thread zuzuweisen, da die Berechnungen sequentiell durchgeführt werden müssen. Die Berechnung einer Schicht kann erst beginnen, wenn das Ergebnis der vorherigen Schicht vorliegt. Die Berechnung eines einzelnen Neurons in einer Schicht hängt nicht von den Berechnungsergebnissen der anderen Neuronen in dieser Schicht ab. Das bedeutet, dass wir für jedes Neuron separate Threads zuweisen und alle Neuronen einer Schicht zur parallelen Berechnung schicken können.
Wenn man auf die Operationen eines Neurons heruntergeht, könnte man die Möglichkeit der Parallelisierung der Berechnung der Produkte der Eingangswerte mit ihren Gewichtskoeffizienten in Betracht ziehen. Die weitere Summierung der resultierenden Werte und die Berechnung des Wertes der Aktivierungsfunktion werden jedoch in einem einzigen Thread zusammengefasst. Ich habe mich entschieden, diese Operationen in einem einzigen OpenCL-Kernel unter Verwendung von Vektorfunktionen zu implementieren.
Autor: Dmitriy Gizlyk