Вот что можно сделать с OpenCL прямо в терминале MetaTrader 5 без всяких DLL - страница 18

 
Aleksei Grebenkin:

Renat Fatkhullin как с вами связаться, обсудить возможность написания на языке MQL5+OpenCL. необходимо задействовать вычислительные мощности видеокарт. если я всё правильно понимаю, то на примере из практики: написанный робот всего 11 параметров оптимизирует 3 машинами, подключенными по локальной сети, период всего 1 год 6 часов. пробовал зарядить 5 лет оптимизацию с полным перебором данных, мне показало что 2 месяца надо ждать. если я правильно понял, то OpenCL данную задачу решает. скорость должна возрасти в сотни раз, так как в расчётах будут задействованы не процессоры, а видеокарты. то есть, с учётом всей торговой системы, примерно будет 200-300 параметров в настройках. такой объём вычислений периода лет 3-5 при исполнении робота в OpenCL будет производиться одной моей машиной за несколько минут-часов. правильно ли я понимаю и возможно ли с вами обсудить написание такого робота?

OpenCL расчеты не участвуют в параллелизации процесса оптимизации.

С помощью OpenCL вы можете конкретную специально подготовленную часть алгоритма просчитать быстрее и параллельно. У нас много статей и обсуждений OpenCL.

 
Maxim Kuznetsov #:

что мешает купить карточку посерьёзнее ?

какую-нить A100 https://www.nvidia.com/ru-ru/data-center/a100/

 Сказано -Сделано.




Ускорение Х2-Х3 от предыдущих вычисления на Gforce RTX2080 TI

Но есть отдельный момент для всех, кто тестирует модели с нейронной сетью в тестере.

OpenCl не дает захватить устройство при многопоточном обращении, если процессов (агентов) больше 10-12. 

Особенно если создается несколько одновременно нейронных сетей для анализа разных данных с объединением в одной.

И несмотря, на то, что на сервере сейчас 96 логических процессоров, пользовать приходится пока 12.

Поэтому в какой то степени выгодней иметь несколько старых компов с сети, вероятно дешевле в разы.


Отдельно хочу отметить отдельную возможность установить пакет AMD SDK , который позволил использовать CPU с OpenCL.

Теперь есть 96 устройств, готовых с той же скоростью выполнять задачу, но уже не зависеть только от мощности карточки.



Однако пришлось поправить библиотеку OpenCl, так как в процесс выбора устройства

CLContextCreate(CL_USE_ANY)

не дает возможность понять, какое устройство в данный момент загружено.

А выбор только GPU или только CPU не дает возможности использовать оба варианта одновременно.


Для решения этой задачи сделал тестирование каждой карточки на текущую скорость вычислений, 

используя этот интересный пример на моделирование вычисления (красиво)

https://www.mql5.com/ru/code/825


в коде библиотеки воплотилось это так:

int COpenCL::ID_FasterDevice()
  {
 
   int cl_prg;
   int cl_krn;
   int cl_mem;
   int cl_ctx;
   string device;
   ulong speed [];
   
   int dCount= (int)CLGetInfoInteger(0,CL_DEVICE_COUNT);
  
   
   if (dCount>1)
   {
   ArrayResize(speed,dCount);
   
      //----------------- измерим текщую производительность и выберем более быстрый девайс ----------
      for(int i = 0; i<dCount;i++)
         {
         cl_ctx=i;
         CLGetInfoString(cl_ctx,CL_DEVICE_NAME,device);
         Print(cl_ctx,": ",device);
         ulong start_time=GetMicrosecondCount();
     
//--- initializing OpenCL objects
   if((cl_ctx=CLContextCreate())==INVALID_HANDLE)
     {
      Print("OpenCL not found");
      return -1;
     }
   if((cl_prg=CLProgramCreate(cl_ctx,cl_src))==INVALID_HANDLE)
     {
      CLContextFree(cl_ctx);
      Print("OpenCL program create failed");
      return -1;
     }
   if((cl_krn=CLKernelCreate(cl_prg,"MFractal"))==INVALID_HANDLE)
     {
      CLProgramFree(cl_prg);
      CLContextFree(cl_ctx);
      Print("OpenCL kernel create failed");
      return -1;
     }
   if((cl_mem=CLBufferCreate(cl_ctx,SIZE_X*SIZE_Y*sizeof(uint),CL_MEM_READ_WRITE))==INVALID_HANDLE)
     {
      CLKernelFree(cl_krn);
      CLProgramFree(cl_prg);
      CLContextFree(cl_ctx);
      Print("OpenCL buffer create failed");
      return -1;
     }
//--- getting ready for execution
   float x0       =-2;
   float y0       =-0.5;
   float x1       =-1;
   float y1       = 0.5;
   uint  max      = 20000;
   uint  offset[2]={0,0};
   uint  work  [2]={SIZE_X,SIZE_Y};
   string objname ="OpenCL_"+IntegerToString(ChartID());
   string resname ="::Mandelbrot_"+IntegerToString(ChartID());
//--- setting unchangeable OpenCL function parameters
   CLSetKernelArg(cl_krn,4,max);
   CLSetKernelArgMem(cl_krn,5,cl_mem);
//--- creating the object for graphics display
   ChartRedraw();
   Comment("Benchmark OpenCl devices");
   ObjectCreate(0,objname,OBJ_BITMAP_LABEL,0,0,0);
   ObjectSetInteger(0,objname,OBJPROP_XDISTANCE,4);
   ObjectSetInteger(0,objname,OBJPROP_YDISTANCE,26);
//--- create initial empty picture
   uint buf[];

   ArrayResize(buf,SIZE_X*SIZE_Y);
   ResourceCreate(resname,buf,SIZE_X,SIZE_Y,0,0,SIZE_X,COLOR_FORMAT_XRGB_NOALPHA);
   ObjectSetString(0,objname,OBJPROP_BMPFILE,resname);
//--- rendering, till we are not stopped from the outside
   for (int samples=0;samples<100;samples++)
     {
      uint x=GetTickCount();
      //--- setting floating parameters
      CLSetKernelArg(cl_krn,0,x0);
      CLSetKernelArg(cl_krn,1,y0);
      CLSetKernelArg(cl_krn,2,x1);
      CLSetKernelArg(cl_krn,3,y1);
      //--- rendering the frame
      CLExecute(cl_krn,2,offset,work);
      //--- taking the frame data
      CLBufferRead(cl_mem,buf);
      //--- outputting the rendering time
      Comment(IntegerToString(GetTickCount()-x)+" msec per frame");
      //--- saving the frame in memory and drawing it
      ResourceCreate(resname,buf,SIZE_X,SIZE_Y,0,0,SIZE_X,COLOR_FORMAT_XRGB_NOALPHA);
      ChartRedraw();
      //--- a small pause and parameters update for the next frame
      Sleep(10);
      x0+=0.001f;
      x1-=0.001f;
      y0+=0.001f;
      y1-=0.001f;
     
     }
//--- removing OpenCL objects
   CLBufferFree(cl_mem);
   CLKernelFree(cl_krn);
   
   CLProgramFree(cl_prg);
   CLContextFree(cl_ctx);
         ulong finishtime=GetMicrosecondCount();
         ulong testtime= finishtime-start_time;  
         speed [i] = testtime; 
         
   ObjectDelete(0,objname);
   Comment("");
     }
      
      m_context= ArrayMinimum(speed,0,WHOLE_ARRAY);
   }
   else 
      m_context=-1;
//--- remove object
  
   return m_context;
  }
//+------------------------------------------------------------------+

в коде советника 

 COpenCL         *TestOpenCL;
      TestOpenCL =new COpenCL;
      int faster_device=TestOpenCL.ID_FasterDevice();
      TestOpenCL.Initialize(cl_program,id_device,true);         

В библиотеке OpenCL учесть возможность выбора устройства

//+------------------------------------------------------------------+
//| Initialize                                                       |
//+------------------------------------------------------------------+
bool COpenCL::Initialize(const string program,const int id_device=-1,const bool show_log=true)
  {  
   
     
     m_context=id_device;
    
     if((m_context=CLContextCreate())==INVALID_HANDLE)
     {
      Print("OpenCL not found");      
     }   
     else if ((m_context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE)
         {
       
               Print("OpenCL not found. Error code=",GetLastError());
                  return(false);     
         }
Файлы:
 

В завтрашнем релизе мы выпускаем штатные matrix/veсtor типы данных для использования в машинном обучении.

Код MQL5 программ здорово упростится и позволит реализовывать большой набор математических операций.

Это первая генерация функционала, а дальше пойдем реализовывать более сложные механизмы, чтобы реализовать возможности таких пакетов, как TensorFlow. Для этого пригодится OpenCL.

 
Какой смысл во всей этой многопоточности для нейросети, когда проход новой эпохи должен опираться на результаты предыдущего прохода. И все параллельные потоки всего лишь будут повторять результаты первого. И в конце концов зальют результат в один файл. Затирая результаты предыдущего потока но по сути не меняя значения...
 
Dmytryi Voitukhov #:
Какой смысл во всей этой многопоточности для нейросети, когда проход новой эпохи должен опираться на результаты предыдущего прохода. И все параллельные потоки всего лишь будут повторять результаты первого. И в конце концов зальют результат в один файл. Затирая результаты предыдущего потока но по сути не меняя значения...

Ренат восклицает, а ты ноешь. Годиков то сколько тебе? 

 

Чуть поправил библиотеку, сделал по красоте

       double testtime= (GetTickCount()-start_time)/1000;  
         speed [i] = NormalizeDouble(MathRound(1000/testtime/8)*8,3); //NormalizeDouble(1000/testtime,2); 
      
      CLGetInfoString(i,CL_DEVICE_NAME,device);
       Print("Device #", i,", speed =",speed [i]," FPS. ",device); 
   ObjectDelete(0,objname);
   Comment("");
     }
      
      m_context= ArrayMaximum(speed,0,WHOLE_ARRAY);
      CLGetInfoString(m_context,CL_DEVICE_NAME,device);
     
      Print("Faster device: #",m_context,", ",device," "); 


Файлы:
Причина обращения: