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

神经网络变得轻松(第十二部分)舍弃

  内容概述 1. 舍弃:提升神经网络收敛性的一种方法 2. 实现 2.1. 为我们的模型创建新的类 2.2. 前馈 2.3. 反馈 2.4. 类的保存和加载方法 2.5. 神经网络基类的变化 3. 测试 结束语 参考 本文中用到的程序
  概述
  自从本系列文章开始以来,我们已在研究各种神经网络模型方面取得了长足的进步。 但学习过程总是在没有我们参与的情况下进行的。 与此同时,总是希望以某种方式帮助神经网络改进训练效果,这也可能会设计神经网络收敛。 在本文中,我们将研究一种名为舍弃的方法。
  1. 舍弃:提升神经网络收敛性的一种方法
  在训练神经网络时,会将大量特征馈入每个神经元,且很难评估每个独立特征的影响。 结果就是,某些神经元的误差会被其他神经元的调整值抹平,这些误差从而会在神经网络输出处累积。 这会导致训练在某个局部最小值处停止,且误差较大。 这种效应涉及特征检测器的协同适应,其中每个特征的影响会随环境而变化。 当环境分解成单独的特征,且可以分别评估每个特征的影响时,很可能会有相反的效果。
  2012年,多伦多大学的一组科学家提议从 学习过程 中随机排除一些神经元,作为复杂协同适应问题的解决方案 [12]。 训练中减少特征的数量,会增加每个特征的重要性,且特征的数量和质量构成的持续变化降低了它们协同适应的风险。 此方法称为舍弃。 有时拿这种方法的应用与决策树进行比较:通过舍弃一些神经元,我们在每次训练迭代中获得一个含有其自身权重的新神经网络。 根据组合规则,这样的网络具有很大的可变性。
  在 神经网络操作 期间评估所有特征和神经元,从而我们能得到所分析环境当前状态的最准确和独立的评估。
  作者在他们的文章(12)中谈及使用该方法来提高预训练模型品质的可能性。
  从数学的角度来看,我们可以这样描述这个过程:以给定的概率  p  从过程中舍弃每个独立的神经元。 换句话说,神经元能够参与神经网络学习过程的概率为  q = 1-p  。
  由含有正态分布的伪随机数生成器来判定将被排除的神经元列表。 这种方式可以实现最大程度地统一排除神经元。 我们将生成一个练习向量,其大小与输入序列相等。 向量中的  "1"  将会参与训练,且  "0"  则为排除元素。
  然而,排除已分析特征无疑会导致神经元激活函数输入量的减少。 为了补偿这种影响,我们将每个特征的值乘以系数   1/q  。 该系数将提升该数值,因为概率  q  始终在 0 到 1 之间。
  ,
  其中: d  — 舍弃结果向量的元素,
  q  — 在训练过程中用到的神经元概率,
  x  — 掩码向量的元素,
  n  — 输入序列的元素.
  在学习过程中的前馈验算过程中,误差梯度乘以上述函数的导数。 如您所见,在舍弃的情况下,反馈验算与前馈验算类似,均采用前馈验算的掩码向量。
  在神经网络的操作过程中,掩码向量用   "1"  填充,这允许数值在两个方向上平滑传递。
  实际上,系数  1/q  在整个训练期间都是恒定的,因此我们可以轻松地一次性计算该系数,然后将其代替 "1" 写入掩码张量当中。 因此,在每次训练迭代中,我们可以排除系数的重新计算操作,并将其乘以掩码 "1"。
  2. 实现
  如今,我们已研究过理论方面,我们来继续研究如何在函数库中实现此方法的变体。 我们遇到的第一件事是实现两种不同算法。 其一在训练过程需要,而第二个则用于生产。 相应地,我们需要根据每种独立情况,为神经元明确指出应采用的算法。 为此目的,我们将在基准神经元级别引入  bTrain  标志。 该标志值对于 训练  应设为  true ,而对于 测试  则设为  false 。 class CNeuronBaseOCL    :  public CObject   { protected:    bool               bTrain;             ///< Training Mode Flag
  以下辅助方法将控制该标志值。    virtual void      TrainMode(bool flag)             {  bTrain=flag;            }///< Set Training Mode Flag         virtual bool      TrainMode(void)                  {  return bTrain;          }///< Get Training Mode Flag
  该标志特意在基准神经元级别实现。 如此在以后开发时能够启用舍弃相关的代码。 2.1. 为我们的模型创建一个新类
  为了实现舍弃算法,我们来创建新的 CNeuronDropoutOCL 类,它将包含在我们的模型当中作为单独的层。 新类将直接继承自 CNeuronBaseOCL 基准神经元类。 在 受保护 模块中声明变量: OutProbability — 指定神经元的舍弃概率。 OutNumber — 神经元的舍弃数量。 dInitValue — 掩码向量初始化值;在本文的理论部分,该系数被指定为  1/q 。
  另外,声明两个指向类的指针: DropOutMultiplier — 舍弃向量。 PrevLayer — 指向上一层对象的指针;它在测试和实际应用时会用到。 class CNeuronDropoutOCL    :  public   CNeuronBaseOCL   { protected:    CNeuronBaseOCL    *PrevLayer;    double            OutProbability;    double            OutNumber;    CBufferDouble     *DropOutMultiplier;    double            dInitValue; //---    virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL);               ///<brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previous layer.    virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) {return true;}        ///< Method for updating weights.@param NeuronOCL Pointer to previous layer. //---    int               RND(void)   { xor128; return (int)((double)(Neurons()-1)/UINT_MAX*rnd_w);  }   ///< Generates a random neuron position to turn off  public:                      CNeuronDropoutOCL(void);                     ~CNeuronDropoutOCL(void); //---    virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons,double out_prob, ENUM_OPTIMIZATION optimization_type);     ///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer #param[in] out_prob Probability of neurons shutdown @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations. //---    virtual int       getOutputIndex(void)          {  return (bTrain ? Output.GetIndex() : PrevLayer.getOutputIndex());             }  ///< Get index of output buffer @return Index    virtual int       getGradientIndex(void)        {  return (bTrain ? Gradient.GetIndex() : PrevLayer.getGradientIndex());          }  ///< Get index of gradient buffer @return Index    //---    virtual int       getOutputVal(double &values[])   {  return (bTrain ? Output.GetData(values) : PrevLayer.getOutputVal(values)); }  ///< Get values of output buffer @param[out] values Array of data @return number of items    virtual int       getOutputVal(CArrayDouble *values)   {  return (bTrain ? Output.GetData(values) : PrevLayer.getOutputVal(values)); }  ///< Get values of output buffer @param[out] values Array of data @return number of items    virtual int       getGradient(double &values[])    {  return (bTrain ? Gradient.GetData(values) : PrevLayer.getGradient(values));    }  ///< Get values of gradient buffer @param[out] values Array of data @return number of items    virtual CBufferDouble   *getOutput(void)           {  return (bTrain ? Output : PrevLayer.getOutput());      }                 ///< Get pointer of output buffer @return Pointer to object    virtual CBufferDouble   *getGradient(void)         {  return (bTrain ? Gradient : PrevLayer.getGradient());  }                 ///< Get pointer of gradient buffer @return Pointer to object //---    virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL);          ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.    //---    virtual bool      Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation    virtual bool      Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation //---    virtual int       Type(void)        const                      {  return defNeuronDropoutOCL;                }///< Identificator of class.@return Type of class   };
  您必须熟悉类方法的清单,因为它们都会覆盖父类的方法。 唯一排除在外的是 RND 方法,它用来生成均匀分布的伪随机数。 在文章的第十三部分中已讲述过该方法的算法。 在我们的神经网络里,为了确保所有对象中数值的最大可能随机性,伪随机序列生成器在实现时以宏替换来定义全局变量。 #define xor128 rnd_t=(rnd_x^(rnd_x<<11));                 rnd_x=rnd_y;                 rnd_y=rnd_z;                 rnd_z=rnd_w;                 rnd_w=(rnd_w^(rnd_w>>19))^(rnd_t^(rnd_t>>8)) uint rnd_x=MathRand(), rnd_y=MathRand(), rnd_z=MathRand(), rnd_w=MathRand(), rnd_t=0;
  所提议算法将生成一个范围在 [0,UINT_MAX=4294967295] 内的整数序列。 因此,在伪随机序列生成器方法中,宏替换执行之后,将结果值常规化为序列的大小。 int               RND(void)   { xor128; return (int)((double)(Neurons()-1)/UINT_MAX*rnd_w);  }
  如果您阅读过本系列中的早前文章,您可能已经注意到,在以前的版本中,我们没有覆盖来自其他对象的操控类数据缓冲区的方法。 当神经元访问上一层或下一层的数据时,这些方法可在神经网络的各层之间交换数据。
  选择该解决方案是为了在实际应用中优化神经网络的运行。 不要忘记仅在神经网络训练时才会用到舍弃层。 在测试和以后的应用期间,会禁用此算法。 通过覆盖数据缓冲区的访问方法,我们启用略过舍弃层。 所有被覆盖的方法都应遵循相同的原理。 取代复制数据,我们实现了用上一层缓冲区替换舍弃层缓冲区。 因此,在以后的操作期间,含有舍弃层的神经网络在速度上可比没有舍弃层的类似网络,而我们在训练阶段已获得了神经元舍弃的所有优势。 virtual int       getOutputIndex(void)     {  return (bTrain ? Output.GetIndex() : PrevLayer.getOutputIndex());      }
  在附件中可找到所有类方法的完整代码。 2.2. 前馈
  传统上,我们在 feedForward 方法中实现前馈验算。 在方法伊始,检查接收到的指向神经网络上一层的指针,和指向 OpenCL 对象的指针的有效性。 此后,保存上一层所用的激活函数,和指向上一层对象的指针。 对于神经网络实际操作模式,舍弃层的前馈验算到此结束。 以后尝试从下一层访问该层将激活上述替换数据缓冲区的机制。 bool CNeuronDropoutOCL::feedForward(CNeuronBaseOCL *NeuronOCL)   {    if(CheckPointer(OpenCL)==POINTER_INVALID || CheckPointer(NeuronOCL)==POINTER_INVALID)       return false; //---    activation=(ENUM_ACTIVATION)NeuronOCL.Activation();    PrevLayer=NeuronOCL;    if(!bTrain)       return true;
  后续迭代仅与神经网络训练模式相关。 首先,生成一个掩码向量,在其中,我们需定义在此步骤中舍弃的神经元。 将掩码写入 DropOutMultiplier 缓冲区中,检查之前创建对象的可用性,并在必要时创建一个新对象。 用初始值初始化缓冲区。 为了降低计算量,我们以递增的因子  1/q  来初始化缓冲区。    if(CheckPointer(DropOutMultiplier)==POINTER_INVALID)       DropOutMultiplier=new CBufferDouble();    if(!DropOutMultiplier.BufferInit(NeuronOCL.Neurons(),dInitValue))       return false;    for(int i=0;i0 ? 1 : 0);
  接下来,指示初始数据缓冲区和变量,并启动内核加以执行。    if(!OpenCL.SetArgumentBuffer(def_k_Dropout,def_k_dout_input,NeuronOCL.getOutputIndex()))       return false;    if(!OpenCL.SetArgumentBuffer(def_k_Dropout,def_k_dout_map,DropOutMultiplier.GetIndex()))       return false;    if(!OpenCL.SetArgumentBuffer(def_k_Dropout,def_k_dout_out,Output.GetIndex()))       return false;    if(!OpenCL.SetArgument(def_k_Dropout,def_k_dout_dimension,Neurons()))       return false;    ResetLastError();    if(!OpenCL.Execute(def_k_Dropout,1,global_work_offset,global_work_size))      {       printf("Error of execution kernel Dropout: %d",GetLastError());       return false;      }
  在方法的最后得到内核执行操作的结果。 在此,掩码缓冲区已从 GPU 内存中删除。    if(!Output.BufferRead())       return false;    DropOutMultiplier.BufferFree(); //---    return true;   }
  完成操作后,以  true  退出方法。
  如果不考虑 GPU 端的操作,前馈方法的描述将是不完整的。 这是内核代码。 __kernel void Dropout (__global double *inputs,    ///<[in] Input matrix                         __global double *map,      ///<[in] Dropout map matrix                         __global double *out,      ///<[out] Output matrix                         int dimension              ///< Dimension of matrix                         )
  内核从参数里接收指向两个含有初始数据的输入张量的指针,和结果张量,以及向量的大小。
  在内核代码中,根据线程编号判定需要相乘的元素。 之后,代码被分为两条分支。 第一条分支是主要分支:运用向量运算将四个连续的元素相乘,并将得到的数据写入结果缓冲区的相应元素。   {    const int i=get_global_id(0)*4;    if(i+30 ? 1 : 0);    if(!OpenCL.SetArgumentBuffer(def_k_Dropout,def_k_dout_input,Gradient.GetIndex()))       return false;    if(!OpenCL.SetArgumentBuffer(def_k_Dropout,def_k_dout_map,DropOutMultiplier.GetIndex()))       return false;    if(!OpenCL.SetArgumentBuffer(def_k_Dropout,def_k_dout_out,NeuronOCL.getGradientIndex()))       return false;    if(!OpenCL.SetArgument(def_k_Dropout,def_k_dout_dimension,Neurons()))       return false;    ResetLastError();    if(!OpenCL.Execute(def_k_Dropout,1,global_work_offset,global_work_size))      {       printf("Error of execution kernel Dropout: %d",GetLastError());       return false;      }    if(!NeuronOCL.getGradient().BufferRead())       return false;    DropOutMultiplier.BufferFree(); //---    return true;   }
  附件中提供了所有类及其方法的完整代码。
  2.4. 数据保存和加载方法
  我们来看一下保存和加载舍弃神经层对象的方法。 无需保存掩码缓冲区对象,因为在每个训练周期都会生成新的掩码。 仅在 CNeuronDropoutOCL 类的初始化方法中添加了一个变量:应加以保存的排除神经元的概率。
  在  Save  方法中,我们将调用父类的相关方法。 成功完成后,我们将保存给定的神经元舍弃概率。 bool CNeuronDropoutOCL::Save(const int file_handle)   {    if(!CNeuronBaseOCL::Save(file_handle))       return false; //---    if(FileWriteDouble(file_handle,OutProbability)<=0)       return false; //---    return true;   }
  在  Load  方法中,我们将从硬盘读取数据,并还原该类的所有元素。 因此,该方法算法比 Save 算法复杂一些。
  与类的保存方法相似,我们调用父类当中的同名方法。 完成后,计算神经元舍弃的概率。 如此即完成了保存方法,但是我们需要复原缺失的元素。 根据神经元舍弃的概率,我们计算需要排除的神经元数量,和递增系数值,该值也用作初始化掩蔽向量的值。 bool CNeuronDropoutOCL::Load(const int file_handle)   {    if(!CNeuronBaseOCL::Load(file_handle))       return false; //---    OutProbability=FileReadDouble(file_handle);    OutNumber=(int)(Neurons()*OutProbability);    dInitValue=1/(1-OutProbability);    if(CheckPointer(DropOutMultiplier)==POINTER_INVALID)       DropOutMultiplier=new CBufferDouble();    if(!DropOutMultiplier.BufferInit(Neurons()+1,dInitValue))       return false; //---    return true;   }
  现在,计算完毕之后,我们可以复原掩码向量。 检查指向 DropOutMultiplier 中数据缓冲区对象的指针的有效性,并在必要时创建一个新对象。 然后采用初始值来初始化掩码缓冲区。 2.5. 神经网络基类的变化
  同样,应将新类正确添加到函数库操作中。 我们从声明操控新内核的宏替换开始。 另外,我们需要为新类设置标识常量。 #define def_k_Dropout               23    ///< Index of the kernel for Dropout process (#Dropout) #define def_k_dout_input            0     ///< Inputs Tensor #define def_k_dout_map              1     ///< Map Tensor #define def_k_dout_out              2     ///< Out Tensor #define def_k_dout_dimension        3     ///< Dimension of Inputs  #define defNeuronDropoutOCL   0x7890      ///=m_data_max)       return false; //---    bool result=false;    CNeuronBase *temp=NULL;    CNeuronProof *temp_p=NULL;    CNeuronBaseOCL *temp_ocl=NULL;    CNeuronConvOCL *temp_con_ocl=NULL;    CNeuronAttentionOCL *temp_at_ocl=NULL;    CNeuronMLMHAttentionOCL *temp_mlat_ocl=NULL;    CNeuronDropoutOCL *temp_drop_ocl=NULL;    if(iFileHandle<=0)      {       temp=new CNeuron();       if(CheckPointer(temp)==POINTER_INVALID || !temp.Init(iOutputs,index,SGD))          return false;       result=true;      }    else      {       int type=FileReadInteger(iFileHandle);       switch(type)         {          case  defNeuron:             temp=new CNeuron();             if(CheckPointer(temp)==POINTER_INVALID)                result=false;             result=temp.Init(iOutputs,index,ADAM);             break;          case  defNeuronProof:             temp_p=new CNeuronProof();             if(CheckPointer(temp_p)==POINTER_INVALID)                result=false;             if(temp_p.Init(iOutputs,index,1,1,1,ADAM))               {                temp=temp_p;                result=true;               }             break;          case  defNeuronConv:             temp_p=new CNeuronConv();             if(CheckPointer(temp_p)==POINTER_INVALID)                result=false;             if(temp_p.Init(iOutputs,index,1,1,1,ADAM))               {                temp=temp_p;                result=true;               }             break;          case  defNeuronLSTM:             temp_p=new CNeuronLSTM();             if(CheckPointer(temp_p)==POINTER_INVALID)                result=false;             if(temp_p.Init(iOutputs,index,1,1,1,ADAM))               {                temp=temp_p;                result=true;               }             break;          case  defNeuronBaseOCL:             if(CheckPointer(OpenCL)==POINTER_INVALID)                return false;             temp_ocl=new CNeuronBaseOCL();             if(CheckPointer(temp_ocl)==POINTER_INVALID)                result=false;             if(temp_ocl.Init(iOutputs,index,OpenCL,1,ADAM))               {                m_data[index]=temp_ocl;                return true;               }             break;          case  defNeuronConvOCL:             if(CheckPointer(OpenCL)==POINTER_INVALID)                return false;             temp_con_ocl=new CNeuronConvOCL();             if(CheckPointer(temp_con_ocl)==POINTER_INVALID)                result=false;             if(temp_con_ocl.Init(iOutputs,index,OpenCL,1,1,1,1,ADAM))               {                m_data[index]=temp_con_ocl;                return true;               }             break;          case  defNeuronAttentionOCL:             if(CheckPointer(OpenCL)==POINTER_INVALID)                return false;             temp_at_ocl=new CNeuronAttentionOCL();             if(CheckPointer(temp_at_ocl)==POINTER_INVALID)                result=false;             if(temp_at_ocl.Init(iOutputs,index,OpenCL,1,1,ADAM))               {                m_data[index]=temp_at_ocl;                return true;               }             break;          case  defNeuronMHAttentionOCL:             if(CheckPointer(OpenCL)==POINTER_INVALID)                return false;             temp_at_ocl=new CNeuronMHAttentionOCL();             if(CheckPointer(temp_at_ocl)==POINTER_INVALID)                result=false;             if(temp_at_ocl.Init(iOutputs,index,OpenCL,1,1,ADAM))               {                m_data[index]=temp_at_ocl;                return true;               }             break;          case  defNeuronMLMHAttentionOCL:             if(CheckPointer(OpenCL)==POINTER_INVALID)                return false;             temp_mlat_ocl=new CNeuronMLMHAttentionOCL();             if(CheckPointer(temp_mlat_ocl)==POINTER_INVALID)                result=false;             if(temp_mlat_ocl.Init(iOutputs,index,OpenCL,1,1,1,1,0,ADAM))               {                m_data[index]=temp_mlat_ocl;                return true;               }             break;          case  defNeuronDropoutOCL:             if(CheckPointer(OpenCL)==POINTER_INVALID)                return false;             temp_drop_ocl=new CNeuronDropoutOCL();             if(CheckPointer(temp_drop_ocl)==POINTER_INVALID)                result=false;             if(temp_drop_ocl.Init(iOutputs,index,OpenCL,1,0.1,ADAM))               {                m_data[index]=temp_drop_ocl;                return true;               }             break;          default:             result=false;             break;         }      }    if(result)       m_data[index]=temp; //---    return (result);   }
  新类应添加到 CNeuronBaseOCL 基类的调度程序方法当中。
  前馈验算 CNeuronBaseOCL::FeedForward。 bool CNeuronBaseOCL::FeedForward(CObject *SourceObject)   {    if(CheckPointer(SourceObject)==POINTER_INVALID)       return false; //---    CNeuronBaseOCL *temp=NULL;    switch(SourceObject.Type())      {       case defNeuronBaseOCL:       case defNeuronConvOCL:       case defNeuronAttentionOCL:       case defNeuronMHAttentionOCL:       case defNeuronMLMHAttentionOCL:       case defNeuronDropoutOCL:          temp=SourceObject;          return feedForward(temp);          break;      } //---    return false;   }
  误差梯度传播方法 CNeuronBaseOCL::calcHiddenGradients。 bool CNeuronBaseOCL::calcHiddenGradients(CObject *TargetObject)   {    if(CheckPointer(TargetObject)==POINTER_INVALID)       return false; //---    CNeuronBaseOCL *temp=NULL;    CNeuronAttentionOCL *at=NULL;    CNeuronMLMHAttentionOCL *mlat=NULL;    CNeuronConvOCL *conv=NULL;    CNeuronDropoutOCL *dropout=NULL;    switch(TargetObject.Type())      {       case defNeuronBaseOCL:          temp=TargetObject;          return calcHiddenGradients(temp);          break;       case defNeuronConvOCL:          conv=TargetObject;          temp=GetPointer(this);          return conv.calcInputGradients(temp);          break;       case defNeuronAttentionOCL:       case defNeuronMHAttentionOCL:          at=TargetObject;          temp=GetPointer(this);          return at.calcInputGradients(temp);          break;       case defNeuronMLMHAttentionOCL:          mlat=TargetObject;          temp=GetPointer(this);          return mlat.calcInputGradients(temp);          break;       case defNeuronDropoutOCL:          dropout=TargetObject;          temp=GetPointer(this);          return dropout.calcInputGradients(temp);          break;      } //---    return false;   }
  而且,令人惊讶的是,此处是权重更新方法 CNeuronBaseOCL::UpdateInputWeights。 bool CNeuronBaseOCL::UpdateInputWeights(CObject *SourceObject)   {    if(CheckPointer(SourceObject)==POINTER_INVALID)       return false; //---    CNeuronBaseOCL *temp=NULL;    switch(SourceObject.Type())      {       case defNeuronBaseOCL:       case defNeuronConvOCL:       case defNeuronAttentionOCL:       case defNeuronMHAttentionOCL:       case defNeuronMLMHAttentionOCL:       case defNeuronDropoutOCL:          temp=SourceObject;          return updateInputWeights(temp);          break;      } //---    return false;   }
  即使上述修改看起来很小或微不足道,但即使缺少了其中之一,也会导致整个神经网络的错误操作。
  附件中提供了所有类及其方法的完整代码。
  3. 测试
  为了保持一致,我们将借用文章第十一部分中的智能交易系统,并在其中添加了 4 个舍弃层: 1 个位于初始数据之后, 1 个位于嵌入代码之后, 1 个位于关注模块之后, 1 个位于完全连接层之后。
  下面的代码描述了神经网络的结构。       //--- 0       CLayerDescription *desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=(int)HistoryBars*12;       desc.type=defNeuronBaseOCL;       desc.optimization=ADAM;       desc.activation=TANH;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 1       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=(int)HistoryBars*12;       desc.type=defNeuronDropoutOCL;       desc.probability=0.2;       desc.optimization=ADAM;       desc.activation=TANH;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 2       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=(int)HistoryBars;       desc.type=defNeuronConvOCL;       desc.window=12;       desc.step=12;       desc.window_out=24;       desc.optimization=ADAM;       desc.activation=SIGMOID;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 3       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=(int)HistoryBars;       desc.type=defNeuronDropoutOCL;       desc.probability=0.2;       desc.optimization=ADAM;       desc.activation=SIGMOID;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 4       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=(int)HistoryBars;       desc.type=defNeuronMLMHAttentionOCL;       desc.window=24;       desc.window_out=4;       desc.step=8;  //heads       desc.layers=5;       desc.optimization=ADAM;       desc.activation=SIGMOID;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 5       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=(int)HistoryBars;       desc.type=defNeuronDropoutOCL;       desc.probability=0.2;       desc.optimization=ADAM;       desc.activation=SIGMOID;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 6       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=200;       desc.type=defNeuron;       desc.activation=TANH;       desc.optimization=ADAM;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 7       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=200;       desc.type=defNeuronDropoutOCL;       desc.probability=0.2;       desc.optimization=ADAM;       desc.activation=TANH;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 8       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=200;       desc.type=defNeuron;       desc.activation=TANH;       desc.optimization=ADAM;       if(!Topology.Add(desc))          return INIT_FAILED;       //--- 9       desc=new CLayerDescription();       if(CheckPointer(desc)==POINTER_INVALID)          return INIT_FAILED;       desc.count=3;       desc.type=defNeuron;       desc.activation=SIGMOID;       desc.optimization=ADAM;
  智能交易系统已基于 EURUSD,H1 时间帧进行了测试,最后 20 根烛条的历史数据被输入到神经网络中。 基于相似数据集测试所有体系结构,可以最大程度地减少外部因素的影响,并可评估相似条件下各种体系结构的性能。
  通过比较含有舍弃和不含有舍弃的两个神经网络学习图表,我们可看到神经网络误差曲线的前 30 个迭代几乎是平行的,而没有舍弃的神经网络则展示出更好的结果。 但是在第 33 个迭代之后,采用舍弃的智能交易系统有所降低。 在第 35 迭代之后,舍弃表现出最好的结果,其有误差降低的趋势。 没有舍弃的智能交易系统会把误差持续保持在同一水平。
  错失的形态图表还表明,采用舍弃技术的智能交易系统的效果更好。 该图表提供了更多详细信息。 采用舍弃的智能交易系统立即展示出差距缩小的趋势。 与之对比,没有舍弃的智能交易系统会逐渐增加错失形态区域。
  两款智能交易系统的预测命中图表非常接近。 经过 44 个迭代的训练,带有舍弃的 EA 仅提升了 0.5%。
  结束语
  在本文中,我们开始研究提升神经网络收敛性的方法,并体验其中一种方法,即舍弃。 该方法已被加入我们以前的智能交易系统之一。 此方法的效率已展示在 EA 测试当中。 当然,利用这种方法会增加神经网络的训练成本。 但这些成本会被最终结果的效率提高所掩盖。
  我邀请所有人尝试这种方法,并评估其有效性。
  参考神经网络变得轻松 神经网络变得轻松(第二部分):网络训练和测试 神经网络变得轻松(第三部分):卷积网络 神经网络变得轻松(第四部分):循环网络 神经网络变得轻松(第五部分):OpenCL 中的多线程计算 神经网络变得轻松(第六部分):神经网络学习率实验 神经网络变得轻松(第七部分):自适应优化方法 神经网络变得轻松(第八部分):关注机制 神经网络变得轻松(第九部分):操作归档 神经网络变得轻松(第十部分):多目击者关注 神经网络变得轻松(第十一部分):自 GPT 获取 通过防止特征检测器的协同适应来改善神经网络 统计评估
  …
  本文中用到的程序
  #
  发行
  类型
  说明
  1
  Fractal_OCL_AttentionMLMH.mq5   智能交易系统   采用 GTP 架构的分类神经网络(输出层中有 3 个神经元)和 5 个关注层的智能交易系统   2
  Fractal_OCL_AttentionMLMH_d.mq5   智能交易系统   采用 GTP 架构的分类神经网络(输出层中有 3 个神经元)和 5 个关注层的智能交易系统 + 舍弃   3
  NeuroNet.mqh   类库   用于创建神经网络的类库   4
  NeuroNet.cl   代码库   OpenCL 程序代码库   5
  NN.chm   HTML 帮助   一个编译后的函数库帮助 CHM 文件。

机构调研驱动实证佳缘科技A股市场机构羊群效应和散户化倾向十分明显,机构调研的动机无非是了解上市公司之前尚未公开的一些信息,为其股票买入或者卖出股票做出参考。结论1每个机构有一套自己的投资体系和选股模型,买人民币升值逼近7元大关,货币升值和货币贬值,哪一个更有利美元爆了,人民币不是我干的!11月14日,1美元对人民币7。0899元,逼近7元大关,汇率创17年来最大单日涨幅。大多数人都觉得,人民币升值有利于进口,但不利于企业出口,无所谓升值墨西哥队世界杯名单希门尼斯奥乔亚领衔小豌豆落选替补门将40岁北京时间11月15日,墨西哥队公布了参加卡塔尔世界杯的26人大名单,英超射手劳尔希门尼斯那不勒斯前锋洛萨诺领衔,37岁的老门将奥乔亚第五次征战世界杯,该队替补门将塔拉韦拉甚至以40三步交易,湖人阵容直冲总冠军!詹姆斯永远只会羡慕别人队友三步交易,湖人阵容直冲总冠军!詹姆斯永远只会羡慕别人队友老詹的能力确实是下滑了毕竟年龄摆在那但是现在这个小球时代没有投篮能力的人还配做为持球核心?湖人需要的是锋线和三分准的球员靠着广州平大连背后降级成定局,三豪门瓜分四干将,韦世豪没人要广州1比1大连,没拿3分基本宣告本赛季保级失败!原因有三一是积分差距,落后长江4分,广州城1分。二是赛程不利。马上打深圳,深圳保级未果还得血拼,其余对手都争四强,河南成都北京,还有双十一的喜与悲传统购物节何去何从?尽管和以往一样,在双十一来临前,由于惯性作用,物流开始显现紧张。但购物节后,却发现今年的双十一同往年相比正在失去热度。双十一的数字看上去像4根棍子,如今,双十一购物节就像棍子一样冷70个大中城市房价跌涨真相,有城市连跌15个月,有城市在悄悄涨尽管2022年以来,各地不断释放楼市松绑政策,一阵又一针的强心剂,但是市场并不买账。房企躺平,没钱赚,盖房子意愿不大。打工人躺平,赚钱难,房价跌,房屋质量问题多,万一运气不好买到烂监狱服刑是不幸,也是万幸没有人愿意主动去监狱服刑,除非外面水深火热的生活还不如监狱里来得轻松。很多人把锒铛入狱视为人生的重大滑铁卢,十分贴切。我们当然可以找出一百种监狱服刑的痛苦,但是不是存在另一种可能,童年,犹如一弯秋月,依旧挂在遥远的天边头条创作挑战赛童年犹如一弯秋月依旧挂在遥远的天边薰香了思念薰香了久违的爱恋它记录着生命的成长承载了逝去的流年那年那月那天早已变了容颜过去了的童年依然有一种熟悉的亲切感往事如同书本中女主聊天记录曝光,打工挣钱供她学习有网友晒出与陈培瑶大学同学的聊天记录,该同学说陈培瑶跟他是室友,睡在下铺,陈培瑶读的是本科,而女生是专科,两年制那种。同学说女生很容易动感情,只要谁对她好,她就跟谁在一起。两人谈恋习近平会见南非总统拉马福萨丨来源新华社当地时间11月15日下午,国家主席习近平在印度尼西亚巴厘岛会见南非总统拉马福萨。新华社记者申宏摄当地时间11月15日下午,国家主席习近平在巴厘岛会见南非总统拉马福萨。习
为什么染了黑头发近段时间就不能染其他颜色了?如果给你讲色素粒子含量表你可能不一定能听懂,如果用一张表,把用数字变成大白话,你瞬间就懂了。这张图告诉你深色可以盖住浅色,浅色盖不住深色。如果你用四万以下的任何数字去减四万,排除负联想称得上是民族品牌吗?你有没有买过联想的产品?以前是,现在己变了味道,买过联想的笔记本电脑,体验很不好,服务很差。联想是国际品牌!我买过好几台联想了!联想曾经是民族品牌。联想最早的电脑和联想汉卡我都用过,几年前开始至今,我不用刘诗雯不出战,导致1比3输了江苏,是伤痛还是保存实力?刘诗雯不出战,肯定有因,我认为原因主要有1,团体赛,各队抽鉴,分为A,B,C,D四组,每组内各队实行循环赛,从今日广东队(刘诗雯所在),江苏队比赛的人员大名单中就没有小枣,所以小枣中国男篮还能回到姚明时代的实力吗?未来十年没有希望,姚明那个时代除了姚明在中锋位置上鹤立鸡群外,外线的朱芳雨王仕鹏也是准的一批,再加上王治郅阿莲刘炜,能打赢斯洛文尼亚和德国和西班牙打进加时,目前这批人也就是想想而已WTT澳门冠军赛的赛程已经出炉了,预测本届比赛的各项冠亚军?wtt冠军赛澳门站比赛将于本月中旬开打,马龙许昕刘诗雯三位老将都会复出参赛,此外樊振东王楚钦陈梦孙颖莎王曼昱等人也会参赛,国乒将派出全主力阵容。从目前已经公布的赛程来看,比赛将于1天津女排轻松夺冠,联赛实力独自一档,这有利于女排联赛发展吗?首先祝贺天津女排夺得联赛冠军,当这个冠军成色不足,就因为排协的一道纸令单外援政策还有中国女排优秀队员不知何因加盟天津,形成了女排联赛天津一支独大,即没有开打就知道冠军归属。也使得其北京理工大学和西北工业大学同属工信部直属高校,哪所学校实力强些?回顾以往我国高等教育的发展实际来看,有很多高校团体,比如国防七子建筑老八校等,其中国防七子在国防领域尤为著名,也构成了我国国防领域中高等教育的最强实力。根据相关资料显示,我国国防七怎么看待广西在第十四届全运会上的倒数战绩?第十四届全运会,广西代表队何时能破金?目前来看,广西代表队处境尴尬。在广西周围的省份,全运会开幕至今只有广西代表队一金未得,只夺得3银2铜,排在总奖牌榜倒数第三位,仅高于青海省代表为什么詹姆斯每个冠军含金量都很高,而击败詹姆斯夺冠的球队的冠军含金量都很低?科比退役后,现在各大论坛基本都是詹姆斯球迷偏多,刚好詹姆斯又处于巅峰期,现在主导舆论的都是詹姆斯球迷,各大篮球论坛提到科比都各种被黑,詹姆斯的各种荣誉都被无限夸大,詹姆斯每次夺冠,十二强赛,中国男足会输给越南吗?如果输了联赛还能办下去吗?十二强赛,中国男足会输给越南吗?如果输了,联赛还能办下去吗,12强赛中越之战是在10月7日进行,中国男足会输越南吗?这不好说,最终结果谁胜谁负,目前中国男足有信心战胜越南,而越南目从目前各路媒体对全红婵的热捧,会不会出现刘翔式的悲剧?我觉得不会,当然也不要过度消费这个孩子。第一刘翔式悲剧,更主要是因为我们在田径赛场的缺失,绝大部分都是黑人为主,国人很疯狂,且刘翔当时思想成熟,想的多,反而压力更大。第二全红婵,从