了解 hyperopt TPE 算法
Understading hyperopt's TPE algorithm
我正在为我的主项目说明 hyperopt 的 TPE 算法,但似乎无法使算法收敛。据我从原始 paper and youtube lecture 中了解到,TPE 算法按以下步骤工作:
(在下文中,x=超参数和 y=loss)
- 首先创建 [x,y] 的搜索历史记录,比如 10 个点。
- 根据损失对超参数进行排序,并使用一些分位数 γ 将它们分成两组(γ = 0.5 意味着这些组的大小相同)
- 对差的超参数组(g(x))和好的超参数组(l(x))进行核密度估计
- 良好的估计在 g(x) 中具有低概率而在 l(x) 中具有高概率,因此我们建议在 argmin(g(x)/l(x))
处评估函数
- 在建议的点评估 (x,y) 对并重复步骤 2-5。
我已经在 python 中对 objective 函数 f(x) = x^2 实现了这个,但是算法无法收敛到最小值。
import numpy as np
import scipy as sp
from matplotlib import pyplot as plt
from scipy.stats import gaussian_kde
def objective_func(x):
return x**2
def measure(x):
noise = np.random.randn(len(x))*0
return x**2+noise
def split_meassures(x_obs,y_obs,gamma=1/2):
#split x and y observations into two sets and return a seperation threshold (y_star)
size = int(len(x_obs)//(1/gamma))
l = {'x':x_obs[:size],'y':y_obs[:size]}
g = {'x':x_obs[size:],'y':y_obs[size:]}
y_star = (l['y'][-1]+g['y'][0])/2
return l,g,y_star
#sample objective function values for ilustration
x_obj = np.linspace(-5,5,10000)
y_obj = objective_func(x_obj)
#start by sampling a parameter search history
x_obs = np.linspace(-5,5,10)
y_obs = measure(x_obs)
nr_iterations = 100
for i in range(nr_iterations):
#sort observations according to loss
sort_idx = y_obs.argsort()
x_obs,y_obs = x_obs[sort_idx],y_obs[sort_idx]
#split sorted observations in two groups (l and g)
l,g,y_star = split_meassures(x_obs,y_obs)
#aproximate distributions for both groups using kernel density estimation
kde_l = gaussian_kde(l['x']).evaluate(x_obj)
kde_g = gaussian_kde(g['x']).evaluate(x_obj)
#define our evaluation measure for sampling a new point
eval_measure = kde_g/kde_l
if i%10==0:
plt.figure()
plt.subplot(2,2,1)
plt.plot(x_obj,y_obj,label='Objective')
plt.plot(x_obs,y_obs,'*',label='Observations')
plt.plot([-5,5],[y_star,y_star],'k')
plt.subplot(2,2,2)
plt.plot(x_obj,kde_l)
plt.subplot(2,2,3)
plt.plot(x_obj,kde_g)
plt.subplot(2,2,4)
plt.semilogy(x_obj,eval_measure)
plt.draw()
#find point to evaluate and add the new observation
best_search = x_obj[np.argmin(eval_measure)]
x_obs = np.append(x_obs,[best_search])
y_obs = np.append(y_obs,[measure(np.asarray([best_search]))])
plt.show()
我怀疑发生这种情况是因为我们一直在我们最确定的地方采样,从而使 l(x) 在这一点周围越来越窄,这根本不会改变我们采样的地方。那么我的理解有哪些不足呢?
所以,我还在学习TPE。但这是这段代码中的两个问题:
这段代码只会评估几个独特的点。因为最佳位置是根据核密度函数的最佳推荐计算出来的,但是代码没有办法进行搜索的探索space。例如,获取功能是做什么的。
因为此代码只是将新观察值附加到 x 和 y 的列表中。它添加了很多重复项。重复导致一组有偏差的观察结果,并导致非常奇怪的分裂,您可以在后面的图中轻松看到这一点。 eval_measure
开始时类似于 objective 函数,但后来有所不同。
如果您删除 x_obs
和 y_obs
中的重复项,您可以删除问题号。 2. 但是,第一个问题只能通过增加一些探索搜索的方式来解决space。
我正在为我的主项目说明 hyperopt 的 TPE 算法,但似乎无法使算法收敛。据我从原始 paper and youtube lecture 中了解到,TPE 算法按以下步骤工作:
(在下文中,x=超参数和 y=loss)
- 首先创建 [x,y] 的搜索历史记录,比如 10 个点。
- 根据损失对超参数进行排序,并使用一些分位数 γ 将它们分成两组(γ = 0.5 意味着这些组的大小相同)
- 对差的超参数组(g(x))和好的超参数组(l(x))进行核密度估计
- 良好的估计在 g(x) 中具有低概率而在 l(x) 中具有高概率,因此我们建议在 argmin(g(x)/l(x)) 处评估函数
- 在建议的点评估 (x,y) 对并重复步骤 2-5。
我已经在 python 中对 objective 函数 f(x) = x^2 实现了这个,但是算法无法收敛到最小值。
import numpy as np
import scipy as sp
from matplotlib import pyplot as plt
from scipy.stats import gaussian_kde
def objective_func(x):
return x**2
def measure(x):
noise = np.random.randn(len(x))*0
return x**2+noise
def split_meassures(x_obs,y_obs,gamma=1/2):
#split x and y observations into two sets and return a seperation threshold (y_star)
size = int(len(x_obs)//(1/gamma))
l = {'x':x_obs[:size],'y':y_obs[:size]}
g = {'x':x_obs[size:],'y':y_obs[size:]}
y_star = (l['y'][-1]+g['y'][0])/2
return l,g,y_star
#sample objective function values for ilustration
x_obj = np.linspace(-5,5,10000)
y_obj = objective_func(x_obj)
#start by sampling a parameter search history
x_obs = np.linspace(-5,5,10)
y_obs = measure(x_obs)
nr_iterations = 100
for i in range(nr_iterations):
#sort observations according to loss
sort_idx = y_obs.argsort()
x_obs,y_obs = x_obs[sort_idx],y_obs[sort_idx]
#split sorted observations in two groups (l and g)
l,g,y_star = split_meassures(x_obs,y_obs)
#aproximate distributions for both groups using kernel density estimation
kde_l = gaussian_kde(l['x']).evaluate(x_obj)
kde_g = gaussian_kde(g['x']).evaluate(x_obj)
#define our evaluation measure for sampling a new point
eval_measure = kde_g/kde_l
if i%10==0:
plt.figure()
plt.subplot(2,2,1)
plt.plot(x_obj,y_obj,label='Objective')
plt.plot(x_obs,y_obs,'*',label='Observations')
plt.plot([-5,5],[y_star,y_star],'k')
plt.subplot(2,2,2)
plt.plot(x_obj,kde_l)
plt.subplot(2,2,3)
plt.plot(x_obj,kde_g)
plt.subplot(2,2,4)
plt.semilogy(x_obj,eval_measure)
plt.draw()
#find point to evaluate and add the new observation
best_search = x_obj[np.argmin(eval_measure)]
x_obs = np.append(x_obs,[best_search])
y_obs = np.append(y_obs,[measure(np.asarray([best_search]))])
plt.show()
我怀疑发生这种情况是因为我们一直在我们最确定的地方采样,从而使 l(x) 在这一点周围越来越窄,这根本不会改变我们采样的地方。那么我的理解有哪些不足呢?
所以,我还在学习TPE。但这是这段代码中的两个问题:
这段代码只会评估几个独特的点。因为最佳位置是根据核密度函数的最佳推荐计算出来的,但是代码没有办法进行搜索的探索space。例如,获取功能是做什么的。
因为此代码只是将新观察值附加到 x 和 y 的列表中。它添加了很多重复项。重复导致一组有偏差的观察结果,并导致非常奇怪的分裂,您可以在后面的图中轻松看到这一点。
eval_measure
开始时类似于 objective 函数,但后来有所不同。
如果您删除 x_obs
和 y_obs
中的重复项,您可以删除问题号。 2. 但是,第一个问题只能通过增加一些探索搜索的方式来解决space。