[PYTHON] [Français] tutoriel hyperopt

Tutoriel ([wiki: FMin rev: a663e] dans la bibliothèque Python hyperopt pour optimiser les espaces de recherche gênants dans les dimensions réelles, discrètes et conditionnelles (https://github.com/hyperopt/hyperopt) (https://github.com/hyperopt/hyperopt/wiki/FMin/a663e64546eb5cd3ed462618dcc1e41863ad8688)) a été traduit par google. Licence


Cette page est un tutoriel sur l'utilisation basique de hyperopt.fmin (). Décrit comment écrire une fonction objectif que fmin peut optimiser et comment écrire un espace de recherche que fmin peut rechercher.

Le travail d'Hyperopt est de trouver la meilleure valeur de fonction stochastique possible pour une valeur scalaire plutôt que l'ensemble des arguments possibles pour cette fonction. Alors que de nombreux packages d'optimisation s'attendent à ce que ces entrées soient dérivées de l'espace vectoriel, Hyperopt vous encourage à décrire votre espace de recherche plus en détail. En fournissant plus d'informations sur l'endroit où votre fonction est définie et où se trouve la valeur optimale, les algorithmes d'hyperopt peuvent être recherchés plus efficacement.

La façon d'utiliser hyperopt est d'écrire:

Ce didacticiel (le plus basique) vous montrera comment créer des fonctions et des espaces de recherche à l'aide de la base de données d'essai par défaut et de l'algorithme de recherche aléatoire factice. La section (1) traite de différentes conventions d'appel pour la communication entre la fonction objectif et hyperopt. La section (2) concerne la description de l'espace de recherche.

Vous pouvez faire des recherches parallèles en remplaçant la base de données «Trials» par la base de données «MongoTrials». Il existe une autre page wiki sur l'utilisation de mongodb pour la recherche parallèle.

Choisir un algorithme de recherche est aussi simple que de passer ʻalgo = hyperopt.tpe.suggest au lieu de ʻalgo = hyperopt.random.suggest. L'algorithme de recherche est en fait un objet appelable et son constructeur accepte les arguments de configuration, ce qui concerne la manière dont l'algorithme de recherche est sélectionné.

1. Définition de la fonction à minimiser

Hyperopt offre plusieurs niveaux de flexibilité et de complexité accrues lors de la spécification pour minimiser la fonction objectif. Questions à réfléchir en tant que designer

Dans les prochaines sections, nous examinerons différentes manières de mettre en œuvre des objectifs qui minimisent l'objectif quadratique pour une seule variable. Dans chaque section, recherchez dans la plage -10 à +10. Ceci peut être décrit dans * espace de recherche *.

space = hp.uniform('x', -10, 10)

Below, Section 2, covers how to specify search spaces that are more complicated.

1.1 Le cas le plus simple

Le protocole le plus simple pour la communication entre l'algorithme d'optimisation d'hyperopt et la fonction objectif est que la fonction objectif reçoit un point valide de l'espace de recherche et a une virgule flottante * perte * (également appelée utilité négative) associée à ce point. revenir.

from hyperopt import fmin, tpe, hp
best = fmin(fn=lambda x: x ** 2,
    space=hp.uniform('x', -10, 10),
    algo=tpe.suggest,
    max_evals=100)
print best

Ce protocole a l'avantage d'être très lisible et facile à taper. Comme vous pouvez le voir, c'est presque une doublure. L'inconvénient de ce protocole est (1) Ce type de fonction ne permet pas de renvoyer des informations supplémentaires sur chaque évaluation dans la base de données de test. Et (2) Ce type de fonction ne peut pas interagir avec des algorithmes de recherche ou d'autres évaluations de fonctions parallèles. L'exemple suivant montre pourquoi vous souhaitez effectuer ces opérations.

1.2 Joindre des informations supplémentaires par objet d'essai

Si la fonction objectif est complexe et prend du temps à s'exécuter, vous souhaiterez peut-être enregistrer davantage d'informations statistiques et de diagnostic, ainsi que la dernière perte en virgule flottante. Dans de tels cas, la fonction fmin peut gérer le dictionnaire comme valeur de retour. Cela signifie que votre fonction de perte peut renvoyer un dictionnaire qui imbrique toutes les statistiques et diagnostics souhaités. La réalité est un peu moins flexible que cela. Par exemple, lors de l'utilisation de mongodb, le dictionnaire doit être un document JSON valide. Néanmoins, il existe une grande flexibilité pour stocker les résultats auxiliaires spécifiques au domaine.

Lorsque la fonction objectif renvoie un dictionnaire, la fonction fmin recherche des paires clé / valeur spéciales dans la valeur de retour et les transmet à l'algorithme d'optimisation. Il existe deux paires clé-valeur requises.

La fonction fmin répond également à certaines touches d'options:

Les dictionnaires utilisent une variété de mécanismes de stockage back-end, vous devez donc vous assurer qu'ils sont compatibles avec JSON. S'il s'agit d'un graphe avec une arborescence de dictionnaire, liste, tapple, nombre, chaîne de caractères, date et heure, il n'y a pas de problème.

** Astuce: ** Pour stocker des tableaux numpy, envisagez de les sérialiser en chaînes et de les enregistrer en tant que pièces jointes.

L'écriture de la fonction ci-dessus dans un style qui renvoie un dictionnaire ressemble à ceci:

import pickle
import time
from hyperopt import fmin, tpe, hp, STATUS_OK

def objective(x):
    return {'loss': x ** 2, 'status': STATUS_OK }

best = fmin(objective,
    space=hp.uniform('x', -10, 10),
    algo=tpe.suggest,
    max_evals=100)

print best

1.3 Objet d'essai

Pour voir réellement le but de renvoyer un dictionnaire, modifiez la fonction objective pour en retourner et passez un argument explicite trial à fmin.

import pickle
import time
from hyperopt import fmin, tpe, hp, STATUS_OK, Trials

def objective(x):
    return {
        'loss': x ** 2,
        'status': STATUS_OK,
        # -- store other results like this
        'eval_time': time.time(),
        'other_stuff': {'type': None, 'value': [0, 1, 2]},
        # -- attachments are handled differently
        'attachments':
            {'time_module': pickle.dumps(time.time)}
        }
trials = Trials()
best = fmin(objective,
    space=hp.uniform('x', -10, 10),
    algo=tpe.suggest,
    max_evals=100,
    trials=trials)

print best

Dans ce cas, l'appel à fmin est le même que précédemment, mais vous pouvez passer l'objet d'essai directement pour inspecter toutes les valeurs de retour calculées pendant l'expérience.

Ainsi, par exemple:

Vous pouvez enregistrer cet objet d'essai, le transmettre à une routine de traçage intégrée ou l'analyser avec votre propre code personnalisé.

«Les pièces jointes» sont gérées par un mécanisme spécial qui vous permet d'utiliser le même code pour «Trials» et «MongoTrials».

Vous pouvez obtenir une pièce jointe d'essai comme celle-ci. Cela obtiendra l'attachement 'time_module' pour le 5e essai

msg = trials.trial_attachments(trials.trials[5])['time_module']
time_module = pickle.loads(msg)

les pièces jointes sont de grandes chaînes, donc si vous utilisez MongoTrials, vous n'avez pas besoin de télécharger plus que ce dont vous avez besoin. Les chaînes peuvent également être attachées globalement à l'ensemble de l'objet d'essai via des essais. les pièces jointes se comportent comme un dictionnaire chaîne-chaîne.

** N.B. ** Actuellement, les pièces jointes spécifiques à la version d'évaluation des objets Trials sont placées dans le dictionnaire des pièces jointes pour la même version d'évaluation globale, mais sont sujettes à modification à l'avenir et ne s'appliquent pas aux MongoTrials.

1.4 Objet Ctrl pour une communication en temps réel avec MongoDB

Il est possible que fmin () donne à votre fonction objectif le handle de mongodb utilisé dans des expériences parallèles. Ce mécanisme vous permet de mettre à jour la base de données avec des résultats partiels et de communiquer avec d'autres processus parallèles qui évaluent différents points. La fonction objectif peut même ajouter de nouveaux points de recherche, tels que random.suggest.

Les techniques de base sont:

Je ne le couvrirai pas dans ce court didacticiel, mais je voudrais mentionner ce qui est possible avec la base de code actuelle. Il comprend également des sources hyperopt, des tests unitaires et des exemples de projets tels que hyperopt-convnet. Veuillez m'envoyer un e-mail ou soumettre un problème github pour accélérer cette partie du code.

2. Définition de l'espace de recherche

L'espace de recherche se compose d'expressions fonctionnelles imbriquées qui contiennent des expressions probabilistes. La représentation probabiliste est un hyperparamètre. L'échantillonnage à partir de ce programme stochastique imbriqué définit un algorithme de recherche aléatoire. L'algorithme d'optimisation des hyperparamètres fonctionne en remplaçant la logique "d'échantillonnage" habituelle par une stratégie de recherche adaptative et ne tente pas réellement d'échantillonner à partir de la distribution spécifiée dans l'espace de recherche.

Il est préférable de considérer l'espace de recherche comme un programme d'échantillonnage d'arguments probabiliste. Par exemple

from hyperopt import hp
space = hp.choice('a',
    [
        ('case 1', 1 + hp.lognormal('c1', 0, 1)),
        ('case 2', hp.uniform('c2', -10, 10))
    ])

Le résultat de l'exécution de ce code est la variable «espace» qui référence le graphique de l'identificateur d'expression et ses arguments. Rien n'a été réellement échantillonné. C'est juste un graphique qui décrit comment échantillonner des points. Le code pour travailler avec ce type de graphe de représentation est dans hyperopt.pyll, et nous appelons ces graphes graphes pyll` ou programmes * pyll *.

Si vous le souhaitez, l'espace échantillon peut être échantillonné et évalué.

import hyperopt.pyll.stochastic
print hyperopt.pyll.stochastic.sample(space)

Cet espace de recherche, décrit par «espace», a trois paramètres:

Une chose à noter ici est que toutes les expressions probabilistes optimisables ont un * label * comme premier argument. Ces étiquettes sont utilisées pour renvoyer les choix de paramètres à l'appelant et sont utilisées en interne de différentes manières.

Une autre chose à noter est l'utilisation de taples au centre du graphe (autour de chaque «cas 1» et «cas 2»). Les listes, dictionnaires et tapples sont tous mis à niveau vers des "expressions fonctionnelles déterministes" et font partie du programme stochastique de l'espace de recherche.

Le troisième notable est l'expression numérique 1 + hp.lognormal ('c1', 0, 1) intégrée dans la description de l'espace de recherche. En ce qui concerne l'algorithme d'optimisation, il n'y a aucune différence en ajoutant 1 directement à l'espace de recherche et 1 dans la logique de la fonction objectif elle-même. Les concepteurs peuvent choisir où placer ce traitement pour obtenir le type de modularité dont ils ont besoin. Le résultat d'une expression intermédiaire dans l'espace de recherche peut être n'importe quel objet Python, même lorsqu'il est optimisé en parallèle à l'aide de mongodb. Il est facile d'ajouter un nouveau type de représentation non probabiliste à la description de l'espace de recherche (voir la section 2.3 ci-dessous).

Quatrièmement, «c1» et «c2» sont des exemples appelés paramètres conditionnels. Chacun de «c1» et «c2» affiche uniquement les nombres de l'échantillon renvoyés pour une valeur particulière de «a». Si "a" vaut 0, "c1" est utilisé mais "c2" n'est pas utilisé. Si "a" vaut 1, "c2" est utilisé mais "c1" n'est pas utilisé. Lorsque cela a du sens, vous devez encoder les paramètres comme conditionnels de cette manière, plutôt que d'ignorer simplement les paramètres de la fonction objectif. Vous pouvez rechercher plus efficacement si vous trouvez que «c1» peut ne pas affecter la fonction objectif (car cela n'affecte pas les arguments de la fonction objectif).

2.1 Expression de paramètre

Les formules probabilistes actuellement reconnues par l'algorithme d'optimisation d'hyperopt sont:

2.2 A Search Space Example: scikit-learn

Pour voir toutes ces possibilités en action, voyons comment scikit-learn décrit les espaces d'hyperparamètres de l'algorithme de classification. (Cette idée a été développée à hyperopt-sklearn.)

from hyperopt import hp
space = hp.choice('classifier_type', [
    {
        'type': 'naive_bayes',
    },
    {
        'type': 'svm',
        'C': hp.lognormal('svm_C', 0, 1),
        'kernel': hp.choice('svm_kernel', [
            {'ktype': 'linear'},
            {'ktype': 'RBF', 'width': hp.lognormal('svm_rbf_width', 0, 1)},
            ]),
    },
    {
        'type': 'dtree',
        'criterion': hp.choice('dtree_criterion', ['gini', 'entropy']),
        'max_depth': hp.choice('dtree_max_depth',
            [None, hp.qlognormal('dtree_max_depth_int', 3, 1, 1)]),
        'min_samples_split': hp.qlognormal('dtree_min_samples_split', 2, 1, 1),
    },
    ])

2.3 Ajout d'expressions non probabilistes utilisant pyll

Vous pouvez utiliser des nœuds comme des arguments pour la fonction pyll (voir pyll). Si vous souhaitez en savoir plus à ce sujet, veuillez soumettre un problème github.

En termes simples, vous décorez simplement les fonctions de niveau supérieur (c'est-à-dire adaptées aux pickles) à utiliser via l'objet scope.

import hyperopt.pyll
from hyperopt.pyll import scope

@scope.define
def foo(a, b=0):
     print 'runing foo', a, b
     return a + b / 2

# -- this will print 0, foo is called as usual.
print foo(0)

#Dans la description de l'espace de recherche, comme Python normal`foo`Peut être utilisé.
#Ces deux appels n'appellent pas foo,
#Enregistrez uniquement que vous devez appeler foo pour évaluer le graphique.

space1 = scope.foo(hp.uniform('a', 0, 10))
space2 = scope.foo(hp.uniform('a', 0, 10), hp.normal('b', 0, 1))

# -- this will print an pyll.Apply node
print space1

# -- this will draw a sample by running foo()
print hyperopt.pyll.stochastic.sample(space1)

2.4 Ajout de nouveaux types d'hyperparamètres

Si possible, il faut éviter d'ajouter de nouveaux types de représentations probabilistes pour décrire l'espace de recherche de paramètres. Pour que tous les algorithmes de recherche fonctionnent dans tous les espaces, les algorithmes de recherche doivent correspondre au type d'hyperparamètre qui décrit l'espace. En tant que responsable de la bibliothèque, j'ouvre la possibilité qu'une sorte d'expression soit ajoutée de temps en temps, mais comme je l'ai dit, je veux éviter autant que possible. L'ajout d'un nouveau type de représentation probabiliste n'est pas l'une des façons dont l'hyperopt est extensible.


Copyright (c) 2013, James Bergstra All rights reserved.

Recommended Posts

[Français] tutoriel hyperopt
Streamlit tutorial traduction japonaise
[Français] scicit-learn 0.18 Tutorial Manipulation des données de texte
Tutoriel Biopython et traduction japonaise du livre de recettes (4.3)
[Français] Table des matières du didacticiel scikit-learn 0.18
Tutoriel Biopython et traduction japonaise de Cookbook (4.1)
Tutoriel Biopython et traduction japonaise du livre de recettes (4.8)
Tutoriel Biopython et traduction japonaise du livre de recettes (4.7)
Tutoriel Biopython et traduction japonaise du livre de recettes (4.9)
Tutoriel Biopython et traduction japonaise du livre de recettes (4.6)
Tutoriel Biopython et traduction japonaise du livre de recettes (4.2)
Tutoriel Biopython et traduction japonaise de Cookbook
didacticiel sqlalchemy
Tutoriel PyODE 2
Tutoriel Python
Tutoriel PyODE 1
Tutoriel PyODE 3
Tutoriel Biopython et traduction japonaise du livre de recettes (Chapitre 1, 2)
Tutoriel du didacticiel TensorFlow