Python教程-在Python中进行网格搜索
在本教程中,我们将讨论网格搜索,以进行超参数调优。我们还将了解网格搜索的工作原理,并在优化机器学习方法的性能方面实施它。
超参数调优对于机器学习模型的适当工作非常重要。像网格搜索这样的方法似乎是超参数优化的基本工具。
网格搜索方法考虑了一些超参数组合,并选择返回较低错误分数的组合。当要优化的超参数很少时,这种方法特别有用。然而,当机器学习模型变得更加复杂时,其他加权随机搜索方法会表现得更好。
因此,让我们从理解网格搜索开始。
理解网格搜索
网格搜索是一种优化算法,允许我们从我们提供的参数选择列表中选择最佳参数以优化问题,从而自动化了“试错”的方法。虽然我们可以将它应用于多个优化问题,但它最常用于机器学习,以获取模型提供最佳准确性的参数。
假设模型接受以下三个参数作为输入:
- 隐藏层的数量 [2, 4]
- 每个层中的神经元数量 [5, 10]
- 迭代次数 [10, 50]
如果我们想要尝试每个参数输入的两个选项(如上方括号中指定的),它将估计不同的组合。例如,一种可能的组合可以是 [2, 5, 10]。手动查找这些组合将会很麻烦。
现在,假设我们有十个不同的参数作为输入,并且我们想要尝试每个参数的五个可能值。每次我们想要更改参数的值时,都需要从程序员端手动输入、重新执行代码并记录每个参数组合的输出。
网格搜索自动化了这个过程,因为它接受每个参数的可能值并执行代码,尝试每个可能的组合并输出具有最佳准确性的组合。
安装所需的库
在我们开始实施Python中的网格搜索之前,让我们简要讨论需要在系统中安装的一些必要库和框架。
这些库和框架如下:
- Python 3
- NumPy
- Pandas
- Keras
- Scikit-Learn
它们都很容易安装。我们可以使用pip安装程序来安装这些库,如下所示:
$ pip install numpy tensorflow pandas scikit-learn keras
注意:如果在执行任何包时出现任何问题,请尝试重新安装并参考每个包的官方文档。
现在,让我们开始在Python中实施网格搜索。
在Python中实施网格搜索
在以下部分中,我们将了解如何在实际应用程序上实施网格搜索。我们将仅执行代码并深入讨论网格搜索的部分,而不讨论机器学习和数据预处理部分。
所以,让我们开始吧。
我们将使用包含有关不同人的身高和体重数据的饮食数据集,这些数据基于各种属性,如性别、年龄和饮食类型。我们可以使用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数据框转换为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()函数创建了模型,还使用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)
解释:
在上面的代码片段中,我们对先前的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编程语言中非常容易实现,为我们节省了大量人力。我们可以列出要调整的所有参数,声明要测试的值,执行代码,然后忘记它。这个过程如此简单和方便,需要程序员的输入较少。一旦找到了最佳参数组合,我们可以将其用于最终模型。