"Новый нейронный" - проект Open Source движка нейронной сети для платформы MetaTrader 5. - страница 59

 

Народ, если вы решите связываться с GPU, учтите следующее. Легко распараллеливаются алгортимы обучения где одна итерация не зависит от другой. Например, генетические, в которых вычисление сотни сетей в поколении не зависят друг от друга, манхэтоновские (тупой перебор всех решений), или оптимизация независимых сетей в комитете. Но таких алгоритмов мало. Методы основанные на градиетных спусках будет сложнее распараллелить так как одна итерация зависит от другой. В таких случаях нужно будет разбивать вычисления нейронов в одном и том же слою на параллельные потоки, что не всегда тривиально.

 

... А генетика не является составной частью сети, но отдельным внешним алгоритмом.

Тут народ сети параллелить хочет.

 
Одно другому не мешает.
 
TheXpert:

... А генетика не является составной частью сети, но отдельным внешним алгоритмом.

Тут народ сети параллелить хочет.

Написать что-то работающее поначалу, а потом параллелить. КУДАвский код долго отлаживается из-за возможных ошибок: тут нужно знать сколько памяти уделить на разные массивы, писать команды загрузки и выгрузки этих массивов из памяти, синхронизации потоков, и т.п. Вот кусок кудовского кода (1/20 всего кода). Заметьте что ни одна команда к самому алгоритму обучения сети не имеет прямого отношения. Для меня это всё китайский язык. 

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

Народ, если вы решите связываться с GPU, учтите следующее. Легко распараллеливаются алгортимы обучения где одна итерация не зависит от другой. Например, генетические, в которых вычисление сотни сетей в поколении не зависят друг от друга, манхэтоновские (тупой перебор всех решений), или оптимизация независимых сетей в комитете. Но таких алгоритмов мало. Методы основанные на градиетных спусках будет сложнее распараллелить так как одна итерация зависит от другой. В таких случаях нужно будет разбивать вычисления нейронов в одном и том же слою на параллельные потоки, что не всегда тривиально.

На GPU получится параллелить только простые вычисления, простые расчёты в пределах одного цикла, так что расчёт разных ФФ генетики под GPU реализовать будет очень сложно (и я сомневаюсь что будет еффективно).

Природа ускорения на GPU лежит в независимости входов от выходов в пределах одной итерации и однотипности операций (как отметил выше gpwr). Не правда ли очень похоже на определение слоя что мы коллегиально вывели выше. Именно поэтому я предложил выделить слой как основной рабочий объект, а объект нейрон лишь как информационную сущность приданую слою.

 
gpwr:

Написать что-то работающее поначалу, а потом параллелить. КУДАвский код долго отлаживается из-за возможных ошибок: тут нужно знать сколько памяти уделить на разные массивы, писать команды загрузки и выгрузки этих массивов из памяти, синхронизации потоков, и т.п. Вот кусок кудовского кода (1/20 всего кода). Заметьте что ни одна команда к самому алгоритму обучения сети не имеет прямого отношения. Для меня это всё китайский язык. 

...

Так никто же не против, писать будем и отлаживать последовательный код, я лишь ратую за то чтоб в код закладывалась возможность параллелить некоторые участки. такие участки можно сразу обозначать давая функциям имена с дополнением "GPU" либо обозначать комментарием в начале цикла. Чтоб народ знал вот тут заложена возможность применения граф. процессора.

 
gpwr:

Написать что-то работающее поначалу, а потом параллелить. КУДАвский код долго отлаживается из-за возможных ошибок: тут нужно знать сколько памяти уделить на разные массивы, писать команды загрузки и выгрузки этих массивов из памяти, синхронизации потоков, и т.п. Вот кусок кудовского кода (1/20 всего кода). Заметьте что ни одна команда к самому алгоритму обучения сети не имеет прямого отношения. Для меня это всё китайский язык.  

CUDA поддерживает ОПП в полной мере

Вот часть кода для гип.тангенса 

#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

Хорошо, что здесь есть спец по OpenCL - предметный диалог и обсуждение технологий пойдет  на пользу всему проекту

Уверен, что нейросети будут реализованы под все возможные технологии (MQL5, C++, OpenCL, CUDA) и пользователи будут выбирать по вкусу и аппаратным возможностям

 

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

Good luck with the EngiNeuro project

 

Варианты подачи примеров обучающему алгоритму:

  • Поштучно
  • Случайными группами
  • Скользящими группами
  • Все сразу

Ничего не забыл?


Подготовил остов проекта, пару дней утрясу и выложу в обсуждение...
 
Urain:

Варианты подачи примеров обучающему алгоритму:

  • Поштучно
  • Случайными группами
  • Скользящими группами
  • Все сразу

Ничего не забыл?


Подготовил остов проекта, пару дней утрясу и выложу в обсуждение...

Поштучно - понимаю.

А остальные варианты - не понял. Как можно подать на обучение сразу все примеры? - или туплю?

Причина обращения: