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

神经网络变得轻松(第二部分)网络训练和测试

  内容概述 1. 定义问题 2. 神经网络模型项目 2.1. 判定输入层中神经元的数量 2.2. 设计隐藏层 2.3. 判定输出层中神经元的数量 3. 编程 3.1. 准备工作 3.2. 初始化类 3.3. 训练神经网络 3.4. 改进梯度计算方法 4. 测试 结束语 本文中用到的程序 概述
  在上一篇名为神经网络变得轻松的文章中,我们曾研究过利用 MQL5 配合完全连接的神经网络一起操作的 CNet 构造原理。 在本文中,我将演示一个示例,说明如何在 EA 中利用该类,并在实际条件下评估该类。
  1. 定义问题
  在开始创建智能交易系统之前,必须定义将为新神经网络设定的目标。 当然,金融市场上所有智能交易系统的共同目标是获利。 然而,此目的太笼统宽泛。 我们需要为神经网络指定更具体的任务。 甚至,我们需要了解如何评估神经网络的未来结果。
  另一个重要的时刻是,先前创建的 CNet 类使用了监督学习的原理,因此它需要标记数据作为训练集合。
  如果您查看价格图表,自然会希望在价格峰值时执行交易操作,这可以通过标准的比尔·威廉姆斯(Bill Williams)分形指标来示意。 而指标的问题在于,它会判断 3 根烛条的峰值,且产生的信号始终会延迟 1 根烛条,而这可能会产生相反的信号。 如果我们设置神经网络以判定第三根烛条形成之前的枢轴点,该怎么办? 这种方法至少会在交易方向移动有一根之前走势的烛条。
  这是指训练集合: 在正向递进中,我们会将当前行情状况输入到神经网络,并输出最后一根收盘烛条上提取的形成概率的评估。 对于逆向递进中,在下一根烛条形成之后,我们将检查前一根烛条上是否存在分形,并将输入结果按权重调整。
  为了评估网络运算的结果,我们可以使用均方预测误差,正确的分形预测的百分比,和无法识别的分形的百分比。
  现在我们需要判定哪些数据应输入到我们的神经网络中。 您还记得,当您尝试根据图表评估行情状况时所做的事情吗?
  首先,建议交易新手从图表中直观评估趋势方向。 因此,我们必须将有关价格变动的信息数字化,并将其输入到神经网络中。 我建议输入有关的开盘价和收盘价、最高价和最低价、交易量和形成时间的数据。
  另一种判定趋势的流行方法是使用振荡器指标。 此类指标操作很方便,因为指标会输出标准化数据。 我决定为本次实验准备四个标准指标:RCI,CCI,ATR 和 MACD,所有指标均带采用标准参数。 我在选择指标及其参数时,没有进行任何其他分析。
  有人可能会说利用指标是没有意义的,因为指标的数据是通过重新计算烛条的价格数据而建立的,我们已经将其输入到神经网络当中。 但这并非完全正确。 指标值是通过计算来自多根烛条的数据来判定的,从而可对所分析的样本进行一定程度的扩展。 神经网络训练过程将判定它们如何影响结果。
  为了能够评估行情动态,我们在一定的历史时期内将全部信息输入到神经网络之中。 2. 神经网络模型项目2.1. 判定输入层中神经元的数量
  此处,我们需要知晓输入层中神经元的数量。 为此,请评估每根烛条上的初始信息,然后将其乘以分析历史记录的深度。
  由于指标数据已经标准化,且指标缓冲区的相关数量已知,因此无需预处理指标数据(上述 4 个指标总共有 5 个值)。 因此,若要在输入层中接收这些指标,我们需要为每根所分析烛条创建 5 个神经元。
  烛条价格数据的情况略有不同。 从图表直观地判定趋势方向和强度时,我们首先分析烛条方向和大小。 只有在此之后,当我们要判定趋势方向,和可能的枢轴点时,我们要注意所分析品种的价位。 因此,有必要在把该数据输入到神经网络之前对其进行标准化。 我个人输入了所述烛条的开盘价与收盘价、最高价和最低价的差值。 在这种方法中,定义三个神经元就足够了,其中第一个神经元的符号判定烛条方向。
  有许多不同的资料论述了各种时间因素对货币波动的影响。 例如,季度线、周线和日线的动态差异,以及欧洲、美洲和亚洲的交易时段,均以不同的方式影响货币汇率。 若要分析这些因素,将烛条形成的月份、时刻和星期几输入进神经网络。 我特意将烛条形成的时间和日期分为几个部分,因为这可令神经网络能够泛化,并找到依赖性。
  另外,我们来包含有关成交量的信息。 如果您的经纪商提供真实的交易量数据,则指明这些交易量;否则指定即时报价的交易量。
  故此,为了应对每根烛条,我们需要 12 个神经元。 将此数字乘以所分析的历史深度,您可得到神经网络输入层的大小。 2.2. 设计隐藏层
  下一步是准备神经网络的隐藏层。 网络结构(层数和神经元数)的选择是最困难的任务之一。 单层感知器善于类的线性分离。 双层网络可跟踪非线性边界。 三层网络可以描述复杂的多连接区域。 当我们增加层数时,功能类别会扩展,但这会导致收敛性变差,和训练成本增加。 每层当中,神经元的数量必须满足功能的预期变化。 实际上,非常简单的网络无法在实际条件下按要求的精度模拟行为,而过于复杂的网络不仅会重复训练目标函数,还有噪声。
  在首篇文章中,我提到了 "5 个为什么" 方法。 现在,我建议继续此实验,并创建一个包含 4 个隐藏层的网络。 我将首个隐藏层中的神经元数量设置为 1000。 不过,也有可能根据分析周期的深度建立一些依赖关系。 遵照帕累托(Pareto)规则,我们将每个后续层中的神经元数量减少 70%。 此外,将遵循如下限制:隐藏层中的神经元数量不得少于 20。 2.3. 判定输出层中神经元的数量
  输出层当中神经元的数量取决于任务,及其解决方案。 若要解决回归问题,只需要一个神经元就能产生期望值即可。 为了解决分类问题,我们需要与期望的类数量相等的神经元 - 每个神经元将为分配给每个类的原始对象生成概率。 而在实际中,对象的类别由最大概率判定。
  对于我们的情况,我建议创建 2 个神经网络变体,并评估它们在实践中应对我们之问题的适用性。 在第一种情况下,输出层仅有一个神经元。 数值在 0.5...1.0 范围内与买入分形对应,而数值在 -0.5..-1.0 范围内与卖出信号对应,数值在 -0.5...0.5 范围内表示没有信号。 在此解决方案中,双曲正切用作激活函数 - 它的输出值范围为 -1.0 到 +1.0。
  在第二种情况下,将在输出层中创建 3 个神经元(买、卖、无信号)。 在这个变体中,我们来训练神经网络,从而获得范围为 0.0...1.0 的结果。 在此,结果就是分形出现的概率。信号将依据最大概率来判定,并根据含有最高概率的神经元的索引来判定信号的方向。 3. 编程3.1. 准备工作
  现在,到编程的时候了。 首先,加入所需的函数库: NeuroNet.mqh — 前一篇文章中创建神经网络的函数库 SymbolInfo.mqh — 接收品种数据的标准库 TimeSeries.mqh — 处理时间序列的标准库 Volumes.mqh — 接收交易量数据的标准库 Oscilators.mqh — 含有振荡器类的标准库 #include "NeuroNet.mqh" #include  #include  #include  #include 
  下一步是编写程序参数,通过它们来设置神经网络和指标参数。 //+------------------------------------------------------------------+ //|   input parameters                                               | //+------------------------------------------------------------------+ input int                  StudyPeriod =  10;            //Study period, years input uint                 HistoryBars =  20;            //Depth of history ENUM_TIMEFRAMES            TimeFrame   =  PERIOD_CURRENT; //--- input group                "---- RSI ----" input int                  RSIPeriod   =  14;            //Period input ENUM_APPLIED_PRICE   RSIPrice    =  PRICE_CLOSE;   //Applied price //--- input group                "---- CCI ----" input int                  CCIPeriod   =  14;            //Period input ENUM_APPLIED_PRICE   CCIPrice    =  PRICE_TYPICAL; //Applied price //--- input group                "---- ATR ----" input int                  ATRPeriod   =  14;            //Period //--- input group                "---- MACD ----" input int                  FastPeriod  =  12;            //Fast input int                  SlowPeriod  =  26;            //Slow input int                  SignalPeriod=  9;             //Signal input ENUM_APPLIED_PRICE   MACDPrice   =  PRICE_CLOSE;   //Applied price
  接下来,声明全局变量 - 稍后会讲解它们的用法。 CSymbolInfo         *Symb; CiOpen              *Open; CiClose             *Close; CiHigh              *High; CiLow               *Low; CiVolumes           *Volumes; CiTime              *Time; CNet                *Net; CArrayDouble        *TempData; CiRSI               *RSI; CiCCI               *CCI; CiATR               *ATR; CiMACD              *MACD; //--- double               dError; double               dUndefine; double               dForecast; double               dPrevSignal; datetime             dtStudied; bool                 bEventStudy;
  准备工作至此完成。 现在继续进行类的初始化。 3.2 初始化类
  类的初始化将在 OnInit 函数中执行。 首先,我们创建处理品种的 CSymbolInfo 类的实例,并更新有关图表品种的数据。 //+------------------------------------------------------------------+ //| Expert initialization function                                   | //+------------------------------------------------------------------+ int OnInit()   { //---    Symb=new CSymbolInfo();    if(CheckPointer(Symb)==POINTER_INVALID || !Symb.Name(_Symbol))       return INIT_FAILED;    Symb.Refresh();
  然后创建时间序列实例。 在您每次创建类实例时,请检查它是否已成功创建,并初始化。 如果发生错误,则以 INIT_FAILED 作为结果退出函数。    Open=new CiOpen();    if(CheckPointer(Open)==POINTER_INVALID || !Open.Create(Symb.Name(),TimeFrame))       return INIT_FAILED; //---    Close=new CiClose();    if(CheckPointer(Close)==POINTER_INVALID || !Close.Create(Symb.Name(),TimeFrame))       return INIT_FAILED; //---    High=new CiHigh();    if(CheckPointer(High)==POINTER_INVALID || !High.Create(Symb.Name(),TimeFrame))       return INIT_FAILED; //---    Low=new CiLow();    if(CheckPointer(Low)==POINTER_INVALID || !Low.Create(Symb.Name(),TimeFrame))       return INIT_FAILED; //---    Volumes=new CiVolumes();    if(CheckPointer(Volumes)==POINTER_INVALID || !Volumes.Create(Symb.Name(),TimeFrame,VOLUME_TICK))       return INIT_FAILED; //---    Time=new CiTime();    if(CheckPointer(Time)==POINTER_INVALID || !Time.Create(Symb.Name(),TimeFrame))       return INIT_FAILED;
  在此示例中采用了即时报价交易量。 若您希望采用真实交易量,则在调用 Volumes.Creare 方法时将 "VOLUME_TICK" 替换为 "VOLUME_REAL"。
  在声明了时间序列之后,创建类的实例,从而以类似方式使用指标。    RSI=new CiRSI();          if(CheckPointer(RSI)==POINTER_INVALID || !RSI.Create(Symb.Name(),TimeFrame,RSIPeriod,RSIPrice))       return INIT_FAILED; //---    CCI=new CiCCI();          if(CheckPointer(CCI)==POINTER_INVALID || !CCI.Create(Symb.Name(),TimeFrame,CCIPeriod,CCIPrice))       return INIT_FAILED; //---    ATR=new CiATR();          if(CheckPointer(ATR)==POINTER_INVALID || !ATR.Create(Symb.Name(),TimeFrame,ATRPeriod))       return INIT_FAILED; //---    MACD=new CiMACD();          if(CheckPointer(MACD)==POINTER_INVALID || !MACD.Create(Symb.Name(),TimeFrame,FastPeriod,SlowPeriod,SignalPeriod,MACDPrice))       return INIT_FAILED;
  现在我们可以直接利用神经网络类运作了。 首先,创建一个类的实例。 在 CNet 类初始化期间,构造函数参数会将引用传递给含有网络结构规范的数组。 请注意,网络训练过程当中会消耗计算资源,且会花费大量时间。 因此,每次重启之后,网络都是不正确的,需要训练。 此处是我如何操作的:首先,我在声明网络实例时未指定结构,然后尝试从本地存储加载先前已训练过的网络(文件名在 #define 中提供)。 #define FileName        Symb.Name()+"_"+EnumToString((ENUM_TIMEFRAMES)Period())+"_"+IntegerToString(HistoryBars,3)+"fr_ea" ... ... ... ...    Net=new CNet(NULL);    ResetLastError();    if(CheckPointer(Net)==POINTER_INVALID || !Net.Load(FileName+".nnw",dError,dUndefine,dForecast,dtStudied,false))      {       printf("%s - %d -> Error of read %s prev Net %d",__FUNCTION__,__LINE__,FileName+".nnw",GetLastError());
  如果无法加载先前已训练的数据,则会将消息打印到日志,指示错误代码,然后开始创建新的未经训练的网络。 首先,声明 CArrayInt 类的实例,并指定神经网络的结构。 元素的数量表示神经网络层的数量,而元素的数值表示相应层中神经元的数量。       CArrayInt *Topology=new CArrayInt();       if(CheckPointer(Topology)==POINTER_INVALID)          return INIT_FAILED;
  正如早前所提到的,我们在输入层中需要 12 个神经元来应对每根烛条。 因此,在第一个数组元素中,用 12 乘以所分析历史记录的深度。       if(!Topology.Add(HistoryBars*12))          return INIT_FAILED;
  然后定义隐藏层。 我们已判定在第一个隐藏层中将包括 4 个含 1000 个神经元的隐藏层。 然后,在后续的每个层中,神经元的数量将减少 70%,但每一层至少含有 20 个神经元。 数据将循环添加到数组当中。       int n=1000;       bool result=true;       for(int i=0;(i<4 && result);i++)         {          result=(Topology.Add(n) && result);          n=(int)MathMax(n*0.3,20);         }       if(!result)         {          delete Topology;          return INIT_FAILED;         }
  在输出层中指示 1 来构建回归模型。       if(!Topology.Add(1))          return INIT_FAILED;
  如果我们采用分类模型,则需要为输出神经元指定 3。
  接下来,删除先前创建的 CNet 类实例,并创建一个新实例,并在其中指明要创建的神经网络的结构。 创建新的神经网络实例后,删除网络结构的类,因为以后不会再用到它。       delete Net;       Net=new CNet(Topology);       delete Topology;       if(CheckPointer(Net)==POINTER_INVALID)          return INIT_FAILED;
  设置变量的初始值,以便收集统计数据: dError - 标准偏差(误差) dUndefine - 未定义分形的百分比 dForecast - 正确预测分形的百分比 dtStudied — 最后一根已训练烛条的日期。       dError=-1;       dUndefine=0;       dForecast=0;       dtStudied=0;      }
  不要忘记,只当没有先前训练过的神经网络,无需从本地存储加载的情况下,我们才需要设置神经网络结构,创建神经网络类的新实例,并初始化统计变量。
  在 OnInit 函数的末尾,创建 CArrayDouble() 类的实例,该实例用来与神经网络交换数据,并开始神经网络训练过程。
  我想在这里分享另一种解决方案。 MQL5 不支持异步函数调用。 如果我们从 OnInit 函数显式调用学习函数,则终端将误认为程序初始化过程尚未完成,直到训练完成。 这就是为什么我们要创建一个自定义事件,从 OnChartEvent 函数调用该训练函数,替代直接调用该函数的原因。 创建事件时,请在 lparam 参数中指定训练开始日期。 这种方法可令我们调用函数,并完成 OnInit 函数。    TempData=new CArrayDouble();    if(CheckPointer(TempData)==POINTER_INVALID)       return INIT_FAILED; //---    bEventStudy=EventChartCustom(ChartID(),1,(long)MathMax(0,MathMin(iTime(Symb.Name(),PERIOD_CURRENT,(int)(100*Net.recentAverageSmoothingFactor*(dForecast>=70 ? 1 : 10))),dtStudied)),0,"Init"); //---    return(INIT_SUCCEEDED);   } //+------------------------------------------------------------------+ //| ChartEvent function                                              | //+------------------------------------------------------------------+ void OnChartEvent(const int id,                   const long &lparam,                   const double &dparam,                   const string &sparam)   { //---    if(id==1001)      {       Train(lparam);       bEventStudy=false;       OnTick();      }   }
  不要忘记清除 OnDeinit 函数中的内存。 //+------------------------------------------------------------------+ //| Expert deinitialization function                                 | //+------------------------------------------------------------------+ void OnDeinit(const int reason)   { //---    if(CheckPointer(Symb)!=POINTER_INVALID)       delete Symb; //---    if(CheckPointer(Open)!=POINTER_INVALID)       delete Open; //---    if(CheckPointer(Close)!=POINTER_INVALID)       delete Close; //---    if(CheckPointer(High)!=POINTER_INVALID)       delete High; //---    if(CheckPointer(Low)!=POINTER_INVALID)       delete Low; //---    if(CheckPointer(Time)!=POINTER_INVALID)       delete Time; //---    if(CheckPointer(Volumes)!=POINTER_INVALID)       delete Volumes; //---    if(CheckPointer(RSI)!=POINTER_INVALID)       delete RSI; //---    if(CheckPointer(CCI)!=POINTER_INVALID)       delete CCI; //---    if(CheckPointer(ATR)!=POINTER_INVALID)       delete ATR; //---    if(CheckPointer(MACD)!=POINTER_INVALID)       delete MACD; //---    if(CheckPointer(Net)!=POINTER_INVALID)       delete Net;    if(CheckPointer(TempData)!=POINTER_INVALID)       delete TempData;   } 3.3. 训练神经网络
  为了训练神经网络,创建 Train 函数。 训练期的开始日期应作为参数传递给函数。 void Train(datetime StartTrainBar=0)
  在函数伊始声明局部变量: count - 学习期计数 prev_un - 前一学习期内未识别分形的百分比 prev_for - 前一学习期内分形正确"预测"的百分比 prev_er - 前一个学习期的误差 bar_time - 重新计算酒吧日期 stop - 用于跟踪强制程序终止调用的标志。    int count=0;    double prev_up=-1;    double prev_for=-1;    double prev_er=-1;    datetime bar_time=0;    bool stop=IsStopped();    MqlDateTime sTime;
  接下来,检查在函数参数中获得的日期是否未超过最初指定的训练周期。    MqlDateTime start_time;    TimeCurrent(start_time);    start_time.year-=StudyPeriod;    if(start_time.year<=0)       start_time.year=1900;    datetime st_time=StructToTime(start_time);    dtStudied=MathMax(StartTrainBar,st_time);
  神经网络训练将在 do-while 循环语句中实现。 在循环开始时,重新计算训练神经网络所需历史柱线数量,并保存先前的递次统计信息。    do      {       int bars=(int)MathMin(Bars(Symb.Name(),TimeFrame,dtStudied,TimeCurrent())+HistoryBars,Bars(Symb.Name(),TimeFrame));       prev_un=dUndefine;       prev_for=dForecast;       prev_er=dError;       ENUM_SIGNAL bar=Undefine;
  然后,调整缓冲区的大小,并加载必要的历史数据。       if(!Open.BufferResize(bars) || !Close.BufferResize(bars) || !High.BufferResize(bars) || !Low.BufferResize(bars) || !Time.BufferResize(bars) ||          !RSI.BufferResize(bars) || !CCI.BufferResize(bars) || !ATR.BufferResize(bars) || !MACD.BufferResize(bars) || !Volumes.BufferResize(bars))          break;       Open.Refresh(OBJ_ALL_PERIODS);       Close.Refresh(OBJ_ALL_PERIODS);       High.Refresh(OBJ_ALL_PERIODS);       Low.Refresh(OBJ_ALL_PERIODS);       Volumes.Refresh(OBJ_ALL_PERIODS);       Time.Refresh(OBJ_ALL_PERIODS);       RSI.Refresh(OBJ_ALL_PERIODS);       CCI.Refresh(OBJ_ALL_PERIODS);       ATR.Refresh(OBJ_ALL_PERIODS);       MACD.Refresh(OBJ_ALL_PERIODS);
  更新跟踪强制程序终止的标志,并声明一个新的标志,指示学习期已经过去(add_loop)。       stop=IsStopped();       bool add_loop=false;
  遍历所有历史数据来组织嵌套的训练循环。 在循环的伊始,检查历史数据是否已触及末尾。 如有必要,更改 add_loop 标志。 另外,在图表上用注释显示神经网络训练的当前状态。 这将有助于监视训练过程。       for(int i=(int)(bars-MathMax(HistoryBars,0)-1); i>=0 && !stop; i--)         {          if(i==0)             add_loop=true;          string s=StringFormat("Study -> Era %d -> %.2f -> Undefine %.2f%% foracast %.2f%%  %d of %d -> %.2f%%  Error %.2f %s -> %.2f",count,dError,dUndefine,dForecast,bars-i+1,bars,(double)(bars-i+1.0)/bars*100,Net.getRecentAverageError(),EnumToString(DoubleToSignal(dPrevSignal)),dPrevSignal);          Comment(s);
  然后检查循环的上一步是否已计算出预测的系统状态。 如果有,则沿正确值的方向调整权重。 为此,清除 TempData 数组的内容,检查在上一根烛条上是否分形已形成,然后向 TempData 数组添加正确的值(以下是在输出层中含有一个神经元的回归神经网络的代码)。 之后,调用神经网络的 backProp 方法,把 TempData 数组的引用作为参数传递。 更新 dForecast(正确预测分形的百分比)和 dUndefine(无法识别分形的百分比)中的统计数据。          if(i<(int)(bars-MathMax(HistoryBars,0)-1) && i>1 && Time.GetData(i)>dtStudied && dPrevSignal!=-2)            {             TempData.Clear();             bool sell=(High.GetData(i+2)bars)             continue; //---          for(int b=0; b<(int)HistoryBars; b++)            {             int bar_t=r+b;             double open=Open.GetData(bar_t);             TimeToStruct(Time.GetData(bar_t),sTime);             if(open==EMPTY_VALUE || !TempData.Add(Close.GetData(bar_t)-open) || !TempData.Add(High.GetData(bar_t)-open) || !TempData.Add(Low.GetData(bar_t)-open) ||                !TempData.Add(Volumes.Main(bar_t)/1000) || !TempData.Add(sTime.mon) || !TempData.Add(sTime.hour) || !TempData.Add(sTime.day_of_week) ||                !TempData.Add(RSI.Main(bar_t)) ||                !TempData.Add(CCI.Main(bar_t)) || !TempData.Add(ATR.Main(bar_t)) || !TempData.Add(MACD.Main(bar_t)) || !TempData.Add(MACD.Signal(bar_t)))                   break;            }          if(TempData.Total()<(int)HistoryBars*12)             break;
  准备好初始数据后,运行 feedForward 方法,并将神经网络结果写入 dPrevSignal 变量。 以下是在输出层中含有一个神经元的回归神经网络的代码。 在输出层中含有三个神经元的分类神经网络的代码随附于后。          Net.feedForward(TempData);          Net.getResults(TempData);          dPrevSignal=TempData[0];
  为了在图表上可视化神经网络的操作,显示最后 200 根蜡烛的预测分形的标签。          bar_time=Time.GetData(i);          if(i<200)            {             if(DoubleToSignal(dPrevSignal)==Undefine)                DeleteObject(bar_time);             else                DrawObject(bar_time,dPrevSignal,High.GetData(i),Low.GetData(i));            }
  在历史数据周期结束时,更新强制程序终止的标志。          stop=IsStopped();         }
  一旦在所有可用的历史数据上针对神经网络进行了训练,就可以增加训练期的计数,并将神经网络的当前状态保存到本地文件之中。 下次启动神经网络数据时,我们将会用到此数据。       if(add_loop)          count++;       if(!stop)         {          dError=Net.getRecentAverageError();          if(add_loop)            {             Net.Save(FileName+".nnw",dError,dUndefine,dForecast,dtStudied,false);             printf("Era %d -> error %.2f %% forecast %.2f",count,dError,dForecast);            }          }
  最后,指定退出训练循环的条件。 条件可以如下:接收信号表示所达目标高于预定级别以上的概率;达到目标误差参数;或在训练期之后,统计数据没有变化,或变化不大(训练停止在局部最小值处)。 您可以自行定义退出训练过程的条件。      }    while((!(DoubleToSignal(dPrevSignal)!=Undefine || dForecast>70) || !(dError<0.1 && MathAbs(dError-prev_er)<0.01 && MathAbs(dUndefine-prev_up)<0.1 && MathAbs(dForecast-prev_for)<0.1)) && !stop);
  在退出训练函数之前,请保存最后一根已训练烛条的时间。    if(count>0)      {       dtStudied=bar_time;      }   }  3.4. 改进梯度计算方法
  我想提请您注意,我在测试过程中发现的如下几点。 当训练神经网络时,在某些情况下,隐藏层神经元的权重系数不受控制地增加,这是因为超出了最大允许变量值,结果导致整个神经网络瘫痪了。 当随后的层错误要求神经元输出的数值,超出了激活函数可能的数值范围时,就会发生这种情况。 我找到的解决方案是标准化神经元的目标值。 经调整后的梯度计算方法代码如下所示。 void CNeuron::calcOutputGradients(double targetVals)   {    double delta=(targetVals>1 ? 1 : targetVals<-1 ? -1 : targetVals)-outputVal;    gradient=(delta!=0 ? delta*CNeuron::activationFunctionDerivative(targetVals) : 0);   }
  附件中提供了所有方法和函数的完整代码。 4. 测试
  在 H1 时间帧内,在 EURUSD 对上进行了神经网络的测试训练。 将 20 根烛条的数据输入到神经网络。 针对最近两年进行了训练。 为了检查结果,我在同一终端的两张图表上同时启动了这个智能交易系统:一个 EA 具有回归神经网络(分形 - 输出层中有 1 个神经元),另一个则是分类神经网络(Fractal_2 - 输出层中有 3 个神经元的分类)。
  第一个训练期是 12432 根柱线,历时 2 小时 20 分钟。 两种 EA 的表现相似,命中率刚超过 6%。
  第一个训练期强烈依赖于在初始阶段随机选择的神经网络的权重。
  经过 35 期的训练,统计数据的差异略有增加 - 回归神经网络模型的效果更好:
  数值
  回归神经网络
  分类神经网络
  根均方误差
  0.68
  0.78
  命中率
  12.68%
  11.22%
  未识别的分形
  20.22%
  24.65%
  测试结果表明,两种神经网络组织变体在训练时间和预测准确性方面产生的结果相似。 于此同时,获得的结果表明神经网络需要额外的时间和资源进行训练。 如果您希望分析神经网络的学习动态,请查看附件中每个学习期的屏幕截图。 结束语
  在本文中,我们研究了神经网络创建、训练和测试的过程。 获得的结果表明,这种技术有潜在的利用价值。 然而,神经网络训练过程会消耗大量计算资源,并会花费大量时间。 本文中用到的程序
  #
  发行
  类型
  说明
  ExpertsNeuroNet_DNG
  1
  Fractal.mq5   智能交易系统   一款含有回归神经网络(输出层中有 1 个神经元)的智能交易系统   2
  Fractal_2.mq5   智能交易系统   一款含有分类神经网络的智能交易系统(输出层中有 3 个神经元)   3
  NeuroNet.mqh   类库   创建神经网络(感知器)的类库   Files   4
  Fractal   目录   包含显示回归神经网络测试的屏幕截图   5
  Fractal_2   目录   包含显示分类神经网络测试的屏幕截图

偷拍性骚扰职场霸凌,这一部剧把女性职场问题都拍完了一餐馆内,猥琐男趁蹲下的功夫,把开着摄像头的手机滑到何悯鸿的裙下。幸好这一幕被余初晖看到,及时制止了偷拍行为。面对偷拍,余初晖没有像其他女生一样选择息事宁人,忍气吞声,而是大胆站了拜托古装剧的衣服都以汉服为标准,卷起来吧近几年的古装剧变得越来越流行,尤其是古偶剧几乎成为了很多新晋流量小花的首选。但是这些古偶要制造往往比较粗糙,哪怕是当红的女明星,服装道具都是一股影楼风。而相比之下,看看汉服圈子里的渣男徐开骋竟然是第二个罗志祥?最近徐开骋张天爱和古力娜扎的瓜想必大家都吃了吧?看看这热度,绝对是徐开骋这个N线小明星的人生巅峰了,当然不排除他以后做出更离谱的事。不得不感叹汪峰老师的法力无边,汪峰定律从来不会让曝朱单伟陈萌十一结婚,所有彩礼会超过陈亚男,婚礼将会举办两次这两天,全网都被朱单伟和陈萌拍摄婚纱照的视频刷屏,这次大衣哥儿子二婚可谓相当高调,不仅请了专业的摄影团队,而且全程在网上直播,热度程度堪比明星。陈萌首次出现在镜头面前完全不胆怯,相吴奇隆接刘诗诗下班!他礼服帅出新高度,刘诗诗连衣裙丝巾真贵气穿衣搭配本身,是一件极其复杂的事,毕竟合格的搭配,都需要注重搭配细节,如果只是通过单品,来体现出想要的风格,穿搭反而会显得更单一,但是选择了不同的配饰,搭配就会变得丰富多彩,甚至可玫瑰之战大结局丰盛逼走顾念宣布分手,方旭最后活出尊严没想到玫瑰之战迎来大结局,竟然狠狠刀了观众一把。本以为顾念和丰盛之间虽然有些小矛盾,但不至于到分手的地步。尤其是丰盛喜欢顾念多年,再加上顾念也终于坚定了自己的心思,选择了丰盛,一切大染坊19年过去,演员差距大,女主角沉了,配角成娱乐圈顶流娱乐圈是个神奇的地方,有人单凭一部剧,吃了大半辈子的红利,有人却在一战成名之后,迅速销声匿迹。2003年,一部讲述小乞丐成长为商界大亨一代传奇的影视著作,横空出世,直接包揽第24届新款小米手表通过3C认证,充电功率2。5WIT之家8月27日消息,8月11日,小米发布了新款智能手表小米手表S1Pro,首发1499元起。今日,又有了小米新手表的消息。据中国质量认证中心官网,小米一款型号为M2207W1的飞行汽车发展的战略意义与未来愿景高升力构型轻质结构高适应性的智能化陆空两栖平台技术,是飞行汽车平台技术的研究重点和主要发展方向(供图时的科技)飞行汽车是指面向低空智能交通和立体智慧交通的载运工具,主要包括电动垂直中国科大等在超冷原子量子模拟研究中获进展来源中国科学院中国科学技术大学潘建伟苑震生等与德国海德堡大学奥地利因斯布鲁克大学意大利特伦托大学的研究人员合作,在超冷原子量子模拟研究中取得进展。科研人员使用超冷原子量子模拟器,对女性航天员在太空中遇到生理期,经血会不会逆行?科学家给出答案我长大了要当一名宇航员!小时候,当宇航员可能也是你的梦想。随着人类科技的不断进步,我们已经有能力逃离地球的束缚,飞向外太空,去探索神秘的宇宙了。而且,我们都知道,国家对于宇航员的挑
女娲要把我捏成什么样,我才配穿低腰裤?席卷2022春夏潮流的原来是它!耳边吹过的风都告诉你2022不穿低腰是要被踢出都市丽人俱乐部的!KendallBellaHailey三姐妹从开年就官宣自己为低腰装代言人,下装几乎没孙铭徽因伤可能无缘最后一战,姚主席错失辽宁总冠军颁奖成遗憾本赛季的CBA联赛很有可能将会在4月26日成为最后的终结点,毕竟目前辽宁队以30的大比分优势手握赛点。而浙江广厦队在缺少两名主力大将胡金秋和赵岩昊的情况下,尽管力拼了三场,不但没有NBA季后赛独行侠胜爵士4月25日,达拉斯独行侠队球员东契奇在比赛中庆祝得分。新华社美联当日,在20212022赛季NBA季后赛西部首轮第五场比赛中,达拉斯独行侠队主场以102比77战胜犹他爵士队,以总比总比分04!篮网遭凯尔特人横扫出局篮网112116不敌凯尔特人,季后赛首轮04遭横扫出局。这是本年度NBA季后赛至今,唯一一个04横扫,谁也没想到,居然会是杜兰特和欧文承受了这一切。本场比赛,杜兰特拿下39分7篮板韩媒嘲讽国足把他们集体卖掉3次,也买不到半个孙兴慜近日,韩国媒体突然发文对中国足球进行了点评,尤其是对国足,韩媒尽显嘲讽之意。在韩国媒体看来,中国的国脚无人可以在欧洲联赛立足,将国足集体卖掉3次,也买不到半个孙兴慜,目前亚洲一哥孙1次助攻,正负值38,全场倒数第一!全明星控卫米切尔,就这?东契奇命中三分之后,他在场边跳起了舞蹈天王山,按理说是势均力敌针尖对麦芒的较量。但独行侠和爵士,变成了一边倒。这是意料之外的事。这场球看下来,我最大的观感就是不同篮球哲学之间的较量慌了,他慌了!32!还是那个味,替老里捏把汗,就问你怕没?输了,费城主场88103不敌猛龙,连输两场后,大比分被追至32,下一场将移师多伦多,就问费城怕了没有。登哥上一场在替补席鼓励气馁大帝的画面历历在目,说好的主场拿下系列赛,没想到主场除了罗曼雷恩斯外,WWE最看重的三位超级巨星,没有大布WWE冠军和环球冠军得主罗曼雷恩斯毫无疑问是WWE如今的头牌门面人物。现在他在WWE享受到的待遇可以和胡克霍根约翰塞纳巨石强森等历史巨星相提并论。不过他并不是WWE唯一看重的超级巨4年后再度问鼎!赵继伟208郭艾伦13分辽宁40广厦夺队史第二冠北京时间4月26日,CBA总决赛第4场,辽宁以10082大胜广厦,以40的大比分夺得总冠军。辽宁上一次夺得总冠军是在20172018赛季,这也是辽宁队史第2次捧起总冠军。辽宁队赵继99已成定局无悬念,FMVP成唯一看点,收下G4即可再捧总冠军奖杯2122赛季CBA联赛接近尾声,在总决赛中辽宁男篮以30大比分领先广厦男篮,7场4胜制系列赛极大可能在第4场结束后,提前画上句号。核心球员胡金秋和赵岩昊因伤病赛季报销,两大外援奥卡本赛季最令人失望的一支球队你以为我会说篮网吗?相较于篮网,主教练纳什的不成熟,蔡老板的任人唯亲,欧神仙的疫苗风波跟禁食,谋求最大利益交易哈登换来有心理疾病的席梦思,杜兰特全明星耍小脾气开始,我一直都对篮网持