2

我正在为单变量线性回归编写一个小的 d3.js 可视化,其中两个参数是通过成本函数的梯度下降(误差平方和又名SSE)来学习的。

截至目前,我们可以看到最佳拟合线随着梯度下降迭代向参数“alpha”和“beta”的成本最小化选择进行调整,其中

 y_i = alpha + beta * x_i

在 javascript 中,数据表示为具有“x”和“y”属性的对象数组。数据生成如下:

  1. 首先,X是从 'lowBound' 和 'upBound' 之间的均匀分布中采样的
  2. 接下来,根据数据生成过程对Y进行采样:y = 3x - 10 + error,

其中误差是从均值为零和方差errorVariance的正态分布中采样的。

我编写了一些 d3.js 代码来实现梯度下降,当我观看可视化时,似乎没有正确学习截距项。这是因为该算法经常调整斜率参数,但仅从其初始值(随机选择)非常轻微地调整截距参数。有三种可能:

  1. 我在数学(或数学的 javascript 表示)中犯了一个错误。
  2. 我在可视化中犯了一个错误(例如 d3 SVG 的东西)。
  3. 我没有犯错,SSE关于截距参数alpha的偏导数远小于斜率参数,因此梯度下降不会对alpha进行太多调整是有道理的。

我实在想不通答案是什么。因此,我将发布我的代码的简化设置,希望有人能够为我提供一些启发。您还可以在此处查看当前形式的可视化(并查看完整源代码)。我们现在只关心数学。如果有人希望我发布将数据连接到 svg 元素的代码,我很乐意这样做,但我认为问题更可能出在此处。

  // Section 1: GENERATE DATA                                                      


  var n = 60;                                                                      
  var upBound = 20;                                                                
  var lowBound = -20;                                                              
  var errorVariance = 6;                                                           
  var data = []                                                                    


  // grab a random x value.                                                        
  var randomX = function() {                                                       
      return Math.random() * (upBound - lowBound) + lowBound;                      
  }                                                                                

  // zero-mean normally distributed error.                                         
  var error = d3.random.normal(0, errorVariance);                                  

  // The following function defines the "data-generating-process":                 
  // y = 3x - 10 + error                                                           
  var dgp = function(x) {                                                          
      return 3*x - 10 + error();                                                   
  }                                                                                

  // Randomly generate data according to the dgp.                                  
  for (var i = 0; i < n; i++) {                                                    
      var newX = randomX()                                                         
      var newY = dgp(newX);                                                        
      data.push({                                                                  
          "x": newX,                                                               
          "y": newY                                                                
      });                                                                          
  } 

这一切都很好,花花公子。然后在第 2 节中,我提供了进行梯度下降的实用程序。

  // define parameters for Gradient Descent                                                                                                       
  var learningRate = 0.00001;                                                                                                                     
  var convThreshold = 0.005;                                                                                                                      


  // Per Observation Cost Function                                                                                                                
  var obsCost = function(alpha, beta, data, i) {                                                                                                  
      return .5 * Math.pow(((alpha + beta * data[i]["x"]) - data[i]["y"]), 2);                                                                    
  }                                                                                                                                               

  // Sum of Squared Errors                                                                                                                        
  var costFuncLR = function(alpha, beta, data) {                                                                                                  
      var sse = 0;                                                                                                                                
      for (var j = 0; j < n; j++) {                                                                                                               
          sse += obsCost(alpha, beta, data, j);                                                                                                   
      }                                                                                                                                           
      return sse;                                                                                                                                 
  }                                                                                                                                               

  var obsErr = function(alpha, beta, data, i) {                                                                                                   
      return (alpha + data[i]["x"] * beta) - data[i]["y"];                                                                                        
  }                                                                                                                                               

  // Partial derivative of cost w.r.t. alpha                                                                                                      
  var pJpAlpha = function(alpha, beta, data) {                                                                                                    
      var sum = 0;                                                                                                                                
      for (var i = 0; i < n; i++) {                                                                                                               
          sum += obsErr(alpha, beta, data, i);                                                                                                    
      }                                                                                                                                           
      //return sum;                                                                                                                               
      return Math.sqrt(2 * costFuncLR(alpha, beta, data));                                                                                        
  }                                                                                                                                               

  // Partial derivative of cost w.r.t. beta                                                                                                       
  var pJpBeta = function(alpha, beta, data) {   
     var sum = 0                                                                                                                                 
      for (var j = 0; j < n; j++ ) {                                                                                                              
          sum += obsErr(alpha, beta, data, j) * data[j]["x"];                                                                                     
      }                                                                                                                                           
      return sum;                                                                                                                                 
  }                                                                                                                                               

  // Performs one iteration of Gradient Descent.                                                                                                  
  var gradientDescentIter = function(data, alphaOld, betaOld, learningRate) {                                                                     
      var pjpa = pJpAlpha(alphaOld, betaOld, data)                                                                                                
      var pjpb = pJpBeta(alphaOld, betaOld, data)                                                                                                 
      var temp0 = alphaOld - (learningRate * pjpa);                                                                                               
      var temp1 = betaOld - (learningRate * pjpb);                                                                                                
      var alphaNew = temp0;                                                                                                                       
      var betaNew = temp1;                                                                                                                        
      var out = [];                                                                                                                               
      out.push(alphaNew);                                                                                                                         
      out.push(betaNew);                                                                                                                          
      console.log(costFuncLR(alphaNew, betaNew, data));                                                                                           
      return out;                                                                                                                                 
  }                       

我提前感谢您的所有帮助。

有点不相关,我想通过参数空间中的等高线图或嵌入欧几里得 3 空间(z 轴是成本)中的表面来显示成本函数的水平集,并观察该空间中的参数变化为出色地。我找到了 mike bostock 关于如何使用等高线图的帖子,但是

4

0 回答 0