SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy (hÀÀldatakse nagu sai pai) on numpy'le pÔhinev matemaatikapakett, mis sisaldab ka C- ja Fortran-raamatukogusid. SciPy muudab interaktiivse Python seansi tÀielikuks andmetöötluskeskkonnaks, nagu MATLAB, IDL, Octave, R vÔi SciLab.

Selles artiklis vaatleme matemaatilise programmeerimise pĂ”himeetodeid — tingimustega optimeerimise probleemide lahendamine mitme muutuja skalaarsest funktsioonist scipy.optimize paketi abil. Ilma tingimusteta optimeerimise algoritmid on juba kĂ€sitletud eelmisel artiklil. Üksikasjalikku ja ajakohast teavet funktsioonide kohta scipy's saab alati kasutada kĂ€su help(), Shift+Tab vĂ”i ametlikust dokumentatsioonist.

Sissejuhatus

Üks ĂŒhtne liides tingimustega ja ilma tingimusteta optimeerimise probleemide lahendamiseks scipy.optimize pakendis antakse funktsiooni kaudu minimize(). Siiski on teada, et universaalset viisi kĂ”igi probleemide lahendamiseks ei eksisteeri, seega langeb sobiva meetodi valik alati uurija Ă”lgadele.
Sobiv optimeerimisalgoritm mÀÀratakse funktsiooni argumendi kaudu minimize(..., method="").
Mitme muutuja tingimustega optimeerimise jaoks on saadaval jÀrgmiste meetodite rakendused:

  • trust-constr — lokaalse miinimumi otsimine usaldusvÀÀrsuspiirkonnas. Artikkel vikis, artikkel habras;
  • SLSQP — jĂ€rjestikune kvadratiivne programmeerimine piirangutega, Newtoni meetod Lagrange'i sĂŒsteemi lahendamiseks. Artikkel vikis.
  • TNC — Truncated Newton Constrained, piiratud iteratsioonide arv, sobiv mitteeline funktsioonide jaoks, millel on palju sĂ”ltumatuid muutujaid. Artikkel vikis.
  • L-BFGS-B — Broyden–Fletcher–Goldfarb–Shanno meetod, mis on rakendatud vĂ€hendatud mĂ€lu tarbimisega, osalise Hess'i maatriksi vektorite laadimise kaudu. Artikkel vikis, artikkel habras.
  • COBYLA — KOBYLA Constrained Optimization By Linear Approximation, piiratud optimeerimine lineaarsest lĂ€henemisest (ilma gradientide arvutamiseta). Artikkel vikis.

SÔltuvalt valitud meetodist mÀÀratakse tingimused ja piirangud probleemide lahendamiseks erinevalt:

  • klassist objekti Bounds meetodite jaoks L-BFGS-B, TNC, SLSQP, trust-constr;
  • loendi (min, max) nende sama meetodite L-BFGS-B, TNC, SLSQP, trust-constr jaoks;
  • objekti vĂ”i objektide loend LinearConstraint, NonlinearConstraint meetodite jaoks COBYLA, SLSQP, trust-constr;
  • sĂ”nastiku vĂ”i sĂ”nastike loendi {'type':str, 'fun':callable, 'jac':callable,opt, 'args':sequence,opt} meetodite jaoks COBYLA, SLSQP.

Artikli plaan:
1) Uurida tingimuslikku optimeerimisalgoritmi usaldusvÀÀrses valdkonnas (method=»trust-constr») piirangutega, mis on mÀÀratletud objektidena. Bounds, LinearConstraint, NonlinearConstraint ;
2) Uurida jÀrjestikust programmeerimist vÀhenenud ruutude meetodil (method=»SLSQP») piirangutega, mis on mÀÀratletud sÔnastikuna. {'type', 'fun', 'jac', 'args'};
3) AnalĂŒĂŒsida toodangu optimeerimise nĂ€idet veebistuudio nĂ€itel.

Tingimuslik optimeerimine method=»trust-constr»

Meetodi rakendamine trust-constr on pĂ”hinenud EQSQP vĂ”rdsete piirangutega probleemidele ja TRIP ebaĂŒhtsete piirangute probleemidele. MĂ”lemad meetodid on ellu viidud usaldusvÀÀrse piirkonna kohaliku miinimumi otsimise algoritmidega ja sobivad hĂ€sti suurte probleemide lahendamiseks.

Probleemi matemaatiline vorm ĂŒldiselt minimumi leidmiseks:

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

Tehete range vĂ”rdsuse puhul seotakse alumine piir ĂŒlemise kĂŒlge. SciPy, optimeerimine tingimustega.
Ühepoolse piirangu korral seatakse ĂŒlemine vĂ”i alumine piir np.inf vastava mĂ€rgiga.
Oletame, et tuleb leida miinimum tuntud Rosenbrocki funktsioonist, mis sÔltub kahest muutuja:

SciPy, optimeerimine tingimustega

Sellel on mÀÀratud jÀrgmised piirangud selle mÀÀramispiirkonnale:

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

Meie juhul on olemas ainus lahendus punktis SciPy, optimeerimine tingimustega, kus kehtivad ainult esimene ja neljas piirang.
Liigume piirangute kaudu alt ĂŒles ja uurime, kuidas neid scipy-s ĂŒles kirjutada.
Piirangud SciPy, optimeerimine tingimustega ja SciPy, optimeerimine tingimustega mÀÀra objekti Bounds abil.

from scipy.optimize import Bounds
bounds = Bounds ([0, -0.5], [1.0, 2.0])

Piirangud SciPy, optimeerimine tingimustega ja SciPy, optimeerimine tingimustega kirjutame lineaarse vormina:

SciPy, optimeerimine tingimustega

MÀÀrame need piirangud objekti LinearConstraint kujul:

import numpy as np
from scipy.optimize import LinearConstraint
linear_constraint = LinearConstraint ([[1, 2], [2, 1]], [-np.inf, 1], [1, 1])

Ja lÔpuks mitte-lineaarne piirang maatriksivormis:

SciPy, optimeerimine tingimustega

MÀÀrame selle piirangu jaoks Jakobian ja Hesse maatriksi lineaarse kombinatsiooni suvalise vektoriga. SciPy, optimeerimine tingimustega:

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

NĂŒĂŒd saame mitte-lineaarse piirangu mÀÀrata objekti NonlinearConstraint:

from scipy.optimize import NonlinearConstraint

def cons_f(x):
     return [x[0]**2 + x[1], x[0]**2 - x[1]]

def cons_J(x):
     return [[2*x[0], 1], [2*x[0], -1]]

def cons_H(x, v):
     return v[0]*np.array([[2, 0], [0, 0]]) + v[1]*np.array([[2, 0], [0, 0]])

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=cons_H)

Kui suurus on suur, saab maatriseid mÀÀrata ka hÔredas vormis:

from scipy.sparse import csc_matrix

def cons_H_sparse(x, v):
     return v[0]*csc_matrix([[2, 0], [0, 0]]) + v[1]*csc_matrix([[2, 0], [0, 0]])

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1,
                                            jac=cons_J, hess=cons_H_sparse)

vÔi objekti LinearOperator:

scipy.sparse.linalg import LinearOperator

def cons_H_linear_operator(x, v):
    def matvec(p):
        return np.array([p[0]*2*(v[0]+v[1]), 0])
    return LinearOperator((2, 2), matvec=matvec)

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1,
                                jac=cons_J, hess=cons_H_linear_operator)

Kui Hessian-matriisi arvutamine SciPy, optimeerimine tingimustega nÔuab suurt ressursikasutust, saab kasutada klassi HessianUpdateStrategy. Saadaval on jÀrgmised strateegiad: BFGS ja SR1.

scipy.optimize import BFGS

nonlinear_constraint = NonlinearConstraint(cons_f, -np.inf, 1, jac=cons_J, hess=BFGS())

Hessianti saab samuti arvutada lÔplike erinevuste abil:

nonlinear_constraint = NonlinearConstraint (cons_f, -np.inf, 1, jac = cons_J, hess = '2-point')

Piirangute Jakobianit saab samuti arvutada lÔplike erinevuste abil. Kuid sel juhul ei saa Hessiani enam lÔplike erinevuste abil arvutada. Hessian peab olema mÀÀratletud funktsioonina vÔi lÀbi klassi HessianUpdateStrategy.

nonlinear_constraint = NonlinearConstraint (cons_f, -np.inf, 1, jac = '2-point', hess = BFGS ())

Optimeerimisprobleemi lahendus on jÀrgmine:

scipy.optimize import minimize
from scipy.optimize import rosen, rosen_der, rosen_hess, rosen_hess_prod

x0 = np.array([0.5, 0])
res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hess=rosen_hess,
                constraints=[linear_constraint, nonlinear_constraint],
                options={'verbose': 1}, bounds=bounds)
print(res.x)

`gtol` lÔpetamise tingimus on tÀidetud.
Iteratsioonide arv: 12, funktsioonide hindamised: 8, CG iteratsioonid: 7, optimaalne: 2.99e-09, piirangute rikkumine: 1.11e-16, tÀitmise aeg: 0.033 s.
[0.41494531 0.17010937]

Vajadusel saab Hessiani arvutamise funktsiooni mÀÀrata klassi LinearOperator abil

def rosen_hess_linop(x):
    def matvec(p):
        return rosen_hess_prod(x, p)
    return LinearOperator((2, 2), matvec=matvec)

res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hess=rosen_hess_linop,
                 constraints=[linear_constraint, nonlinear_constraint],
                 options={'verbose': 1}, bounds=bounds)

print(res.x)

vÔi Hessiani ja suvalise vektori korrutamine parametri hessp:

res = minimize(rosen, x0, method='trust-constr', jac=rosen_der, hessp=rosen_hess_prod,
                constraints=[linear_constraint, nonlinear_constraint],
                options={'verbose': 1}, bounds=bounds)
print(res.x)

Alternatiivselt saab optimeeritava funktsiooni esimesi ja teisi tuletusi ligikaudselt arvutada. NÀiteks saab Hessiani approximiseerida funktsiooni SR1 (kvasi-Newtoni lÀhenemine). Gradienti saab ligikaudselt arvutada lÔplike erinevustega.

scipy.optimize import SR1
res = minimize(rosen, x0, method='trust-constr',  jac="2-point", hess=SR1(),
               constraints=[linear_constraint, nonlinear_constraint],
               options={'verbose': 1}, bounds=bounds)
print(res.x)

Konventsionaalne optimeerimine method=»SLSQP»

SLSQP meetod on mÔeldud funktsiooni minimeerimise probleemide lahendamiseks kujul:

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

SciPy, optimeerimine tingimustega

Kus SciPy, optimeerimine tingimustega ja SciPy, optimeerimine tingimustega — hulk indekseid, mis kirjeldavad piiranguid vĂ”rduste vĂ”i ebavĂ”rdsuste kujul. SciPy, optimeerimine tingimustega — hulk alumisi ja ĂŒlemisi piire funktsiooni mÀÀramispiirkonnale.

Lineaarseid ja mitte-lineaarseid piiranguid kirjeldatakse sÔnaraamatutena, millel on vÔtmed type, lÔbu ja jac.

ineq_cons = {'type': 'ineq',
             'fun': lambda x: np.array ([1 - x [0] - 2 * x [1],
                                          1 - x [0] ** 2 - x [1],
                                          1 - x [0] ** 2 + x [1]]),
             'jac': lambda x: np.array ([[- 1.0, -2.0],
                                          [-2 * x [0], -1.0],
                                          [-2 * x [0], 1.0]])
            }

eq_cons = {'type': 'eq',
           'fun': lambda x: np.array ([2 * x [0] + x [1] - 1]),
           'jac': lambda x: np.array ([2.0, 1.0])
          }

Minimeerimise protseduur toimub jÀrgmiselt:

x0 = np.array([0.5, 0])
res = minimize(rosen, x0, method='SLSQP', jac=rosen_der,
               constraints=[eq_cons, ineq_cons], options={'ftol': 1e-9, 'disp': True},
               bounds=bounds)

print(res.x)

Optimeerimine lĂ”petati edukalt.    (VĂ€ljamineku reĆŸiim 0)
            Praegune funktsiooni vÀÀrtus: 0.34271757499419825
            Iteratsioonid: 4
            Funktsiooni hindamised: 5
            Gradientide hindamised: 4
[0.41494475 0.1701105 ]

Optimeerimise nÀide

Seoses viienda tehnoloogilise tsĂŒkli ĂŒleminekuga vaatleme tootmise optimeerimist veebistuudio nĂ€itel, mis toob meile vĂ€ikese, kuid stabiilse tulu. Kujutame ette, et oleme galerii direktor, kus toodetakse kolme tĂŒĂŒpi tooteid:

  • x0 — mĂŒĂŒvad landindid, alates 10 t. r.
  • x1 — ettevĂ”tte veebilehed, alates 20 t. r.
  • x2 — internetipoed, alates 30 t. r.

Meie sĂ”bralik töörĂŒhm koosneb neljast algajatest, kahest keskastme töötajast ja ĂŒhest kogenud spetsialistist. Nende tööaja fond kuus:

  • algajad: 4 * 150 = 600 inimene * tund,
  • keskastme töötajad: 2 * 150 = 300 inimene * tund,
  • kogenud spetsialist: 150 inimene * tund.

Oletame, et ĂŒhe tĂŒĂŒpi veebilehe (x0, x1, x2) arendamiseks ja juurutamiseks peab esimene juba tekkiv algaja kulutama (10, 20, 30) tundi, keskastme töötaja — (7, 15, 20), kogenud spetsialist — (5, 10, 15) parima ajaga oma elust.

Nagu igale normaalsele direktorile, soovime maksimeerida igakuist kasumit. Esimene samm edusammudeks — kirjutame sihtfunktsiooni value kui kuu jooksul toodetud toodete tulu summana:

def value(x):
    return - 10*x[0] - 20*x[1] - 30*x[2]

See ei ole viga; sihtfunktsiooni maksimeerimisel minimeeritakse see vastupidise mÀrgiga.

JĂ€rgmine samm — keelame oma töötajatel ĂŒletunde ja kehtestame piirangud tööaja fondile:

SciPy, optimeerimine tingimustega

Mis on ekvivalentne:

SciPy, optimeerimine tingimustega

ineq_cons = {'type': 'ineq',
             'fun': lambda x: np.array ([600 - 10 * x [0] - 20 * x [1] - 30 * x[2],
                                         300 - 7  * x [0] - 15 * x [1] - 20 * x[2],
                                         150 - 5  * x [0] - 10 * x [1] - 15 * x[2]])
            }

Formaalne piirang on see, et toodang peab olema ainult positiivne:

bnds = Bounds ([0, 0, 0], [np.inf, np.inf, np.inf])

Ja lĂ”puks kĂ”ige roosilisem eeldus — madala hinna ja kĂ”rge kvaliteedi tĂ”ttu seisavad meie juures pidevalt rahulolevate klientide read. Saame ise valida kuukohustused toodangute tootmisel, lĂ€htudes tingimuslikust optimeerimisĂŒlesandest. scipy.optimize:

x0 = np.array([10, 10, 10])
res = minimize(value, x0, method='SLSQP', constraints=ineq_cons, bounds=bnds)
print(res.x)

[7.85714286 5.71428571 3.57142857]

Ümmardame ligikaudu tĂ€isarvudeni ja arvutame kuukoormuse optimiseeritud toodangu korral. x = (8, 6, 3) :

  • algajad: 8 * 10 + 6 * 20 + 3 * 30 = 290 inimest * tund;
  • keskastme töötajad: 8 * 7 + 6 * 15 + 3 * 20 = 206 inimest * tund;
  • kogenud spetsialist: 8 * 5 + 6 * 10 + 3 * 15 = 145 inimest * tund.

JÀreldus: et direktor saaks oma teenitud maksimumi, on optimaalne kuus teha 8 maandumist, 6 keskmist veebilehte ja 3 poodi. Seniors peab samal ajal tÔeliselt vaeva nÀgema, loaderite koormus jÀÀb umbes 2/3, juniorite vÀhem kui pool.

KokkuvÔte

Artiklis on esitatud pĂ”hitehnikad paketi scipy.optimize, mida kasutatakse tingimuslikku minimeerimise ĂŒlesannete lahendamiseks. Isiklikult kasutan ma scipy puhas akadeemiliste eesmĂ€rkide nimel, seega on antud nĂ€ide naljakas.

Palju teooriat ja haruldasi nĂ€iteid saab leida nĂ€iteks I.L. Akulichi raamatust "Matemaatiline programmeerimine nĂ€idete ja ĂŒlesannetega". Kaheldamatum rakendus scipy.optimize 3D struktuuri loomine pildigruppide pĂ”hjal (artikkel habras) on nĂŒĂŒd vĂ”imalik nĂ€ha scipy-cookbook.

Peamine teabe allikas on docs.scipy.org, kes soovivad panustada tÔlkesesse ja teistesse osadesse, scipy teretulemast GitHub.

AitÀh mephistopheies osalemise eest vÀljaande ettevalmistamisel.

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