机器学习 —— 用于超参数随机化搜索的几个分布

机器学习中超参数搜索的常用方法为 Grid Search,然而如果参数一多则容易碰到维数诅咒的问题,即参数之间的组合呈指数增长。如果有 \(m\) 个参数,每个有 \(n\) 个取值,则时间复杂度为 \(\Theta(n^m)\)。 Bengio 等人在 《Random Search for Hyper-Parameter Optimization》 中提出了随机化搜索的方法。他们指出大部分参数空间存在 “低有效维度 (low effective dimensionality)” 的特点,即有些参数对目标函数影响较大,另一些则几乎没有影响。而且在不同的数据集中通常有效参数也不一样。 在这种情况下 Random Search 通常效果较好,下图是一个例子,其中只有两个参数,绿色的参数影响较大,而黄色的参数则影响很小:

Grid Search 会评估每个可能的参数组合,所以对于影响较大的绿色参数,Grid Search 只探索了3个值,同时浪费了很多计算在影响小的黄色参数上; 相比之下 Random Search 则探索了9个不同的绿色参数值,因而效率更高,在相同的时间范围内 Random Search 通常能找到更好的超参数 (当然这并不绝对)。 另外,Random Search 可以在连续的空间搜索,而 Grid Search 则只能在离散空间搜索,而对于像神经网络中的 learning rate,SVM 中的 gamma 这样的连续型参数宜使用连续分布。

在实际的应用中,Grid Search 只需为每个参数事先指定一个参数列表就可以了,而 Random Search 则通常需要为每个参数制定一个概率分布,进而从这些分布中进行抽样。然而对什么样的参数应该选择什么样的分布?这就大有讲究了,如果选的分布不恰当可能就永远找不到合适的参数值了,本文主要介绍一些超参数搜索的常用分布以及它们的特点和使用范围。这些分布都出自 scipy.stats 模块,共同特点是提供了 rvs 方法用于独立随机抽样。

Randint 分布

Randint 分布的概率质量函数 (PMF) 为:

\[
f(x) = \frac{1}{high - low}
\]

其中 \(x = low,\,...,high - 1\) ,下面画出随机抽样10000次后各个取值的分布图:

np.random.seed(42)
randint = sp.stats.randint(low=-10, high=11)
randint_distribution = randint.rvs(size=10000, random_state=42)

start = randint.ppf(0.01)
end = randint.ppf(0.99)
x = np.arange(start, end+1)

randint_dict = dict(zip(*np.unique(randint_distribution, return_counts=True)))   # 计算各个数的频次
randint_count = list(map(lambda x: x[1], sorted(list(randint_dict.items()), key=lambda x: x[0])))

plt.figure(figsize=(8,5))
plt.bar(x, randint_count, color=‘b‘, alpha=0.5, edgecolor=‘k‘,  label="random_samples")
plt.axhline(y=450, xmin=0.01, xmax=0.99, color=‘#FF00FF‘, linestyle="--")
plt.legend(frameon=False, fontsize=10)
plt.title("randint distribution", fontsize=17)
plt.show()

从上图可以看出 Randint 分布为离散型均匀分布,适用于必须为整数的参数 (比如神经网络的层数,决策树的深度)。

Uniform 分布

Uniform 是 Randint 分布的连续版本,概率密度函数为:

\[
f(x) = \frac{1}{high - low}
\]

其中 \(x \in [low, high]\)

np.random.seed(42)
uniform = sp.stats.uniform(loc=10, scale=10)
uniform_distribution = uniform.rvs(size=10000, random_state=42)
start = uniform.ppf(0.01)
end = uniform.ppf(0.99)
x = np.linspace(start, end, num=10000)

plt.figure(figsize=(8,5))
plt.plot(x, uniform.pdf(x), ‘r--‘, lw=2, label="uniform distribution PDF")
plt.hist(uniform_distribution, bins=30, color=‘b‘, alpha=0.5, edgecolor = ‘k‘, normed=True, label="random samples")
plt.legend(frameon=False, fontsize=10)
plt.title("uniform distribution", fontsize=17)
plt.show()

Geometric 分布

Geometric 分布的概率质量函数为 :

\[
f(x) = (1-p)^{x-1} p
\]

其中 \(x \geqslant 1\)

np.random.seed(42)
plt.figure(figsize=(8,5))
geom_distribution = sp.stats.geom.rvs(0.5, size=10000, random_state=42)
plt.hist(geom_distribution, bins=30, color=‘b‘, alpha=0.5, edgecolor = ‘k‘, label="random samples")
plt.legend(frameon=False, fontsize=10)
plt.title("Geometric Distribution, p = 0.5", fontsize=17)
plt.show()

Geometric 分布为离散型分布,表示得到一次成功所需要的试验次数,如果参数集中于少数几个值且可能性呈离散型单调递减,则适用此分布。

Geometric 分布概率质量函数中的 \(p\) 指定了一次试验成功的概率。如果改变此值则会增大或缩小采样范围。

np.random.seed(42)
plt.figure(figsize=(15,5))
plt.subplot(121)
geom_distribution = sp.stats.geom.rvs(0.8, size=10000, random_state=42)
plt.hist(geom_distribution, bins=30, color=‘b‘, alpha=0.5, edgecolor = ‘k‘, label="random samples")
plt.legend(frameon=False, fontsize=10)
plt.title("Geometric Distribution, p = 0.8", fontsize=17)

plt.subplot(122)
geom_distribution = sp.stats.geom.rvs(0.01, size=10000, random_state=42)
plt.hist(geom_distribution, bins=30, color=‘b‘, alpha=0.5, edgecolor = ‘k‘, label="random samples")
plt.legend(frameon=False, fontsize=10)
plt.title("Geometric Distribution, p = 0.01", fontsize=17)
plt.show()

Exponential 分布

Exponential 分布是 Geometric 分布的连续版本,其概率密度函数为 :

\[
f(x) = e^{-x}
\]

可以看到上图中当Geometric 分布中的 \(p\) 非常小时,就会变得非常接近 exponential 分布。

plt.figure(figsize=(16,4))
expon_distribution = sp.stats.expon.rvs(loc=0, scale=1, size=10000, random_state=42)

plt.subplot(121)
start = sp.stats.expon.ppf(0.001)
end = sp.stats.expon.ppf(0.999)
x = np.linspace(start, end, num=10000)
plt.plot(x, sp.stats.expon.pdf(x), ‘r--‘, lw=2, label=" exponential \ndistribution PDF")
plt.hist(expon_distribution, bins=30, color=‘b‘, alpha=0.5, edgecolor = ‘k‘, normed=True, label="random samples")
plt.legend(frameon=False, fontsize=13)
plt.title("exponential distribution", fontsize=17)

plt.subplot(122)
plt.hist(np.log(expon_distribution), bins=30, edgecolor = ‘k‘, color=‘b‘, alpha=0.5)
plt.title("log of exponential distribution", fontsize=17)
plt.axvline(x=-5, color=‘#FF00FF‘, linestyle="--")
plt.axvline(x=2, color=‘#FF00FF‘, linestyle="--")
plt.show()

从右边的 log 分布图来看,大部分值集中于 \(e^{-5}\) 到 \(e^2\) 之间,即 \(0.0067 \sim 7.389\) 。如果有一些先验知识,知道参数在0附近,且值越大可能性越小 (如svm中的gamma),则适用此分布。当然也可以调整位置 (loc) 和 比例 (scale) 参数来改变搜索范围。此时对应的概率密度函数为 (下面演示 loc=10,scale=10 的情况):

\[
f(x) = \frac{e^{-\frac{x - loc}{scale}}}{scale}
\]

Reciprocal 分布

reciprocal 分布的概率密度函数为:

\[
f(x, a, b) = \frac{1}{x \text{log}(b/a)} = \frac{1}{x\text{log}b - x\text{log}a}
\]

其中 \(a < x < b, \; b > a > 0\)

np.random.seed(42)
plt.figure(figsize=(15,5))
reciprocal = sp.stats.reciprocal(a=0.1, b=100)
reciprocal_distribution = reciprocal.rvs(size=10000, random_state=42)

plt.subplot(121)
start = reciprocal.ppf(0.3)
end = reciprocal.ppf(0.99)
x = np.linspace(start, end, num=10000)
plt.plot(x, reciprocal.pdf(x), ‘r--‘, lw=2, label="  reciprocal \ndistribution PDF")
plt.hist(reciprocal_distribution, bins=30, color=‘b‘, alpha=0.5, edgecolor = ‘k‘, normed=True, label="random samples")
plt.legend(frameon=False, fontsize=13)
plt.title("reciprocal distribution", fontsize=17)

plt.subplot(122)
plt.hist(np.log10(reciprocal_distribution), bins=30, color=‘b‘, alpha=0.5, edgecolor = ‘k‘)
plt.title("log of reciprocal distribution", fontsize=17)
plt.show()

上图中 reciprocal 分布的PDF和 exponential 分布比较相似,然而右边的 log 分布图却是比较平均的,可见 reciprocal 分布是一个典型的对数均匀分布,以10为底为例,线性空间中10倍的差距在对数空间中均为1,设$x_2 = 10,x_1 $:

\[
\begin{align*}
\text{log}\,f(x_1, a, b) - \text{log}\, f(x_2, a, b) &= \text{log} \frac{1}{x_1 \text{log}(b/a)} - \text{log} \frac{1}{x_2 \text{log}(b/a)} \\[1ex]
& = -\text{log} \, [x_1\text{log}(b/a)] + \text{log} \, [x_2\text{log}(b/a)] \\[1ex]
& = -\text{log}\, x_1 + \text{log} \, x_2 \\[1ex]
& = \text{log} \frac{x_2}{x_1} = 1
\end{align*}
\]

下面用 np.random.uniform 可以模拟类似的分布。

np.random.seed(42)
log_uniform = 10 ** np.random.uniform(-1, 2, size=10000)

plt.figure(figsize=(15,5))
plt.subplot(121)
plt.hist(log_uniform, bins=30, color=‘b‘, alpha=0.5, normed=True, edgecolor=‘k‘)
plt.title("$10^{(-1 \sim 2)}$ distribution", fontsize=17)

plt.subplot(122)
plt.hist(np.log10(log_uniform), bins=30, color=‘b‘, alpha=0.5, edgecolor=‘k‘)
plt.title("log of $10^{(-1 \sim 2)}$ distribution", fontsize=17)
plt.show()

这种分布的好处是在不同的取值范围内也能均匀地抽样。如上图中参数 \(x\) 的取值范围是 \(0.1 \sim 100\), 即 \(10^{-1} \sim 10^2\),如果是一般的均匀分布中抽样,\(10 \sim 100\) 这个范围被取样到的概率会远大于 \(1 \sim 10\) 和 \(0.1 \sim 1\) 这两个范围,因为前者的距离更大,但在对数均匀分布中三者的范围却是一样的,都是10的倍数,这样被抽样到的概率也就类似。下面的代码显示一个例子:

a = 0
b = 0
c = 0

reciprocal_distribution = sp.stats.reciprocal.rvs(a=0.1, b=100, size=10000, random_state=42)

for val in reciprocal_distribution:
    if val > 10 and val < 100:
        a += 1
    elif val > 1 and val < 10:
        b += 1
    elif val > 0.1 and val < 1:
        c +=1

print("10  到 100 之间取样 {} 次".format(a))  # 10 到 100 之间取样 3233 次
print("1   到 10  之间取样 {} 次".format(b))  # 1 到 10 之间取样 3392 次
print("0.1 到 1  之间取样 {} 次".format(c))   # 0.1 到 1 之间取样 3375 次

对于像 learning rate 这样的参数,我们希望 \(0.01\sim0.1\) 和 \(0.1\sim1\) 范围之间的抽样概率是类似的。举例来说,0.11和0.1的学习率可能相差不大,但0.01和0.02的学习率结果更可能大不相同,虽然这两个范围的绝对差异均为0.01。因此在这样的参数中不同值之间的比率更适合作为超参数变化范围。 另外实际上我们可以做到 “完全” 的对数均匀分布,这要用到 numpy 中的 logspace。 然而使用 np.logspace 的缺点是只能生成一个间隔均匀的固定数组进行采样,从而丧失了一定的随机性。

logspace = np.logspace(-1, 2, base=10, num=10000)
plt.figure(figsize=(15,4))
plt.subplot(121)
plt.hist(logspace, bins=30, color=‘b‘, alpha=0.5, normed=True, edgecolor=‘k‘)
plt.title("logspace", fontsize=17)
plt.subplot(122)
plt.hist(np.log10(logspace), bins=30, color=‘b‘, alpha=0.5, edgecolor=‘k‘)
plt.title("log of logspace", fontsize=17)
plt.show()



最后用scikit-learn中的 RandomizedSearchCV 来比较一下 Grid Search 和 Random Search 的效果,使用了 Kaggle 上的 HousePrices 比赛中的一个 Kernel 进行数据预处理,最后的特征数为410,使用的模型为超参数较多的 GBDT,评估指标为 RMSE:

  1. 树的数量 (n_estimators)
  2. 损失函数类型 (loss)
  3. 学习率 (learning_rate)
  4. 子采样率 (subsample)
  5. 叶结点上的最少样本数 (min_samples_leaf)
  6. 最大深度 (max_depth)
  7. 分裂时考虑的特征数 (max_features)

下面先尝试 GridSearchCV

from sklearn.model_selection import GridSearchCV, RandomizedSearchCV

def neg_sqrt(val):  # 定义 RMSE
    return np.sqrt(-val)

model = GradientBoostingRegressor()
param_grid = {
    "learning_rate": [0.01, 0.05, 0.1],
    "n_estimators": [400, 800, 1500],
    "subsample": [0.8, 1.0],
    "max_depth": [2, 3, 4],
    "max_features": [0.8, 1.0],
    "min_samples_leaf": [1, 2],
    "loss": ["ls", "huber"],
    "random_state": [42],
}

grid_search = GridSearchCV(model, param_grid, scoring="neg_mean_squared_error", cv=5, verbose=3, n_jobs=-1)
grid_search.fit(X_scaled, y_log)
print("最优参数为: ", grid_search.best_params_, ‘\n‘)
print("RMSE 为: ", neg_sqrt(grid_search.best_score_))

结果如下:

最优参数为:  {‘min_samples_leaf‘: 2, ‘learning_rate‘: 0.05, ‘max_depth‘: 2, ‘random_state‘: 42, ‘n_estimators‘: 1500, ‘loss‘: ‘huber‘, ‘subsample‘: 0.8, ‘max_features‘: 1.0} 

RMSE 为:  0.11852064590041982

上面过程中总共的参数组合为 \(3 \times 3 \times 2 \times 3 \times 2 \times 2 \times 2 = 432\) 个,接下来的RandomizedSearchCV 用了差不多的400个,其中 learning_rate 用了 reciprocal 这样的对数均匀分布,原因前文已经说了。叶结点上的最少样本数 (min_samples_leaf) 使用了 Geometric 分布,主要考虑到大部分值可能集中在 1和2左右。其他参数都使用均匀分布:

model = GradientBoostingRegressor()
param_distribution = {
    "learning_rate": sp.stats.reciprocal(a=0.01, b=0.1),
    "n_estimators": sp.stats.randint(low=400, high=1500),
    "subsample": sp.stats.uniform(loc=0.8, scale=0.2),
    "max_depth": sp.stats.randint(low=2, high=4),
    "max_features": sp.stats.uniform(loc=0.8, scale=0.2),
    "min_samples_leaf": sp.stats.geom(p=0.6),
    "loss": ["ls", "huber"],
    "random_state": [42],
}

random_search = RandomizedSearchCV(model, param_distribution, n_iter=400, scoring="neg_mean_squared_error", cv=5,
                                   verbose=3, random_state=42, n_jobs=-1)
random_search.fit(X_scaled, y_log)
print("最优参数为: ", random_search.best_params_, ‘\n‘)
print("RMSE 为: ", neg_sqrt(random_search.best_score_))

结果如下:

最优参数为:  {‘min_samples_leaf‘: 3, ‘learning_rate‘: 0.03181845026156779, ‘max_depth‘: 2, ‘random_state‘: 42, ‘n_estimators‘: 1476, ‘loss‘: ‘huber‘, ‘subsample‘: 0.8978905520555127, ‘max_features‘: 0.8557292928473224} 

RMSE 为:  0.11835604958840028

在这个数据集上 Random Search 的效果确实比 Grid Search 稍好,当然前提是为每个参数都选择合适的分布。

/

原文地址:https://www.cnblogs.com/massquantity/p/10289285.html

时间: 2024-10-10 04:38:52

机器学习 —— 用于超参数随机化搜索的几个分布的相关文章

python 超参数 自动搜索模块GridSearchCV(收藏)

1. 引言 当我们跑机器学习程序时,尤其是调节网络参数时,通常待调节的参数有很多,参数之间的组合更是繁复.依照注意力>时间>金钱的原则,人力手动调节注意力成本太高,非常不值得.For循环或类似于for循环的方法受限于太过分明的层次,不够简洁与灵活,注意力成本高,易出错.本文介绍sklearn模块的GridSearchCV模块,能够在指定的范围内自动搜索具有不同超参数的不同模型组合,有效解放注意力. 2. GridSearchCV模块简介 这个模块是sklearn模块的子模块,导入方法非常简单

【机器学习】超参数调优

超参数调优方法 网格搜索 通过查找搜索范围内的所有的点来确定最优值.如果采用较大的搜索范围以及较小的步长,网络搜索有很大概率找到全局最优值.然而,这种搜索方案十分消耗计算资源和时间,特别是需要调优的超参数比较多的时候,因此,在实际应用中,网格搜索法一般会使用较广的搜索范围和步长,来寻找全局最优值可能的位置:然后会逐渐缩小搜索范围和步长,来寻找更精确的最优值.这种方案可以降低所需的时间和计算量,但由于目标函数一般是非凸的,所以很可能会错过全局最优值. 随机搜索 理论依据是如果样本集足够大,那么通过

机器学习 | 特征工程- 超参数调优方法整理

特征工程是机器学习当中很重要的部分,可以帮助我们设计.创建新特征,以便模型从中提取重要相关性.本文将记录并持续更新相关特征工程的工具包介绍,包括自动模型选择和超参数调优等各方面. · Featuretools Featuretools 是一个开源的Python 库,用于自动化特征工程.自动特征工程能够缩减时间成本,构建更优秀的预测模型,生成更有意义的特征,还能防止数据泄漏(data leakage). 目标任务:从数据表格集中获取所有的数据信息并整合到一张表中,再创建特征. 解决方案:采用深度特

深度学习模型超参数搜索实用指南

要知道,与机器学习模型不同,深度学习模型里面充满了各种超参数.而且,并非所有参数变量都能对模型的学习过程产生同样的贡献. 考虑到这种额外的复杂性,在一个多维空间中找到这些参数变量的最佳配置并不是件容易的事情. 每一位科学家和研究人员,都希望在现有的资源条件下(计算.金钱和时间),找到最佳的模型. 通常情况下,研究人员和业余爱好者会在开发的最后阶段尝试一种搜索策略.这可能会有助改进他们辛辛苦训练出来的模型. 此外,在半自动/全自动深度学习过程中,超参数搜索也是的一个非常重要的阶段. 超参数到底是什

Spark2.0机器学习系列之2:基于Pipeline、交叉验证、ParamMap的模型选择和超参数调优

Spark中的CrossValidation Spark中采用是k折交叉验证 (k-fold cross validation).举个例子,例如10折交叉验证(10-fold cross validation),将数据集分成10份,轮流将其中9份做训练1份做验证,10次的结果的均值作为对算法精度的估计. 10折交叉检验最常见,是因为通过利用大量数据集.使用不同学习技术进行的大量试验,表明10折是获得最好误差估计的恰当选择,而且也有一些理论根据可以证明这一点.但这并非最终结论,争议仍然存在.而且似

机器学习:kNN的超参数

一.评测标准 模型的测评标准:分类的准确度(accuracy): 预测准确度 = 预测成功的样本个数/预测数据集样本总数 二.超参数 超参数:运行机器学习算法前需要指定的参数: kNN算法中的超参数:k.weights.P: 一般超参数之间也相互影响: 调参,就是调超参数: 1)问题 # 以kNN算法为例 平票:如果k个点中,不同类型的样本数相等,怎么选取? 如果选取的k个点中,数量多的一类样本点距离测试样本较远,数量少的一类样本点距离测试样本较近,此时选取数量较多的类型作为输出结果,不具说服力

机器学习算法中如何选取超参数:学习速率、正则项系数、minibatch size

机器学习算法中如何选取超参数:学习速率.正则项系数.minibatch size 本文是<Neural networks and deep learning>概览 中第三章的一部分,讲机器学习算法中,如何选取初始的超参数的值.(本文会不断补充) 学习速率(learning rate,η) 运用梯度下降算法进行优化时,权重的更新规则中,在梯度项前会乘以一个系数,这个系数就叫学习速率η.下面讨论在训练时选取η的策略. 固定的学习速率.如果学习速率太小,则会使收敛过慢,如果学习速率太大,则会导致代价

机器学习-kNN-寻找最好的超参数

一 .超参数和模型参数 超参数:在算法运行前需要决定的参数 模型参数:算法运行过程中学习的参数 - kNN算法没有模型参数- kNN算法中的k是典型的超参数 寻找好的超参数 领域知识 经验数值 实验搜索 二.通过sklearn中的数据集进行测试 import numpy as np from sklearn import datasets # 装载sklearn中的手写数字数据集 digits = datasets.load_digits() x = digits.data y = digits

机器学习:SVM(scikit-learn 中的 RBF、RBF 中的超参数 γ)

一.高斯核函数.高斯函数 μ:期望值,均值,样本平均数:(决定告诉函数中心轴的位置:x = μ) σ2:方差:(度量随机样本和平均值之间的偏离程度:, 为总体方差,  为变量,  为总体均值,  为总体例数) 实际工作中,总体均数难以得到时,应用样本统计量代替总体参数,经校正后,样本方差计算公式:S^2= ∑(X-  ) ^2 / (n-1),S^2为样本方差,X为变量,  为样本均值,n为样本例数. σ:标准差:(反应样本数据分布的情况:σ 越小高斯分布越窄,样本分布越集中:σ 越大高斯分布越