SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

Mae SciPy (sai pie wedi'i ynganu) yn becyn mathemateg sy'n seiliedig ar numpy sydd hefyd yn cynnwys llyfrgelloedd C a Fortran. Mae SciPy yn troi eich sesiwn Python rhyngweithiol yn amgylchedd gwyddor data cyflawn fel MATLAB, IDL, Octave, R, neu SciLab.

Yn yr erthygl hon, byddwn yn edrych ar dechnegau sylfaenol rhaglennu mathemategol - datrys problemau optimization amodol ar gyfer swyddogaeth sgalar o sawl newidyn gan ddefnyddio'r pecyn scipy.optimize. Mae algorithmau optimeiddio anghyfyngedig eisoes wedi'u trafod yn erthygl olaf. Gellir cael cymorth mwy manwl a chyfredol ar ffwythiannau scipy drwy ddefnyddio'r gorchymyn help(), Shift+Tab neu yn dogfennaeth swyddogol.

Cyflwyniad

Darperir rhyngwyneb cyffredin ar gyfer datrys problemau optimeiddio amodol a heb gyfyngiad yn y pecyn scipy.optimize gan y swyddogaeth minimize(). Fodd bynnag, mae'n hysbys nad oes dull cyffredinol ar gyfer datrys pob problem, felly mae'r dewis o ddull digonol, fel bob amser, yn disgyn ar ysgwyddau'r ymchwilydd.
Mae'r algorithm optimeiddio priodol wedi'i nodi gan ddefnyddio'r ddadl swyddogaeth minimize(..., method="").
Er mwyn optimeiddio swyddogaeth sawl newidyn yn amodol, mae gweithrediadau o'r dulliau canlynol ar gael:

  • trust-constr — chwilio am isafswm lleol yn y rhanbarth hyder. Erthygl Wici, erthygl ar Habré;
  • SLSQP — rhaglennu cwadratig dilyniannol gyda chyfyngiadau, dull Newtonaidd ar gyfer datrys system Lagrange. Erthygl Wici.
  • TNC - Newton cwtogi Nifer cyfyngedig o iteriadau, yn dda ar gyfer swyddogaethau aflinol gyda nifer fawr o newidynnau annibynnol. Erthygl Wici.
  • L-BFGS-B — dull gan dîm Broyden-Fletcher-Goldfarb-Shanno, a weithredwyd gyda llai o ddefnydd cof oherwydd llwytho fectorau yn rhannol o'r matrics Hessian. Erthygl Wici, erthygl ar Habré.
  • COBYLA — Optimeiddio Cyfyngedig MARE Trwy Brasamcaniad Llinol, optimeiddio cyfyngedig gyda brasamcan llinol (heb gyfrifo graddiant). Erthygl Wici.

Yn dibynnu ar y dull a ddewiswyd, mae amodau a chyfyngiadau ar gyfer datrys y broblem yn cael eu gosod yn wahanol:

  • gwrthrych dosbarth Bounds ar gyfer dulliau L-BFGS-B, TNC, SLSQP, trust-constr;
  • y rhestr (min, max) ar gyfer yr un dulliau L-BFGS-B, TNC, SLSQP, trust-constr;
  • gwrthrych neu restr o wrthrychau LinearConstraint, NonlinearConstraint ar gyfer COBYLA, SLSQP, dulliau ymddiriedaeth-constr;
  • geiriadur neu restr o eiriaduron {'type':str, 'fun':callable, 'jac':callable,opt, 'args':sequence,opt} ar gyfer COBYLA, dulliau SLSQP.

Amlinelliad o'r erthygl:
1) Ystyried defnyddio algorithm optimeiddio amodol yn y rhanbarth ymddiriedaeth (method="trust-constr") gyda chyfyngiadau wedi'u nodi fel gwrthrychau Bounds, LinearConstraint, NonlinearConstraint ;
2) Ystyried rhaglennu dilyniannol gan ddefnyddio'r dull sgwariau lleiaf (dull = "SLSQP") gyda chyfyngiadau wedi'u nodi ar ffurf geiriadur {'type', 'fun', 'jac', 'args'};
3) Dadansoddwch enghraifft o optimeiddio cynhyrchion gweithgynhyrchu gan ddefnyddio enghraifft stiwdio we.

Dull optimeiddio amodol = "trust-constr"

Gweithredu'r dull trust-constr yn seiliedig ar EQSQP am broblemau gyda chyfyngiadau ffurf cydraddoldeb ac ymlaen TRIP am broblemau gyda chyfyngiadau ar ffurf anghydraddoldebau. Mae'r ddau ddull yn cael eu gweithredu gan algorithmau ar gyfer dod o hyd i leiafswm lleol yn y rhanbarth hyder ac maent yn addas iawn ar gyfer problemau ar raddfa fawr.

Ffurfio'r broblem o ddod o hyd i isafswm ar ffurf gyffredinol yn fathemategol:

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

Ar gyfer cyfyngiadau cydraddoldeb llym, mae'r arffin isaf wedi'i osod yn hafal i'r ffin uchaf SciPy, optimeiddio gydag amodau.
Ar gyfer cyfyngiad unffordd, gosodir y terfyn uchaf neu isaf np.inf gyda'r arwydd cyfatebol.
Gadewch iddo fod yn angenrheidiol i ddarganfod y lleiafswm o swyddogaeth Rosenbrock hysbys o ddau newidyn:

SciPy, optimeiddio gydag amodau

Yn yr achos hwn, gosodir y cyfyngiadau canlynol ar ei barth diffiniad:

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

Yn ein hachos ni, mae yna ateb unigryw ar y pwynt SciPy, optimeiddio gydag amodau, y mae'r cyfyngiad cyntaf a'r pedwerydd cyfyngiad yn unig yn ddilys ar ei gyfer.
Gadewch i ni fynd trwy'r cyfyngiadau o'r gwaelod i'r brig ac edrych ar sut y gallwn eu hysgrifennu yn scipy.
Cyfyngiadau SciPy, optimeiddio gydag amodau и SciPy, optimeiddio gydag amodau gadewch i ni ei ddiffinio gan ddefnyddio'r gwrthrych Bounds.

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

Cyfyngiadau SciPy, optimeiddio gydag amodau и SciPy, optimeiddio gydag amodau Gadewch i ni ei ysgrifennu ar ffurf llinol:

SciPy, optimeiddio gydag amodau

Gadewch i ni ddiffinio'r cyfyngiadau hyn fel gwrthrych LlinellolConstraint:

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

Ac yn olaf y cyfyngiad aflinol ar ffurf matrics:

SciPy, optimeiddio gydag amodau

Rydym yn diffinio matrics Jacobiaidd ar gyfer y cyfyngiad hwn a chyfuniad llinol o'r matrics Hessian â fector mympwyol SciPy, optimeiddio gydag amodau:

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

Nawr gallwn ddiffinio cyfyngiad aflinol fel gwrthrych 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)

Os yw'r maint yn fawr, gellir nodi matricsau ar ffurf denau hefyd:

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)

neu fel gwrthrych LinearOperator:

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

Wrth gyfrifo'r matrics Hessian SciPy, optimeiddio gydag amodau angen llawer o ymdrech, gallwch ddefnyddio dosbarth HessianUpdateStrategy. Mae’r strategaethau canlynol ar gael: BFGS и SR1.

from scipy.optimize import BFGS

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

Gellir cyfrifo'r Hesian hefyd gan ddefnyddio gwahaniaethau meidraidd:

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

Gellir cyfrifo'r matrics Jacobiaidd ar gyfer cyfyngiadau hefyd gan ddefnyddio gwahaniaethau cyfyngedig. Fodd bynnag, yn yr achos hwn ni ellir cyfrifo matrics Hessian gan ddefnyddio gwahaniaethau meidraidd. Rhaid diffinio'r Hessian fel ffwythiant neu ddefnyddio'r dosbarth HessianUpdateStrategy.

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

Mae'r ateb i'r broblem optimeiddio yn edrych fel hyn:

from 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` termination condition is satisfied.
Number of iterations: 12, function evaluations: 8, CG iterations: 7, optimality: 2.99e-09, constraint violation: 1.11e-16, execution time: 0.033 s.
[0.41494531 0.17010937]

Os oes angen, gellir diffinio'r swyddogaeth ar gyfer cyfrifo'r Hessian gan ddefnyddio'r dosbarth LinearOperator

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)

neu gynnyrch yr Hessian a fector mympwyol trwy'r paramedr 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)

Fel arall, gellir brasamcanu deilliadau cyntaf ac ail y swyddogaeth sy'n cael ei optimeiddio. Er enghraifft, gellir brasamcanu'r Hessian gan ddefnyddio'r ffwythiant SR1 (brasamcan lled-Newtonaidd). Gellir brasamcanu'r graddiant gan wahaniaethau cyfyngedig.

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

Dull optimeiddio amodol = "SLSQP"

Mae'r dull SLSQP wedi'i gynllunio i ddatrys problemau lleihau swyddogaeth yn y ffurf:

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

SciPy, optimeiddio gydag amodau

Lle SciPy, optimeiddio gydag amodau и SciPy, optimeiddio gydag amodau — setiau o fynegeion ymadroddion sy'n disgrifio cyfyngiadau ar ffurf cydraddoldebau neu anghydraddoldebau. SciPy, optimeiddio gydag amodau — setiau o ffiniau isaf ac uchaf ar gyfer parth diffinio'r swyddogaeth.

Disgrifir cyfyngiadau llinol ac aflinol ar ffurf geiriaduron gydag allweddi type, fun и 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])
          }

Gwneir y chwiliad am yr isafswm fel a ganlyn:

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)

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 0.34271757499419825
            Iterations: 4
            Function evaluations: 5
            Gradient evaluations: 4
[0.41494475 0.1701105 ]

Enghraifft Optimization

Mewn cysylltiad â'r newid i'r pumed strwythur technolegol, gadewch i ni edrych ar optimeiddio cynhyrchu gan ddefnyddio'r enghraifft o stiwdio we, sy'n dod ag incwm bach ond sefydlog i ni. Gadewch i ni ddychmygu ein hunain fel cyfarwyddwr gali sy'n cynhyrchu tri math o gynnyrch:

  • x0 - gwerthu tudalennau glanio, o 10 tr.
  • x1 - gwefannau corfforaethol, o 20 tr.
  • x2 - siopau ar-lein, o 30 tr.

Mae ein tîm gwaith cyfeillgar yn cynnwys pedwar aelod iau, dau ganolwr ac un hŷn. Eu cronfa oriau gwaith misol:

  • Mehefin: 4 * 150 = 600 чел * час,
  • canol: 2 * 150 = 300 чел * час,
  • senor: 150 чел * час.

Gadewch i'r iau cyntaf sydd ar gael dreulio (0, 1, 2) oriau ar ddatblygu a defnyddio un safle o'r math (x10, x20, x30), canol - (7, 15, 20), uwch - (5, 10, 15 ) oriau o amser gorau eich bywyd.

Fel unrhyw gyfarwyddwr arferol, rydym am wneud y mwyaf o elw misol. Y cam cyntaf i lwyddiant yw ysgrifennu'r swyddogaeth wrthrychol value fel swm yr incwm o gynhyrchion a gynhyrchir bob mis:

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

Nid gwall yw hwn; wrth chwilio am yr uchafswm, mae'r swyddogaeth wrthrychol yn cael ei lleihau gyda'r arwydd gyferbyn.

Y cam nesaf yw gwahardd ein gweithwyr rhag gorweithio a chyflwyno cyfyngiadau ar oriau gwaith:

SciPy, optimeiddio gydag amodau

Beth sy'n cyfateb:

SciPy, optimeiddio gydag amodau

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]])
            }

Cyfyngiad ffurfiol yw bod yn rhaid i allbwn cynnyrch fod yn gadarnhaol yn unig:

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

Ac yn olaf, y dybiaeth fwyaf poblogaidd yw, oherwydd y pris isel ac ansawdd uchel, bod ciw o gwsmeriaid bodlon yn gyson i ni. Gallwn ddewis y cyfrolau cynhyrchu misol ein hunain, yn seiliedig ar ddatrys y broblem optimeiddio gyfyngedig 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]

Gadewch i ni dalgrynnu'n llac i rifau cyfan a chyfrifo'r llwyth misol o rwyfwyr gyda'r dosbarthiad gorau posibl o gynhyrchion x = (8, 6, 3) :

  • Mehefin: 8 * 10 + 6 * 20 + 3 * 30 = 290 чел * час;
  • canol: 8 * 7 + 6 * 15 + 3 * 20 = 206 чел * час;
  • senor: 8 * 5 + 6 * 10 + 3 * 15 = 145 чел * час.

Casgliad: er mwyn i'r cyfarwyddwr dderbyn ei uchafswm haeddiannol, mae'n well creu 8 tudalen lanio, 6 safle canolig a 3 siop y mis. Yn yr achos hwn, mae'n rhaid i'r uwch aredig heb edrych i fyny o'r peiriant, bydd llwyth y canol tua 2/3, yr iau yn llai na hanner.

Casgliad

Mae'r erthygl yn amlinellu'r technegau sylfaenol ar gyfer gweithio gyda'r pecyn scipy.optimize, a ddefnyddir i ddatrys problemau lleihau amodol. Yn bersonol dwi'n defnyddio scipy at ddibenion academaidd yn unig, a dyna pam fod yr enghraifft a roddir mor ddigrif ei natur.

Gellir dod o hyd i lawer o theori ac enghreifftiau rhithwir, er enghraifft, yn y llyfr gan IL Akulich “Rhaglennu mathemategol mewn enghreifftiau a phroblemau.” Mwy o gais craidd caled scipy.optimize i adeiladu strwythur 3D o set o ddelweddau (erthygl ar Habré) gellir ei weld yn llyfr coginio scipy.

Y brif ffynhonnell wybodaeth yw docs.scipy.orgrhai sy'n dymuno cyfrannu at gyfieithu'r adran hon ac adrannau eraill scipy Croeso i GitHub.

Diolch meffistoffees ar gyfer cymryd rhan yn y gwaith o baratoi'r cyhoeddiad.

Ffynhonnell: hab.com

Ychwanegu sylw