SciPy, optimeerimine

SciPy, optimeerimine

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:

  1. Mitme muutuja skalarfunktsioonide tingimuslik ja tingimusteta minimeerimine (minim) erinevate algoritmidega (Nelder-Mead simplex, BFGS, Newtoni konjugaatgradendid, COBYLA ja SLSQP)
  2. Globaalne optimeerimine (nÀiteks: basinhopping, diff_evolution)
  3. JÀÀkide minimeerimine MNLK (least_squares) ja mittelineaarse MNLK (curve_fit) kÔverate sobitamise algoritmid
  4. Skalarse funktsiooni minimeerimine ĂŒhe muutuja korral (minim_scalar) ja juurte leidmine (root_scalar)
  5. Mitme mÔÔtmelistele vĂ”rrandite sĂŒsteemide lahendamine (root) erinevate algoritmide abil (hĂŒbriidne Powell, Levenbergi-Marquardt vĂ”i suurte meetodite, nagu Newtoni-Krylov).

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.

SciPy, optimeerimine

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()

SciPy, optimeerimine

Teades ette, et miinimum on 0, kui SciPy, optimeerimine, 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. Nelder-Meadi simplex (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 Pauli meetod. 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 BFGS 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:

SciPy, optimeerimine

SciPy, optimeerimine

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

SciPy, optimeerimine

SciPy, optimeerimine

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 der

Gradienti 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 Newtoni konjugaatide gradientide on muudetud Newtoni meetod.
Newtoni meetod pĂ”hineb funktsiooni lĂ€hialas teise astme polĂŒnoomi abil lĂ€hendamisel:

SciPy, optimeerimine

kus SciPy, optimeerimine 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:

SciPy, optimeerimine

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:

SciPy, optimeerimine

SciPy, optimeerimine

kus SciPy, optimeerimine ja SciPy, optimeerimine, mÀÀravad maatriksi SciPy, optimeerimine.

ÜlejÀÀnud mitte nullid maatriksi elemendid on:

SciPy, optimeerimine

SciPy, optimeerimine

SciPy, optimeerimine

SciPy, optimeerimine

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

SciPy, optimeerimine

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 SciPy, optimeerimine on jĂ€rgmine:

SciPy, optimeerimine

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: 66

Usalduspiiri (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 usalduspiiri meetodit (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.x

Optimeerimine 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: https://docs.scipy.org/doc/scipy/reference/

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster