范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

神经网络变得轻松(第五部分)OpenCL中的多线程计算

  内容概述 1. MQL5 中如何组织多线程计算 2. 神经网络中的多线程计算 3. 利用 OpenCL 实现多线程计算 3.1. 前馈内核 3.2. 反向传播内核 3.3. 更新权重 3.4. 创建主程序的类 3.5. 创建基础神经元类来操控 OpenCL 3.6. CNet 类中的附加 4. 测试 结束语 链接 本文中用到的程序
  概述
  在之前的文章中,我们讨论过某些类型的神经网络实现。 如您所见,神经网络由大量相同类型的神经元组成,并在其中执行相同的操作。 然而,网络拥有的神经元越多,它消耗的计算资源也就越多。 结果就是,训练神经网络所需的时间呈指数增长,这是因为在隐藏层添加一个神经元,需要了解上一层和下一层中所有神经元的连接。 有一种减少神经网络训练时间的方法。 现代计算机的多线程功能可以同时计算多个神经元。 由于线程数量的增加,时间将可预见地大大减少。
  1. MQL5 中如何组织多线程计算
  MetaTrader 5 终端具有多线程体系架构。 终端中的线程分布受到严格控制。 根据文档,脚本和智能交易系统是在单独的线程中启动。 至于指示器,每个品种会提供单独的线程。 即时报价处理和历史记录同步于指标所在线程中执行。 这意味着终端只为每个智能交易系统分配一个线程。 某些计算可以在指标中执行,其可提供一个额外的线程。 然而,指标中过多的计算会减慢与即时报价数据处理相关的终端操作,这可能会导致针对市场状况的失控。 这种状况能对 EA 性能产生负面影响。
  不过,有一个解决方案。 MetaTrader 5 开发人员为其提供了利用第三方 DLL 的能力。 在多线程体系结构上创建动态库会自动为函数库中实现的操作提供多线程支持。 在此,EA 操作以及与函数库之间的数据交换依然保留在智能交易系统的主线程之中。
  第二个选项是利用 OpenCL 技术。 在这种情况下,我们可以用标准方法在支持该技术的处理器和视频卡上规划多线程计算。 对于此选项,程序代码不依赖所使用的设备。 该站点上有许多与 OpenCL 技术有关的出版物。 特别是,该主题在 [第五篇] 和 [第六篇] 文章里已有很好介绍。
  因此,我决定使用 OpenCL。 首先,运用该技术时,用户不需要额外配置终端,并为第三方 DLL 设置权限。 其次,这样的智能交易系统可通过一个 EX5 文件在终端之间传送。 这允许将计算部分转移到视频卡,因视频卡通常在终端操作期间处于空闲状态。
  2. 神经网络中的多线程计算
  我们已选择了该技术。 现在,我们需要决定将计算部分拆分为线程的过程。 您还记得完全连接感知器算法吗? 信号顺序从输入层转至隐藏层,然后转至输出层。 没必要为每个层分配线程,因为计算必须按顺序执行。 直到收到来自上一层的结果之后,该层才能开始计算。 一层中独立神经元的计算不依赖该层中其他神经元的计算结果。 这意味着我们可为每个神经元分配单独的线程,并发送一整层的所有神经元进行并行计算。
  深入到一个神经元的运算,我们可以研究把计算输入值与权重系数的乘积并行化的可能性。 不过,结果值的进一步求和,以及计算激活函数的数值被合并到一个线程当中。 我决定利用 vector 函数在单个 OpenCL 内核中实现这些操作。
  类似的方法也用来拆分反馈线程。 其实现如下所示。 3. 利用 OpenCL 实现多线程计算
  选择了基本方法后,我们就能够继续实现了。 我们从创建内核(可执行的OpenCL函数)开始。 根据以上逻辑,我们将创建 4 个内核。 3.1. 前馈内核。
  与之前文章中讨论的方法类似,我们创建一个前馈推算内核  FeedForward  。
  不要忘记内核是在每个线程中运行的函数。 调用内核时需设置此类线程的数量。 在内核内部的操作是特定循环内的嵌套操作;循环的迭代次数等于被调用线程的次数。如此,在前馈内核中,我们可以指定计算独立神经元状态的操作,并可从主程序调用内核时以指定神经元数量。
  内核从参数中接收权重矩阵,输入数据数组和输出数据数组的引用,以及输入数组的元素数量,和激活函数类型。 请注意,OpenCL 中的所有数组都是一维的。 因此,如果在 MQL5 中将二维数组用做权重系数,则此处我们需要计算初始位置的位移,以便读取第二个、及后续神经元的数据。 __kernel void FeedForward(__global double *matrix_w,                               __global double *matrix_i,                               __global double *matrix_o,                               int inputs, int activation)
  在内核的开头,我们获得线程的序列号,其可判定所计算神经元的序列号。 声明私密(内部)变量,包括向量变量  inp  和  weight 。 还要定义我们的神经元权重的位移。   {    int i=get_global_id(0);    double sum=0.0;    double4 inp, weight;    int shift=(inputs+1)*i;
  接下来,组织一个循环来获取输入值与其权重的乘积的合计。 如上所述,我们用到 4 个元素  inp  和  weight  的向量来计算乘积合计。 然而,内核接收的所有数组并非都是 4 的倍数,因此缺少的元素应替换为零值。 注意输入数据向量中的一个 "1" - 它对应于贝叶斯偏差的权重。    for(int k=0; k<=inputs; k=k+4)      {       switch(inputs-k)         {          case 0:            inp=(double4)(1,0,0,0);            weight=(double4)(matrix_w[shift+k],0,0,0);            break;          case 1:            inp=(double4)(matrix_i[k],1,0,0);            weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],0,0);            break;          case 2:            inp=(double4)(matrix_i[k],matrix_i[k+1],1,0);            weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],matrix_w[shift+k+2],0);            break;          case 3:            inp=(double4)(matrix_i[k],matrix_i[k+1],matrix_i[k+2],1);            weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],matrix_w[shift+k+2],matrix_w[shift+k+3]);            break;          default:            inp=(double4)(matrix_i[k],matrix_i[k+1],matrix_i[k+2],matrix_i[k+3]);            weight=(double4)(matrix_w[shift+k],matrix_w[shift+k+1],matrix_w[shift+k+2],matrix_w[shift+k+3]);            break;         }       sum+=dot(inp,weight);      }
  获得乘积之和后,计算激活函数,并将结果写入输出数据数组。    switch(activation)      {       case 0:         sum=tanh(sum);         break;       case 1:         sum=pow((1+exp(-sum)),-1);         break;      }    matrix_o[i]=sum;   } 3.2. 反向传播内核。
  为反向传播误差梯度创建两个内核。 在第一个   CaclOutputGradient  中计算输出层误差。 它的逻辑很简单。 所获参考值在激活函数的数值范围进行常规化。 然后,将参考值和实际值之间的差乘以激活函数的导数。 将结果值写入梯度数组的相应单元格中。 __kernel void CaclOutputGradient(__global double *matrix_t,                                  __global double *matrix_o,                                  __global double *matrix_ig,                                  int activation)   {    int i=get_global_id(0);    double temp=0;    double out=matrix_o[i];    switch(activation)      {       case 0:         temp=clamp(matrix_t[i],-1.0,1.0)-out;         temp=temp*(1+out)*(1-(out==1 ? 0.99 : out));         break;       case 1:         temp=clamp(matrix_t[i],0.0,1.0)-out;         temp=temp*(out==0 ? 0.01 : out)*(1-(out==1 ? 0.99 : out));         break;      }    matrix_ig[i]=temp;   }
  在第二个内核中,在  CaclHiddenGradient  里计算隐藏层神经元的误差梯度。 内核构建类似于上述的前馈内核。 它还用到了向量运算。 区别在于前馈推算中以下一层的梯度向量替代前一层的输出值,并采用不同的权重矩阵。 而且,代替计算激活函数,结果合计是与激活函数导数的乘积。 内核代码给出如下。 __kernel void CaclHiddenGradient(__global double *matrix_w,                               __global double *matrix_g,                               __global double *matrix_o,                               __global double *matrix_ig,                               int outputs, int activation)   {    int i=get_global_id(0);    double sum=0;    double out=matrix_o[i];    double4 grad, weight;    int shift=(outputs+1)*i;    for(int k=0;k0)      {       if(CheckPointer(Weights)==POINTER_INVALID)         {          Weights=new CBufferDouble();          if(CheckPointer(Weights)==POINTER_INVALID)             return false;         }       int count=(int)((numNeurons+1)*numOutputs);       if(!Weights.Reserve(count))          return false;       for(int i=0;i1 ? 1 : target<-1 ? -1 : target)-result[n];       error+=delta*delta;      }    error/= total;    error = sqrt(error);    recentAverageError+=(error-recentAverageError)/recentAverageSmoothingFactor;     if(!neuron.calcOutputGradients(targetVals))       return;; //--- Calc Hidden Gradients    CObject *temp=NULL;    total=layers.Total();    for(int layerNum=total-2; layerNum>0; layerNum--)      {       CLayer *nextLayer=currentLayer;       currentLayer=layers.At(layerNum);       neuron=currentLayer.At(0);       neuron.calcHiddenGradients(nextLayer.At(0));      } //---    CLayer *prevLayer=layers.At(total-1);    for(int layerNum=total-1; layerNum>0; layerNum--)      {       currentLayer=prevLayer;       prevLayer=layers.At(layerNum-1);       neuron=currentLayer.At(0);       neuron.updateInputWeights(prevLayer.At(0));      }   }
  针对 getResult 方法略微进行了一些修改。    if(CheckPointer(opencl)!=POINTER_INVALID && output.At(0).Type()==defNeuronBaseOCL)      {       CNeuronBaseOCL *temp=output.At(0);       temp.getOutputVal(resultVals);       return;      }
  附件中提供了所有方法和函数的完整代码。 4. 测试
  采用与之前测试相同的条件,测试所创建类的操作。 已创建 Fractal_OCL EA 用于测试,它与先前创建的 Fractal_2 完全相同。 在 H1 时间帧,EURUSD 货币对上测试了神经网络的训练。 将 20 根烛条的数据输入到神经网络。 训练时采用最近两年的数据。 实验在支持 OpenCL 的 "Intel(R) Core(TM)2 Duo CPU T5750 @ 2.00GHz" 设备上运行。
  在 5 小时 27 分钟的测试中,利用 OpenCL 技术的 EA 共执行了 75 个训练时期。 对于 12405 根烛条的区间,这平均需要 4 分 22 秒。 未利用 OpenCL 技术的同一智能交易系统,在同一台笔记本电脑上的相同神经网络体系结构下,每个时期平均要花费 40 分钟 48 秒。 如此,利用 OpenCL 可以令学习过程快 9.35 倍。
  结束语
  本文演示了利用 OpenCL 技术在神经网络中规划多线程计算的可能性。 测试表明,在同一 CPU 上,性能几乎提高了 10 倍。 期望利用 GPU 进一步提高算法性能 - 在这种情况下,将计算转移到兼容的 GPU 不需要修改智能交易系统代码。
  总体而言,结果证明该方向的进一步发展具有良好的前景。
  链接神经网络变得轻松 神经网络变得轻松(第二部分):网络训练和测试 神经网络变得轻松(第三部分):卷积网络 神经网络变得轻松(第四部分):循环网络 OpenCL: 通往并行世界的桥梁 OpenCL: 从初学到精通编程
  本文中用到的程序
  #
  名称
  类型
  说明
  1
  Fractal_OCL.mq5   智能交易系统   利用 OpenCL 技术的含有分类神经网络(输出层中有 3 个神经元)的智能交易系统   2
  NeuroNet.mqh   类库   用于创建神经网络的类库   3
  NeuroNet.cl   代码库   OpenCL 程序代码库

摊牌了?国内手机厂商扛起中国制造的大旗,被比尔盖茨说准了在华为被卡脖后,不少欧美企业都不忘踩上一脚,公开表态,拒绝和华为继续合作。然而,作为微软的创始人,比尔盖茨则有不同的看法。他表示,打压华为是错误的,最终会推动中国科技的发展,反而会A股史上最大骗局!多家上市公司坠入千亿财务黑洞文法人杂志全媒体记者岳雷图片来源资料图被喻为A股史上最大骗局的专网通信谜案进入追责阶段。12月26日,上海电气(601727。SH)公告称,收到上海证监局500万元罚单。此外,ST医保缴费12月31日截止,还未缴纳的抓紧时间啦!视频加载中接下来进入民生新闻板块。2023年度株洲市居民医保正常参保缴费期即将于2022年12月31日截止,还没有购买2023年医保的,可要抓紧时间了。醴陵融媒记者杨呈祥刘主播,2荣耀处女座操作平板和手机统一价格,天玑8100吃定3299最近,荣耀80GT和荣耀平板V8Pro一起发布了,荣耀80GT共有两个版本,其中12256GB版卖3299,巧了这不是,12。1英寸的荣耀平板V8Pro新品也是12256GB卖32上交所发布2023年全年休市安排12月27日,上海证券交易所发布2023年全年休市安排的通知,根据中国证监会关于2023年部分节假日放假和休市安排的通知(证监办发2022113号)要求,上海证券交易所(以下简称本衡水3条线路入选河北冬农趣休闲农业与乡村旅游线路12月23日,从衡水市农业农村局获悉,日前,河北省农业农村厅联合各市农业农村局推荐了30条冬农趣系列休闲农业与乡村旅游线路,其中,衡水市耕读民俗文化体验游悠然采摘游和冀州古村落民俗永创智能研究报告产品优势下游驱动,迈向全厂智能化解决方案(报告出品方作者财通证券,佘炜超,谢铭)1公司简介深耕包装机械近20载,行稳致远1。1基本概况产品种类多元,智能包装领域引领者秉承无人包装智能系统理念的包装解决方案提供商。公司自成中超0浙江5个净胜球优势领跑斯坦丘任意球建功戴维森点射北京时间12月27日,中超联赛第33轮,武汉三镇主场对阵浙江队。上半场伤停补时阶段,斯坦丘主罚任意球破门。最后时刻,戴维森主罚点球破门。最终,武汉三镇20击败浙江队,与泰山队同积72022年最佳,被称体验不输苹果!安卓这块手表到底有什么优势?2022年即将结束,在过去的一年里,要问哪一款智能手表给我留下了最深刻的印象的话,我的答案一定是OPPOWatch3Pro,虽说在智能手表领域苹果依然是佼佼者,但是OPPOWatc美媒文章中国经济发展更注重质量和效率参考消息网12月27日报道美国外交学者网站12月20日发表文章解读2022年中央经济工作会议。文章称,12月15日至16日,中国举行了中央经济工作会议,该会议常被认为是关于经济前景中国葡萄酒庄园宁夏贺兰山银色高地银色高地的先锋已毋需多言宁夏贺兰山东麓,第一个用橡木桶陈酿第一个走星级酒店高端路线第一个出口波尔多(目前占宁夏葡萄酒出口总值的50以上)第一批被世界葡萄酒地图收录,以及中国第一个车
2022年,中国的产房静悄悄2021年,1062万个婴儿在中国降生,比以饥荒载入史册的1960年还少了340万个,这是新中国成立以来出生人数最少的一年2021年是新中国成立以来,新生婴儿数量最少的一年,但很可浅谈为什么云南旅游能吸引来半个中国的人随着暑假尾声的到来,云南旅游业的火热也逐渐褪去了,今天小编就为大家详解一下云南旅游旺盛背后的原因。1云南得天独厚的地理自然人文环境造就了旅游热。云南是多少数民族的省份,各少数民族文浅谈为什么云南旅游能吸引来半个中国的人随着暑假尾声的到来,云南旅游业的火热也逐渐褪去了,今天小编就为大家详解一下云南旅游旺盛背后的原因。1云南得天独厚的地理自然人文环境造就了旅游热。云南是多少数民族的省份,各少数民族文中缅边境神奇村一寨两国,一半在中国一半在缅甸,差距有多大?众所周知,我国幅员辽阔,有着960万平方公里的土地,陆地边界线全长约2。28万公里,有着哈萨克斯坦俄罗斯朝鲜蒙古越南印度等14个邻国。照理说,我国的边境不是茫茫的戈壁高山就是宽阔的中缅边境神奇村一寨两国,一半在中国一半在缅甸,差距有多大?众所周知,我国幅员辽阔,有着960万平方公里的土地,陆地边界线全长约2。28万公里,有着哈萨克斯坦俄罗斯朝鲜蒙古越南印度等14个邻国。照理说,我国的边境不是茫茫的戈壁高山就是宽阔的四天3万人次光顾点亮海门之美文旅夜市8月7日晚,由区委宣传部区文广旅局主办的为期4天的点亮海门之美文旅夜市在江海文化公园落下帷幕,近50个摊位带来的各式娱乐和美食,吸引了大批市民前来游玩,四天活动共接待3万人次。活动四天3万人次光顾点亮海门之美文旅夜市8月7日晚,由区委宣传部区文广旅局主办的为期4天的点亮海门之美文旅夜市在江海文化公园落下帷幕,近50个摊位带来的各式娱乐和美食,吸引了大批市民前来游玩,四天活动共接待3万人次。活动时下最IN的水上运动已至柘林,还不快来体验夏日炎炎,户外水上运动是市民朋友日常锻炼亲子嬉戏的首选。而谈起时下最IN最潮流的水上运动,SUB桨板必有一席之地。凭借易上手安全性高老少皆宜的优势,这项源于夏威夷的新运动成了水上运时下最IN的水上运动已至柘林,还不快来体验夏日炎炎,户外水上运动是市民朋友日常锻炼亲子嬉戏的首选。而谈起时下最IN最潮流的水上运动,SUB桨板必有一席之地。凭借易上手安全性高老少皆宜的优势,这项源于夏威夷的新运动成了水上运出门旅游欢乐多酒后驾车危险来大小新闻8月9日讯(YMG全媒体记者何晓波通讯员王锦升摄影报道)旅游在外美酒助兴,却因此酒驾得不偿失。8月8日,在莱山收费站附近,从安徽来烟旅游的王某某被查出酒驾,给旅途生活增添一出门旅游欢乐多酒后驾车危险来大小新闻8月9日讯(YMG全媒体记者何晓波通讯员王锦升摄影报道)旅游在外美酒助兴,却因此酒驾得不偿失。8月8日,在莱山收费站附近,从安徽来烟旅游的王某某被查出酒驾,给旅途生活增添一