文章 "神经网络变得轻松(第九部分):操作归档"

 

新文章 神经网络变得轻松(第九部分):操作归档已发布:

我们已经经历了很长一段路,并且函数库中的代码越来越庞大。 这令跟踪所有连接和依赖性变得难以维护。 因此,我建议为先前创建的代码创建文档,并保持伴随每个新步骤进行更新。 正确准备的文档将有助我们看到操作的完整性。

一旦程序完成,您将收到一个现成的文档。 Some screenshots are shown below. 附件中提供了完整的文档。



作者:Dmitriy Gizlyk

 

伟大而有用的文章素材

谢谢!

 
酷!有文档可查--你可以在 SB 中实现它。虽然有必要在内核 上拧紧 LSTM,但你打算这么做吗?
 
Aleksey Mavrin:
酷!有文档可查--你可以在 SB 中实现它。虽然有必要在内核 中加入 LSTM,但这是计划中的吗?

是的,计划中:)

 
Dmitriy Gizlyk:

是的,已经计划好了)

德米特里,我一开始没意识到为什么要在输入值上添加正弦和余弦值。

neuron.setOutputVal(inputVals.At(i)+(i%2==0 ? sin(i) : cos(i)) );

我还需要一些建议--我是否应该尝试以某种方式使输入数据正常化,以完成我的任务?

在我所理解的示例中,一切都是 "按原样 "给出的。但是,即使是在分形示例中,也有一些振荡指标从 0 到 1,而根据不同的工具,价格可能比 1 高得多。

在对非标准化输入进行训练时,这难道不会产生初始偏差吗?

 
Aleksey Mavrin:

德米特里,请告诉我为什么要在输入值上添加正弦和余弦。

我还需要一些建议--我是否应该尝试以某种方式使输入数据正常化,以完成我的任务?

在我所理解的示例中,一切都是 "按原样 "给出的。但是,即使在分形示例中,一些振荡器的振幅也是从 0 到 1,而根据不同的工具,价格可能比 1 高得多。

在对非标准化输入进行训练时,这难道不会产生初始偏差吗?

这是针对时间嵌入而言的。我将在下一篇文章中详细介绍。
 
Dmitriy Gizlyk:
这是为了嵌入时间。我将在下一篇文章中详细介绍。

我正在努力理解其中的含义)

无论输入数据是什么及其绝对值 是多少,输入值都会被算术调整为从 0 到 1 的恒定矩阵。

我对这种意义上的时间嵌入的理解如下--在时间序列上叠加正弦波,使过去蜡烛的意义随时间波动。

好了,很清楚了,显然每个条形图的输入数据的波动相位不同并不重要,或者说这是一个特征。

但是,关于正常化的问题就变得更加重要了。例如,欧元兑美元和 SP500 的意义是完全不同的。

显然,将这种时间嵌入从圣经转移到 Train 函数是正确的。

 
阅读有关位置嵌入的文章会很有趣。但有人怀疑它们是否非常必要。你可以使用波动率,它就像一个正弦曲线。但我意识到这是时间序列 的常见做法。也许还有其他的 "诀窍"。
 

@Dmitriy Gizlyk,这个问题是在学习和使用库时提出的:

在计算隐藏层梯度的方法中,你添加了outputVal

这是为了在后面的计算输出梯度方法中补偿其值,以实现普遍性,对吗?

你还添加了梯度归一化

bool CNeuron::calcHiddenGradients(CLayer *&nextLayer)
  {
   double targetVal=sumDOW(nextLayer)+outputVal;
   return calcOutputGradients(targetVal);
  }
//+------------------------------------------------------------------+
bool CNeuron::calcOutputGradients(double targetVal)
  {
   double delta=(targetVal>1 ? 1 : targetVal<-1 ? -1 : targetVal)-outputVal;
   gradient=(delta!=0 ? delta*activationFunctionDerivative(outputVal) : 0);
   return true;
  }

问题是,如果不对目标值进行归一化,而是 像这样对最终的 delta 进行归一化,是否会更正确

double delta=targetVal-outputVal;
delta=delta>1?1:delta<-1?-1:delta;

为什么?举例:如果输出值接近 1,而下一层的总加权梯度也很高且为正值,那么我们现在得到的最终 delta 值接近零,这似乎是不对的。

毕竟,梯度的 delta 值应该与下一层的误差成正比,也就是说,当神经元的有效权重为负时(也可能在其他一些情况下),神经元受到的误差惩罚要小于权重为正时。我的解释可能比较简单,但我希望熟悉这门学科的人能够理解我的想法:)也许您已经注意到了这一点,并做出了这样的决定,如果能说明原因,那将会很有意思。

OCL 代码也是如此

__kernel void CalcHiddenGradient(__global double *matrix_w,
                                 __global double *matrix_g,
                                 __global double *matrix_o,
                                 __global double *matrix_ig,
                                 int outputs, int activation)
  {
..............   
switch(activation)
     {
      case 0:
        sum=clamp(sum+out,-1.0,1.0)-out;
        sum=sum*(1-pow(out==1 || out==-1 ? 0.99999999 : out,2));
 
Aleksey Mavrin:

@Dmitriy Gizlyk,这个问题是在学习和使用图书馆时产生的:

在隐藏层的梯度计算方法中,你添加了outputVal

这是为了在计算输出梯度方法中进一步补偿其值,以实现普遍性,对吗?

您还添加了梯度归一化

问题是,如果不对目标值进行归一化,而是对最终的 delta 进行归一化,是否会更正确

为什么?例如:如果输出值接近 1,而下一层的总加权梯度也很高且为正值,那么现在我们得到的最终 delta 值接近 0,这似乎是不对的。

毕竟,梯度的 delta 值应该与下一层的误差成正比,也就是说,当神经元的有效权重为负时(也可能在其他一些情况下),神经元受到的误差惩罚要小于权重为正时。我的解释可能比较简单,但我希望熟悉这门学科的人能够理解我的想法:)也许你已经注意到了这一点,并做出了这样的决定,如果能说明原因,那将会很有意思。

OCL 代码也是如此

并非如此。我们会检查目标值,就像在隐藏层中,我们会将 outpuVal 加入梯度以获得目标值并检查其值。如果我们惩罚神经元的偏差并无限增加权重系数,就会导致权重溢出。毕竟,如果某个神经元的权重值等于 1,而随后传递错误信息的层则认为我们应该将权重值增加到 1.5。因此,我将目标值限制在激活函数可接受值的范围内。而超出范围的调整则由后续层的权重来完成。

 
Dmitriy Gizlyk:

其实不然。我们要检查目标值,就像在隐藏层中,我们将 outpuVal 加到梯度上以得到目标值并检查其值一样。如果我们惩罚神经元的偏差并无限制地增加权重系数,就会导致权重溢出。毕竟,如果某个神经元的权重值等于 1,而随后传递错误信息的层却要求我们将权重值增加到 1.5。因此,我将目标值限制在激活函数可接受值的范围内。而超出范围的调整则由后续层的权重来完成。

我想我做到了。但我还是想知道,这样的例子是否正确:

如果网络犯了一个错误,在实际值为 1 时给出了 0。那么从最后一层开始,上一层的梯度加权(我的理解很可能是)为正,并且可能大于 1,比如说 1,6。

假设上一层有一个神经元产生了 +0.6,即它产生了正确的值,那么它的权重就应该增加。通过这种归一化处理,我们可以削减其权重的变化。

结果是 norm(1,6)=1。1-0,6=0,4,如果我们按照我的建议进行归一化处理,结果将是 1。在这种情况下,我们会减慢正确神经元的放大速度。

您怎么看?

关于权重的无限增加,我听说在 "误差函数不好 "的情况下会出现这种情况,比如有很多局部极小值而没有明显的全局极小值,或者函数不是凸的,诸如此类,我不是超级专家,我只是相信你可以而且应该用无限权重和其他方法来解决这个问题。

我要求做一个实验来测试这两种变体。如果我想好了如何进行测试 )