"New Neural" est un projet de moteur de réseau neuronal Open Source pour la plateforme MetaTrader 5. - page 59

 

Si vous décidez de jouer avec les GPU, tenez compte des points suivants. Il est facile de paralléliser les algorithmes d'apprentissage où une itération est indépendante de l'autre. Par exemple, la génétique, où le calcul de centaines de réseaux dans une génération ne dépend pas les uns des autres, Manhattan (énumération muette de toutes les solutions), ou l'optimisation de réseaux indépendants dans un comité. Mais ces algorithmes sont peu nombreux. Les méthodes basées sur la descente de gradient seraient plus difficiles à paralléliser car une itération dépend d'une autre. Dans ce cas, il faut diviser le calcul des neurones d'une même couche en fils parallèles, ce qui n'est pas toujours trivial.

 

... Et la génétique ne fait pas partie du réseau, mais est un algorithme externe distinct.

Les gens ici veulent des réseaux parallèles.

 
L'un n'exclut pas l'autre.
 
TheXpert:

... Et la génétique ne fait pas partie du réseau, mais est un algorithme externe distinct.

Les gens ici veulent paralléliser les réseaux.

Écrivez quelque chose qui fonctionne au début, puis mettez-le en parallèle. Le code de KUDav prend beaucoup de temps à déboguer en raison des erreurs possibles : il faut savoir quelle quantité de mémoire allouer aux différents tableaux, écrire des commandes pour charger et décharger ces tableaux de la mémoire, synchroniser les threads, etc. Voici un fragment du code Kuda (1/20 du code entier). Notez qu'aucune de ces commandes n'est directement liée à l'algorithme d'apprentissage du réseau lui-même. C'est du chinois pour moi.

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

Si vous décidez de jouer avec les GPU, tenez compte des points suivants. Il est facile de paralléliser les algorithmes d'apprentissage où une itération est indépendante de l'autre. Par exemple, la génétique, où le calcul de centaines de réseaux dans une génération ne dépend pas les uns des autres, Manhattan (énumération muette de toutes les solutions), ou l'optimisation de réseaux indépendants dans un comité. Mais ces algorithmes sont peu nombreux. Les méthodes basées sur la descente de gradient seraient plus difficiles à paralléliser car une itération dépend d'une autre. Dans ce cas, il faut diviser le calcul des neurones d'une même couche en fils parallèles, ce qui n'est pas toujours trivial.

Sur les GPU, nous ne pourrons paralléliser que des calculs simples, des calculs simples au sein d'un même cycle, il serait donc très difficile (et je doute que ce soit efficace) de mettre en œuvre des calculs de différentes phases de la génétique sur GPU.

La nature de l'accélération des GPU réside dans l'indépendance des entrées par rapport aux sorties au sein d'une même itération et dans l'uniformité des opérations (comme l'a noté gpwr ci-dessus). N'est-ce pas très similaire à la définition de la couche que nous avons collégialement dérivée ci-dessus. C'est pourquoi j'ai suggéré de distinguer la couche comme l'objet de travail principal, et l'objet neurone seulement comme une entité informationnelle attachée à la couche.

 
gpwr:

Écrivez quelque chose qui fonctionne au début, puis mettez-le en parallèle. Le code KUDAW prend beaucoup de temps à déboguer en raison des erreurs possibles : il faut savoir quelle quantité de mémoire allouer aux différents tableaux, écrire des commandes pour charger et décharger ces tableaux de la mémoire, synchroniser les threads, etc. Voici un fragment du code Kuda (1/20 du code entier). Notez qu'aucune de ces commandes n'est directement liée à l'algorithme d'apprentissage du réseau lui-même. C'est du chinois pour moi.

...

De tels fragments peuvent être marqués à la fois en donnant des noms aux fonctions avec l'annexe "GPU" ou marqués avec un commentaire au début d'une boucle. Pour que les gens sachent qu'il est possible d'utiliser un processeur graphique.

 
gpwr:

Écrivez quelque chose qui fonctionne au début, puis mettez-le en parallèle. Le code KUDAV est long à déboguer en raison des erreurs possibles : il faut savoir quelle quantité de mémoire allouer aux différents tableaux, écrire des commandes pour charger et décharger ces tableaux de la mémoire, synchroniser les threads, etc. Voici un fragment du code Kuda (1/20 du code entier). Notez qu'aucune de ces commandes n'est directement liée à l'algorithme d'apprentissage du réseau lui-même. C'est du chinois pour moi.

CUDA prend en charge les RPM dans toute la mesure du possible.

Voici une partie du code de 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

C'est une bonne chose qu'il y ait un expert d'OpenCL ici - un dialogue de fond et une discussion sur les technologies profiteront à l'ensemble du projet.

Je suis sûr que les réseaux neuronaux seront mis en œuvre en utilisant toutes les technologies possibles (MQL5, C++, OpenCL, CUDA) et que les utilisateurs pourront choisir en fonction de leurs goûts et des capacités de leur matériel.

 

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

Bonne chance avec le projet EngiNeuro !

 

Options pour soumettre des exemples à l'algorithme d'apprentissage:

  • Un par un
  • En groupes aléatoires
  • Groupes de glissement
  • Tous en même temps

Tu n'oublies rien ?


J'ai préparé un cadre de projet, je le soumettrai à la discussion dans quelques jours...
 
Urain:

Options pour soumettre des exemples à l'algorithme d'apprentissage :

  • Un par un
  • Groupes aléatoires.
  • En groupes coulissants.
  • Tout à la fois.

Tu n'oublies pas quelque chose ?


Préparé le cadre du projet, quelques jours pour secouer les choses et le mettre en discussion...

Un à la fois - je vois.

Et le reste des options - je ne comprends pas. Comment puis-je soumettre tous les exemples à étudier en même temps ? - Ou suis-je bête ?