"New Neural" è un progetto di motore di rete neurale Open Source per la piattaforma MetaTrader 5. - pagina 59

 

Gente, se decidete di pasticciare con le GPU, considerate quanto segue. È facile parallelizzare algoritmi di apprendimento in cui un'iterazione è indipendente dall'altra. Per esempio, genetica, dove il calcolo di centinaia di reti in una generazione non dipende l'uno dall'altro, Manhattan (enumerazione muta di tutte le soluzioni), o ottimizzazione di reti indipendenti in un comitato. Ma tali algoritmi sono pochi. I metodi basati sulla discesa del gradiente sarebbero più difficili da parallelizzare perché un'iterazione dipende dall'altra. In questi casi, è necessario dividere il calcolo dei neuroni nello stesso strato in thread paralleli, che non è sempre banale.

 

... E la genetica non è parte della rete, ma un algoritmo esterno separato.

La gente qui vuole reti parallele.

 
L'uno non esclude l'altro.
 
TheXpert:

... E la genetica non è parte della rete, ma un algoritmo esterno separato.

La gente qui vuole parallelizzare le reti.

Scrivete qualcosa che funzioni all'inizio, e poi parallelizzatelo. Il codice di KUDav richiede molto tempo per il debug a causa dei possibili errori: bisogna sapere quanta memoria allocare per i diversi array, scrivere i comandi per caricare e scaricare questi array dalla memoria, sincronizzare i thread, ecc. Ecco un frammento del codice Kuda (1/20 dell'intero codice). Si noti che nessuno dei comandi è direttamente collegato all'algoritmo di apprendimento della rete stessa. Per me è tutto cinese.

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

Gente, se decidete di pasticciare con le GPU, considerate quanto segue. È facile parallelizzare algoritmi di apprendimento in cui un'iterazione è indipendente dall'altra. Per esempio, genetica, dove il calcolo di centinaia di reti in una generazione non dipende l'uno dall'altro, Manhattan (enumerazione muta di tutte le soluzioni), o ottimizzazione di reti indipendenti in un comitato. Ma tali algoritmi sono pochi. I metodi basati sulla discesa del gradiente sarebbero più difficili da parallelizzare perché un'iterazione dipende dall'altra. In questi casi, è necessario dividere il calcolo dei neuroni nello stesso strato in thread paralleli, che non è sempre banale.

Sulla GPU saremo in grado di mettere in parallelo solo i calcoli semplici, calcoli semplici all'interno di un ciclo, quindi sarebbe molto difficile (e dubito che sarebbe efficace) implementare calcoli di diverse fasi della genetica sulla GPU.

La natura dell'accelerazione della GPU risiede nell'indipendenza degli input dagli output all'interno della stessa iterazione e nell'uniformità delle operazioni (come gpwr ha notato sopra). Non è molto simile alla definizione di strato che abbiamo derivato collegialmente sopra. Ecco perché ho suggerito di distinguere il livello come l'oggetto principale di lavoro, e l'oggetto neurone solo come un'entità informativa collegata al livello.

 
gpwr:

Scrivete qualcosa che funzioni all'inizio e poi parallelizzatelo. Il codice KUDAW richiede molto tempo per il debug a causa dei possibili errori: bisogna sapere quanta memoria allocare per i diversi array, scrivere i comandi per caricare e scaricare questi array dalla memoria, sincronizzare i thread, ecc. Ecco un frammento del codice Kuda (1/20 dell'intero codice). Si noti che nessuno dei comandi è direttamente collegato all'algoritmo di apprendimento della rete stessa. Per me è tutto cinese.

...

Tali frammenti possono essere marcati in una volta sola dando i nomi alle funzioni con l'appendice "GPU" o marcati con un commento all'inizio di un ciclo. Solo per far sapere alla gente che c'è la possibilità di usare il processore grafico.

 
gpwr:

Scrivete qualcosa che funzioni all'inizio e poi parallelizzatelo. Il codice KUDAW richiede molto tempo per il debug a causa dei possibili errori: bisogna sapere quanta memoria allocare per i diversi array, scrivere i comandi per caricare e scaricare questi array dalla memoria, sincronizzare i thread, ecc. Ecco un frammento del codice Kuda (1/20 dell'intero codice). Si noti che nessuno dei comandi è direttamente collegato all'algoritmo di apprendimento della rete stessa. Per me è tutto cinese.

CUDA supporta al massimo gli RPM.

Ecco una parte del codice per 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

È un bene che ci sia un esperto di OpenCL qui - un dialogo sostanziale e una discussione sulle tecnologie andrà a beneficio dell'intero progetto

Sono sicuro che le reti neurali saranno implementate utilizzando tutte le tecnologie possibili (MQL5, C++, OpenCL, CUDA) e gli utenti saranno in grado di scegliere in base ai loro gusti e capacità hardware

 

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

Buona fortuna con il progetto EngiNeuro!

 

Opzioni per sottoporre esempi all'algoritmo di apprendimento:

  • Uno per uno
  • In gruppi casuali
  • Gruppi scorrevoli
  • Tutto in una volta

Non stai dimenticando niente?


Ho preparato un quadro di progetto, lo metterò in discussione tra un paio di giorni...
 
Urain:

Opzioni per sottoporre esempi all'algoritmo di apprendimento:

  • Uno per uno
  • Gruppi casuali.
  • In gruppi scorrevoli.
  • Tutto in una volta.

Non stai dimenticando qualcosa?


Preparato il quadro del progetto, un paio di giorni per scuotere le cose e metterlo in discussione...

Uno alla volta - vedo.

E il resto delle opzioni - non capisco. Come posso presentare tutti gli esempi da studiare in una volta sola? - O sono scemo io?