在Python中的网格搜索
在本教程中,我们将讨论网格搜索作为超参数调优的方法。我们还将学习网格搜索的工作原理,并实施它以优化机器学习(ML)方法的性能。
超参数调优 对于机器学习(ML)模型的正确工作非常重要。像 网格搜索 这样的方法似乎是超参数优化的基本工具。
网格搜索 方法考虑一些超参数组合,并选择返回较低误差分数的组合。当只有一些需要优化的超参数时,这种方法特别有用。然而,当机器学习模型变得复杂时,它的性能被其他加权随机搜索方法超越。
所以让我们开始了解网格搜索。
理解网格搜索
网格搜索 是一种优化算法,允许我们从我们提供的参数选择列表中选择最佳参数以优化问题,从而自动化“试错”方法。尽管我们可以将其应用于多个优化问题;但是,它最常被用于机器学习中以获取使模型提供最佳准确性的参数。
让我们考虑模型在输入中接受以下三个参数:
- 隐藏层的数量[2, 4]
- 每个层的神经元数量[5, 10]
- 迭代次数[10, 50]
如果我们想要尝试每个参数输入的两个选项(如上方方括号中所指定的),它将估计不同的组合。例如,一个可能的组合可能是[2, 5, 10]。手动找到这样的组合会非常麻烦。
现在,假设我们有十个不同的输入参数,并且我们想要尝试每个参数的五个可能值。每次我们想要改变参数的值,重新执行代码,并为参数的每种组合记录输出,都需要程序员手动输入。。
网格搜索自动化了这个过程,它接受每个参数的可能值并执行代码,以尝试每个可能的组合输出,并输出具有最佳准确性的组合。
安装所需的库
在 Python编程语言 中实施网格搜索之前,让我们简要讨论一些需要在系统中安装的必要库和框架。
这些库和框架如下:
安装它们都非常简单。我们可以使用pip安装程序来安装这些库,如下所示:
$ pip install numpy tensorflow pandas scikit-learn keras
注意:如果在执行任何程序包时出现任何问题,请尝试重新安装并参考每个程序包的官方文档。
现在,让我们开始在Python中实现网格搜索。
Python中网格搜索的实现
在接下来的部分,我们将了解如何在实际应用中实现网格搜索。我们将仅执行代码,并深入讨论网格搜索所涉及的部分,而不讨论机器学习和数据预处理部分。
所以,让我们开始吧。
我们将使用包含有关不同人员的身高和体重的Diet数据集,根据性别、年龄和饮食类型等各种属性。我们可以借助Pandas的read_csv()
函数直接从在线资源导入数据。
但在此之前,我们必须导入所需的程序包:
文件:mygrid.py
import sys
import pandas as pd
import numpy as np
from sklearn.model_selection import GridSearchCV, KFold
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.optimizers import Adam
解释:
在上面的代码片段中,我们导入了项目所需的包和库。可以保存程序文件并执行,以检查库和包是否已正确安装和导入。
成功导入包后,我们必须使用以下代码片段导入数据集并打印其前五行。
文件:mygrid.py
# importing the dataset
mydf = pd.read_csv("Diet_Dataset.csv")
# printing the first five lines of dataset
print(mydf.head())
输出:
Person gender Age Height pre.weight Diet weight6weeks
0 25 41 171 60 2 60.0
1 26 32 174 103 2 103.0
2 1 0 22 159 58 1 54.2
3 2 0 46 192 60 1 54.0
4 3 0 55 170 64 1 63.3
说明:
在上面的代码片段中,我们使用 pandas 库的 read_csv() 方法导入了数据集,并将其存储在变量 mydf 中。然后我们使用 head() 函数和 mydf 变量打印了前五行数据。
现在,我们将数据分成特征集和标签集,以便对数据集应用标准缩放。
下面是相同操作的代码片段:
文件:mygrid.py
# converting dataframe into numpy array
mydataset = mydf.values
X = mydataset[:, 0:6]
Y = mydataset[:, 6].astype(int)
# Normalizing the data using sklearn StandardScaler
from sklearn.preprocessing import StandardScaler
myscaler = StandardScaler().fit(X)
# Transforming and displaying the training data
X_stdized = myscaler.transform(X)
mydata = pd.DataFrame(X_stdized)
解释:
在上面的代码片段中,我们将pandas dataframe转换为NumPy数组。然后我们从sklearn库中导入StandardScaler模块,并使用该函数对数据进行归一化处理。然后我们使用transform()函数对训练数据进行转换和显示。
现在,让我们考虑以下代码片段以创建一个简单的深度学习模型。
文件:mygrid.py
# defining the function to create model
def create_my_model(learnRate, dropoutRate):
# Creating model
mymodel = Sequential()
mymodel.add(Dense(6, input_dim = 6, kernel_initializer = 'normal', activation = 'relu'))
mymodel.add(Dropout(dropoutRate))
mymodel.add(Dense(3, input_dim = 6, kernel_initializer = 'normal', activation = 'relu'))
mymodel.add(Dropout(dropoutRate))
mymodel.add(Dense(1, activation = 'sigmoid'))
# Compiling the model
my_Adam = Adam(learning_rate = learnRate)
mymodel.compile(loss = 'binary_crossentropy', optimizer = my_Adam, metrics = ['accuracy'])
return mymodel
解释:
下面的代码片段定义了一个函数, create_my_model() 接受两个参数, learnRate 和 dropoutRate ,我们使用 Sequential() 函数创建了模型 mymodel 。我们还使用了 add() 函数和 Dense() 函数、 Dropout() 函数。最后,我们使用 compile() 函数编译了模型。
因此,当我们执行这段代码时,将加载数据集,对其进行预处理,并创建一个机器学习模型。由于我们只关心网格搜索的工作原理,我们没有进行训练/测试分割,并且我们将模型拟合到了整个数据集上。
在下一节中,我们将了解网格搜索如何通过优化参数来简化程序员的工作。
不使用网格搜索训练模型
在下面显示的代码片段中,我们将根据随机选择的参数值或基于直觉创建一个模型,并查看模型的性能:
文件:mygrid.py
# Declaring the values of the parameter
dropoutRate = 0.1
epochs = 1
batchSize = 20
learnRate = 0.001
# Creating the model object by calling the create_my_model function we created above
mymodel = create_my_model(learnRate, dropoutRate)
# Fitting the model onto the training data
mymodel.fit(X_stdized, Y, batch_size = batchSize, epochs = epochs, verbose = 1)
输出:
4/4 [==============================] - 41s 14ms/step - loss: 0.9364 - accuracy: 0.0000e+00
解释:
在上面的代码片段中,我们声明了参数的值,即 dropoutRate,epochs,batchSize 和 learnRate 。然后,我们调用 create_my_model() 函数创建模型对象。然后,我们将模型拟合到训练数据上。
结果是,我们得到的准确率是0.0000e+00。
使用网格搜索优化超参数
如果我们不使用网格搜索方法,我们可以直接在上面创建的模型上调用 fit() 函数。但是为了使用网格搜索方法,我们必须传入一些参数给 create_my_model() 函数。此外,我们还必须为每个参数声明具有不同选项的网格以尝试。让我们在不同的部分中执行。
首先,我们将尝试修改 create_my_model() 函数以便接受来自调用函数的参数,如下所示:
文件:mygrid.py
def create_my_model(learnRate, dropoutRate):
# Creating the model
mymodel = Sequential()
mymodel.add(Dense(6, input_dim = 6, kernel_initializer = 'normal', activation = 'relu'))
mymodel.add(Dropout(dropoutRate))
mymodel.add(Dense(3, input_dim = 6, kernel_initializer = 'normal', activation = 'relu'))
mymodel.add(Dropout(dropoutRate))
mymodel.add(Dense(1, activation = 'sigmoid'))
# Compile the model
myadam = Adam(learning_rate = learnRate)
mymodel.compile(loss = 'binary_crossentropy', optimizer = myadam, metrics = ['accuracy'])
return mymodel
# Creating the model object
mymodel = KerasClassifier(build_fn = create_my_model, verbose = 1)
Explanation:
在上面的代码片段中,我们对之前的 create_my_model 函数进行了一些更改,并使用了 KerasClassifier 来创建模型对象。
现在,让我们实现网格搜索算法,并将数据集拟合到其中:
文件:mygrid.py
# Defining the arguments that we want to use in Grid Search along
# with the list of values that we want to try out
learnRate = [0.001, 0.02, 0.2]
dropoutRate = [0.0, 0.2, 0.4]
batchSize = [10, 20, 30]
epochs = [1, 5, 10]
# Making a dictionary of the grid search parameters
paramgrid = dict(learnRate = learnRate, dropoutRate = dropoutRate, batch_size = batchSize, epochs = epochs )
# Building and fitting the GridSearchCV
mygrid = GridSearchCV(estimator = mymodel, param_grid = paramgrid, cv = KFold(random_state = None), verbose = 10)
gridresults = mygrid.fit(X_stdized, Y)
# Summarizing the results in a readable format
print("Best: " + gridresults.best_score_ + " using " + gridresults.best_params_)
means = gridresults.cv_results_['mean_test_score']
stds = gridresults.cv_results_['std_test_score']
params = gridresults.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
print(mean + "(" + stdev + ")" + " with: " + param)
输出:
Best: 0.00347268912077, using {batch_size=10, dropoutRate=0.4, epochs=5, learnRate=0.2}
说明:
以上输出显示了产生最佳准确率的参数组合。
最后,我们可以得出结论,网格搜索在Python编程语言中非常容易实现,为我们节省了大量的人力成本。我们可以列出所有需要调整的参数,声明需要测试的值,执行代码,然后忘记它。这个过程非常简单方便,需要程序员输入较少。一旦找到了最佳的参数组合,我们可以将其用于最终模型。