SciPy, optimeerimine

SciPy, optimeerimine

SciPy (hÀÀldatakse kui sai pai) on rakenduslike matemaatiliste protseduuride paket, mis pĂ”hineb Python'i Numpy laiendusel. SciPy muudab interaktiivse Python'i seansi samasuguseks tĂ€ielikuks andmete töötlemise ja keerukate sĂŒsteemide prototĂŒĂŒpimise keskkonnaks nagu MATLAB, IDL, Octave, R-Lab ja SciLab. TĂ€na tahan lĂŒhidalt rÀÀkida sellest, kuidas rakendada mĂ”ningaid tuntud optimeerimisalgoritme scipy.optimize pakendis. Ülevaatlikku ja ajakohast dokumentatsiooni funktsioonide rakendamise kohta saab alati kĂ€ivitades kĂ€sku help() vĂ”i kasutades Shift+Tab klahvikombinatsiooni.

Sissejuhatus

Kuna tahaksin end ja lugejaid sÀÀsta allikate otsimisest ja lugemisest, viidatakse meetodite kirjelduste osas peamiselt vikipeedia lehtedele. Üldiselt piisab sellest infost meetodite ĂŒldiseks mĂ”istmiseks ja nende rakendustingimuste tundmiseks. Matemaatiliste meetodite olemuse mĂ”istmiseks suundume linkide kaudu autoriteetsematesse vĂ€ljaannetesse, mille leiate iga artikli lĂ”pus vĂ”i oma lemmikotsingumootorist.

Seega sisaldab modul scipy.optimize jÀrgmisi protseduure:

  1. Konditsionaalne ja tingimusteta mitme muutuja skalaarsed funktsioonid (minim) erinevate algoritmide (Nelder-Meade simplex, BFGS, Newtoni konjugaatgraafikud) abil. COBYLA ja SLSQP)
  2. Globaalne optimeerimine (nÀiteks: basinhopping, diff_evolution)
  3. JÀÀkide minimaliseerimine MNLK (least_squares) ja mittelineaarsete MNLK kÔverate sobitamise algoritmid (curve_fit)
  4. Ühe muutujaga skalaarsete funktsioonide minimaliseerimine (minim_scalar) ja juurte otsimine (root_scalar)
  5. MitmemÔÔtmelised vĂ”rrandite lahendajad (root) erinevate algoritmide abil (hĂŒbriidne Powell, Levenbergi-Marquardt vĂ”i suuremassilised meetodid, nagu Newtoni-Krylov).

KĂ€esolevas artiklis vaatleme ainult nimekirja esimest punkti.

Tingimusteta mitme muutuja skalaarsest funktsioonist

Paketi scipy.optimize funktsioon minim pakub ĂŒldist liidest mitme muutuja skalaarsed funktsioonid tingimusliku ja tingimusteta minimiseerimiseks. Selle töö demonstreerimiseks vajame sobivat mitme muutuja funktsiooni, mida me tahame erinevalt minimeerida.

Selleks sobib suurepÀraselt Rosenbrocki funktsioon N muutuja jaoks, mille kuju on jÀrgmine:

SciPy, optimeerimine

Kuigi Rosenbrocki funktsioon ja tema Jakobi ja Hesse maatriksid (esimene ja teine derivaat vastavalt) on juba mÀÀratletud scipy.optimize pakettis, mÀÀratlegem see 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 jÀrgi.

Joonistamise kood

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

# DĂŒnaamiline 3D joonis
fig = plt.figure(figsize=[15, 10])
ax = fig.gca(projection='3d')

# MÀÀrame vaatenurga
ax.view_init(45, 30)

# Loome andmed joonise 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 pinda
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm)
plt.show()

SciPy, optimeerimine

Teades eelnevalt, et miinimum on 0, kui SciPy, optimeerimine, vaatleme nÀiteid, kuidas leida Rosenbrocki funktsiooni miinimum erinevate scipy.optimize protseduuride abil.

Nelder-Meadi simplex meetod

Olgu meil algpunkt x0 5-mÔÔtmelises ruumis. Leiame selle lÀhedal asuva miinimumpunkti Rosenbrocki funktsiooni jaoks, kasutades Nelder-Meadi simplex'i (meetod on mÀÀratud parameetri method vÀÀrtusena):

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Ôpetati edukalt.
         Praegune funktsiooni vÀÀrtus: 0.000000
         Iteratsioonid: 339
         Funktsiooni hindamised: 571
[1. 1. 1. 1. 1.]

Simplex meetod on kĂ”ige lihtsam viis selgelt mÀÀratletud ja ĂŒsna sujuva funktsiooni miinimumini viimiseks. See ei vaja funktsiooni tuletiste arvutamist, piisab vaid selle vÀÀrtuste sisestamisest. Nelder-Meadi meetod on hea valik lihtsate optimeerimisĂŒlesannete jaoks. Kuid kuna see ei kasuta gradientide hinnanguid, vĂ”ib miinimumi leidmiseks kuluda rohkem aega.

Powelli meetod

Teine optimeerimise algoritm, kus arvutatakse ainult funktsioonide vÀÀrtusi, on Powelli meetod.Seda kasutamiseks peab meetodi vÀÀrtuseks olema seatud '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Ôpetati edukalt.
         Praegune funktsiooni vÀÀrtus: 0.000000
         Iteratsioonid: 19
         Funktsiooni hindamised: 1622
[1. 1. 1. 1. 1.]

Broyden-Fletcher-Goldfarb-Shanno (BFGS) algoritm

Kiirema lahenduse saavutamiseks kasutage protseduuri BFGS kasutab sihtfunktsiooni gradienti. Gradient saab olla mÀÀratud funktsioonina vÔi arvutatuna esimese jÀrgu erinevustega. Igal juhul nÔuab meetod BFGS tavaliselt vÀhem funktsioonikutsungeid kui simplex-meetod.

Leiame Rosenbrocki funktsiooni derivaadi analĂŒĂŒtiliselt:

SciPy, optimeerimine

SciPy, optimeerimine

See avaldis on kehtiv kÔigi muutujate derivaatide jaoks, vÀlja arvatud esimene ja viimane, mis mÀÀratakse jÀrgmiselt:

SciPy, optimeerimine

SciPy, optimeerimine

Vaadakem Python'i 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ÀÀratakse minim-funktsiooni parameetri jac vÀÀrtusena, nagu on nÀidatud allpool.

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]

Konjugaatide gradientide algoritm (Newtoni)

Algoritm Newtoni konjugaatide gradientide on muudetud Newtoni meetod.
Newtoni meetod pĂ”hineb funktsiooni ligikaudsel esitlemisel kohalikus piirkonnas teise astme polĂŒnoomiga:

SciPy, optimeerimine

kus SciPy, optimeerimine on teise jÀrgu derivaatide maatriks (Hessi maatriks, hessiaan).
Kui hessiaan on positiivselt mÀÀratud, saab selle funktsiooni kohalikku miinimumi leida, seades ruutfunktsiooni nullgradienti nulliks. Tulemuseks on avaldis:

SciPy, optimeerimine

Hessi tagasi arvutatakse konjugaatide gradientide meetodi abil. Allpool on nÀide selle meetodi kasutamisest Rosenbrocki funktsiooni minimeerimiseks. Newtone-CG meetodi kasutamiseks tuleb mÀÀrata funktsioon, mis arvutab hessiaani.
Rosenbrocki funktsiooni hessiaan analĂŒĂŒtiliselt vĂ”rdub:

SciPy, optimeerimine

SciPy, optimeerimine

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

ÜlejÀÀnud mitte null elemendid maatriksis on:

SciPy, optimeerimine

SciPy, optimeerimine

SciPy, optimeerimine

SciPy, optimeerimine

NÀiteks viie mÔÔtmelises ruumis N = 5, Rosenbrocki funktsiooni Hessi maatriks on lintkujuline:

SciPy, optimeerimine

Kood, mis arvutab selle hessiaani koos koodiga Rosenbrocki funktsiooni minimeerimiseks konjugaatide gradientide meetodi (Newtoni) abil:

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Ôpetati edukalt.
         Praegune funktsiooni vÀÀrtus: 0.000000
         Iteratsioonid: 24
         Funktsiooni hindamised: 33
         Gradientide hindamised: 56
         Hessianide hindamised: 24
[1.         1.         1.         0.99999999 0.99999999]

NÀide Hessi maatriksi ja juhusliku vektori mÀÀramisest

Reaalsetes ĂŒlesannetes vĂ”ib Hessi maatriksi tĂ€ieliku arvutamise ja salvestamise protsess nĂ”uda mĂ€rkimisvÀÀrseid ressursse, nagu aega ja mĂ€lu. Samas pole tegelikult vaja mÀÀrata Hessi maatriksit, kuna minimaalsete protseduuride jaoks on vajalik ainult vektor, mis vĂ”rdub Hessi maatriksi ja mĂ”ne muu juhusliku vektori korrutisega. SeetĂ”ttu on arvutuslikult palju mugavam kohe mÀÀratleda funktsioon, mis tagastab Hessi maatriksi korrutise juhusliku vektoriga.

Vaatleme funktsiooni hess, mis vĂ”tab minimaalse vektori esimesena argumendina ning juhusliku vektori teise argumendina (koos teiste minimiseeritava funktsiooni argumentidega). Meie puhul pole Rosenbrocki funktsiooni Hessi maatriksi korrutise arvutamine juhusliku vektoriga vĂ€ga keeruline. Kui p — juhuslik vektor, siis korrutis SciPy, optimeerimine on kujul:

SciPy, optimeerimine

Hessi maatriksi ja juhusliku vektori korrutuse arvutamiseks edastatakse funktsioon argumendina hessp minimiseerimise funktsioonile:

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.
         Praegune funktsiooni vÀÀrtus: 0.000000
         Iteratsioonid: 24
         Funktsiooni hindamised: 33
         Gradientide hindamised: 56
         Hessianide hindamised: 66

Usalduspiirkonna (trust region) paarisgradientide (Newtoni) algoritm

Hessi maatriksi halb mÀÀramatus ja vale otsingu suunad vÔivad pÔhjustada seda, et paarisgradientide Newtoni algoritm vÔib olla ebatÔhus. Sellistes olukordades eelistatakse usalduspiirkonna meetodit (trust-region) paarisgradientide Newtoni meetodit.

NÀide Hessi maatriksi mÀÀramisest:

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
         Hessiani hindamised: 19
[1. 1. 1. 1. 1.]

NĂ€ide hessiani ja juhusliku vektori korrutamise 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
         Hessiani hindamised: 0
[1. 1. 1. 1. 1.]

Krylov'i tĂŒĂŒpi meetodid

Sarnaselt trust-ncg meetodile sobivad Krylov'i tĂŒĂŒpi meetodid hĂ€sti suurte probleemide lahendamiseks, kuna need kasutavad ainult maatriksi-vektori korrutamisi. Nende tuum on usaldusvÀÀrse piirkonna lahendamine, mida piirab Krylov'i lĂ”igatud alamruum. MÀÀramata probleemide korral on parem kasutada seda meetodit, kuna see vajab vĂ€hem mittekonkreetseid iteratsioone madalama maatriksi-vektori korrutamiste arvu tĂ”ttu ĂŒhe alaprobleemi puhul vĂ”rreldes trust-ncg meetodiga. Lisaks leitakse kvadrilise alaprobleemi lahendus tĂ€psemalt kui trust-ncg meetodiga.
NÀide Hessi maatriksi mÀÀramisest:

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

Optimeerimine lÔpetati edukalt.
         Praegune funktsiooni vÀÀrtus: 0.000000
         Iteratsioonid: 19
         Funktsiooni hindamised: 20
         Gradientide hindamised: 20
         Hessiani hindamised: 18

print(res.x)

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

NĂ€ide hessiani ja juhusliku vektori korrutamise 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.
         Praegune funktsiooni vÀÀrtus: 0.000000
         Iteratsioonid: 19
         Funktsiooni hindamised: 20
         Gradientide hindamised: 20
         Hessiani hindamised: 0

print(res.x)

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

UsaldusvÀÀrse piirkonna lÀhenemisviisi algoritm

KÔik meetodid (Newton-CG, trust-ncg ja trust-krylov) sobivad hÀsti suurte probleemide lahendamiseks (tuhandete muutujatega). See tuleneb asjaolust, et nende aluseks olev konjugeeritud gradientide algoritm eeldab Hessiani pöördmatrise ligikaudset leidmist. Lahendus leitakse iteratiivselt, ilma Hessiani selges vormis lagundamiseta. Kuna on vajalik mÀÀrata ainult funktsioon Hessiani ja juhusliku vektori korrutamiseks, on see algoritm eriti hea haruldaste (vööndi diagonaalsete) maatriskatega töötamiseks. See tagab madalad mÀlukulud ja olulise ajakokkuhoiu.

Keskmise suurusega ĂŒlesannetes salvestamise ja Hessiani faktorisatsiooni kulud ei ole mÀÀravad. See tĂ€hendab, et lahenduse vĂ”ib saada vĂ€hemate iteratsioonide arvuga, lahendades usalduspiirkonna osauuringud peaaegu tĂ€pselt. Selleks lahendatakse mĂ”ned mittejoonised iteratiivselt iga ruutĂŒlesande jaoks. Selline lahendus nĂ”uab tavaliselt 3-4 Cholesky dekompositsiooni Hessiani maatriksi jaoks. SeetĂ”ttu konverdib meetod vĂ€hemate iteratsioonidega ja nĂ”uab vĂ€hem eesmĂ€rgi funktsiooni arvutusi kui teised rakendatud usalduspiirkonna meetodid. See algoritm eeldab ainult tĂ€ieliku Hessiani maatriksi mÀÀratlemist ning ei toeta vĂ”imalust kasutada Hessiani funktsiooni ja mis tahes vektori produktsiooni.

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Ôpetatud eduka 
         Praegune funktsiooni vÀÀrtus: 0.000000
         Iteratsioonide arv: 13
         Funktsiooni arvutused: 14
         Gradientide arvutused: 13
         Hessiani arvutused: 14

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

Sellele paneme tĂ”enĂ€oliselt punkti. JĂ€rgmises artiklis pĂŒĂŒan rÀÀkida kĂ”ige huvitavamast tingimuslikust minimeerimisest, minimeerimise rakendamisest approximatsiooni ĂŒlesannete lahendamisel, ĂŒhe muutuja funktsiooni minimeerimisest, mis tahes minimeerijatest ja vĂ”rrandisĂŒsteemide juurte leidmisest scipy.optimize paketi abil.

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

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster