SciPy, Optimierung


SciPy (ausgesprochen sai pie) ist ein mathematisches Anwendungspaket, das auf der Erweiterung Numpy Python basiert. Mit SciPy wird aus einer interaktiven Python-Sitzung dieselbe komplexe Datenverarbeitungs- und Prototyping-Umgebung fĂŒr komplexe Systeme wie MATLAB, IDL, Octave, R-Lab und SciLab. Heute möchte ich kurz darĂŒber sprechen, wie einige bekannte Optimierungsalgorithmen im Paket scipy.optimize verwendet werden. Eine detailliertere und aktuellere Hilfe zur Verwendung von Funktionen erhalten Sie immer mit dem Befehl help () oder mit Umschalt + Tab.


EinfĂŒhrung


Um sich und den Lesern das Durchsuchen und Lesen der Quelle zu ersparen, werden Links zu Methodenbeschreibungen hauptsĂ€chlich auf Wikipedia verweist. Diese Informationen reichen in der Regel aus, um die Methoden allgemein und die Bedingungen fĂŒr ihre Anwendung zu verstehen. Um die Essenz mathematischer Methoden zu verstehen, folgen wir den Links zu maßgeblicheren Veröffentlichungen, die am Ende jedes Artikels oder in Ihrer bevorzugten Suchmaschine zu finden sind.


Das Modul scipy.optimize umfasst also die Implementierung der folgenden Verfahren:


  1. Bedingte und bedingungslose Minimierung der Skalarfunktionen mehrerer Variablen (minim) unter Verwendung verschiedener Algorithmen (Nelder-Mead-Simplex, BFGS, konjugierte Newton-Gradienten, COBYLA und SLSQP )
  2. Globale Optimierung (zB: basinhopping , diff_evolution )
  3. Minimierung von Residuen der kleinsten Quadrate (Least_Squares) und Algorithmen zum Anpassen von Kurven an nichtlineare Least Squares (Curve_fit)
  4. Minimierung der Skalarfunktionen einer Variablen (minim_scalar) und Auffinden von Wurzeln (root_scalar)
  5. Mehrdimensionale Löser des Gleichungssystems (Wurzel) unter Verwendung verschiedener Algorithmen (Hybrid-Powell, Levenberg-Marquardt oder groß angelegte Methoden wie Newton-Krylov ).

In diesem Artikel wird nur das erste Element aus dieser gesamten Liste betrachtet.


Bedingungslose Minimierung der Skalarfunktion mehrerer Variablen


Die Minim-Funktion aus dem Paket scipy.optimize bietet eine gemeinsame Schnittstelle zur Lösung der Probleme der bedingten und bedingungslosen Minimierung von Skalarfunktionen mehrerer Variablen. Um seine Arbeit zu demonstrieren, benötigen wir eine geeignete Funktion mehrerer Variablen, die wir auf unterschiedliche Weise minimieren.


FĂŒr diese Zwecke ist die Rosenbrock-Funktion von N Variablen perfekt, die die Form hat:


f l e f t ( m a t h b f x r i g h t ) = s u m N - 1 i = 1 [ 100 l e f t ( x i + 1 - x 2 i r i g h t ) 2 + l e f t ( 1 - x i        right)2]


Obwohl die Rosenbrock-Funktion und ihre Jacobi- und Hessischen Matrizen (die erste bzw. zweite Ableitung) bereits im Paket scipy.optimize definiert sind, definieren wir sie selbst.


import numpy as np def rosen(x): """The Rosenbrock function""" return np.sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0, axis=0) 

Zur Verdeutlichung zeichnen wir in 3D die Werte der Rosenbrock-Funktion zweier Variablen.


Code zum Rendern
 from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from matplotlib import cm from matplotlib.ticker import LinearLocator, FormatStrFormatter #  3D  fig = plt.figure(figsize=[15, 10]) ax = fig.gca(projection='3d') #    ax.view_init(45, 30) #     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])) #   surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm) plt.show() 


Im Voraus wissen, dass das Minimum 0 fĂŒr ist xi=1 Betrachten Sie Beispiele fĂŒr die Bestimmung des Mindestwerts der Rosenbrock-Funktion mithilfe verschiedener scipy.optimize-Verfahren.


Die Nelder-Mead-Simplex-Methode (Nelder-Mead)


Es sei ein Anfangspunkt x0 im 5-dimensionalen Raum. Ermitteln Sie den nÀchstgelegenen Mindestpunkt der Rosenbrock-Funktion mithilfe des Nelder-Mead-Simplex- Algorithmus (der Algorithmus wird als Wert des Methodenparameters angegeben):


 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) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 339 Function evaluations: 571 [1. 1. 1. 1. 1.] 

Die Simplex-Methode ist der einfachste Weg, um eine klar definierte und ziemlich reibungslose Funktion zu minimieren. Es ist nicht erforderlich, Ableitungen einer Funktion zu berechnen, sondern nur deren Werte anzugeben. Die Nelder-Mead-Methode ist eine gute Wahl fĂŒr einfache Minimierungsprobleme. Da jedoch keine GradientenschĂ€tzungen verwendet werden, kann es lĂ€nger dauern, das Minimum zu finden.


Powell-Methode


Ein weiterer Optimierungsalgorithmus, bei dem nur Funktionswerte berechnet werden, ist die Powell-Methode . Um es zu verwenden, mĂŒssen Sie in der Minim-Funktion method = 'powell' setzen.


 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) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 19 Function evaluations: 1622 [1. 1. 1. 1. 1.] 

Broyden-Fletcher-Goldfarb-Channo-Algorithmus (BFGS)


Um eine schnellere Konvergenz zur Lösung zu erhalten, verwendet das BFGS- Verfahren den Gradienten der Zielfunktion. Der Gradient kann als Funktion angegeben oder anhand von Differenzen erster Ordnung berechnet werden. In jedem Fall erfordert die BFGS-Methode normalerweise weniger Funktionsaufrufe als die Simplex-Methode.


Wir finden die Ableitung der Rosenbrock-Funktion in der analytischen Form:


 frac partiellef partiellexj= summe grenzenNi=1200(xi−x2i−1)( deltai,j−2xi−1,j)−2(1−xi−1) deltai−1,j=


=200(xj−x2j−1)−400xj(xj+1−x2j)−2(1−xj)


Dieser Ausdruck gilt fĂŒr Ableitungen aller Variablen mit Ausnahme der ersten und der letzten, die wie folgt definiert sind:


 frac partiellef partiellex0=−400x0(x1−x20)−2(1−x0),


 frac partiellef partiellexN−1=200(xN−1−x2N−2).


Schauen wir uns die Python-Funktion an, die diesen Gradienten berechnet:


 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 

Die Gradientenberechnungsfunktion wird wie unten gezeigt als Wert des jac-Parameters der Minim-Funktion angegeben.


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

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 25 Function evaluations: 30 Gradient evaluations: 30 [1.00000004 1.0000001 1.00000021 1.00000044 1.00000092] 

Konjugierter Gradientenalgorithmus (Newton)


Der Newton-Konjugatgradientenalgorithmus ist eine modifizierte Newton-Methode.
Newtons Methode basiert auf der Approximation einer Funktion in einer lokalen Region durch ein Polynom zweiten Grades:


f left( mathbfx right) approxf left( mathbfx0 right)+ nablaf left( mathbfx0 right) cdot left( mathbfx− mathbfx0 right)+ frac12 left( mathbfx− mathbfx0 rechts)T mathbfH links( mathbfx0 rechts) links( mathbfx− mathbfx0 rechts)


wo  mathbfH left( mathbfx0 right) ist eine Matrix von zweiten Ableitungen (Hessische Matrix, Hessische).
Wenn der Hessische positiv definit ist, kann das lokale Minimum dieser Funktion gefunden werden, indem der Nullgradient der quadratischen Form mit Null gleichgesetzt wird. Das Ergebnis ist ein Ausdruck:


 mathbfx textrmopt= mathbfx0− mathbfH−1 nablaf


Inverses Hessisches wird unter Verwendung der konjugierten Gradientenmethode berechnet. Ein Beispiel fĂŒr die Verwendung dieser Methode zur Minimierung der Rosenbrock-Funktion ist unten angegeben. Um die Newton-CG-Methode verwenden zu können, mĂŒssen Sie eine Funktion definieren, die Hessisch auswertet.
Die hessische Funktion des Rosenbrock in analytischer Form ist gleich:


Hi,j= frac partiell2f partiellxixj=200( deltai,j−2xi−1 deltai−1,j−400xi( deltai+1,j−2xi deltai,j)−400 deltai,j(xi+1−x2i)+2 deltai,j=


=(202+1200x2i−400xi+1) deltai,j−400xi deltai+1,j−400xi−1 deltai−1,j


wo i,j in left[1,N−2 right] und i,j in left[0,N−1 right] Bestimmen Sie die Matrix N malN .


Die verbleibenden Nicht-Null-Elemente der Matrix sind gleich:


 frac partiell2f partiellx20=1200x20−400x1+2


 frac partiell2f partiellx0x1= frac partiell2f partiellx1x0=−400x0


 frac partiell2f partiellxN−1xN−2= frac partiell2f partiellxN−2xN−1=−400xN−2


 frac partiell2f partiellx2N−1=200x


Beispielsweise hat im fĂŒnfdimensionalen Raum N = 5 die hessische Matrix fĂŒr die Rosenbrock-Funktion die Bandform:


\ tiny \ mathbf {H} = \ begin {bmatrix} 1200x_ {0} ^ {2} -400x_ {1} +2 & -400x_ {0} & 0 & 0 & 0 \\ -400x_ {0} & 202 + 1200x_ {1} ^ {2} -400x_ {2} & -400x_ {1} & 0 & 0 \\ 0 & -400x_ {1} & 202 + 1200x_ {2} ^ {2} -400x_ {3} & -400x_ {2} & 0 \\ 0 & & -400x_ {2} & 202 + 1200x_ {3} ^ {2} -400x_ {4} & -400x_ {3} \\ 0 & 0 & 0 & -400x_ { 3} & 200 \ end {bmatrix}


Der Code, der dieses Hessische zusammen mit dem Code berechnet, um die Rosenbrock-Funktion unter Verwendung der konjugierten Gradientenmethode (Newton) zu minimieren:


 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) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 24 Function evaluations: 33 Gradient evaluations: 56 Hessian evaluations: 24 [1. 1. 1. 0.99999999 0.99999999] 

Ein Beispiel mit der Definition der Funktion des Produkts des Hessischen und eines beliebigen Vektors


Bei realen Problemen kann das Berechnen und Speichern der gesamten hessischen Matrix erhebliche Zeit- und Speicherressourcen erfordern. DarĂŒber hinaus besteht in der Tat keine Notwendigkeit, die hessische Matrix selbst anzugeben, da Das Minimierungsverfahren erfordert nur einen Vektor, der dem Produkt des Hessischen mit einem anderen beliebigen Vektor entspricht. Aus rechnerischer Sicht ist es daher sehr vorzuziehen, die Funktion, die das Ergebnis des Produkts des Hessischen mit einem beliebigen Vektor zurĂŒckgibt, sofort zu bestimmen.


Betrachten Sie die hess-Funktion, die einen Minimierungsvektor als erstes Argument und einen beliebigen Vektor als zweites Argument verwendet (zusammen mit anderen Argumenten der minimierten Funktion). In unserem Fall ist es nicht sehr schwierig, das Produkt der hessischen Rosenbrock-Funktion mit einem beliebigen Vektor zu berechnen. Wenn p ein beliebiger Vektor ist, dann das Produkt H(x) cdotp hat die Form:


 mathbfH left( mathbfx right) mathbfp= beginbmatrix left(1200x20−400x1+2 right)p0−400x0p1 vdots−400xi−1pi−1+ left(202+1200x2i−400xi+1 right)pi−400xipi+1 vdots−400xN−2pN−2+200pN−1 endbmatrix.


Eine Funktion, die das Produkt aus dem Hessischen und einem beliebigen Vektor berechnet, wird als Wert des Hessp-Arguments an die Minimierungsfunktion ĂŒbergeben:


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

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 24 Function evaluations: 33 Gradient evaluations: 56 Hessian evaluations: 66 

Der Trust-Region-Algorithmus fĂŒr konjugierte Gradienten (Newton)


Eine schlechte KonditionalitĂ€t der hessischen Matrix und falsche Suchrichtungen können dazu fĂŒhren, dass der Algorithmus fĂŒr konjugierte Newton-Gradienten ineffizient sein kann. In solchen FĂ€llen wird die Vertrauensbereichsmethode fĂŒr konjugierte Newton-Gradienten bevorzugt.


Beispiel einer hessischen Matrixdefinition:


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

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 20 Function evaluations: 21 Gradient evaluations: 20 Hessian evaluations: 19 [1. 1. 1. 1. 1.] 

Ein Beispiel mit der Produktfunktion des Hessischen und einem beliebigen Vektor:


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

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 20 Function evaluations: 21 Gradient evaluations: 20 Hessian evaluations: 0 [1. 1. 1. 1. 1.] 

Methoden vom Krylovsky-Typ


Wie die Trust-NCG-Methode eignen sich Krylovsky-Methoden gut zur Lösung von Problemen im großen Maßstab, da sie nur Matrixvektorprodukte verwenden. Ihre Essenz besteht darin, das Problem im vertraulichen Bereich zu lösen, der durch den abgeschnittenen Krylov-Unterraum begrenzt ist. FĂŒr unsichere Aufgaben ist es besser, diese Methode zu verwenden, da im Vergleich zur Trust-NCG-Methode weniger nichtlineare Iterationen verwendet werden, da weniger Matrixvektorprodukte pro Unteraufgabe vorhanden sind. DarĂŒber hinaus ist die Lösung fĂŒr die quadratische Teilaufgabe genauer als die Trust-NCG-Methode.
Beispiel einer hessischen Matrixdefinition:


 res = minimize(rosen, x0, method='trust-krylov', jac=rosen_der, hess=rosen_hess, options={'gtol': 1e-8, 'disp': True}) Optimization terminated successfully. Current function value: 0.000000 Iterations: 19 Function evaluations: 20 Gradient evaluations: 20 Hessian evaluations: 18 print(res.x) [1. 1. 1. 1. 1.] 

Ein Beispiel mit der Produktfunktion des Hessischen und einem beliebigen Vektor:


 res = minimize(rosen, x0, method='trust-krylov', jac=rosen_der, hessp=rosen_hess_p, options={'gtol': 1e-8, 'disp': True}) Optimization terminated successfully. Current function value: 0.000000 Iterations: 19 Function evaluations: 20 Gradient evaluations: 20 Hessian evaluations: 0 print(res.x) [1. 1. 1. 1. 1.] 

Vertrauensbasierter NĂ€herungsalgorithmus


Alle Methoden (Newton-CG, trust-ncg und trust-krylov) eignen sich gut zur Lösung großer Aufgaben (mit Tausenden von Variablen). Dies liegt an der Tatsache, dass der zugrunde liegende Algorithmus fĂŒr konjugierte Gradienten eine ungefĂ€hre Bestimmung der inversen hessischen Matrix impliziert. Die Lösung ist iterativ ohne explizite Zerlegung des Hessischen. Da nur die Funktion fĂŒr das Produkt des Hessischen und eines beliebigen Vektors bestimmt werden muss, eignet sich dieser Algorithmus besonders fĂŒr die Arbeit mit spĂ€rlichen (Banddiagonal-) Matrizen. Dies bietet niedrige Speicherkosten und erhebliche Zeiteinsparungen.


Bei mittelgroßen Problemen sind die Kosten fĂŒr die Speicherung und Faktorisierung des Hessischen nicht kritisch. Dies bedeutet, dass eine Lösung in weniger Iterationen erhalten werden kann, wodurch die Unteraufgaben des Vertrauensbereichs fast genau aufgelöst werden. Dazu werden einige nichtlineare Gleichungen fĂŒr jede quadratische Teilaufgabe iterativ gelöst. Eine solche Lösung erfordert normalerweise 3 oder 4 Zerlegungen der Holets-Hessischen Matrix. Infolgedessen konvergiert das Verfahren in weniger Iterationen und erfordert weniger Berechnung der Zielfunktion als andere implementierte Verfahren des Vertrauensbereichs. Dieser Algorithmus impliziert nur die Bestimmung der vollstĂ€ndigen hessischen Matrix und unterstĂŒtzt nicht die FĂ€higkeit, die Produktfunktion des hessischen und eines beliebigen Vektors zu verwenden.


Ein Beispiel fĂŒr die Minimierung der Rosenbrock-Funktion:


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

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 13 Function evaluations: 14 Gradient evaluations: 13 Hessian evaluations: 14 array([1., 1., 1., 1., 1.]) 

Dies verweilen vielleicht. Im nĂ€chsten Artikel werde ich versuchen, das Interessanteste ĂŒber die bedingte Minimierung, die Anwendung der Minimierung bei der Lösung von Approximationsproblemen, die Minimierung der Funktion einer Variablen, beliebige Minimierer und das Finden der Wurzeln des Gleichungssystems mithilfe des scipy.optimize-Pakets zu erzĂ€hlen.


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

Source: https://habr.com/ru/post/de439288/


All Articles