【问题标题】:calculate gradient output for Theta update rule计算 Theta 更新规则的梯度输出
【发布时间】:2015-05-09 12:06:37
【问题描述】:

由于它使用 sigmoid 函数而不是零/一激活函数,我想这是计算梯度下降的正确方法,对吗?

  static double calculateOutput( int theta, double weights[], double[][] feature_matrix, int file_index, int globo_dict_size )
  {
     //double sum = x * weights[0] + y * weights[1] + z * weights[2] + weights[3];
     double sum = 0.0;

     for (int i = 0; i < globo_dict_size; i++) 
     {
         sum += ( weights[i] * feature_matrix[file_index][i] );
     }
     //bias
     sum += weights[ globo_dict_size ];

     return sigmoid(sum);
  }

  private static double sigmoid(double x)
  {
      return 1 / (1 + Math.exp(-x));
  }

我正在尝试更新我的 Θ 值的以下代码(相当于感知器中的权重,不是吗?),为此我在related question 中获得了这个公式LEARNING_RATE * localError * feature_matrix__train[p][i] * output_gradient[i]。我从我的感知器中注释掉了权重更新。

这个新的更新规则是正确的方法吗?

output_gradient 是什么意思?这相当于我在calculateOutput 方法中计算的总和吗?

      //LEARNING WEIGHTS
      double localError, globalError;
      int p, iteration, output;

      iteration = 0;
      do 
      {
          iteration++;
          globalError = 0;
          //loop through all instances (complete one epoch)
          for (p = 0; p < number_of_files__train; p++) 
          {
              // calculate predicted class
              output = calculateOutput( theta, weights, feature_matrix__train, p, globo_dict_size );
              // difference between predicted and actual class values
              localError = outputs__train[p] - output;
              //update weights and bias
              for (int i = 0; i < globo_dict_size; i++) 
              {
                  //weights[i] += ( LEARNING_RATE * localError * feature_matrix__train[p][i] );

                  weights[i] += LEARNING_RATE * localError * feature_matrix__train[p][i] * output_gradient[i]

              }
              weights[ globo_dict_size ] += ( LEARNING_RATE * localError );

              //summation of squared error (error value for all instances)
              globalError += (localError*localError);
          }

          /* Root Mean Squared Error */
          if (iteration < 10) 
              System.out.println("Iteration 0" + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
          else
              System.out.println("Iteration " + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
          //System.out.println( Arrays.toString( weights ) );
      } 
      while(globalError != 0 && iteration<=MAX_ITER);

更新 现在我更新了一些东西,看起来更像这样:

  double loss, cost, hypothesis, gradient;
  int p, iteration;

  iteration = 0;
  do 
  {
    iteration++;
    cost = 0.0;
    loss = 0.0;

    //loop through all instances (complete one epoch)
    for (p = 0; p < number_of_files__train; p++) 
    {

      // 1. Calculate the hypothesis h = X * theta
      hypothesis = calculateHypothesis( theta, feature_matrix__train, p, globo_dict_size );

      // 2. Calculate the loss = h - y and maybe the squared cost (loss^2)/2m
      loss = hypothesis - outputs__train[p];

      // 3. Calculate the gradient = X' * loss / m
      gradient = calculateGradent( theta, feature_matrix__train, p, globo_dict_size, loss );

      // 4. Update the parameters theta = theta - alpha * gradient
      for (int i = 0; i < globo_dict_size; i++) 
      {
          theta[i] = theta[i] - (LEARNING_RATE * gradient);
      }

    }

    //summation of squared error (error value for all instances)
    cost += (loss*loss);


  /* Root Mean Squared Error */
  if (iteration < 10) 
      System.out.println("Iteration 0" + iteration + " : RMSE = " + Math.sqrt( cost/number_of_files__train ) );
  else
      System.out.println("Iteration " + iteration + " : RMSE = " + Math.sqrt( cost/number_of_files__train ) );
  //System.out.println( Arrays.toString( weights ) );

  } 
  while(cost != 0 && iteration<=MAX_ITER);


}

static double calculateHypothesis( double theta[], double[][] feature_matrix, int file_index, int globo_dict_size )
{
    double hypothesis = 0.0;

     for (int i = 0; i < globo_dict_size; i++) 
     {
         hypothesis += ( theta[i] * feature_matrix[file_index][i] );
     }
     //bias
     hypothesis += theta[ globo_dict_size ];

     return hypothesis;
}

static double calculateGradent( double theta[], double[][] feature_matrix, int file_index, int globo_dict_size, double loss )
{
    double gradient = 0.0;

     for (int i = 0; i < globo_dict_size; i++) 
     {
         gradient += ( feature_matrix[file_index][i] * loss);
     }

     return gradient;
}

public static double hingeLoss()
{
    // l(y, f(x)) = max(0, 1 − y · f(x))

    return HINGE;
}

【问题讨论】:

    标签: java gradient-descent


    【解决方案1】:

    您的calculateOutput 方法看起来正确。你的下一段代码我真的不这么认为:

    weights[i] += LEARNING_RATE * localError * feature_matrix__train[p][i] * output_gradient[i]
    

    查看您在other question 中发布的图片:

    让我们尝试在代码中识别这些规则的每一部分。

    1. Theta0 andTheta1:在您的代码中看起来像 weights[i];希望globo_dict_size = 2;

    2. alpha:好像是你的LEARNING_RATE;

    3. 1 / m:我在你的更新规则中找不到这个。 m 是 Andrew Ng 视频中的训练实例数。在您的情况下,我认为应该是1 / number_of_files__train;不过这不是很重要,即使没有它也应该可以正常工作。

    4. 总和:您使用calculateOutput 函数执行此操作,您在localError 变量中使用其结果,然后将其乘以feature_matrix__train[p][i](相当于Andrew Ng 表示法中的x(i))。

      这部分是你的偏导数,也是梯度的一部分!

      为什么?因为[h_theta(x(i)) - y(i)]^2 对Theta0 的偏导数等于:

      2*[h_theta(x(i)) - y(i)] * derivative[h_theta(x(i)) - y(i)]
      derivative[h_theta(x(i)) - y(i)] =
      derivative[Theta0 * x(i, 1) + Theta1*x(i, 2) - y(i)] =
      x(i, 1)
      

      当然,您应该推导出整个总和。这也是 Andrew Ng 使用 1 / (2m) 作为成本函数的原因,所以 2 将与我们从推导中得到的 2 抵消。

      请记住,x(i, 1),或者只是 x(1) 应该由所有的组成。在您的代码中,您应该确保:

      feature_matrix__train[p][0] == 1
      
    5. 就是这样!我不知道output_gradient[i] 应该在你的代码中是什么,你没有在任何地方定义它。

    我建议您查看this tutorial 以更好地了解您使用的算法。由于您使用 sigmoid 函数,因此您似乎想要进行分类,但是您应该使用不同的成本函数。该文档也涉及逻辑回归。

    【讨论】:

    • 当您说feature_matrix__train[p][i] == 1 时,我对您的解释的理解完全崩溃了,这是什么意思?!?当然不是== 1,而是它对应的单词在全球词典中出现的次数!它可以等于 1,但也可以等于 0 或 500!
    • @S.Matthew_English - 我的错,我本来打算写 0 而不是 i。仅对于第一个元素,它应该等于 1。抱歉,我现在更正了。
    • 这和偏置项一样吗?为什么一定要放在开头,可以放在结尾吗?
    • @S.Matthew_English - 是的,这是偏见术语。它通常放在开头,因为这样可以更轻松地进行矢量化,但您可以将它放在您的案例中的任何位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 1970-01-01
    • 2021-04-01
    相关资源
    最近更新 更多