Un optimiseur trouve-t-il toujours le meilleur point ?
SciPy est une bibliothèque Python de calcul scientifique, et sa fonction minimize cherche le minimum d’une fonction à votre place. Elle va vite, mais elle peut s’arrêter sur un faux minimum ou échouer.
Savoir lire son résultat est aussi important que de savoir la lancer.
À la fin de cette leçon
Remarque
Je peux utiliser l’optimiseur de SciPy et dire quand une descente reste coincée ou diverge.
Mots clés
| Mot | Ce que ça veut dire |
|---|---|
| Optimiseur | un programme qui cherche le minimum d’une fonction |
| Point de départ | la valeur à partir de laquelle la recherche commence |
| Minimum local | un creux plus bas que ses voisins, mais pas le plus bas |
| Minimum global | le point le plus bas de toute la fonction |
| Terrain plat | une zone où la pente est presque nulle |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
La fonction minimize fait la descente pour vous
On donne à minimize la fonction et un point de départ. Elle fait ses pas et rend un objet résultat. Trois champs comptent.
success dit si elle s’est arrêtée sans problème. x est le point trouvé. fun est la valeur de la fonction à ce point.
Exemple travaillé : lire le résultat de minimize
| Champ | Ce qu’il dit | Valeur pour (x - 3) au carré plus (y + 1) au carré |
|---|---|---|
| success | la recherche a fini sans erreur | True |
| x | le point trouvé | [3, -1] |
| fun | la valeur de la fonction en ce point | 0 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Minimiser une fonction de deux variables
docker exec jupyter python3 -c "from scipy.optimize import minimize; r = minimize(lambda v: (v[0] - 3) ** 2 + (v[1] + 1) ** 2, [0, 0]); print(r.success, [round(float(v), 3) for v in r.x], round(float(r.fun), 6))"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Un minimum local n’est pas le minimum global
Certaines fonctions ont deux creux. Une descente tombe dans celui qui est de son côté. Selon le point de départ, elle s’arrête dans l’un ou dans l’autre.
Le creux atteint est un minimum local. Il peut être plus haut que le minimum global. Pour s’en méfier, on essaie plusieurs points de départ.
Exemple travaillé : deux creux, deux réponses
| Point de départ | Creux atteint (x) | Valeur de la fonction | Lecture |
|---|---|---|---|
| -2 | -1,301 | -3,514 | le minimum global |
| 2 | 1,131 | -1,07 | un minimum local, plus haut |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Lancer l’optimiseur depuis deux départs
docker exec jupyter python3 -c "from scipy.optimize import minimize; f = lambda v: v[0] ** 4 - 3 * v[0] ** 2 + v[0]; print([round(float(minimize(f, [x0]).x[0]), 3) for x0 in (-2, 2)], [round(float(minimize(f, [x0]).fun), 3) for x0 in (-2, 2)])"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Un terrain plat arrête la descente
Une descente s’arrête quand la pente est presque nulle. Or la pente peut être nulle ailleurs qu’au fond : sur un replat, par exemple.
La fonction x au cube a une dérivée nulle en x = 0. Pourtant elle est négative à gauche et positive à droite : ce n’est pas un minimum.
Regarder la fonction autour d’un replat
docker exec jupyter python3 -c "f = lambda x: x ** 3; print(round(f(-0.1), 4), round(f(0), 4), round(f(0.1), 4), 3 * 0 ** 2)"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Une divergence fait exploser les valeurs
Quand le taux est trop grand, x s’éloigne de plus en plus. Le programme n’affiche pas d’erreur : les valeurs grandissent sans fin.
On fixe donc une limite, comme 100, et on arrête si x la dépasse. Il suffit alors de réduire le taux, ou d’essayer plusieurs taux.
Détecter une divergence dans une boucle
# Repérer une divergence : x dépasse une limite.
def derivee(x):
return 2 * (x - 3)
x = 0.0
taux = 1.1
for pas in range(1, 31):
x = x - taux * derivee(x)
if abs(x) > 100:
print("diverge au pas", pas)
break
# Mettez taux à 0.9 : le programme n’affiche plus rien. Pourquoi ?
Une erreur fréquente
Attention
Beaucoup pensent que le point rendu par un optimiseur est forcément le meilleur. Il est seulement le creux où la recherche est tombée. Essayez plusieurs points de départ et gardez la plus petite valeur de la fonction.
Pour aller plus loin
Dans un carnet, appelez minimize sur l’erreur d’une droite avec les deux réglages a et b, puis comparez au résultat de polyfit. Ils doivent s’accorder.
Essayez ensuite minimize(f, [x0], method="Nelder-Mead") et voyez si le résultat change.