Lesson 10.1 超参数优化与枚举网格的理论极限和随机网格搜索 RandomSearchCV

本文涉及的产品
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 首先,导入我们需要的库

文章目录

  • 一、超参数优化与枚举网格的理论极限

1. 超参数优化 HPO(HyperParameter Optimization)

2. 网格搜索的理论极限与缺点

3. 建立 benchmark:随机森林中枚举网格搜索的结果

二、随机网格搜索 RandomizedSearchCV

1. 基本原理

2. 随机网格搜索的实现

3. 相同的全域参数空间

4. 随机网格搜索的理论极限

5. 更大/更密集的全域空间

6. 连续型的参数空间


首先,导入我们需要的库。

import numpy as np
import pandas as pd
import sklearn
import matplotlib as mlp
import matplotlib.pyplot as plt
import seaborn as sns
import time
import re, pip, conda

一、超参数优化与枚举网格的理论极限

1. 超参数优化 HPO(HyperParameter Optimization)


每一个机器学习算法都会有超参数,而超参数的设置很大程度上影响了算法实际的使用效果,因此调参是机器学习算法工程师最为基础和重要的任务。

现代机器学习与深度学习算法的超参数量众多,不仅实现方法异常灵活、算法性能也受到更多的参数的复合影响,因此当人工智能浪潮来临时,可以自动选择超参数的超参数优化 HPO 领域也迎来了新一轮爆发。

在算法的世界中,我们渴望一切流程最终都走向完美自动化,专门研究机器学习自动化的学科被称为 AutoML,而超参数自动优化是 AutoML 中最成熟、最深入、也是最知名的方向。

理论上来说,当算力与数据足够时,HPO 的性能一定是超过人类的。HPO 能够降低人为工作量,并且 HPO 得出的结果比认为搜索的复现可能性更高,所以 HPO 可以极大程度提升科学研究的复现性和公平性。当代超参数优化算法主要可以分为:

(1) 基于网格的各类搜索(Grid)。

(2) 基于贝叶斯优化的各类优化算法(Baysian)。

(3) 基于梯度的各类优化(Gradient-based)。

(4) 基于种群的各类优化(进化算法,遗传算法等)。

其中,各类网格搜索方法与基于贝叶斯的优化方法是最为盛行的,贝叶斯优化方法甚至可以被称为是当代超参数优化中的 SOTA 模型。这些模型对于复杂集成算法的调整有极大的作用与意义。


2. 网格搜索的理论极限与缺点


在所有超参数优化的算法当中,枚举网格搜索是最为基础和经典的方法。在搜索开始之前,我们需要人工将每个超参数的备选值一一列出,多个不同超参数的不同取值之间排列组合,最终将组成一个参数空间(parameter space)。

枚举网格搜索算法会将这个参数空间当中所有的参数组合带入模型进行训练,最终选出泛化能力最强的组合作为模型的最终超参数。

对网格搜索而言,如果参数空间中的某一个点指向了损失函数真正的最小值,那枚举网格搜索时一定能够捕捉到该最小值以及对应的参数(相对的,假如参数空间中没有任意一点指向损失函数真正的最小值,那网格搜索就一定无法找到最小值对应的参数组合)。

参数空间越大、越密,参数空间中的组合刚好覆盖损失函数最小值点的可能性就会越大。这是说,极端情况下,当参数空间穷尽了所有可能的取值时,网格搜索一定能够找到损失函数的最小值所对应的最优参数组合,且该参数组合的泛化能力一定是强于人工调参的。

但是,参数空间越大,网格搜索所需的算力和时间也会越大,当参数维度上升时,网格搜索所需的计算量更是程指数级上升的。以随机森林为例:

只有 1 个参数 n_estimators,备选范围是 [50,100,150,200,250,300],需要建模 6 次。

当我们增加参数 max_depth,且备选范围是 [2,3,4,5,6],需要建模 30 次。

当我们增加参数 min_sample_split,且备选范围为 [2,3,4,5],需要建模 120 次。

同时,参数优化的目标是找出令模型泛化能力最强的组合,因此需要交叉验证来体现模型的泛化能力,假设交叉验证次数为 5,则三个参数就需要建模 600 次。

在面对超参数众多、且超参数取值可能无限的人工神经网络、融合模型、集成模型时,伴随着数据和模型的复杂度提升,网格搜索所需要的时间会急剧增加,完成一次枚举网格搜索可能需要耗费几天几夜。


3. 建立 benchmark:随机森林中枚举网格搜索的结果

from sklearn.ensemble import RandomForestRegressor as RFR
from sklearn.model_selection import cross_validate, KFold, GridSearchCV
data = pd.read_csv(r"D:\Pythonwork\2021ML\PART 2 Ensembles\datasets\House Price\train_encode.csv",index_col=0)
X = data.iloc[:,:-1]
y = data.iloc[:,-1]
X.shape
#(1460, 80)
X.head()
y.describe() #RMSE
#参数空间
param_grid_simple = {"criterion": ["squared_error","poisson"]
                     , 'n_estimators': [*range(20,100,5)]
                     , 'max_depth': [*range(10,25,2)]
                     , "max_features": ["log2","sqrt",16,32,64,"auto"]
                     , "min_impurity_decrease": [*np.arange(0,5,10)]
                    }
#参数空间大小计算
2 * len([*range(20,100,5)]) * len([*range(10,25,2)]) * len(["log2","sqrt",16,32,64,"auto"]) * len([*np.arange(0,5,10)])
#1536
#直接使用循环计算
no_option = 1
for i in param_grid_simple:
    no_option *= len(param_grid_simple[i])
no_option
#1536
#模型,交叉验证,网格搜索
reg = RFR(random_state=1412,verbose=True,n_jobs=-1)
cv = KFold(n_splits=5,shuffle=True,random_state=1412)
search = GridSearchCV(estimator=reg
                     ,param_grid=param_grid_simple
                     ,scoring = "neg_mean_squared_error"
                     ,verbose = True
                     ,cv = cv
                     ,n_jobs=-1)
#=====【TIME WARNING: 7mins】=====#
start = time.time()
search.fit(X,y)
print(time.time() - start)
Fitting 5 folds for each of 1536 candidates, totalling 7680 fits
#381.6039867401123
381.6039/60
#6.3600650000000005
search.best_estimator_
#RandomForestRegressor(max_depth=23, max_features=16, min_impurity_decrease=0,
#                      n_estimators=85, n_jobs=-1, random_state=1412,
#                      verbose=True)
abs(search.best_score_)**0.5
#29179.698261599166
#按最优参数重建模型,查看效果
ad_reg = RFR(n_estimators=85, max_depth=23, max_features=16, random_state=1412)
cv = KFold(n_splits=5,shuffle=True,random_state=1412)
result_post_adjusted = cross_validate(ad_reg,X,y,cv=cv,scoring="neg_mean_squared_error"
                          ,return_train_score=True
                          ,verbose=True
                          ,n_jobs=-1)
def RMSE(cvresult,key):
    return (abs(cvresult[key])**0.5).mean()
RMSE(result_post_adjusted,"train_score")
#11000.81099038192
RMSE(result_post_adjusted,"test_score")
#28572.070208366855
HPO方法 默认参数 网格搜索
搜索空间/全域空间 - 1536/1536
运行时间(分钟) - 6.36
搜索最优(RMSE) 30571.266 29179.698
重建最优(RMSE) - 28572.070
#打包成函数供后续使用
#评估指标RMSE
def RMSE(cvresult,key):
    return (abs(cvresult[key])**0.5).mean()
#计算参数空间大小
def count_space(param):
    no_option = 1
    for i in param_grid_simple:
        no_option *= len(param_grid_simple[i])
    print(no_option)
#在最优参数上进行重新建模验证结果
def rebuild_on_best_param(ad_reg):
    cv = KFold(n_splits=5,shuffle=True,random_state=1412)
    result_post_adjusted = cross_validate(ad_reg,X,y,cv=cv,scoring="neg_mean_squared_error"
                                          ,return_train_score=True
                                          ,verbose=True
                                          ,n_jobs=-1)
    print("训练RMSE:{:.3f}".format(RMSE(result_post_adjusted,"train_score")))
    print("测试RMSE:{:.3f}".format(RMSE(result_post_adjusted,"test_score")))


二、随机网格搜索 RandomizedSearchCV

1. 基本原理


在讲解网格搜索时我们提到,伴随着数据和模型的复杂度提升,网格搜索所需要的时间急剧增加。以随机森林算法为例,如果使用过万的数据,搜索时间则会立刻上升好几个小时。因此,我们急需寻找到一种更加高效的超参数搜索方法。

首先,当所使用的算法确定时,决定枚举网格搜索运算速度的因子一共有两个:

(1) 参数空间的大小:参数空间越大,需要建模的次数越多。

(2) 数据量的大小:数据量越大,每次建模时需要的算力和时间越多。

因此,sklearn 中的网格搜索优化方法主要包括两类,其一是调整搜索空间,其二是调整每次训练的数据。其中,调整参数空间的具体方法,是放弃原本的搜索中必须使用的全域超参数空间,改为挑选出部分参数组合,构造超参数子空间,并只在子空间中进行搜索。

以下图的二维空间为例,在这个 n_estimators 与 max_depth 共同组成的参数空间中,n_estimators 的取值假设为 [50,100,150,200,250,300],max_depth 的取值假设为 [2,3,4,5,6],则枚举网格搜索必须对 30 种参数组合都进行搜索。

当我们调整搜索空间,我们可以只抽样出橙色的参数组合作为子空间,并只对橙色参数组合进行搜索。

fig, [ax1, ax2] = plt.subplots(1,2,dpi=300)
n_e_list = [*range(50,350,50)]
m_d_list = [*range(2,7)]
comb = pd.DataFrame([(n_estimators, max_depth) for n_estimators in n_e_list for max_depth in m_d_list])
ax1.scatter(comb.iloc[:,0],comb.iloc[:,1],cmap="Blues")
ax1.set_xticks([*range(50,350,50)])
ax1.set_yticks([*range(2,7)])
ax1.set_xlabel("n_estimators")
ax1.set_ylabel("max_depth")
ax1.set_title("GridSearch")
ax2.scatter(comb.iloc[:,0],comb.iloc[:,1],cmap="Blues")
ax2.scatter([50,250,200,200,300,100,150,150],[4,2,6,3,2,3,2,5],cmap="red",s=20,linewidths=5)
ax2.set_xticks([*range(50,350,50)])
ax2.set_yticks([*range(2,7)])
ax2.set_xlabel("n_estimators")
ax2.set_ylabel("max_depth")
ax2.set_title("RandomSearch");


0550666ef5b445a3aa8447c463dabbd3.png


在 sklearn 中,随机抽取参数子空间并在子空间中进行搜索的方法叫做随机网格搜索 RandomizedSearchCV。

由于搜索空间的缩小,需要枚举和对比的参数组的数量也对应减少,整体搜索耗时也将随之减少,因此:

当设置相同的全域空间时,随机搜索的运算速度比枚举网格搜索快很多。

当设置相同的训练次数时,随机搜索可以覆盖的空间比枚举网格搜索大很多。

同时,绝妙的是,随机网格搜索得出的最小损失与枚举网格搜索得出的最小损失很接近。

可以说,是提升了运算速度,又没有过多地伤害搜索的精度。

不过,需要注意的是,随机网格搜索在实际运行时,并不是先抽样出子空间,再对子空间进行搜索,而是仿佛循环迭代一般,在这一次迭代中随机抽取 1 组参数进行建模,下一次迭代再随机抽取 1 组参数进行建模,由于这种随机抽样是不放回的,因此不会出现两次抽中同一组参数的问题。

我们可以控制随机网格搜索的迭代次数,来控制整体被抽出的参数子空间的大小,这种做法往往被称为赋予随机网格搜索固定的计算量,当全部计算量被消耗完毕之后,随机网格搜索就停止。


2. 随机网格搜索的实现

from sklearn.model_selection import RandomizedSearchCV


其函数语法模板如下:

class sklearn.model_selection.RandomizedSearchCV(estimator, param_distributions, *, n_iter=10, scoring=None, n_jobs=None, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score=nan, return_train_score=False)

全部参数解读如下,其中加粗的是随机网格搜索独有的参数:21.png

我们依然借用之前在网格搜索上见过的 X 和 y,以及随机森林回归器,来实现随机网格搜索:

X.shape
#(1460, 80)
X.head()
y.describe()

3. 相同的全域参数空间

  • 我们先创造参数空间,也就是和使用与网格搜索时完全一致的空间,以便于进行对比操作。
param_grid_simple = {"criterion": ["squared_error","poisson"]
                     , 'n_estimators': [*range(20,100,5)]
                     , 'max_depth': [*range(10,25,2)]
                     , "max_features": ["log2","sqrt",16,32,64,"auto"]
                     , "min_impurity_decrease": [*np.arange(0,5,10)]
                    }
  • 然后建立回归器。进行交叉验证。
reg = RFR(random_state=1412,verbose=True,n_jobs=-1)
cv = KFold(n_splits=5,shuffle=True,random_state=1412)


  • 计算全域参数空间大小,这是我们能够抽样的最大值。
count_space(param_grid_simple)
#1536


进行定义随机搜索。

search = RandomizedSearchCV(estimator=reg
                            ,param_distributions=param_grid_simple
                            ,n_iter = 800 #子空间的大小是全域空间的一半左右
                            ,scoring = "neg_mean_squared_error"
                            ,verbose = True
                            ,cv = cv
                            ,random_state=1412
                            ,n_jobs=-1
                           )

训练随机搜索评估器。

#=====【TIME WARNING: 5~10min】=====#
start = time.time()
search.fit(X,y)
print(time.time() - start)
#Fitting 5 folds for each of 800 candidates, totalling 4000 fits
#170.16785073280334
170.1678/60
#2.83613

查看模型结果。

search.best_estimator_
#RandomForestRegressor(max_depth=24, max_features=16, min_impurity_decrease=0,
#                      n_estimators=85, n_jobs=-1, random_state=1412,
#                      verbose=True)
abs(search.best_score_)**0.5
#29251.284326350575

根据最优参数重建模型。

ad_reg = RFR(max_depth=24, max_features=16, min_impurity_decrease=0,
                      n_estimators=85, n_jobs=-1, random_state=1412,
                      verbose=True)
rebuild_on_best_param(ad_reg)
#训练RMSE:11031.299
#测试RMSE:28639.969
HPO方法 默认参数 网格搜索 随机搜索
搜索空间/全域空间 - 1536/1536 800/1536
运行时间(分钟) - 6.36 2.83(↓)
搜索最优(RMSE) 30571.266 29179.698 29251.284
重建最优(RMSE) - 28572.070 28639.969(↑)
  • 很明显,在相同参数空间、相同模型的情况下,随机网格搜索的运算速度是普通网格搜索的一半,当然,这与子空间是全域空间的一半有很大的联系。
  • 由于随机搜索只是降低搜索的次数,并非影响搜索过程本身,因此其运行时间基本就等于n_iter/全域空间组合数 * 网格搜索的运行时间。


4. 随机网格搜索的理论极限


在机器学习算法当中,有非常多通过随机来提升运算速度(比如 Kmeans,随机挑选样本构建簇心,小批量随机梯度下降,通过随机来减少每次迭代需要的样本)、或通过随机来提升模型效果的操作(比如随机森林,比如极度随机树)。

两种随机背后的原理完全不同,而随机网格搜索属于前者,这一类机器学习方法总是伴随着“从某个全数据集/全域中进行抽样”的操作,而这种操作能够有效的根本原因在于:

(1)抽样出的子空间可以一定程度上反馈出全域空间的分布,且子空间相对越大(含有的参数组合数越多),子空间的分布越接近全域空间的分布。

(2) 当全域空间本身足够密集时,很小的子空间也能获得与全域空间相似的分布。

(3) 如果全域空间包括了理论上的损失函数最小值,那一个与全域空间分布高度相似的子空间很可能也包括损失函数的最小值,或包括非常接近最小值的一系列次小值。

我们可以通过绘制图像来直观地呈现这些事实。许多在数学上比较抽象的概念都可以被可视化。在这里,我们借助 matplotlib 工具库 mplot3d 中的一组默认数据。


from mpl_toolkits.mplot3d import axes3d
p1, p2, MSE = axes3d.get_test_data(0.05)
  • 其中,get_test_data 巨头自动获取数据的功能,可以自动生成复合某一分布的数据。我们现在假设这一组数据中有两个参数,p1 与 p2,两个参数组成的参数组合对应着损失函数值 MSE。
  • 参数 0.05 是指参数空间中,点与点之间的距离。因此该数字越小,取出来的样本越多。
len(p1) #参数1的取值有120个
#120
len(p2) #参数2的取值也有120个
#120
  • 那么,现在参数空间当中一共有 120*120=14400 种组合,所以参数空间中一共有 14400 个点。
MSE.shape #损失函数值,总共14400个点
#(120, 120)

随后,我们绘制 P1 与 P2 的参数空间,这是一个呈现出 14400 个点的密集空间。

plt.figure(dpi=300)
plt.scatter(p1,p2,s=0.2)
plt.xticks(fontsize=9)
plt.yticks(fontsize=9)

eae31d29e03346ae8d1eeda91626e9e4.png


参数与损失共同构建的函数。

p1, p2, MSE = axes3d.get_test_data(0.05)
plt.figure(dpi=300)
ax = plt.axes(projection="3d")
ax.plot_wireframe(p1,p2,MSE,rstride=2,cstride=2,linewidth=0.5)
ax.view_init(2, -15)
ax.zaxis.set_tick_params(labelsize=7)
ax.xaxis.set_tick_params(labelsize=7)
ax.yaxis.set_tick_params(labelsize=7)

8bb8ddd489c84981a038c8f321e7ff79.png


np.min(MSE) #整个参数空间中,可获得的MSE最小值是-73.39
#-73.39620971601681

现在,我们从该空间上抽取子空间。

MSE.shape
#(120, 120)

我们从空间中抽取 n 个组合,n 越大子空间越大。现在总共有 14400 个组合,对被抽中的点来说,损失函数的值就是 MSE,对没有抽中的点来说,损失函数值是空值。

因此,我们只需要找出没有抽中的点,并让它的损失函数值 MSE 为空就可以了。从 0~14400 中生成(14400-n)个随机数,形成没有被抽到子空间中的点的索引。

n = 100
unsampled = np.random.randint(0,14400,14400-n)​
p1, p2, MSE = axes3d.get_test_data(0.05)
  • 拉平 MSE,并将所有没抽中的点的损失函数变为空值。
MSE = MSE.ravel()
MSE[unsampled] = np.nan
MSE = MSE.reshape((120,120))


设置完毕空值后,记得把 MSE 恢复成原来的结构,否则绘图报错。

#参数与损失共同构建的函数
plt.figure(dpi=300)
ax = plt.axes(projection="3d")
ax.view_init(2, -15)
ax.plot_wireframe(p1,p2,MSE,rstride=2,cstride=2,linewidth=0.5)
ax.zaxis.set_tick_params(labelsize=7)
ax.xaxis.set_tick_params(labelsize=7)
ax.yaxis.set_tick_params(labelsize=7)

求出当前损失函数上的最小值,注意此时因为 MSE 中含有了空值,因此要先排除空值影响,否则 min 函数会返回空值。

MSE = MSE.ravel().tolist()
MSE = [x for x in MSE if str(x) != 'nan']
print(np.min(MSE))
#-73.24243733589367



9c17dd4254174586b0691b4bf9dd4cb1.png


我们可以在图像上验证如下事实:

(1) 抽样出的子空间可以一定程度上反馈出全域空间的分布,且子空间相对越大(含有的参数组合数越多),子空间的分布越接近全域空间的分布。

(2) 当全域空间本身足够密集时,很小的子空间也能获得与全域空间相似的分布。

(3) 如果全域空间包括了理论上的损失函数最小值,那一个与全域空间分布高度相似的子空间很可能也包括损失函数的最小值,或包括非常接近最小值的一系列次小值。

因此,只要子空间足够大,随机网格搜索的效果一定是高度逼近枚举网格搜索的。在全域参数空间固定时,随机网格搜索可以在效率与精度之间做权衡。子空间越大,精度越高,子空间越小,效率越高。


5. 更大/更密集的全域空间


  • 不过,由于随机网格搜索计算更快,所以在相同计算资源的前提下,我们可以对随机网格搜索使用更大的全域空间,因此随机搜索可能得到比网格搜索更好的效果。
  • 我们可以创造参数空间 ,从而让整体参数空间变得更密。
param_grid_simple = {'n_estimators': [*range(80,100,1)]
                     , 'max_depth': [*range(10,25,1)]
                     , "max_features": [*range(10,20,1)]
                     , "min_impurity_decrease": [*np.arange(0,5,10)]
                    }
  • 计算全域参数空间大小,这是我们能够抽样的最大值。
count_space(param_grid_simple)
#3000


  • 建立回归器,进行交叉验证。
reg = RFR(random_state=1412,verbose=True,n_jobs=-1)
cv = KFold(n_splits=5,shuffle=True,random_state=1412)


定义随机搜索。

search = RandomizedSearchCV(estimator=reg
                            ,param_distributions=param_grid_simple
                            ,n_iter = 1536 #使用与枚举网格搜索类似的拟合次数
                            ,scoring = "neg_mean_squared_error"
                            ,verbose = True
                            ,cv = cv
                            ,random_state=1412
                            ,n_jobs=-1)

训练随机搜索评估器。

start = time.time()
search.fit(X,y)
end = time.time() - start
print(end/60)
#Fitting 5 folds for each of 1536 candidates, totalling 7680 fits
#3.8464645385742187

查看最佳评估器。

search.best_estimator_
RandomForestRegressor(max_depth=22, max_features=14, min_impurity_decrease=0,
                      n_estimators=89, n_jobs=-1, random_state=1412,
                      verbose=True)

查看最终评估指标。

abs(search.best_score_)**0.5
#29012.90569846546
rebuild_on_best_param(search.best_estimator_)
#训练RMSE:11208.818
#测试RMSE:28346.673

23.png

可以发现,当全域参数空间增大之后,随即网格搜索可以使用与小空间上的网格搜索相似或更少的时间,来探索更密集/更大的空间,从而获得更好的结果。除了可以容忍更大的参数空间之外,随机网格搜索还可以接受连续性变量作为参数空间的输入。


6. 连续型的参数空间

  • 对于网格搜索来说,参数空间中的点是分布均匀、间隔一致的,因为网格搜索无法从某种“分布”中提取数据,只能使用组合好的参数组合点,而随机搜索却可以接受分”作为输入。

如上图所示,对于网格搜索来说,损失函数的最低点很不幸的、位于两组参数之间,在这种情况下,枚举网格搜索是 100% 不可能找到最小值的。但对于随机网格搜索来说,由于是一段分布上随机选择参数点,因此在同样的参数空间中,取到更好的值的可能性更大。

import scipy #使用scipy来帮助我们建立分布
scipy.stats.uniform(loc=1,scale=100)
#<scipy.stats._distn_infrastructure.rv_frozen at 0x137a147d7c0>

uniform 是均匀分布,默认生成 [0,1] 之间的数字,可以使用 loc 来调整起点,scale 来调整终点。我们还可以选择其他的分布,比如指数分布 expon, gamma 分布, 或者是 randint。注意 scipy 这里并不是像 np.linspace() 一样生成一段离散的数字,而是直接生成一个分布对象。

并且,我们并没有在分布对象中指定尺寸,也就是说,在这段分布上究竟要取几个随机的参数备选值,是由随机搜索自己决定的。理论上来说,我们给出的 n_iter 越大,任意参数的分布上可能被取到的点就越多。因此,当参数空间中包含某个分布的时候,我们无法估计全域参数空间的大小。

在之前调整随机森林的时候,我们给出的所有参数都是只能接纳正整数的参数,因此在这里我们可以使用 scipy.stats.randint,不过 randint 并不是严格意义上的连续分布。

严格来说,连续型搜索更适用于学习率,C,alpha 这样的参数(无上限,以浮点数为主),随机森林的参数中最接近这个定义的是 min_impurity_decrease,表示决策树在分枝是可以容忍的最小的不纯度下降量。我们借着这个参数,使用均匀分布来进行搜索试试看。

param_grid_simple = {'n_estimators': [*range(80,100,1)]
                     , 'max_depth': [*range(10,25,1)]
                     , "max_features": [*range(10,20,1)]
                     , "min_impurity_decrease": scipy.stats.uniform(0,50)
                    }
#建立回归器、交叉验证
reg = RFR(random_state=1412,verbose=True,n_jobs=12)
cv = KFold(n_splits=5,shuffle=True,random_state=1412)
#定义随机搜索
search = RandomizedSearchCV(estimator=reg
                            ,param_distributions=param_grid_simple
                            ,n_iter = 1536 #还是使用1536这个搜索次数
                            ,scoring = "neg_mean_squared_error"
                            ,verbose = True
                            ,cv = cv
                            ,random_state=1412
                            ,n_jobs=12)
#训练随机搜索评估器
start = time.time()
search.fit(X,y)
end = time.time() - start
print(end/60)
#Fitting 5 folds for each of 1536 candidates, totalling 7680 fits
#3.921058924992879
#查看最佳评估器
search.best_estimator_
#RandomForestRegressor(max_depth=22, max_features=14,
#                      min_impurity_decrease=20.070367229896224, n_estimators=98,
#                      n_jobs=12, random_state=1412, verbose=True)
#查看最终评估指标
abs(search.best_score_)**0.5
#29148.381610182565
rebuild_on_best_param(search.best_estimator_)
#训练RMSE:11184.428
#测试RMSE:28495.682

22.png


在本次搜索当中,由于我们之前已经知道最好的可能的 min_impurity_decrease 的值为 0,因此强行向更大的数拓展搜索空间可能会导致模型效果下降。不过在随机森林当中,min_impurity_decrease 是唯一可以使用分布进行搜索的参数,因此在这里我们就容忍了这部分表现上升。


理论上来说,当枚举网格搜索所使用的全域参数空间足够大/足够密集时,枚举网格搜索的最优解是随机网格搜索的上限,因此理论上随机网格搜索不会得到比枚举网格搜索更好的结果。


但现实中的问题是,由于枚举网格搜索的速度太慢,因此枚举网格搜索的全域参数空间往往无法设置得很大,也无法设置得很密集,因此网格搜索的结果很难接近理论上的最优值。当随机网格搜索将空间设置更大、更密集时,就可以捕获更广空间的分布,也自然就可能捕获到理论上的最优值了。


相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
4月前
|
机器学习/深度学习 算法 数据可视化
利用网格搜索对超参数进行调节
【8月更文挑战第8天】利用网格搜索对超参数进行调节。
49 1
|
2月前
|
机器学习/深度学习 计算机视觉 Python
模型预测笔记(三):通过交叉验证网格搜索机器学习的最优参数
本文介绍了网格搜索(Grid Search)在机器学习中用于优化模型超参数的方法,包括定义超参数范围、创建参数网格、选择评估指标、构建模型和交叉验证策略、执行网格搜索、选择最佳超参数组合,并使用这些参数重新训练模型。文中还讨论了GridSearchCV的参数和不同机器学习问题适用的评分指标。最后提供了使用决策树分类器进行网格搜索的Python代码示例。
128 1
|
3月前
|
机器学习/深度学习 算法
R语言超参数调优:深入探索网格搜索与随机搜索
【9月更文挑战第2天】网格搜索和随机搜索是R语言中常用的超参数调优方法。网格搜索通过系统地遍历超参数空间来寻找最优解,适用于超参数空间较小的情况;而随机搜索则通过随机采样超参数空间来寻找接近最优的解,适用于超参数空间较大或计算资源有限的情况。在实际应用中,可以根据具体情况选择适合的方法,并结合交叉验证等技术来进一步提高模型性能。
|
4月前
|
SQL 自然语言处理 算法
预训练模型STAR问题之计算伪OOD样本的软标签的问题如何解决
预训练模型STAR问题之计算伪OOD样本的软标签的问题如何解决
|
5月前
|
机器学习/深度学习 人工智能 分布式计算
算法金 | 最难的来了:超参数网格搜索、贝叶斯优化、遗传算法、模型特异化、Hyperopt、Optuna、多目标优化、异步并行优化
机器学习中的超参数调优是提升模型性能的关键步骤,包括网格搜索、随机搜索、贝叶斯优化和遗传算法等方法。网格搜索通过穷举所有可能的超参数组合找到最优,但计算成本高;随机搜索则在预设范围内随机采样,降低计算成本;贝叶斯优化使用代理模型智能选择超参数,效率高且适应性强;遗传算法模拟生物进化,全局搜索能力强。此外,还有多目标优化、异步并行优化等高级技术,以及Hyperopt、Optuna等优化库来提升调优效率。实践中,应结合模型类型、数据规模和计算资源选择合适的调优策略。
213 0
算法金 | 最难的来了:超参数网格搜索、贝叶斯优化、遗传算法、模型特异化、Hyperopt、Optuna、多目标优化、异步并行优化
|
6月前
|
机器学习/深度学习 算法
机器学习中的超参数优化涉及手动尝试、网格搜索、随机搜索、贝叶斯优化、梯度优化、进化算法等策略
【6月更文挑战第28天】**机器学习中的超参数优化涉及手动尝试、网格搜索、随机搜索、贝叶斯优化、梯度优化、进化算法等策略。工具如scikit-optimize、Optuna助力优化,迁移学习和元学习提供起点,集成方法则通过多模型融合提升性能。资源与时间考虑至关重要,交叉验证和提前停止能有效防止过拟合。**
82 0
|
6月前
|
机器学习/深度学习 存储 算法
技术笔记:LSH近似最近邻查找
技术笔记:LSH近似最近邻查找
53 0
|
7月前
|
算法
R语言随机搜索变量选择SSVS估计贝叶斯向量自回归(BVAR)模型
R语言随机搜索变量选择SSVS估计贝叶斯向量自回归(BVAR)模型
|
人工智能 计算机视觉
CVPR 2019|APCNet:基于全局引导的局部匹配度自适应金字塔上下文网络
不同物体可能有相似的特征,如木桌和椅子有相似的纹理,会造成歧义
178 0
CVPR 2019|APCNet:基于全局引导的局部匹配度自适应金字塔上下文网络
|
机器学习/深度学习 算法
Lesson 9.3 集成算法的参数空间与网格优化和使用网格搜索在随机森林上进行调参
如随机森林中所展示的,集成算法的超参数种类繁多、取值丰富,且参数之间会相互影响、共同作用于算法的最终结果,因此集成算法的调参是一个难度很高的过程。