如何创建一个简单的梯度下降算法
我正在学习一些简单的机器学习算法,首先从简单的梯度下降开始,但在用Python实现时遇到了一些问题。
这是我想要复现的例子,我有一些关于房子的资料,包括(居住面积(平方英尺)和卧室数量),以及对应的价格:
居住面积(平方英尺):2104
卧室数量:3
价格(千美元):400
我想用梯度下降法做一个简单的回归分析,但我的算法不太好使……这个算法故意不使用向量(我想一步一步理解它)。
i = 1
import sys
derror=sys.maxint
error = 0
step = 0.0001
dthresh = 0.1
import random
theta1 = random.random()
theta2 = random.random()
theta0 = random.random()
while derror>dthresh:
diff = 400 - theta0 - 2104 * theta1 - 3 * theta2
theta0 = theta0 + step * diff * 1
theta1 = theta1 + step * diff * 2104
theta2 = theta2 + step * diff * 3
hserror = diff**2/2
derror = abs(error - hserror)
error = hserror
print 'iteration : %d, error : %s' % (i, error)
i+=1
我理解数学原理,我正在构建一个预测函数
其中
和
是变量(居住面积、卧室数量),而
是估算的价格。
我在使用成本函数()(针对一个点):
这是一个常见的问题,但我更像是一个软件工程师,正在一步一步学习,你能告诉我哪里出错了吗?
我用这段代码让它工作了:
data = {(2104, 3) : 400, (1600,3) : 330, (2400, 3) : 369, (1416, 2) : 232, (3000, 4) : 540}
for x in range(10):
i = 1
import sys
derror=sys.maxint
error = 0
step = 0.00000001
dthresh = 0.0000000001
import random
theta1 = random.random()*100
theta2 = random.random()*100
theta0 = random.random()*100
while derror>dthresh:
diff = 400 - (theta0 + 2104 * theta1 + 3 * theta2)
theta0 = theta0 + step * diff * 1
theta1 = theta1 + step * diff * 2104
theta2 = theta2 + step * diff * 3
hserror = diff**2/2
derror = abs(error - hserror)
error = hserror
#print 'iteration : %d, error : %s, derror : %s' % (i, error, derror)
i+=1
print ' theta0 : %f, theta1 : %f, theta2 : %f' % (theta0, theta1, theta2)
print ' done : %f' %(theta0 + 2104 * theta1 + 3*theta2)
最终得到的结果是这样的:
theta0 : 48.412337, theta1 : 0.094492, theta2 : 50.925579
done : 400.000043
theta0 : 0.574007, theta1 : 0.185363, theta2 : 3.140553
done : 400.000042
theta0 : 28.588457, theta1 : 0.041746, theta2 : 94.525769
done : 400.000043
theta0 : 42.240593, theta1 : 0.096398, theta2 : 51.645989
done : 400.000043
theta0 : 98.452431, theta1 : 0.136432, theta2 : 4.831866
done : 400.000043
theta0 : 18.022160, theta1 : 0.148059, theta2 : 23.487524
done : 400.000043
theta0 : 39.461977, theta1 : 0.097899, theta2 : 51.519412
done : 400.000042
theta0 : 40.979868, theta1 : 0.040312, theta2 : 91.401406
done : 400.000043
theta0 : 15.466259, theta1 : 0.111276, theta2 : 50.136221
done : 400.000043
theta0 : 72.380926, theta1 : 0.013814, theta2 : 99.517853
done : 400.000043
1 个回答
8
第一个问题是,如果你只用一组数据来运行这个程序,就会出现一个不确定的系统……这意味着可能会有无数个解。对于三个变量来说,至少应该有三组数据,最好是更多。
其次,使用梯度下降法时,如果步长是梯度的缩放版本,通常不保证能找到解,除非你在解的附近。你可以通过改用固定步长朝着负梯度的方向(速度慢)或者在负梯度方向上进行线搜索(速度快,但稍微复杂一点)来解决这个问题。
所以对于固定步长,不是用
theta0 = theta0 - step * dEdtheta0
theta1 = theta1 - step * dEdtheta1
theta2 = theta2 - step * dEdtheta2
而是用这个
n = max( [ dEdtheta1, dEdtheta1, dEdtheta2 ] )
theta0 = theta0 - step * dEdtheta0 / n
theta1 = theta1 - step * dEdtheta1 / n
theta2 = theta2 - step * dEdtheta2 / n
另外,看起来你的步骤中可能有个符号错误。
我也不太确定 derror 是否是一个好的停止标准。(不过,找到合适的停止标准通常是很难的)
最后一点是,梯度下降法在参数拟合时非常慢。你可能想用共轭梯度法或 Levenberg-Marquardt 方法来代替。我怀疑这两种方法在 Python 的 numpy 或 scipy 包中已经存在(这两个包不是 Python 默认自带的,但安装起来相对简单)。