You are on page 1of 18

23/5/2022 6_Non-linear_metaheuristics

Μάθημα 6ο

Μετα-ευριστικές μέθοδοι αριθμητικής


βελτιστοποίησης
In [5]:

import numpy as np
from scipy.optimize import fmin_bfgs
import matplotlib.pyplot as plt

Στο προηγούμενο μάθημα είδαμε πώς ορίζουμε συναρτήσεις, και πώς χρησιμοποιούμε την fmin_bfgs (από το
scipy), για την ελαχιστοποίησή της.

Έστω η συνάρτηση: $$f(x)=x^2$$ που είναι, στην ουσία, η συνάρτηση σφαίρας σε μια διάσταση.

In [3]:

def f(x): return x**2

x = np.arange(-100,100)

plt.plot(x,f(x));

Στο προηγούμενο μάθημα είδαμε πώς χρησιμοποιούμε την fmin_bfgs για να βρούμε το ελάχιστο σημείο της
συνάρτησης.

http://localhost:8888/lab 1/18
23/5/2022 6_Non-linear_metaheuristics

In [6]:

fmin_bfgs(f,
x0=np.array([-1.2]))

Optimization terminated successfully.


Current function value: 0.000000
Iterations: 2
Function evaluations: 9
Gradient evaluations: 3

Out[6]:

array([-8.07760955e-09])

Η fmin_bfgs απαιτεί να δώσουμε ώς όρισμα μια αρχική "μαντεψιά" για το πού περίπου βρίσκεται το ελάχιστο
της συνάρτησης.

Ας σχεδιάσουμε ξανά την συνάρτηση, δείχνοντας με πράσινη βούλα το x0, η αρχική τιμή που δίνουμε για να
ξεκινήσει η αναζήτηση, και με κόκκινο αστέρι την λύση που βρήκε η fmin_bfgs.

In [33]:

x0 = -6.2

fmin = fmin_bfgs(f,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,f(x));
plt.plot(x0,f(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,f(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: 0.000000
Iterations: 3
Function evaluations: 12
Gradient evaluations: 4

solution x = [6.4000544e-08]

http://localhost:8888/lab 2/18
23/5/2022 6_Non-linear_metaheuristics

Ας το επαναλάβουμε μερικές φορές για διάφορες τιμές x0.

In [34]:

x0 = -20

fmin = fmin_bfgs(f,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,f(x));
plt.plot(x0,f(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,f(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: 0.000000
Iterations: 3
Function evaluations: 15
Gradient evaluations: 5

solution x = [4.78360347e-08]

http://localhost:8888/lab 3/18
23/5/2022 6_Non-linear_metaheuristics

In [36]:

x0 = -80

fmin = fmin_bfgs(f,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,f(x));
plt.plot(x0,f(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,f(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: 0.000000
Iterations: 3
Function evaluations: 18
Gradient evaluations: 6

solution x = [9.42292193e-07]

http://localhost:8888/lab 4/18
23/5/2022 6_Non-linear_metaheuristics

In [29]:

x0 = 89

fmin = fmin_bfgs(f,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,f(x));
plt.plot(x0,f(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,f(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: 0.000000
Iterations: 3
Function evaluations: 18
Gradient evaluations: 6

solution x = [1.80888756e-06]

Βλέπουμε πως ότι x0 και να δώσουμε, η fmin_bfgs βρίσκει πάντα το ολικό βέλτιστο.

Ας δούμε τώρα μια άλλη συνάρτηση

http://localhost:8888/lab 5/18
23/5/2022 6_Non-linear_metaheuristics

In [178]:

def f(x): return (-3*x**2 + 5*x + 3) * np.cos(x/10)

x = np.arange(0,100)
plt.plot(x,f(x));

Τρέχουμε τώρα, για την καινούργια συνάρτηση, τρέχοντας την fmin_bfgs για διάφορες τιμές x0 και
σχεδιάζοντας τα αποτελέσματα.

http://localhost:8888/lab 6/18
23/5/2022 6_Non-linear_metaheuristics

In [179]:

x0 = 20

fmin = fmin_bfgs(f,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,f(x));
plt.plot(x0,f(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,f(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: -138.359234
Iterations: 8
Function evaluations: 27
Gradient evaluations: 9

solution x = [11.05084033]

http://localhost:8888/lab 7/18
23/5/2022 6_Non-linear_metaheuristics

In [180]:

x0 = 60

fmin = fmin_bfgs(f,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,f(x));
plt.plot(x0,f(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,f(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: -12103.494325
Iterations: 8
Function evaluations: 27
Gradient evaluations: 9

solution x = [65.81860792]

Βλέπουμε ότι η αρχική τιμή που δώσαμε επηρέασε το τελικό αποτέλεσμα, το οποίο δεν ήταν πάντα βέλτιστο.

Ας το δούμε αυτό ξανά σε μια καινούργια, διαφορετική συνάρτηση. Με πράσινη βούλα συμβολίζονται οι
αρχικές τιμές που δίνουμε, και με κόκκινο σταυρό οι λύσεις που βρίσκει η fmin_bfgs.

http://localhost:8888/lab 8/18
23/5/2022 6_Non-linear_metaheuristics

In [78]:

func = lambda x: np.sin(x)*np.exp(-0.1*(x-0.6)**2)


x = np.arange(-10,10,0.2)
x0 = 0.5
fmin = fmin_bfgs(func,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,func(x));
plt.plot(x0,func(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,func(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: -0.674305
Iterations: 4
Function evaluations: 18
Gradient evaluations: 6

solution x = [-1.22144316]

http://localhost:8888/lab 9/18
23/5/2022 6_Non-linear_metaheuristics

In [74]:

func = lambda x: np.sin(x)*np.exp(-0.1*(x-0.6)**2)


x = np.arange(-10,10,0.2)
x0 = 7.5

fmin = fmin_bfgs(func,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,func(x));
plt.plot(x0,func(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,func(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: -0.000080
Iterations: 6
Function evaluations: 30
Gradient evaluations: 10

solution x = [9.91202952]

http://localhost:8888/lab 10/18
23/5/2022 6_Non-linear_metaheuristics

In [76]:

func = lambda x: np.sin(x)*np.exp(-0.1*(x-0.6)**2)


x = np.arange(-10,10,0.2)
x0 = 6.3

fmin = fmin_bfgs(func,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,func(x));
plt.plot(x0,func(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,func(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: -0.240376
Iterations: 3
Function evaluations: 30
Gradient evaluations: 10

solution x = [4.10148757]

http://localhost:8888/lab 11/18
23/5/2022 6_Non-linear_metaheuristics

In [140]:

func = lambda x: np.sin(x)*np.exp(-0.1*(x-0.6)**2)


x = np.arange(-10,10,0.2)
x0 = 1.5
fmin = fmin_bfgs(func,
x0=np.array([x0]))
print('')
print('solution x =',fmin)
print('')

plt.plot(x,func(x));
plt.plot(x0,func(x0),marker='o',markersize=8,color='g');
plt.plot(fmin,func(fmin),marker='*',markersize=12,color='r');

Optimization terminated successfully.


Current function value: -0.240376
Iterations: 3
Function evaluations: 27
Gradient evaluations: 9

solution x = [4.10146311]

Βλέπουμε ότι σε συναρτήσεις με διάφορα τοπικά ελάχιστα, η fmin_bfgs παίρνει την αρχική τιμή που δίνουμε,
"κατηφορίζει" προς όποια κατεύθυνση είναι κατηφορική, και σταματάει σε οποιοδήποτε ελάχιστο συναντήσει.
Το αν αυτό το ελάχιστο θα είναι τοπικό ή ολικό, είναι καθαρά θέμα τύχης, που εξαρτάται από το αν το x0
τυχαίνει να είναι κοντά στο ολικό βέλτιστο.

Για μια συνάρτηση σαν την παρκάτω είναι προφανές πως δεν υπάρχει καν λόγος να τρέξουμε την fmin_bfgs.

http://localhost:8888/lab 12/18
23/5/2022 6_Non-linear_metaheuristics

In [112]:

x = np.arange(0,100)
f= lambda x:(-3*x**2 + 75*x*np.sin(x) + 3) * np.cos(x/7)
plt.plot(x,f(x));

Είναι προφανές ότι για τέτοιες περιπτώσεις θα χρειαστούμε ένα διαφορετικό είδος αλγορίθμου.

Μετα-ευριστικές μέθοδοι του scipy


To scipy έχει μια πληθώρα μετα-ευριστικών μεθόδων βελτιστοποίησης, εκ των οποίων εμείς θα δούμε τρεις.
Αυτές είναι οι dual_annealing, differential_evolution, και shgo. Δεν θα τις αναλύσουμε, παρά μόνο θα δούμε
πως χρησιμοποιούνται.

Τις εισάγουμε στην python ως εξής:

In [136]:

from scipy.optimize import dual_annealing, differential_evolution, shgo

Θα δοκιμάσουμε πρώτα σε μια συνάρτηση που χρησιμοποιήσαμε παραπάνω, που την ορίσαμε ως εξής

http://localhost:8888/lab 13/18
23/5/2022 6_Non-linear_metaheuristics

In [181]:

func = lambda x: np.sin(x)*np.exp(-0.1*(x-0.6)**2)


x = np.arange(-10,10,0.2)

plt.plot(x,func(x));

Πριν τρέξουμε τους μεταευριστικούς αλγόριθμους, θα βρόυμε την βέλτιστη λύση, για να επαληθεύσουμε τα
αποτελέσματα των αλγορίθμων.

Η ελάχιστη τιμή που μπορεί να πάρει η func(x) είναι

In [183]:

np.min(func(x))

Out[183]:

-0.6740974948332839

Η τιμή x που ελαχιστοποιεί την συνάρτηση είναι

In [184]:

x[np.argmin(func(x))]

Out[184]:

-1.2000000000000313

http://localhost:8888/lab 14/18
23/5/2022 6_Non-linear_metaheuristics

Οι τρεις μεταευριστικοί αλγόριθμοι που θα δούμε έχουν όλοι τους την εξής σύνταξη:
$$algorithm(function,bounds)$$

όπου algorithm το όνομα του αλγόριθμου, function το όνομα της συνάρτησης που θέλουμε να
ελαχιστοποιήσουμε, και bounds το διάστημα που επιτρέπεται να πάρουν οι τιμές x. Αν, για παράδειγμα,
θέλουμε το x να παίρνει τιμές από μείον δέκα έως δέκα, γράφουμε bounds=[(-10,10)]

Δοκιμάζουμε τώρα τους τρεις αλγόριθμους. Θυμηθείται ότι θέλουμε να μας βρουν μια λύση γύρω στο -1.2

In [146]:

dual_annealing(func,
bounds=[(-10,10)])

Out[146]:

fun: array([-0.6743051])
message: ['Maximum number of iteration reached']
nfev: 2013
nhev: 0
nit: 1000
njev: 0
x: array([-1.22144842])

In [147]:

differential_evolution(func,
bounds=[(-10,10)])

Out[147]:

fun: array([-0.6743051])
jac: array([1.11022302e-08])
message: 'Optimization terminated successfully.'
nfev: 111
nit: 6
success: True
x: array([-1.22144843])

In [182]:

shgo(func,
bounds=[(-10,10)])

Out[182]:

fun: -8.026429359839729e-05
funl: array([-8.02642936e-05])
message: 'Optimization terminated successfully.'
nfev: 30
nit: 2
nlfev: 27
nlhev: 0
nljev: 9
success: True
x: array([9.91730485])
xl: array([[9.91730485]])

http://localhost:8888/lab 15/18
23/5/2022 6_Non-linear_metaheuristics

Βλέπουμε ότι ενώ τα dual_annealing και differential_evolution είχαν άριστη απόδοση, η shgo δεν μας έδωσε
την σωστή λύση. Αυτό δεν σημαίνει ότι δεν δουλεύει.

Την ξανατρέχω, και αυτή την φορά χρησιμοποιώ την παράμετρο iters. Αυτός είναι ο αριθμός επαναλήψεων
που τρέχει η εντολή, και ενώ η προεπιλογή είναι μία επανάληψη, εμείς θα τις αυξήσουμε σε 5.

Θέτοντας $iters=5$ βλέπουμε ότι μας δίνει σωστό αποτέλεσμα.

In [158]:

shgo(func,
iters=5,
bounds=[(-10,10)])

Out[158]:

fun: -0.6743051024666705
funl: array([-6.74305102e-01, -2.40375639e-01, -2.08875401e-03, -8.026
42936e-05])
message: 'Optimization terminated successfully.'
nfev: 106
nit: 5
nlfev: 89
nlhev: 0
nljev: 29
success: True
x: array([-1.22144846])
xl: array([[-1.22144846],
[ 4.10146617],
[-6.87286227],
[ 9.91730485]])

Τώρα πάμε στην άλλη συνάρτηση. Ας την ξανασχεδιάσουμε.

In [160]:

x = np.arange(0,100)
f= lambda x:(-3*x**2 + 75*x*np.sin(x) + 3) * np.cos(x/7)
plt.plot(x,f(x));

http://localhost:8888/lab 16/18
23/5/2022 6_Non-linear_metaheuristics

Η βέλτιστη τιμή που ελαχιστοποιεί την συνάρτηση, καθώς και η τιμή που παίρνει η συνάρτηση, υπολογίζονται
παρακάτω.

In [162]:

x[np.argmin(f(x))], np.min(f(x))

Out[162]:

(87, -27800.31210245675)

Ας δοκιμάσουμε τώρα τους τρεις μεταευριστικούς αλγορίθμους του scipy, και ας συγκρίνουμε τις λύσεις που
υπολογίζουν με τις πραγματικές.

In [164]:

dual_annealing(f,bounds=[(0,100)])

Out[164]:

fun: array([-28306.9934827])
message: ['Maximum number of iteration reached']
nfev: 2035
nhev: 0
nit: 1000
njev: 0
x: array([86.61099446])

In [165]:

differential_evolution(f,bounds=[(0,100)])

Out[165]:

fun: array([-28306.9934827])
jac: array([0.0007276])
message: 'Optimization terminated successfully.'
nfev: 132
nit: 7
success: True
x: array([86.61099454])

In [166]:

shgo(f,bounds=[(0,100)])

Out[166]:

fun: -8486.550386356275
funl: array([-8486.55038636])
message: 'Optimization terminated successfully.'
nfev: 25
nit: 2
nlfev: 22
nlhev: 0
nljev: 6
success: True
x: array([48.48133589])
xl: array([[48.48133589]])

http://localhost:8888/lab 17/18
23/5/2022 6_Non-linear_metaheuristics

H shgo βλέπουμε για άλλη μια φορά πως μας έδωσε υποβέλτιστο αποτέλεσμα. Αν αυξήσουμε κατά ελάχιστα
τον αριθμό των επαναλήψεων, όμως, και από 1 τον κάνουμε 3, μας δίνει το βέλτιστο αποτέλεσμα.

In [177]:

shgo(f,iters=3,bounds=[(0,100)])

Out[177]:

fun: -28306.99348270172
funl: array([-2.83069935e+04, -8.48655039e+03, 3.00000000e+00])
message: 'Optimization terminated successfully.'
nfev: 88
nit: 3
nlfev: 83
nlhev: 0
nljev: 16
success: True
x: array([86.61099448])
xl: array([[86.61099448],
[48.48133588],
[ 0. ]])

http://localhost:8888/lab 18/18

You might also like