根据我在博客上发现的内容,我使用渐变下降来实现线性回归。它似乎适用于较小的值,但对于较大的值,输出会上升! 以下是我的实施
let inps = [1.;2.;4.;3.;5.]
let targs = [1.;3.;3.;2.;5.]
let train inps targs =
let rec aux inps targs n slope intercept i =
match n with
| 0 -> [intercept;slope]
| n ->
let inp = List.nth inps i in
let output = inp*.slope +. intercept in
let error = (List.nth targs i) -. output in
let slope' = slope +. 0.01*.error*.inp in
let intercept' = intercept +. 0.01*.error in
aux inps targs (n-1) slope' intercept' ((i+1) mod (List.length inps))
in
aux inps targs 200 0. 0. 0
适用于上述inps
和targs
,输出为
utop # train inps targs;;
- : float list = [0.274637254235572281; 0.845725879951186532]
但是当我更改inps
时,它会提供不正确且非常大的值
utop # let inps' = List.map (function x -> x*.10.) inps;;
val inps' : float list = [10.; 20.; 40.; 30.; 50.]
─( 22:53:28 )─< command 141 >────────────────────────────────────{ counter: 0 }─
utop # train inps' targs;;
- : float list = [9.50572250044365676e+69; 4.58043753555103929e+71]
这里有什么问题?
答案 0 :(得分:3)
首先,你的实现并不是真正的梯度下降,而是一种多梯度下降的形式,你试图连续减少模型和给定点数据之间的距离而不是全局距离。
其次,使用List.nth通常表示您需要数组而不是列表。
第三,当步长太大时,过冲是梯度下降的经典问题。这个问题在这里强调,你为步长因子选择常数γ= 0.01,你的下一个点定义为:
x_{n+1} = x_n - γ ∇F_n(x_n)
在你的情况下,距离最小值越远,渐变越大,下一次跳跃越长。因此,这些跳跃在最小值附近振荡而不会收敛。例如,打印截距和斜率的中间值
0.010000,0.100000
0.019900,0.298000
-0.069499,-3.277960
0.934584,26.844530
-12.447027,-642.236005
51.911044,1.344703
51.152993,-13.816317
56.197990,187.983555
-0.739057,-1520.127837
759.382253,36485.937627
-2896.795332,-75.838225
-2852.629734,807.473742
解决方案是手动减小步长或实现更好的线搜索子算法。