O "New Neural" é um projecto de motor de rede neural Open Source para a plataforma MetaTrader 5. - página 59

 

Pessoal, se você decidir mexer com GPUs, considerem o seguinte. É fácil paralelizar algoritmos de aprendizagem onde uma iteração é independente da outra. Por exemplo, genética, onde computar centenas de redes em uma geração não depende uma da outra, Manhattan (enumeração burra de todas as soluções), ou otimização de redes independentes em um comitê. Mas tais algoritmos são poucos. Métodos baseados em descida por gradiente seriam mais difíceis de paralelizar porque uma iteração depende da outra. Nesses casos, é necessário dividir o cálculo dos neurônios na mesma camada em fios paralelos, o que nem sempre é trivial.

 

... E a genética não faz parte da rede, mas sim de um algoritmo externo separado.

As pessoas aqui querem redes paralelas.

 
Um não exclui o outro.
 
TheXpert:

... E a genética não faz parte da rede, mas sim de um algoritmo externo separado.

As pessoas aqui querem paralelizar as redes.

Escreva algo que funcione no início, e depois faça o paralelismo. O código do KUDav leva muito tempo para ser depurado devido a possíveis erros: você precisa saber quanta memória alocar para diferentes matrizes, escrever comandos para carregar e descarregar essas matrizes da memória, sincronizar threads, etc. Aqui está um fragmento do código Kuda (1/20 do código completo). Note que nenhum dos comandos está directamente relacionado com o próprio algoritmo de aprendizagem da rede. Para mim é tudo chinês.

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

Pessoal, se você decidir mexer com GPUs, considerem o seguinte. É fácil paralelizar algoritmos de aprendizagem onde uma iteração é independente da outra. Por exemplo, genética, onde computar centenas de redes em uma geração não depende uma da outra, Manhattan (enumeração burra de todas as soluções), ou otimização de redes independentes em um comitê. Mas tais algoritmos são poucos. Métodos baseados na descida por gradiente seriam mais difíceis de paralelizar porque uma iteração depende da outra. Nesses casos, é necessário dividir o cálculo dos neurônios na mesma camada em fios paralelos, o que nem sempre é trivial.

Na GPU só conseguiremos paralisar cálculos simples, cálculos simples dentro de um ciclo, pelo que seria muito difícil (e duvido que fosse eficaz) implementar cálculos de diferentes fases da genética na GPU.

A natureza da aceleração da GPU está na independência das entradas das saídas dentro da mesma iteração e na uniformidade das operações (como gpwr observado acima). Isso não é muito parecido com a definição de camada que nós colegialmente derivamos acima. Por isso sugeri distinguir camada como o principal objeto de trabalho, e objeto neuronal apenas como uma entidade informativa ligada à camada.

 
gpwr:

Escreva algo que funcione no início e depois faça o paralelismo. O código KUDAV demora muito tempo a depurar devido a possíveis erros: é necessário saber quanta memória deve ser alocada para diferentes matrizes, escrever comandos para carregar e descarregar estas matrizes da memória, sincronizar threads, etc. Aqui está um fragmento do código Kuda (1/20 do código completo). Note que nenhum dos comandos está directamente relacionado com o próprio algoritmo de aprendizagem da rede. Para mim é tudo chinês.

...

Tais fragmentos podem ser marcados imediatamente dando nomes às funções com o apêndice "GPU" ou marcados com comentários no início de um laço. Só para que as pessoas saibam aqui é uma possibilidade de usar o processador gráfico.

 
gpwr:

Escreva algo que funcione no início e depois faça o paralelismo. O código KUDAV demora muito tempo a depurar devido a possíveis erros: é necessário saber quanta memória deve ser alocada para diferentes matrizes, escrever comandos para carregar e descarregar estas matrizes da memória, sincronizar threads, etc. Aqui está um fragmento do código Kuda (1/20 do código completo). Note que nenhum dos comandos está directamente relacionado com o próprio algoritmo de aprendizagem da rede. Para mim é tudo chinês.

A CUDA apoia a SRF em toda a sua extensão.

Aqui está parte do código para hip.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

É bom que haja aqui um especialista em OpenCL - um diálogo substantivo e discussão de tecnologias irá beneficiar todo o projeto

Tenho certeza que as redes neurais serão implementadas usando todas as tecnologias possíveis (MQL5, C++, OpenCL, CUDA) e os usuários poderão escolher de acordo com seu gosto e capacidades de hardware

 

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

Boa sorte com o projecto EngiNeuro!

 

Opções para submeter exemplos ao algoritmo de aprendizagem:

  • Um a um
  • Em grupos aleatórios
  • Grupos deslizantes
  • Tudo de uma vez

Não te estás a esquecer de nada?


Preparei um quadro de projecto, vou colocá-lo para discussão daqui a uns dias...
 
Urain:

Opções para submeter exemplos ao algoritmo de aprendizagem:

  • Um a um
  • Grupos aleatórios.
  • Em grupos deslizantes.
  • Tudo de uma vez.

Não te estás a esquecer de nada?


Preparei o enquadramento do projecto, uns dias para agitar as coisas e colocá-lo para discussão...

Um de cada vez - estou a ver.

E o resto das opções - eu não entendo. Como posso submeter todos os exemplos para estudar de uma só vez? - Ou eu sou burro?

Razão: