文号
825206
阅读
9333
回复
4
收藏
5
JavaScript: 梯度下降法拟合函数
2016/09/04
IP:广东

环境是node 4.x

先定义一个函数: y = f(x) = 3x^2 + 2x

然后在 [-50,50) 上采样一组数据,并添加白噪声。

function target(x){
  return 3 * x * x + 2 * x  // y = 3x^2 + 2x
}

var input = [], output = []

for(i=-50;i<50;i++){ fill test data input.push(i) output.push(target(i)+math.random()*3) with random errors } < code></50;i++){>

此时,input数组包含[-50,50)上的一组输入值,output数组包含对应的输出值。


问题:已知原函数的形式是 y = f(x) = ax^2 + bx,求 a 和 b。

首先定义我们的假设:y = p0x^2 + p1x,接受x为输入,以及params为参数数组。

function hypothesis(x,params){
  return params[0] * x * x + params[1] * x
}

然后给待求参数指定一个初始值 (p0,p1) = (0,0)

var solution = [0,0]

然后我们定义误差函数。误差的定义是[给定参数下,函数的输出值(output)和实际输出值的RMSE]

function error_of_hypothesis(params){
  var total_square_err = 0.0;
  for(i in input){
    var x = input[i]
    var difference = hypothesis(x,params) - output[i]

    total_square_err += difference * difference
  }
  return Math.sqrt(total_square_err/input.length) //RMSE
}

然后定义[梯度计算及下降]函数。[梯度]就是误差函数在点(p1,p2)处对p1,p2分别求偏导得到的矢量。说白了就是求那个点的“上坡方向”的矢量。

此处求偏导使用了数值方法。

function calculate_gradient_and_descend(stepsize){
  // calculate error(p0,p1)
  var err = error_of_hypothesis(solution)

  // calculate gradient of error(p0,p1)
  var delta = 0.00000001
  var gradient = []

  for(i in solution){
    // calculate partial derivative of error(p0,p1)
    var delta_solution = []
    delta_solution[0] = solution[0]
    delta_solution[1] = solution[1]

    delta_solution[i] += delta
    gradient[i] = (error_of_hypothesis(delta_solution) - err)/delta
  }

  // descend (p0,p1)
  for(i in solution){
    solution[i] -= gradient[i]*stepsize
  }

  return err
}

上面可以看到:每运行一次下降函数,solution矢量就会朝当前梯度方向的反方向前进stepsize距离。

这会让我们越来越接近谷底。

下面定义我们的梯度下降循环:

function run_descent(iterations,stepsize){
  for(var i=0;i<iterations;i++){ var err="calculate_gradient_and_descend(stepsize)" if(i%(iterations 10)="=0||i">iterations-10){
      console.log('-------------');
      console.log('gradient descent iteration',i);
      console.log('RMSE=',err);
      console.log('solution:',solution,'after descent.');
    }
  }
  return err
}

run_descent(1000,0.001)
run_descent(1000,0.0001)
run_descent(1000,0.00001)
run_descent(10000,0.000001)
</iterations;i++){>

结果:

-------------
gradient descent iteration 9997
RMSE= 1.2756225981845384
solution: [ 3.001084043830482, 2.001937055426506 ] after descent.
-------------
gradient descent iteration 9998
RMSE= 1.275622596459923
solution: [ 3.0010840438762454, 2.001937096928974 ] after descent.
-------------
gradient descent iteration 9999
RMSE= 1.275622594737627
solution: [ 3.0010840439171016, 2.0019371384060625 ] after descent.
10年3个月前IP:江苏
825393
1楼
最近看了一个三次样条拟合,用在浓度与检测值转换上
引用
评论
10年3个月前IP:美国
825405
2楼
Is there any matrix calculation packages for JavaScript? Just Like Numpy for Python
引用
评论
10年3个月前IP:广东
825596
3楼
引用 Cirno:
Is there any matrix calculation packages for JavaScript? Just Like Numpy for Python
ConvnetJS by Andrej Karparthy
引用
评论
10年3个月前IP:上海
825898
4楼
js 有求梯度的库么?
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的