
SciPy (hÀÀldatakse nagu sai pai) on rakenduslike matemaatiliste protseduuride paket, mis pĂ”hineb Python'i Numpy laiendusel. SciPy muudab interaktiivse Python seansi tĂ€ielikuks andmete töötlemise ja keerukate sĂŒsteemide prototĂŒĂŒpimise keskkonnaks, vĂ”rreldav MATLAB'i, IDL'i, Octave'i, R-Labi ja SciLabiga. TĂ€na tahan ma lĂŒhidalt rÀÀkida, kuidas rakendada mĂ”ningaid tuntud optimeerimisalgoritme scipy.optimize paketis. Podrobnejat ja ajakohast teavet funktsioonide kasutamise kohta vĂ”ib alati saada kĂ€su help() vĂ”i Shift+Tab abil.
Sissejuhatus
Kuna soovin ennast ja lugejat sÀÀsta esmaste allikate otsimisest ja lugemisest, on linkide viidatud meetodite kirjeldustele peamiselt Wikipedia. Ăldiselt on see teave piisav, et mĂ”ista meetodeid laiemalt ja nende rakendustingimusi. Matemaatiliste meetodite sĂŒdamiku mĂ”istmiseks jĂ€rgime linke autoriteetsematele vĂ€ljaannetele, mida saab leida iga artikli lĂ”pus vĂ”i oma lemmikotsingumootorist.
Seega sisaldab moodul scipy.optimize jÀrgmiste protseduuride teostust:
- Mitme muutuja skalarfunktsioonide tingimuslik ja tingimusteta minimeerimine (minim) erinevate algoritmidega (Nelder-Mead simplex, BFGS, Newtoni konjugaatgradendid, ja )
- Globaalne optimeerimine (nÀiteks: , )
- JÀÀkide minimeerimine (least_squares) ja mittelineaarse MNLK (curve_fit) kÔverate sobitamise algoritmid
- Skalarse funktsiooni minimeerimine ĂŒhe muutuja korral (minim_scalar) ja juurte leidmine (root_scalar)
- Mitme mÔÔtmelistele vĂ”rrandite sĂŒsteemide lahendamine (root) erinevate algoritmide abil (hĂŒbriidne Powell, vĂ”i suurte meetodite, nagu ).
Selles artiklis kÀsitleme vaid loendi esimest punkti.
Tingimusteta skalarse funktsiooni minimeerimine mitme muutuja korral
Scipy.optimize paketi funktsioon minim pakub ĂŒldist liidest mitme muutuja skalarfunktsioonide tingimusliku ja tingimusteta minimeerimise probleemide lahendamiseks. Selle töö demonstreerimiseks vajame sobivat mitme muutuja funktsiooni, mida me eri viisil minimeerime.
Selleks sobib suurepÀraselt Rosenbrocki funktsioon, mis on mÀÀratud N muutuja jaoks.

Kuigi Rosenbrocki funktsioon ja selle Jakobian ja Hesseni maatriksid (esimene ja teine jÀreldus vastavalt) on juba mÀÀratletud paketis scipy.optimize, mÀÀratleme selle ise.
import numpy as np
def rosen(x):
"""Rosenbrocki funktsioon"""
return np.sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0, axis=0)Selguse huvides joonistame 3D-s Rosenbrocki funktsiooni vÀÀrtused kahe muutuja osas.
Kood joonistamiseks
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
# Seadistame 3D diagrammi
fig = plt.figure(figsize=[15, 10])
ax = fig.gca(projection='3d')
# MÀÀrame vaatenurga
ax.view_init(45, 30)
# Loome andmed diagrammi jaoks
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]))
# Joonistame pinna
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm)
plt.show()

Teades ette, et miinimum on 0, kui
, vaatleme Rosenbrocki funktsiooni miinimumvÀÀrtuse kindlaksmÀÀramise nÀiteid erinevate scipy.optimize protseduuride abil.
Nelder-Meadi simplex meetod
Oletame, et algne punkt x0 asub 5-mÔÔtmelises ruumis. Otsime lÀheima miinimumpunkti Rosenbrocki funktsiooni jaoks, kasutades algoritmi. (algoritm on mÀÀratud parameetri method vÀÀrtuseks):
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)Optimeerimine lÔppes edukalt.
Praegune funktsiooni vÀÀrtus: 0.000000
Iteratsioonid: 339
Funktsiooni hindamisi: 571
[1. 1. 1. 1. 1.]Simpelksimeetod on kĂ”ige lihtsam viis minimaalsete selgelt mÀÀratletud ja ĂŒsna sujuvate funktsioonide saavutamiseks. See ei nĂ”ua funktsiooni tuletiste arvutamist, piisab ainult selle vÀÀrtuste mÀÀramisest. Nelder-Meadi meetod on hea valik lihtsate optimeerimisĂŒlesannete jaoks. Kuna see ei kasuta gradientide hinnanguid, vĂ”ib miinimumi leidmiseks kuluda rohkem aega.
Pauli meetod
Teine optimeerimisalgoritm, kus arvutatakse ainult funktsiooni vÀÀrtused, on . Selle kasutamiseks tuleb seada method = 'powell' funktsioonis minim.
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)Optimeerimine lÔppes edukalt.
Praegune funktsiooni vÀÀrtus: 0.000000
Iteratsioonid: 19
Funktsiooni hindamisi: 1622
[1. 1. 1. 1. 1.]Broyden-Fletcher-Goldfarb-Shanno (BFGS) algoritm
Kiirema lahenduse saavutamiseks protseduur kasutab sihtfunktsiooni gradienti. Gradient vÔib olla mÀÀratletud funktsiooni abil vÔi arvutatud esmakordsete vahede abil. Igal juhul nÔuab BFGS meetod tavaliselt vÀhem funktsioonikutsungeid kui simplex-meetod.
Leidke Rosenbrocki funktsiooni tuletis analĂŒĂŒtiliselt:


See avaldis kehtib kÔigi muutujate tuletiste kohta, vÀlja arvatud esimene ja viimane, mis mÀÀratletakse jÀrgmiselt:


Vaatame Pythonis funktsiooni, mis arvutab selle gradienti:
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 derGradienti arvutamise funktsioon mÀÀratletakse minim funktsiooni parameetri jac vÀÀrtusena, nagu allpool nÀidatud.
res = minimize(rosen, x0, method='BFGS', jac=rosen_der, options={'disp': True})
print(res.x)Optimeerimine lÔpetati edukalt.
Praegune funktsiooni vÀÀrtus: 0.000000
Iteratsioonid: 25
Funktsiooni hindamised: 30
Gradientide hindamised: 30
[1.00000004 1.0000001 1.00000021 1.00000044 1.00000092]Kaheksanda astme gradientide (Newtoni) algoritm
Algoritm on muudetud Newtoni meetod.
Newtoni meetod pĂ”hineb funktsiooni lĂ€hialas teise astme polĂŒnoomi abil lĂ€hendamisel:

kus
on teise tuletise maatriks (Hesse maatriks, hessiĂĄn).
Kui hessiån on positiivselt mÀÀratud, saab selle funktsiooni lokaalse miinimumi leida, seades ruutfunktsiooni nulligradiendi nulliks. Tulemusena saadakse vÀljend:

Tagumine hessiån arvutatakse konjugeeritud gradientide meetodi abil. Allpool on toodud nÀide selle meetodi kasutamisest Rosenbrocki funktsiooni minimeerimiseks. Newton-CG meetodi kasutamiseks peab olema mÀÀratud funktsioon, mis arvutab hessiåni.
Rosenbrocki funktsiooni hessiĂĄn analĂŒĂŒtiliselt on:


kus
ja
, mÀÀravad maatriksi
.
ĂlejÀÀnud mitte nullid maatriksi elemendid on:




NÀiteks viie mÔÔtmelises ruumis N = 5, Hesse maatriks Rosenbrocki funktsiooni jaoks on ribakujuline:

Kood, mis arvutab selle hessiĂĄni koos koodiga Rosenbrocki funktsiooni minimeerimiseks konjugeeritud gradientide meetodi abil (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)Optimeerimine lÔpetatud edukalt.
Praegune funktsiooni vÀÀrtus: 0.000000
Iteratsioonide arv: 24
Funktsiooni hindamised: 33
Gradientide hindamised: 56
Hessiani hindamised: 24
[1. 1. 1. 0.99999999 0.99999999]NÀide hessiaani ja juhusliku vektori funktsiooni mÀÀratlemisest
Tegelike probleemide korral vÔib kogu Hessiani maatriksi arvutamine ja salvestamine nÔuda mÀrkimisvÀÀrseid aja- ja mÀluresursse. Samas pole Hessiani maatriksi mÀÀratlemine tegelikult vajalik, kuna minimaalsuse protseduuriks on vajalik ainult vektor, mis on vÔrdsed Hessiani tulemusega, mis on korrutatud mingi teise juhusliku vektoriga. Seega on arvutuslikult palju eelistatavam kohe mÀÀratleda funktsioon, mis tagastab Hessiani ja juhusliku vektori korrutise tulemuse.
AnalĂŒĂŒsime funktsiooni hess, mis vĂ”tab optimeerimise vektori esimeseks argumendiks ja suvalise vektori teiseks argumendiks (koos teiste minimaalsete funktsioonide argumentidega). Meie puhul ei ole Rosenbrocki funktsiooni hessi vektori suvalise vektoriga korrutamine vĂ€ga keeruline. Kui p â suvaline vektor, siis korrutamine
on jÀrgmine:

Funktsioon, mis arvutab hessi ja suvalise vektori korrutise, edastatakse argumendi hessp vÀÀrtusena funktsioonile minimize:
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})
Optimeerimine lÔpetati edukalt.
Hetke funktsioonivÀÀrtus: 0.000000
Iteratsioonid: 24
FunktsioonivÀÀrdustuste arv: 33
Gradientide hindamised: 56
Hessi hindamised: 66Usalduspiiri (trust region) lineaarsete gradientide (Newtoni) algoritm
Halva Hesse'i maatriksi halb tingimus ja vale otsingu suunad vÔivad pÔhjustada, et Newtoni seotud gradientide algoritm osutub ebaefektiivseks. Sellistel juhtudel eelistatakse (trust-region) Newtoni seotud gradientide.
Hesse'i maatriksi mÀÀratlemise nÀide:
res = minimize(rosen, x0, method='trust-ncg',
jac=rosen_der, hess=rosen_hess,
options={'gtol': 1e-8, 'disp': True})
print(res.x)Optimeerimine lÔpetati edukalt.
Praegune funktsiooni vÀÀrtus: 0.000000
Iteratsioonid: 20
Funktsiooni hindamised: 21
Gradientide hindamised: 20
Hesse'i hindamised: 19
[1. 1. 1. 1. 1.]NĂ€ide Hesse'i maatriksi ja suvalise vektori korrutise funktsioonist:
res = minimize(rosen, x0, method='trust-ncg',
jac=rosen_der, hessp=rosen_hess_p,
options={'gtol': 1e-8, 'disp': True})
print(res.x)Optimeerimine lÔpetati edukalt.
Praegune funktsiooni vÀÀrtus: 0.000000
Iteratsioonid: 20
Funktsiooni hindamised: 21
Gradientide hindamised: 20
Hesse'i hindamised: 0
[1. 1. 1. 1. 1.]Krylov'i tĂŒĂŒpmeetodid
Trust-ncg meetodile sarnased Krylov tĂŒĂŒpi meetodid sobivad suuremate ĂŒlesannete lahendamiseks hĂ€sti, kuna need kasutavad ainult maatriks-vektorite korrutusi. Nende olemus seisneb ĂŒlesande lahendamises usaldusvÀÀrses valdkonnas, mis on piiratud kĂ€rbitud Krylov'i alamruumiga. MÀÀramatute probleemide puhul on parem kasutada seda meetodit, kuna see nĂ”uab vĂ€hem mittelineaarseid iteratsioone, tĂ€nu vĂ€iksemale maatriks-vektorite korrutuste arvule iga alamĂŒlesande jaoks vĂ”rreldes trust-ncg meetodiga. Lisaks on ruutude alamĂŒlesande lahendus tĂ€psem kui trust-ncg meetodil.
Hesse'i maatriksi mÀÀratlemise nÀide:
res = minimize(rosen, x0, method='trust-krylov',
jac=rosen_der, hess=rosen_hess,
options={'gtol': 1e-8, 'disp': True})
Optimeerimine lÔpetati edukalt.
Hetke funktsiooni vÀÀrtus: 0.000000
Iteratsioonid: 19
Funktsiooni hindamised: 20
Gradientide hindamised: 20
Hessiaani hindamised: 18
print(res.x)
[1. 1. 1. 1. 1.]
NĂ€ide Hesse'i maatriksi ja suvalise vektori korrutise funktsioonist:
res = minimize(rosen, x0, method='trust-krylov',
jac=rosen_der, hessp=rosen_hess_p,
options={'gtol': 1e-8, 'disp': True})
Optimeerimine lÔpetati edukalt.
Hetke funktsiooni vÀÀrtus: 0.000000
Iteratsioonid: 19
Funktsiooni hindamised: 20
Gradientide hindamised: 20
Hessiaani hindamised: 0
print(res.x)
[1. 1. 1. 1. 1.]
UsaldusvÀÀrses valdkonnas ligikaudse lahendamise algoritm
KÔik meetodid (Newton-CG, trust-ncg ja trust-krylov) sobivad suurepÀraselt ulatuslike probleemide lahendamiseks (tuhandete muutujatega). See on seotud sellega, et aluseks olev gradientide paaritusalgoritm eeldab Hessiani pöördmatriisi ligikaudset leidmist. Lahendust otsitakse iteratiivselt, ilma Hessiani avaldamiseta. Kuna on vajalik mÀÀrata ainult funktsioon, mis sisaldab Hessiani ja suvalise vektori korrutamist, on see algoritm eriti efektiivne hÔredate (lint-diagonaalsete) maatriksitega töötamisel. See tagab madalad mÀlukulud ja mÀrkimisvÀÀrse ajakasutuse kokkuhoiu.
Keskmise suurusega ĂŒlesannetes ei ole Hessiandi salvestamise ja faktoriseerimise kulud kriitilise tĂ€htsusega. See tĂ€hendab, et lahendus saab kĂ€tte vĂ€hemate iteratsioonidega, lahendades usalduspiirkonna alateemasid peaaegu tĂ€pselt. Selleks lahendatakse mĂ”ned mitte-lineaarsed vĂ”rrandid iteratiivselt iga ruutfunktsiooni alateema jaoks. Selline lahendus nĂ”uab tavaliselt 3 vĂ”i 4 Hessiandi Cholecki lagundamist. Tulemusena konvergib meetod vĂ€hemate iteratsioonidega ja vajab vĂ€hem eesmĂ€rgifunktsiooni arvutusi kui teised rakendatud usalduspiirkonna meetodid. See algoritm eeldab vaid Hessiandi tĂ€ieliku maatriksi mÀÀratlemist ja ei toeta Hessiandi ja suvalise vektori tootefunktsiooni kasutamise vĂ”imalust.
Rosenbrocki funktsiooni minimeerimise nÀide:
res = minimize(rosen, x0, method='trust-exact',
jac=rosen_der, hess=rosen_hess,
options={'gtol': 1e-8, 'disp': True})
res.xOptimeerimine lÔpetati edukalt.
Praegune funktsiooni vÀÀrtus: 0.000000
Iteratsioonide arv: 13
Funktsiooni hindamised: 14
Gradientide hindamised: 13
Hessiandi hindamised: 14
array([1., 1., 1., 1., 1.])KĂ€esolevaga lĂ”petame. JĂ€rgmistes artiklites pĂŒĂŒan rÀÀkida huvitavamatest teemadest, sealhulgas tingimuslikust minimeerimisest, minimeerimise rakendamisest approximatsiooni ĂŒlesannete lahendamisel, ĂŒhe muutuja funktsiooni minimeerimisest, erinevatest minimeerijatest ning vĂ”rrandisĂŒsteemi juurte otsimisest paketiga scipy.optimize.
Allikas:
Allikas: habr.com
