Optimisation bayésienne (Référence: Introduction to Bayesian Optimization, Introduction to Bayesian Optimization for Machine Learning En utilisant lamantin / detail / id = 59393)), il est possible que vous puissiez rechercher efficacement des hyper paramètres qui doivent être décidés par divers Try & Error pendant l'apprentissage automatique.
Je peux comprendre l'idée etc. grâce à l'augmentation de divers articles de commentaires récemment, mais je n'ai pas pu le trouver sur le Web sous la forme de la bibliothèque GridSearch, donc je l'ai fait cette fois. Je suis sûr que c'est une réinvention des roues, mais je suis heureux que la réinvention soit une expérience d'apprentissage.
bayesian_optimizer.py
from itertools import product
from sklearn.gaussian_process import GaussianProcess
# The MIT License (C) 2016 mokemokechicken
class BayesianOptimizer:
x_list = None
y_list = None
yielding_index = None
k_band = 5
verbose = False
def __init__(self, params):
self.params = params
self.keys = []
self.values = []
for k, v in sorted(self.params.items()):
self.keys.append(k)
self.values.append(v)
@property
def n_pattern(self):
return len(list(product(*self.values)))
def output(self, *args, **kwargs):
if self.verbose:
print(*args, **kwargs)
def supply_next_param(self, max_iter=None):
self.x_list = []
self.y_list = []
all_parameters = list(product(*self.values)) # [(0.01, [0, 0], 0, [10, 10]), (0.01, [0, 0], 0, [15, 15]), ...
index_space = [list(range(len(v))) for v in self.values] # [[0], [0, 1, 2], [0], [0, 1, 2]]
all_index_list = list(product(*index_space)) # [(0, 0, 0, 0), (0, 0, 0, 1), ...
# examine 2 random points initially
idx = list(range(len(all_index_list)))
np.random.shuffle(idx)
searched_index_list = []
for index in idx[:2]:
param = self.to_param(all_parameters[index])
self.yielding_index = all_index_list[index]
searched_index_list.append(index)
yield param
# Bayesian Optimization
max_iter = int(min(max_iter or max(np.sqrt(self.n_pattern)*4, 20), self.n_pattern)) #Calculez le nombre maximum de recherches de manière appropriée.
for iteration in range(max_iter):
k = 1 + np.exp(-iteration / max_iter * 3) * self.k_band #Réduire progressivement la valeur de k pour mettre l'accent sur la recherche → se concentrer sur l'utilisation
gp = self.create_gp_and_fit(np.array(self.x_list), np.array(self.y_list))
mean_array, mse_array = gp.predict(all_index_list, eval_MSE=True)
next_index, acq_array = self.acquisition(mean_array, mse_array, k, excludes=searched_index_list)
self.output("--- Most Expected Predictions")
for acq, ps in sorted(zip(acq_array, all_parameters), reverse=True)[:3]:
self.output("%.2f: %s" % (acq, list(zip(self.keys, ps))))
self.output("--- Past Best Results")
for acq, vs, ps in self.best_results(3):
self.output("%.2f: %s" % (acq, list(zip(self.keys, vs))))
if next_index in searched_index_list:
break
searched_index_list.append(next_index)
self.yielding_index = all_index_list[next_index]
yield self.to_param(all_parameters[next_index])
@staticmethod
def create_gp_and_fit(x, y, max_try=100):
#Méfiant par ici
theta0 = 0.1
for i in range(max_try+1):
try:
gp = GaussianProcess(theta0=theta0)
gp.fit(x, y)
return gp
except Exception as e:
theta0 *= 10
if i == max_try:
print(theta0)
raise e
def to_param(self, row):
return dict(zip(self.keys, row))
def report(self, score):
self.x_list.append(self.yielding_index)
self.y_list.append(score)
def best_results(self, n=5):
index_list = []
param_list = []
for xs in self.x_list:
values = [self.values[i][x] for i, x in enumerate(xs)]
index_list.append(values)
param_list.append(self.to_param(values))
return sorted(zip(self.y_list, index_list, param_list), reverse=True)[:n]
@staticmethod
def acquisition(mean_array, mse_array, k, excludes=None):
excludes = excludes or []
values = mean_array + np.sqrt(mse_array) * k
for_argmax = np.copy(values)
for ex in excludes:
for_argmax[ex] = -np.Inf
return np.argmax(for_argmax), values
L'utilisation de base est la suivante.
params = {
"parameter1": [10, 20, 25, 50],
"parameter2": ['p1', 'p2'],
...
}
bo = BayesianOptimizer(params) #Passer une combinaison de paramètres dans un dictionnaire
for param in bo.supply_next_param(): #Le paramètre qui doit être vérifié ensuite est passé par dict
y = unknown_score_function(param) #Évaluer le paramètre d'une manière ou d'une autre
bo.report(y) #Je vais vous dire la valeur d'évaluation
print(bo.best_results()) #Je me souviens de la meilleure valeur de score et des paramètres
Voici ce que j'ai essayé sur le notebook Jupyter pour voir si cela fonctionne. https://gist.github.com/mokemokechicken/7f3cf33c71d33bf0ec242c37cb3f2a75
Après avoir fait plusieurs ondulations avec sin et cos sur le plan 50 x 50 suivant, préparez un espace bidimensionnel légèrement inégal avec du bruit.
La partie avec le point rouge (ligne = 3, col = 29) est le point avec la valeur la plus élevée.
Je vais procéder ainsi. Le nombre de recherches est de 200.
Tout d'abord, j'étudie l'espace dans son ensemble. Un peu Go-like w.
Heureusement, il semble avoir cherché plusieurs fois près de son favori au milieu.
Le point favori a été longuement étudié.
Vérifiez soigneusement l'autre montagne en bas à gauche qui a l'air bien. La zone autour du favori au milieu est également couverte.
Vérifiez les espaces vides pour tout ce qui semble bon.
Il n'y a rien d'autre qui semble particulièrement bon et ça se termine. Eh bien, même si les humains le font, ça ressemble à ça.
se produit souvent dans
fit () du processus gaussien de (?) Sklearn. On me dit "Pourquoi ne pas agrandir
theta0 ou
thetaU`? ", C'est ce que je fais pour le moment (je ne suis pas sûr que ce soit bien). En fait, dans le cas de l'évaluation d'hyperparamètres d'apprentissage automatique, ce problème survient souvent car il est assez bruyant.Quand je le fais, il semble qu'il puisse être utilisé dans une grande variété de scènes. La vie est comme ça.
Recommended Posts