SciPy, optimalizace

SciPy, optimalizace

SciPy (vyslovováno sai pie) je matematický aplikační balíček založený na rozšíření Numpy Python. Se SciPy se vaše interaktivní relace v Pythonu stane stejným prostředím pro kompletní datovou vědu a komplexním systémovým prototypováním jako MATLAB, IDL, Octave, R-Lab a SciLab. Dnes chci krátce pohovořit o tom, jak používat některé známé optimalizační algoritmy v balíčku scipy.optimize. Podrobnější a aktuálnější nápovědu k používání funkcí lze vždy získat pomocí příkazu help() nebo pomocí Shift+Tab.

úvod

Abyste sebe i čtenáře ušetřili hledání a čtení primárních zdrojů, budou odkazy na popisy metod hlavně na Wikipedii. Tyto informace zpravidla postačují k pochopení metod obecně a podmínek jejich aplikace. Abyste pochopili podstatu matematických metod, postupujte podle odkazů na autoritativnější publikace, které najdete na konci každého článku nebo ve svém oblíbeném vyhledávači.

Modul scipy.optimize tedy zahrnuje implementaci následujících procedur:

  1. Podmíněná a nepodmíněná minimalizace skalárních funkcí několika proměnných (minim) pomocí různých algoritmů (Nelder-Mead simplex, BFGS, Newtonovy konjugované gradienty, COBYLA и SLSQP)
  2. Globální optimalizace (například: basinhopping, diff_evolution)
  3. Minimalizace zbytků MNC (nejmenší_čtverce) a algoritmy prokládání křivek pomocí nelineárních nejmenších čtverců (curve_fit)
  4. Minimalizace skalárních funkcí jedné proměnné (minim_scalar) a hledání kořenů (root_scalar)
  5. Vícerozměrné řešiče soustav rovnic (kořen) využívající různé algoritmy (hybridní Powell, Levenberg-Marquardt nebo metody ve velkém měřítku, jako např Newton-Krylov).

V tomto článku se budeme zabývat pouze první položkou z celého tohoto seznamu.

Bezpodmínečná minimalizace skalární funkce více proměnných

Funkce minim z balíku scipy.optimize poskytuje obecné rozhraní pro řešení problémů podmíněné a nepodmíněné minimalizace skalárních funkcí několika proměnných. Abychom demonstrovali, jak to funguje, budeme potřebovat vhodnou funkci několika proměnných, které budeme různými způsoby minimalizovat.

Pro tyto účely je perfektní Rosenbrockova funkce N proměnných, která má tvar:

SciPy, optimalizace

Navzdory tomu, že Rosenbrockova funkce a její Jacobiho a Hessova matice (první a druhá derivace) jsou již definovány v balíčku scipy.optimize, nadefinujeme si ji sami.

import numpy as np

def rosen(x):
    """The Rosenbrock function"""
    return np.sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0, axis=0)

Pro přehlednost nakreslíme ve 3D hodnoty Rosenbrockovy funkce dvou proměnných.

Kód výkresu

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter

# Настраиваем 3D график
fig = plt.figure(figsize=[15, 10])
ax = fig.gca(projection='3d')

# Задаем угол обзора
ax.view_init(45, 30)

# Создаем данные для графика
X = np.arange(-2, 2, 0.1)
Y = np.arange(-1, 3, 0.1)
X, Y = np.meshgrid(X, Y)
Z = rosen(np.array([X,Y]))

# Рисуем поверхность
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm)
plt.show()

SciPy, optimalizace

Předem vědět, že minimum je 0 at SciPy, optimalizace, podívejme se na příklady, jak určit minimální hodnotu Rosenbrockovy funkce pomocí různých postupů scipy.optimize.

Nelder-Mead simplexová metoda

Nechť je počáteční bod x0 v 5-rozměrném prostoru. Pomocí algoritmu najdeme minimální bod Rosenbrockovy funkce, který je k ní nejblíže Nelder-Mead simplex (algoritmus je uveden jako hodnota parametru metody):

from scipy.optimize import minimize
x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])
res = minimize(rosen, x0, method='nelder-mead',
    options={'xtol': 1e-8, 'disp': True})
print(res.x)

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 339
         Function evaluations: 571
[1. 1. 1. 1. 1.]

Simplexová metoda je nejjednodušší způsob, jak minimalizovat explicitně definovanou a poměrně hladkou funkci. Nevyžaduje výpočet derivací funkce, stačí zadat pouze její hodnoty. Metoda Nelder-Mead je dobrou volbou pro jednoduché problémy s minimalizací. Protože však nepoužívá odhady gradientu, může nalezení minima trvat déle.

Powellova metoda

Dalším optimalizačním algoritmem, ve kterém se počítají pouze funkční hodnoty, je Powellova metoda. Chcete-li ji použít, musíte ve funkci minim nastavit metodu = 'powell'.

x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])
res = minimize(rosen, x0, method='powell',
    options={'xtol': 1e-8, 'disp': True})
print(res.x)

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 19
         Function evaluations: 1622
[1. 1. 1. 1. 1.]

Algoritmus Broyden-Fletcher-Goldfarb-Shanno (BFGS).

Chcete-li získat rychlejší konvergenci k řešení, postup BFGS používá gradient účelové funkce. Gradient lze zadat jako funkci nebo vypočítat pomocí rozdílů prvního řádu. V každém případě metoda BFGS obvykle vyžaduje méně volání funkcí než simplexní metoda.

Najdeme derivaci Rosenbrockovy funkce v analytické podobě:

SciPy, optimalizace

SciPy, optimalizace

Tento výraz je platný pro derivace všech proměnných kromě první a poslední, které jsou definovány jako:

SciPy, optimalizace

SciPy, optimalizace

Podívejme se na funkci Pythonu, která vypočítá tento gradient:

def rosen_der (x):
    xm = x [1: -1]
    xm_m1 = x [: - 2]
    xm_p1 = x [2:]
    der = np.zeros_like (x)
    der [1: -1] = 200 * (xm-xm_m1 ** 2) - 400 * (xm_p1 - xm ** 2) * xm - 2 * (1-xm)
    der [0] = -400 * x [0] * (x [1] -x [0] ** 2) - 2 * (1-x [0])
    der [-1] = 200 * (x [-1] -x [-2] ** 2)
    return der

Funkce výpočtu přechodu je určena jako hodnota parametru jac funkce minima, jak je uvedeno níže.

res = minimize(rosen, x0, method='BFGS', jac=rosen_der, options={'disp': True})
print(res.x)

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 25
         Function evaluations: 30
         Gradient evaluations: 30
[1.00000004 1.0000001  1.00000021 1.00000044 1.00000092]

Algoritmus konjugovaného gradientu (Newton)

Algoritmus Newtonovy konjugované gradienty je modifikovaná Newtonova metoda.
Newtonova metoda je založena na aproximaci funkce v lokální oblasti polynomem druhého stupně:

SciPy, optimalizace

kde SciPy, optimalizace je matice druhých derivací (Hessova matice, Hessian).
Je-li Hessian kladně definitní, pak lze lokální minimum této funkce nalézt přirovnáním nulového gradientu kvadratické formy k nule. Výsledkem bude výraz:

SciPy, optimalizace

Inverzní Hessian se vypočítá pomocí metody konjugovaného gradientu. Níže je uveden příklad použití této metody k minimalizaci funkce Rosenbrock. Chcete-li použít metodu Newton-CG, musíte zadat funkci, která vypočítá Hessian.
Hessián Rosenbrockovy funkce v analytické formě se rovná:

SciPy, optimalizace

SciPy, optimalizace

kde SciPy, optimalizace и SciPy, optimalizace, definujte matici SciPy, optimalizace.

Zbývající nenulové prvky matice se rovnají:

SciPy, optimalizace

SciPy, optimalizace

SciPy, optimalizace

SciPy, optimalizace

Například v pětirozměrném prostoru N = 5 má Hessova matice pro Rosenbrockovu funkci tvar pásma:

SciPy, optimalizace

Kód, který vypočítá tento Hessian spolu s kódem pro minimalizaci Rosenbrockovy funkce pomocí metody konjugovaného gradientu (Newton):

def rosen_hess(x):
    x = np.asarray(x)
    H = np.diag(-400*x[:-1],1) - np.diag(400*x[:-1],-1)
    diagonal = np.zeros_like(x)
    diagonal[0] = 1200*x[0]**2-400*x[1]+2
    diagonal[-1] = 200
    diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:]
    H = H + np.diag(diagonal)
    return H

res = minimize(rosen, x0, method='Newton-CG', 
               jac=rosen_der, hess=rosen_hess,
               options={'xtol': 1e-8, 'disp': True})
print(res.x)

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 24
         Function evaluations: 33
         Gradient evaluations: 56
         Hessian evaluations: 24
[1.         1.         1.         0.99999999 0.99999999]

Příklad s definicí součinové funkce Hessianu a libovolného vektoru

V problémech reálného světa může výpočet a ukládání celé Hessovy matice vyžadovat značné časové a paměťové zdroje. V tomto případě vlastně není potřeba specifikovat samotnou Hessovu matici, protože minimalizační procedura vyžaduje pouze vektor rovný součinu Hessianu s jiným libovolným vektorem. Z výpočetního hlediska je tedy mnohem vhodnější okamžitě definovat funkci, která vrací výsledek součinu Hessianu s libovolným vektorem.

Uvažujme funkci hess, která bere minimalizační vektor jako první argument, a libovolný vektor jako druhý argument (spolu s dalšími argumenty funkce, která má být minimalizována). V našem případě není výpočet součinu Hessianovy Rosenbrockovy funkce s libovolným vektorem příliš obtížný. Li p je libovolný vektor, pak součin SciPy, optimalizace má tvar:

SciPy, optimalizace

Funkce, která vypočítá součin Hessianu a libovolného vektoru, je předána jako hodnota argumentu hessp funkci minimalizace:

def rosen_hess_p(x, p):
    x = np.asarray(x)
    Hp = np.zeros_like(x)
    Hp[0] = (1200*x[0]**2 - 400*x[1] + 2)*p[0] - 400*x[0]*p[1]
    Hp[1:-1] = -400*x[:-2]*p[:-2]+(202+1200*x[1:-1]**2-400*x[2:])*p[1:-1] 
    -400*x[1:-1]*p[2:]
    Hp[-1] = -400*x[-2]*p[-2] + 200*p[-1]
    return Hp

res = minimize(rosen, x0, method='Newton-CG',
               jac=rosen_der, hessp=rosen_hess_p,
               options={'xtol': 1e-8, 'disp': True})

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 24
         Function evaluations: 33
         Gradient evaluations: 56
         Hessian evaluations: 66

Algoritmus konjugované oblasti důvěryhodnosti gradientu (Newton)

Špatná úprava Hessovy matice a nesprávné směry hledání mohou způsobit, že Newtonův algoritmus sdruženého gradientu bude neúčinný. V takových případech se dává přednost metoda důvěryhodné oblasti (trust-region) konjugovat Newtonovy gradienty.

Příklad s definicí hessovské matice:

res = minimize(rosen, x0, method='trust-ncg',
               jac=rosen_der, hess=rosen_hess,
               options={'gtol': 1e-8, 'disp': True})
print(res.x)

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 20
         Function evaluations: 21
         Gradient evaluations: 20
         Hessian evaluations: 19
[1. 1. 1. 1. 1.]

Příklad s funkcí součinu Hessianu a libovolného vektoru:

res = minimize(rosen, x0, method='trust-ncg', 
                jac=rosen_der, hessp=rosen_hess_p, 
                options={'gtol': 1e-8, 'disp': True})
print(res.x)

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 20
         Function evaluations: 21
         Gradient evaluations: 20
         Hessian evaluations: 0
[1. 1. 1. 1. 1.]

Metody Krylovova typu

Stejně jako metoda trust-ncg jsou metody Krylovova typu dobře vhodné pro řešení rozsáhlých problémů, protože používají pouze produkty maticových vektorů. Jejich podstatou je vyřešit problém v oblasti důvěry omezené zkráceným Krylovovým podprostorem. Pro nejisté problémy je lepší použít tuto metodu, protože používá menší počet nelineárních iterací kvůli menšímu počtu matic-vektorových produktů na podproblém ve srovnání s metodou trust-ncg. Řešení kvadratického dílčího problému je navíc nalezeno přesněji než pomocí metody trust-ncg.
Příklad s definicí hessovské matice:

res = minimize(rosen, x0, method='trust-krylov',
               jac=rosen_der, hess=rosen_hess,
               options={'gtol': 1e-8, 'disp': True})

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 19
         Function evaluations: 20
         Gradient evaluations: 20
         Hessian evaluations: 18

print(res.x)

    [1. 1. 1. 1. 1.]

Příklad s funkcí součinu Hessianu a libovolného vektoru:

res = minimize(rosen, x0, method='trust-krylov',
               jac=rosen_der, hessp=rosen_hess_p,
               options={'gtol': 1e-8, 'disp': True})

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 19
         Function evaluations: 20
         Gradient evaluations: 20
         Hessian evaluations: 0

print(res.x)

    [1. 1. 1. 1. 1.]

Algoritmus pro přibližné řešení v oblasti spolehlivosti

Všechny metody (Newton-CG, trust-ncg a trust-krylov) jsou vhodné pro řešení rozsáhlých problémů (s tisíci proměnnými). To je způsobeno skutečností, že základní algoritmus konjugovaného gradientu implikuje přibližné určení inverzní Hessovy matice. Řešení se nalézá iterativně, bez explicitního rozšíření hessia. Vzhledem k tomu, že potřebujete definovat funkci pouze pro součin Hessianu a libovolného vektoru, je tento algoritmus obzvláště vhodný pro práci s řídkými (pásmovými diagonálními) maticemi. To poskytuje nízké náklady na paměť a významnou úsporu času.

U středně velkých problémů nejsou náklady na ukládání a faktoring Hessian kritické. To znamená, že je možné získat řešení v menším počtu iterací, které řeší dílčí problémy důvěryhodné oblasti téměř přesně. K tomu jsou některé nelineární rovnice řešeny iterativně pro každý kvadratický podproblém. Takové řešení obvykle vyžaduje 3 nebo 4 Choleského rozklady Hessovy matice. Výsledkem je, že metoda konverguje v menším počtu iterací a vyžaduje méně výpočtů objektivních funkcí než jiné implementované metody oblasti spolehlivosti. Tento algoritmus zahrnuje pouze určení kompletní hessovské matice a nepodporuje možnost použití součinové funkce hessovské matice a libovolného vektoru.

Příklad s minimalizací funkce Rosenbrock:

res = minimize(rosen, x0, method='trust-exact',
               jac=rosen_der, hess=rosen_hess,
               options={'gtol': 1e-8, 'disp': True})
res.x

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 13
         Function evaluations: 14
         Gradient evaluations: 13
         Hessian evaluations: 14

array([1., 1., 1., 1., 1.])

Tam se asi zastavíme. V příštím článku se pokusím říci to nejzajímavější o podmíněné minimalizaci, aplikaci minimalizace při řešení aproximačních úloh, minimalizaci funkce jedné proměnné, libovolných minimalizátorech a hledání kořenů soustavy rovnic pomocí scipy.optimize balík.

Zdroj: https://docs.scipy.org/doc/scipy/reference/

Zdroj: www.habr.com

Kupte si spolehlivý hosting pro stránky s DDoS ochranou, VPS VDS servery 🔥 Kupte si spolehlivý webhosting s ochranou DDoS, VPS VDS servery | ProHoster