"New Neural" ist ein Open-Source-Projekt für neuronale Netzwerke für die MetaTrader 5-Plattform. - Seite 59

 

Leute, wenn ihr euch entscheidet, mit GPUs herumzuspielen, bedenkt Folgendes. Es ist einfach, Lernalgorithmen zu parallelisieren, bei denen eine Iteration unabhängig von der anderen ist. Zum Beispiel die genetische Methode, bei der die Berechnung von Hunderten von Netzen in einer Generation nicht voneinander abhängt, Manhattan (stumme Aufzählung aller Lösungen) oder die Optimierung unabhängiger Netze in einem Ausschuss. Aber solche Algorithmen gibt es nur wenige. Methoden, die auf dem Gradientenabstieg beruhen, sind schwieriger zu parallelisieren, da eine Iteration von einer anderen abhängt. In solchen Fällen wäre es notwendig, die Berechnung der Neuronen in derselben Schicht in parallele Threads aufzuteilen, was nicht immer trivial ist.

 

... Und die Genetik ist nicht Teil des Netzes, sondern ein separater externer Algorithmus.

Die Menschen hier wollen parallele Netzwerke.

 
Das eine schließt das andere nicht aus.
 
TheXpert:

... Und die Genetik ist nicht Teil des Netzes, sondern ein separater externer Algorithmus.

Die Leute hier wollen Netzwerke parallelisieren.

Schreiben Sie etwas, das zunächst funktioniert, und parallelisieren Sie es dann. Die Fehlersuche im Code von KUDav ist aufgrund möglicher Fehler sehr zeitaufwändig: Man muss wissen, wie viel Speicher für die verschiedenen Arrays zuzuweisen ist, Befehle zum Laden und Entladen dieser Arrays aus dem Speicher schreiben, Threads synchronisieren usw. Hier ist ein Fragment des Kuda-Codes (1/20 des gesamten Codes). Beachten Sie, dass keiner der Befehle direkt mit dem Netzlernalgorithmus selbst zusammenhängt. Für mich ist das alles Chinesisch.

#define SHARED_BUFFER_SIZE 512

#define MAX_DATA_SIZE 227

#define MAX_FILTER_33_SIZE 73

#define MAX_MASK_23_SIZE 27

#define MAX_MASK_34_SIZE 27

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

__constant__ float M33_Filter[ MAX_FILTER_33_SIZE ][ MAX_FILTER_33_SIZE ];

__constant__ float M23_Mask [ MAX_MASK_23_SIZE ][ MAX_MASK_23_SIZE ];

__constant__ float M34_Mask [ MAX_MASK_34_SIZE ][ MAX_MASK_34_SIZE ];

__shared__ float SharedBuf[ SHARED_BUFFER_SIZE ];

#define ALLIGN 32

#define ROUND_UP( val ) ( ( ( ( val ) + ALLIGN - 1 ) / ALLIGN ) * ALLIGN )

__host__ __device__ int Get2DIndex( int dataSize, int row, int col )

{

int dataSizeP = ROUND_UP( dataSize );

int idx = row * dataSizeP + col;

//assert( idx >= 0 && idx < dataSize * dataSizeP );

return idx;

}

__host__ __device__ float Get2D( float *data, int dataSize, int row, int col )

{

int idx = Get2DIndex( dataSize, row, col );

return data[ idx ];

}

__host__ __device__ void Set2D( float *data, int dataSize, int row, int col, float val )

{

int idx = Get2DIndex( dataSize, row, col );

data[ idx ] = val;

}

__host__ __device__ int Get4DIndex( int dataSize, int filtSize, int row, int col, int rowF, int colF )

{

int dataSizeP = ROUND_UP( dataSize );

int filtSizeP = ROUND_UP( filtSize );

int idx;

idx = row;

idx = idx * filtSizeP + rowF;

idx = idx * filtSizeP + colF;

idx = idx * dataSizeP + col;

//assert( idx >= 0 && idx < dataSize * dataSizeP * filtSizeP * filtSizeP );

return idx;

}

__host__ __device__ float Get4D( float *filt, int dataSize, int filtSize, int row, int col, int rowF, int colF )

{

int idx = Get4DIndex( dataSize, filtSize, row, col, rowF, colF );

return filt[ idx ];

}

__host__ __device__ void Set4D( float *filt, int dataSize, int filtSize, int row, int col, int rowF, int colF, float val )

{

int idx = Get4DIndex( dataSize, filtSize, row, col, rowF, colF );

filt[ idx ] = val;

}

__global__ void Calc_1_kernel( float* o2, float* i3, float* fi3, float* o3, float* o3tmp, float *w23, int n2, int n3, int n23, int h23, int ntot23, float a3 )

{

int numBlocks = gridDim.x;

int numThreads = blockDim.x;

int blockId = blockIdx.x;

int threadId = threadIdx.x;

///* DEBUG */for( int blockId = 0; blockId < numBlocks; ++blockId )

{

for( int i = blockId; i < n3; i += numBlocks )

{

///* DEBUG */for( int threadId = 0; threadId < numThreads; ++threadId )

{

// clear output

for( int j = threadId; j < n3; j += numThreads )

{

Set2D( fi3, n3, i, j, 0 );

}

}

__syncthreads();

// process 'n23' rows

for( int dx = 0; dx < n23; ++dx )

{

int x;

if( n2 == n3 )

{

x = i + dx - h23;

if( x < 0 ) x += n2;

if( x >= n2 ) x -= n2;

}

else

{

x = i + dx;

}

///* DEBUG */for( int threadId = 0; threadId < numThreads; ++threadId )

{

// read one row of input data to shared memory ( row 'x' )

int dj;

if( n2 == n3 )

{

dj = h23;

}

else

{

dj = 0;

}

for( int jj = threadId; jj < n2; jj += numThreads )

{

float o2Val = Get2D( o2, n2, x, jj );

SharedBuf[ jj + dj ] = o2Val;

}

if( n2 == n3 )

{

for( int dj = threadId; dj < h23; dj += numThreads )

{

SharedBuf[ dj ] = SharedBuf[ n2 + dj ];

}

for( int dj = threadId; dj < h23 + 1; dj += numThreads )

{

SharedBuf[ n2 + h23 + dj ] = SharedBuf[ h23 + dj ];

}

}

}

__syncthreads();

///* DEBUG */for( int threadId = 0; threadId < numThreads; ++threadId )

{

// filter one row

for( int j = threadId; j < n3; j += numThreads )

{

float fi3Val = Get2D( fi3, n3, i, j );

for( int dy = 0; dy < n23; ++dy )

{

float w23Val = Get4D( w23, n3, n23, i, j, dx, dy );

float o2Val = SharedBuf[ j + dy ];

fi3Val += o2Val * w23Val;

}

Set2D( fi3, n3, i, j, fi3Val );

}

}

__syncthreads();

}

__syncthreads();

 
gpwr:

Leute, wenn ihr euch entscheidet, mit GPUs herumzuspielen, bedenkt Folgendes. Es ist einfach, Lernalgorithmen zu parallelisieren, bei denen eine Iteration unabhängig von der anderen ist. Zum Beispiel die genetische Methode, bei der die Berechnung von Hunderten von Netzen in einer Generation nicht voneinander abhängt, Manhattan (stumme Aufzählung aller Lösungen) oder die Optimierung unabhängiger Netze in einem Ausschuss. Aber solche Algorithmen gibt es nur wenige. Methoden, die auf dem Gradientenabstieg basieren, sind schwieriger zu parallelisieren, da eine Iteration von der anderen abhängt. In solchen Fällen müssen Sie die Berechnung der Neuronen in derselben Schicht in parallele Threads aufteilen, was nicht immer trivial ist.

Auf der GPU können wir nur einfache Berechnungen parallel durchführen, einfache Berechnungen innerhalb eines Zyklus, so dass es sehr schwierig wäre (und ich bezweifle, dass es effektiv wäre), Berechnungen verschiedener Phasen der Genetik auf der GPU durchzuführen.

Das Wesen der GPU-Beschleunigung liegt in der Unabhängigkeit der Eingaben von den Ausgaben innerhalb derselben Iteration und in der Einheitlichkeit der Operationen (wie gpwr oben bemerkte). Ist das nicht sehr ähnlich zu der Definition von Schicht, die wir oben kollegial abgeleitet haben? Deshalb habe ich vorgeschlagen, die Schicht als das Hauptarbeitsobjekt zu betrachten und das Neuronenobjekt nur als eine mit der Schicht verbundene Informationseinheit.

 
gpwr:

Schreiben Sie etwas, das zunächst funktioniert, und parallelisieren Sie es dann. Die Fehlersuche in KUDAW-Code ist aufgrund möglicher Fehler sehr zeitaufwändig: Sie müssen wissen, wie viel Speicher für verschiedene Arrays zuzuweisen ist, Befehle zum Laden und Entladen dieser Arrays aus dem Speicher schreiben, Threads synchronisieren usw. Hier ist ein Fragment des Kuda-Codes (1/20 des gesamten Codes). Beachten Sie, dass keiner der Befehle direkt mit dem Netzlernalgorithmus selbst zusammenhängt. Für mich ist das alles Chinesisch.

...

Solche Fragmente können durch die Benennung von Funktionen mit dem Anhang "GPU" oder durch einen Kommentar am Anfang einer Schleife gekennzeichnet werden. Nur um die Leute wissen zu lassen, dass es eine Möglichkeit gibt, einen Grafikprozessor zu verwenden.

 
gpwr:

Schreiben Sie etwas, das zunächst funktioniert, und parallelisieren Sie es dann. Die Fehlersuche in KUDAW-Code ist aufgrund möglicher Fehler sehr zeitaufwändig: Sie müssen wissen, wie viel Speicher für verschiedene Arrays zuzuweisen ist, Befehle zum Laden und Entladen dieser Arrays aus dem Speicher schreiben, Threads synchronisieren usw. Hier ist ein Fragment des Kuda-Codes (1/20 des gesamten Codes). Beachten Sie, dass keiner der Befehle direkt mit dem Netzlernalgorithmus selbst zusammenhängt. Für mich ist das alles Chinesisch.

CUDA unterstützt SRF in vollem Umfang.

Hier ist ein Teil des Codes für die hyp.tangent

#ifndef LAYER_TANH_H
#define LAYER_TANH_H

#ifndef CUDA
        #include <map>
        #include <boost/regex.hpp>
        extern std::map<std::string,int> mapObjects;
#endif
//---------------------------------------------------------------------------//
//                               CLayerTanh                                  //
//---------------------------------------------------------------------------//

namespace
#ifdef CUDA
        cuda
#else
        host
#endif
{

class CLayerTanh : public CLayerWSum
{
public:

#ifdef CUDA     
        __device__ static void run ( CLayer* layer )
        {
                CLayerTanh* L = static_cast<CLayerTanh*>(layer);
                if ( threadIdx.x < L->neuronCount )
                {
                        CLayerWSum::run(layer);
                        float * v = L->getNeuronPtr (threadIdx.x);
                        *v = tanh(*v);
                };
        }
#endif

};

} // namespace

#endif // LAYER_TANH

Es ist gut, dass hier ein OpenCL-Experte anwesend ist - ein substanzieller Dialog und die Diskussion von Technologien wird dem gesamten Projekt zugute kommen

Ich bin mir sicher, dass neuronale Netze mit allen möglichen Technologien implementiert werden (MQL5, C++, OpenCL, CUDA) und die Benutzer können je nach Geschmack und Hardwarekapazitäten wählen

 

Rebyata, ya budu seldom syuda zahodit'. Esli est' voprosi or interes k sovmestnim razrabotkami, pishite na moy yahoo email (ukazan v profile).

Viel Erfolg mit dem EngiNeuro-Projekt!

 

Optionen für die Übermittlung von Beispielen an den Lernalgorithmus:

  • Einer nach dem anderen
  • In zufälligen Gruppen
  • Gleitende Gruppen
  • Alles auf einmal

Vergessen Sie denn gar nichts?


Ich habe einen Projektrahmen vorbereitet, den ich in ein paar Tagen zur Diskussion stellen werde...
 
Urain:

Optionen für die Übermittlung von Beispielen an den Lernalgorithmus:

  • Einer nach dem anderen
  • Zufällige Gruppen.
  • In gleitenden Gruppen.
  • Alles auf einmal.

Hast du nicht etwas vergessen?


Ich habe den Rahmen des Projekts vorbereitet, ein paar Tage Zeit, um die Dinge aufzurütteln und es zur Diskussion zu stellen...

Einer nach dem anderen - ich verstehe.

Und die restlichen Optionen verstehe ich nicht. Wie kann ich alle Beispiele auf einmal zur Prüfung vorlegen? - Oder bin ich dumm?