问题描述
我有几行不收敛的代码。如果有人知道为什么,我将不胜感激。原方程写成 def f(x,y,b,m),我需要找到参数 b,m。
np.random.seed(42)
x = np.random.normal(0,5,100)
y = 50 + 2 * x + np.random.normal(0,2,len(x))
def f(x,m):
return (1/len(x))*np.sum((y - (b + m*x))**2) # it is supposed to be a sum operator
def dfb(x,m): # partial derivative with respect to b
return b - m*np.mean(x)+np.mean(y)
def dfm(x,m): # partial derivative with respect to m
return np.sum(x*y - b*x - m*x**2)
b0 = np.mean(y)
m0 = 0
alpha = 0.0001
beta = 0.0001
epsilon = 0.01
while True:
b = b0 - alpha * dfb(x,b0,m0)
m = m0 - alpha * dfm(x,m0)
if np.sum(np.abs(m-m0)) <= epsilon and np.sum(np.abs(b-b0)) <= epsilon:
break
else:
m0 = m
b0 = b
print(m,f(x,m))
解决方法
两种衍生品都有一些混淆:
def dfb(x,y,b,m): # partial derivative with respect to b
# return b - m*np.mean(x)+np.mean(y)
# ^-------------^------ these are incorrect
return b + m*np.mean(x) - np.mean(y)
def dfm(x,m): # partial derivative with respect to m
# v------ this should be negative
return -np.sum(x*y - b*x - m*x**2)
实际上,这些导数还缺少一些常量:
-
dfb
应该乘以2
-
dfm
应该乘以2/len(x)
我想这还不错,因为无论如何梯度都会按 alpha
缩放,但它可能会使收敛速度变差。
如果您确实使用了正确的导数,您的代码将在一次迭代后收敛:
def dfb(x,m): # partial derivative with respect to b
return 2 * (b + m * np.mean(x) - np.mean(y))
def dfm(x,m): # partial derivative with respect to m
# Used `mean` here since (2/len(x)) * np.sum(...)
# is the same as 2 * np.mean(...)
return -2 * np.mean(x * y - b * x - m * x**2)