SciPy, optimizācija

SciPy, optimizācija

SciPy (izrunā kā 'sai pai') ir pielietoto matemātisko procedÅ«ru pakete, kas balstÄ«ta uz Numpy Python paplaÅ”inājuma. Ar SciPy mijiedarbÄ«bas sesija Python pārvērÅ”as pilnvērtÄ«gā datu apstrādes un sarežģītu sistēmu prototipēŔanas vidē, lÄ«dzÄ«gi kā MATLAB, IDL, Octave, R-Lab un SciLab. Å odien es vēlos Ä«si pastāstÄ«t par to, kā vajadzētu piemērot dažus pazÄ«stamus optimizācijas algoritmus paketē scipy.optimize. SÄ«kāku un aktuālāku informāciju par funkciju izmantoÅ”anu var vienmēr iegÅ«t, izmantojot komandu help() vai Shift+Tab.

Ievads

Lai atbrÄ«votos no veltÄ«gas laika tērēŔanas sev un lasÄ«tājiem, saites uz metožu aprakstiem bÅ«s galvenokārt uz Vikipēdiju. Parasti Ŕīs informācijas pietiek, lai izprastu metodes vispārÄ«gās iezÄ«mes un to pielietoÅ”anas apstākļus. Lai saprastu matemātisko metožu bÅ«tÄ«bu, pārvietojamies uz saiknēm uz autoritatÄ«vākām publikācijām, kuras var atrast katras raksta beigās vai savā iecienÄ«tajā meklētājā.

Tātad, modulis scipy.optimize ietver Ŕādu procedūru īstenoŔanu:

  1. Nosacītā un beznosacījuma minimizācija skalarfunkcijām ar vairākiem mainīgajiem (minim) dažādu algoritmu (Neldera-Mida simplex, BFGS, Ņūtona konjugēto gradientu) palīdzību, COBYLA un SLSQP)
  2. Globālā optimizācija (piemēram: basinhopping, diff_evolution)
  3. Minimizācija atliekām MKM (least_squares) un nelineāro MNM (curve_fit) algoritmi
  4. Minimizācija skalarfunkcijām ar vienu mainÄ«go (minim_scalar) un sakņu meklēŔana (root_scalar)
  5. Daudzdimensionālie vienādojumu risinātāji (root), izmantojot dažādus algoritmus (hipbridais Pauels, Levenberga-Marquardt vai masveida metodes, piemēram, Ņūtons-Krilovs).

Šajā rakstā aplūkosim tikai pirmo punktu no visa Ŕī saraksta.

Beznosacījumu minimizācija skalarfunkcijai ar vairākiem mainīgajiem

Funkcija minim no paketes scipy.optimize nodroÅ”ina vispārēju interfeisu skalarfunkciju ar vairākiem mainÄ«gajiem nosacÄ«tās un beznosacÄ«juma minimizācijas uzdevumu risināŔanai. Lai demonstrētu tās darbÄ«bu, mums bÅ«s nepiecieÅ”ama piemērota funkcija ar vairākiem mainÄ«gajiem, kuru mēs dažādi minimizēsim.

Å iem nolÅ«kiem lieliski derēs Rozemberga funkcija no N mainÄ«gajiem, kas ir Ŕāda:

SciPy, optimizācija

Neskatoties uz to, ka Rozebrokas funkcija un tās Jākobi un Hess matriks (pirmā un otrā atvasinājums attiecÄ«gi) jau ir definēti paketē scipy.optimize, noskaidrosim to paÅ”i.

import numpy as np

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

Lai parādītu, attēlosim 3D Rozebrokas funkcijas vērtības no divām mainīgajām.

Kods attēloÅ”anai

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

# Iestatām 3D grafiku
fig = plt.figure(figsize=[15, 10])
ax = fig.gca(projection='3d')

# Norādām skatījuma leņķi
ax.view_init(45, 30)

# Izveidojam datus grafikam
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]))

# Zīmējam virsmu
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm)
plt.show()

SciPy, optimizācija

Zinot iepriekÅ”, ka minimums ir 0 pie SciPy, optimizācija, aplÅ«kosim piemērus, kā noteikt Rozebrokas funkcijas minimālo vērtÄ«bu, izmantojot dažādas procedÅ«ras scipy.optimize.

Nelder-Mead simpliksa metode

Pieņemot, ka ir sākumpunkts x0 5 dimensiju telpā. Atrast tuvāko minimuma punktu Rozebrokas funkcijai, izmantojot algoritmu Nelder-Mead simplices (algoritms norādīts kā parametra method vērtība):

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)

Optimizācija veiksmīgi pabeigta.
         PaÅ”reizējā funkcijas vērtÄ«ba: 0.000000
         Iterācijas: 339
         Funkciju novērtējumi: 571
[1. 1. 1. 1. 1.]

Simpliksa metode ir visvienkārŔākais veids, kā minimizēt skaidri definētu un diezgan gludu funkciju. Tā neprasa funkcijas atvasinājumu aprēķināŔanu, pietiek tikai norādÄ«t tās vērtÄ«bas. Nelder-Mead metode ir laba izvēle vienkārŔām minimizācijas uzdevumiem. Tomēr, jo tā neizmanto gradienta novērtējumus, minimuma atraÅ”anai var bÅ«t nepiecieÅ”ams vairāk laika.

Pauela metode

Cits optimizācijas algoritms, kurā tiek aprēķinātas tikai funkciju vērtÄ«bas, ir Pauela metode.Lai to izmantotu, nepiecieÅ”ams noregulēt method = 'powell' funkcijā 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)

Optimizācija veiksmīgi pabeigta.
         PaÅ”reizējā funkcijas vērtÄ«ba: 0.000000
         Iterācijas: 19
         Funkciju novērtējumi: 1622
[1. 1. 1. 1. 1.]

Broyden-Fletcher-Goldfarb-Shanno (BFGS) algoritms

Lai sasniegtu ātrāku konverÄ£enci uz risinājumu, procedÅ«ra BFGS izmanto mērÄ·a funkcijas gradientu. Gradientu var norādÄ«t kā funkciju vai aprēķināt, izmantojot pirmās kārtas atŔķirÄ«bas. Jebkurā gadÄ«jumā BFGS metode parasti prasa mazāk funkciju izsaukumu nekā simplex metode.

Apskatīsim Rōzenbroka funkcijas atvasinājumu analītiskā veidā:

SciPy, optimizācija

SciPy, optimizācija

Å is izteikums ir spēkā visām mainÄ«gajām atvasinājumiem, izņemot pirmo un pēdējo, kuras tiek noteiktas Ŕādi:

SciPy, optimizācija

SciPy, optimizācija

PārbaudÄ«sim Python funkciju, kas aprēķina Å”o gradientu:

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

Gradienta aprēķināŔanas funkcija tiek norādÄ«ta kā parametra jac vērtÄ«ba funkcijā minim, kā parādÄ«ts zemāk.

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

Optimizācija veiksmīgi beigusies.
         PaÅ”reizējā funkcionālā vērtÄ«ba: 0.000000
         Iterācijas: 25
         Funkciju novērtējumi: 30
         Gradienta novērtējumi: 30
[1.00000004 1.0000001  1.00000021 1.00000044 1.00000092]

Kopējo gradientu algoritms (Ņūtona)

Algoritms Ņūtona kopējo gradientu ir modificētā Ņūtona metode.
Ņūtona metode balstās uz funkcijas apmēram lokālā apgabalā ar otrā ŔķirÄ«bas polinomu:

SciPy, optimizācija

kur SciPy, optimizācija ir otro atvasinājumu matrica (Hesse matrica, hesians).
Ja hesians ir pozitīvi noteikts, tad lokālo minimumu var atrast, pielāgojot nulles gradienta kvadrātveida formu nullei. Rezultātā iegūsim izteikumu:

SciPy, optimizācija

ApmainÄ«tais hesians tiek aprēķināts, izmantojot kopējo gradientu metodi. Zemāk ir piemērs, kā izmantot Å”o metodi Rōzenbroka funkcijas minimizācijai. Lai izmantotu Newton-CG metodi, ir jānorāda funkcija, kas aprēķina hesianu.
Rōzenbroka funkcijas hesians analītiskā veidā ir:

SciPy, optimizācija

SciPy, optimizācija

kur SciPy, optimizācija un SciPy, optimizācija, nosaka matricu SciPy, optimizācija.

Pārējie nenulles elementu matrica ir:

SciPy, optimizācija

SciPy, optimizācija

SciPy, optimizācija

SciPy, optimizācija

Piemēram, piecu dimensiju telpā N = 5, Hesse matrica Rōzenbroka funkcijai ir joslas veidā:

SciPy, optimizācija

Kods, kas aprēķina Å”o hesianu kopā ar kodu Rōzenbroka funkcijas minimizācijai, izmantojot kopējo gradientu metodi (Ņūtona):

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)

Optimizācija tika veiksmīgi pabeigta.
         EsoŔā funkcionālā vērtÄ«ba: 0.000000
         Iterācijas: 24
         Funkciju novērtējumi: 33
         Gradienta novērtējumi: 56
         Hesiāna novērtējumi: 24
[1.         1.         1.         0.99999999 0.99999999]

Piemērs ar Hesiāna funkcijas un jauka vektora noteikÅ”anu

Reālās problēmās Hesiāna matricas aprēķins un saglabāŔana var prasÄ«t ievērojamus laika un atmiņas resursus. Tādējādi faktiski nav nepiecieÅ”ams noteikt paÅ”u Hesiāna matricu, jo minimizēŔanas procedÅ«rai nepiecieÅ”ams tikai vektors, kas ir Hesiāna reizinājums ar citu jauku vektoru. Tādējādi, no aprēķinu viedokļa, daudz gaidāmāka ir tÅ«lÄ«tēja funkcijas noteikÅ”ana, kas atgriež Hesiāna reizinājuma rezultātu ar jauku vektoru.

ApskatÄ«sim funkciju hess, kas pieņem minimizēŔanas vektoru kā pirmo argumentu un jauku vektoru kā otro argumentu (kopā ar citiem minimizējamās funkcijas argumentiem). MÅ«su gadÄ«jumā aprēķināt Hesiāna reizinājumu ar funkciju Rosenbrock nav pārāk sarežģīti. Ja p — jauks vektors, tad reizinājums SciPy, optimizācija ir Ŕāds:

SciPy, optimizācija

Funkcija, kas aprēķina Hesiāna un jauka vektora reizinājumu, tiek nodota kā argumenta hessp vērtība funkcijai 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})

Optimizācija tika veiksmīgi pabeigta.
         EsoŔā funkcionālā vērtÄ«ba: 0.000000
         Iterācijas: 24
         Funkciju novērtējumi: 33
         Gradienta novērtējumi: 56
         Hesiāna novērtējumi: 66

Uzticības reģiona (trust region) konjugēto gradientu (Newton) algoritms

Slikta Hesiāna matricas nosegtÄ«ba un nepareizi meklēŔanas virzieni var izraisÄ«t Newton konjugēto gradientu algoritmu neefektÄ«vu. Šādos gadÄ«jumos priekÅ”roka tiek dota uzticÄ«bas reÄ£iona metodei (trust-region) konjugēto gradientu Newton algoritmam.

Piemērs ar Hesiāna matricas noteikÅ”anu:

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

Optimizācija sekmīgi pabeigta.
         PaÅ”reizējā funkcijas vērtÄ«ba: 0.000000
         Iterācijas: 20
         Funkciju novērtējumi: 21
         Gradientu novērtējumi: 20
         Hesiena novērtējumi: 19
[1. 1. 1. 1. 1.]

Piemērs ar hesiena funkcijas un nejauÅ”a vektora reizinājumu:

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

Optimizācija sekmīgi pabeigta.
         PaÅ”reizējā funkcijas vērtÄ«ba: 0.000000
         Iterācijas: 20
         Funkciju novērtējumi: 21
         Gradientu novērtējumi: 20
         Hesiena novērtējumi: 0
[1. 1. 1. 1. 1.]

Krylov tipu metodes

LÄ«dzÄ«gi kā trust-ncg metode, Krylov tipu metodes ir labi piemērotas lielo uzdevumu risināŔanai, jo tām tiek izmantotas tikai matricas-vektoru reizinājumi. Tās bÅ«tÄ«ba ir uzdevuma risināŔana uzticÄ«bas jomā, kas ierobežota ar Krylov trÄ«sdaļu apakÅ”telpu. Neizmantotām problēmām Ŕī metode ir labākā izvēle, jo tā izmanto mazāk nelineāru iterāciju, pateicoties mazākam matricas-vektoru reizinājumu skaitam vienai apakÅ”uzdevumam, salÄ«dzinot ar trust-ncg metodi. Turklāt kvadrātiskā apakÅ”uzdevuma risinājums tiek iegÅ«ts precÄ«zāk nekā ar trust-ncg metodi.
Piemērs ar Hesiāna matricas noteikÅ”anu:

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

Optimizācija sekmīgi pabeigta.
         PaÅ”reizējā funkcijas vērtÄ«ba: 0.000000
         Iterācijas: 19
         Funkciju novērtējumi: 20
         Gradientu novērtējumi: 20
         Hesiena novērtējumi: 18

print(res.x)

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

Piemērs ar hesiena funkcijas un nejauÅ”a vektora reizinājumu:

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

Optimizācija sekmīgi pabeigta.
         PaÅ”reizējā funkcijas vērtÄ«ba: 0.000000
         Iterācijas: 19
         Funkciju novērtējumi: 20
         Gradientu novērtējumi: 20
         Hesiena novērtējumi: 0

print(res.x)

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

Uzticības jomā iegūtā risinājuma algoritms

Visas metodes (Newton-CG, trust-ncg un trust-krylov) ir labi piemērotas lielo uzdevumu risināŔanai (ar tÅ«kstoÅ”iem mainÄ«go). Tas ir saistÄ«ts ar to, ka tās pamats ir otru gradientu algoritms, kas nozÄ«mē galÄ«go Hesiena apgriezto matricas meklēŔanu. Risinājums nonāk pakāpeniski, neveicot skaidru hesiena sadalÄ«jumu. Tā kā ir jānosaka tikai funkcija hesiena un nejauÅ”a vektora reizināŔanai, Å”is algoritms ir Ä«paÅ”i labs, strādājot ar retām (slāņveida diagonālām) matricām. Tas nodroÅ”ina zemu atmiņas patēriņu un bÅ«tisku laika ietaupÄ«jumu.

Vidēja lieluma uzdevumos uzglabāŔanas un Hessiana faktorizācijas izmaksas nav izŔķiroÅ”as. Tas nozÄ«mē, ka risinājumu var iegÅ«t mazākā iterāciju skaitā, gandrÄ«z precÄ«zi atrisinot uzticÄ«bas reÄ£iona apakÅ”uzdevumus. Tādējādi daži nelineārie vienādojumi tiek atrisināti iteratÄ«vi katram kvadrātiskajam apakÅ”uzdevumam. Šāds risinājums parasti prasa 3 vai 4 Holeska matricas dekompozÄ«cijas. Rezultātā metode konverģē mazākā iterāciju skaitā un prasa mazāk mērÄ«jumu no mērÄ·a funkcijas, nekā citi Ä«stenotie uzticÄ«bas reÄ£iona algoritmi. Å is algoritms paredz tikai pilnas Hessiana matricas noteikÅ”anu un neatbalsta iespēju izmantot Hessiana un nejauÅ”a vektora reizinājumu.

Piemērs ar Rozenbroka funkcijas minimizēŔanu:

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

Optimizācija veiksmīgi pabeigta.
         PaÅ”reizējā funkcijas vērtÄ«ba: 0.000000
         Iterācijas: 13
         Funkciju novērtējumi: 14
         Gradienta novērtējumi: 13
         Hessiana novērtējumi: 14

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

Uz Å”o, domāju, apstāsimies. Nākamajā rakstā centīŔos pastāstÄ«t interesantāko par nosacÄ«tu minimizāciju, minimizācijas pielietojumu aptuvenoÅ”anu risināŔanā, vienas mainÄ«gās funkcijas minimizāciju, dažādiem minimizatoriem un sistēmas vienādojumu sakņu meklēŔanu, izmantojot scipy.optimize pakotni.

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

Avots: habr.com

Iegādājieties uzticamu tÄ«mekļa hostingu ar DDoS aizsardzÄ«bu, VPS VDS serveriem šŸ”„ Iegādājieties uzticamu tÄ«mekļa hostingu ar DDoS aizsardzÄ«bu, VPS VDS serveriem | ProHoster