Градиентный спуск с использованием Sympy - PullRequest
0 голосов
/ 09 ноября 2018

Я практикую реализацию алгоритма градиентного спуска для двух переменных в библиотеке Sympy в Python 2.7.

Моя цель - найти минимум двух переменных функций, используя вектор производных, согласно следующим шагам:

  1. Для функции f (a, b) двух вариабельных чисел определить матрицу частичные дифференциалы - М .
  2. Затем я передаю точку статинга a, b (например, V0 = (1.0,1.0)) в M и умножаю это на шаг - это дает M0 * ? матрица.
  3. Далее вычтите результат, вычисленный выше, из вектора начальные значения - V0 . Это дает новый вектор переменных a, b - V1 .
  4. Наконец, значения V1 снова помещаются в M. Если результаты матрицы M меньше, чем epsilon => продолжить итерации.

Код и описание шагов прилагается. Я полагаю, что проблема заключается в цикле while, поскольку он дает значения для работы, а алгоритм принимает только первую итерацию. введите описание изображения здесь

Не могли бы вы посоветовать улучшения?

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

1 Ответ

0 голосов
/ 10 ноября 2018

В коде слишком много проблем, чтобы перечислить. В качестве небольшого примера: f не определено, но, по-видимому, его возвращаемое значение имеет метод .all() (который в NumPy возвращает bool), который затем сравнивается с epsilon? Не имеет смысла. Обычно при использовании SymPy не нужно кодировать символические функции как функции Python. Они представляются в виде выражений SymPy, которые могут быть разбиты, когда скорость желательна, или могут быть оценены напрямую с помощью 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')
...