使用 Sympy 的多变量梯度下降
multi-variable Gradient descent using Sympy
我在 Python 2.7 的 Sympy 库中练习两个变量的梯度下降算法实现。
我的目标是根据以下步骤使用导数向量找到两个变量函数的最小值:
- 对于两个变量的函数 f(a,b) 定义第一个矩阵
偏微分 - M。
- 然后,我将 a、b 的起始点(例如 V0 = (1.0,1.0))传递给 M,然后将其乘以 step - 这给出 M0 * 矩阵。
- 接下来,用向量减去上面计算的结果
起始值 - V0。这给出了一个新的变量向量 a,b - V1。
- 最后将V1的值重新放入M。如果矩阵 M 的结果小于 epsilon => 继续迭代。
附上代码和步骤说明。我想问题出在 while 循环中,因为它给出了 worng 值并且算法只进行了第 i 次迭代。
enter image description here
能否请您提出改进建议?
import sympy as sp
from sympy import *
from sympy import lambdify
a=Symbol('a')
b=Symbol('b')
alpha=Symbol('alpha')
def test_f(a, b):
# define a test function of a,b
test_f=4*a**2 + 25*b**2
return test_f
def deriv_matrix(f, a, b):
# define the matrix of derivatives
d1=diff(f(a,b), a, 1)
d2=diff(f(a,b), b, 1)
M=Matrix([d1,d2])
return M
epsilon=0.02
alpha=0.1
i=1 # strat the iteration from 1
vector1=Matrix([1,1]) # starting point
while (i<100) & (f(vector1[0], vector1[1]).all()> epsilon):
f = lambdify((a,b), deriv_matrix(test_f, a, b))
vector=vector1
N=-(alpha/i)*f(vector[0],vector[1])
vector1=vector1+N
i+=i
print vector1
代码中的问题太多,无法一一列出。作为一个小样本:f
未定义,但显然它的 return 值具有方法 .all()
(在 NumPy return 中是一个布尔值),然后将其与 epsilon 进行比较?没有意义。通常,在使用 SymPy 时,不需要将符号函数编码为 Python 函数。它们被表示为 SymPy 表达式,当需要速度时可以对其进行 lambdified,或者当速度不是问题时直接使用 subs
进行评估。例如:
from sympy import *
a, b = symbols('a b')
f = 4*a**2 + 25*b**2 # this is a SymPy expression, not a function
grad_f = lambdify((a, b), derive_by_array(f, (a, b))) # lambda from an expression for graduent
epsilon = 0.02
alpha = 0.01 # the value of 0.1 is too large for convergence here
vector = Matrix([1, 1])
for i in range(100): # to avoid infinite loop
grad_value = Matrix(grad_f(vector[0], vector[1]))
vector += -alpha*grad_value
if grad_value.norm() < epsilon: # gradient is small, we are done
break
if grad_value.norm() < epsilon:
print('Converged to {}'.format(vector)) # only print vector if successful
else:
print('Failed to converge')
我在 Python 2.7 的 Sympy 库中练习两个变量的梯度下降算法实现。
我的目标是根据以下步骤使用导数向量找到两个变量函数的最小值:
- 对于两个变量的函数 f(a,b) 定义第一个矩阵 偏微分 - M。
- 然后,我将 a、b 的起始点(例如 V0 = (1.0,1.0))传递给 M,然后将其乘以 step - 这给出 M0 * 矩阵。
- 接下来,用向量减去上面计算的结果 起始值 - V0。这给出了一个新的变量向量 a,b - V1。
- 最后将V1的值重新放入M。如果矩阵 M 的结果小于 epsilon => 继续迭代。
附上代码和步骤说明。我想问题出在 while 循环中,因为它给出了 worng 值并且算法只进行了第 i 次迭代。 enter image description here
能否请您提出改进建议?
import sympy as sp
from sympy import *
from sympy import lambdify
a=Symbol('a')
b=Symbol('b')
alpha=Symbol('alpha')
def test_f(a, b):
# define a test function of a,b
test_f=4*a**2 + 25*b**2
return test_f
def deriv_matrix(f, a, b):
# define the matrix of derivatives
d1=diff(f(a,b), a, 1)
d2=diff(f(a,b), b, 1)
M=Matrix([d1,d2])
return M
epsilon=0.02
alpha=0.1
i=1 # strat the iteration from 1
vector1=Matrix([1,1]) # starting point
while (i<100) & (f(vector1[0], vector1[1]).all()> epsilon):
f = lambdify((a,b), deriv_matrix(test_f, a, b))
vector=vector1
N=-(alpha/i)*f(vector[0],vector[1])
vector1=vector1+N
i+=i
print vector1
代码中的问题太多,无法一一列出。作为一个小样本:f
未定义,但显然它的 return 值具有方法 .all()
(在 NumPy return 中是一个布尔值),然后将其与 epsilon 进行比较?没有意义。通常,在使用 SymPy 时,不需要将符号函数编码为 Python 函数。它们被表示为 SymPy 表达式,当需要速度时可以对其进行 lambdified,或者当速度不是问题时直接使用 subs
进行评估。例如:
from sympy import *
a, b = symbols('a b')
f = 4*a**2 + 25*b**2 # this is a SymPy expression, not a function
grad_f = lambdify((a, b), derive_by_array(f, (a, b))) # lambda from an expression for graduent
epsilon = 0.02
alpha = 0.01 # the value of 0.1 is too large for convergence here
vector = Matrix([1, 1])
for i in range(100): # to avoid infinite loop
grad_value = Matrix(grad_f(vector[0], vector[1]))
vector += -alpha*grad_value
if grad_value.norm() < epsilon: # gradient is small, we are done
break
if grad_value.norm() < epsilon:
print('Converged to {}'.format(vector)) # only print vector if successful
else:
print('Failed to converge')