引言
神经网络是机器学习的一个迷人的领域,但是它们有时很难优化和解释。事实上,它们有几个超参数。要优化的最常见的超参数是隐藏层中的神经元数量。让我们看看如何为我们的数据集找到一个神经网络的最佳神经元数量。
什么是神经网络?
神经网络是一种特定模型,它可以根据一层神经元来捕捉特征与目标之间的相关性,从而转换数据集。一个神经网络是由几层神经元组成的。每个神经元获取一些输入,转换它们并返回输出。一个神经元的输出可以成为下一层神经元的输入等等,构建越来越复杂的架构。
第一层称为输入层,由返回特征值本身的神经元构成。然后,第一层的每个神经元连接到隐藏层的所有神经元,负责网络的学习能力。隐藏层后面可以跟几个其他隐藏层,这是深度学习网络的典型特征。最后,将最后一个隐藏层的输出提供给给出结果(即目标变量的值)的输出层。
在最简单的形式中,神经网络只有一个隐藏层,如下图所示。
输入层的神经元数目等于特征数目。根据目标变量定义输出层的神经元数。接下来的问题是如何为隐藏层找到正确的神经元数量。
数量太少可能会产生欠拟合,因为网络可能无法正确学习。但是数量太多有可能产生过拟合,因为从网络中学习了太多从而无法泛化。因此必须有合适数量的神经元来确保良好的训练。
如何优化神经元的数量
该过程非常简单,它使用交叉验证:
设置一定数量的神经元
在 k 折交叉验证中计算某些性能指标的平均值
用不同数量的神经元重复这个过程
选择神经元的数量,最大化 k 交叉验证的平均值
交叉验证很重要,因为使用它我们可以确保模型不会过拟合或欠拟合。
这个过程非常类似于超参数调优,因为隐藏层中的神经元数量实际上是一个要调优的超参数。
现在让我们看看如何在 Python 中实现这个过程。
在 Python 中的示例
在这个例子中,我将展示如何使用 scikit-learn 库优化 Python 中的神经元数量。事实上,你也可能会使用 Keras 来构建神经网络,但概念是完全相同的。
我将使用 scikit-learn 中包含的乳腺癌示例数据集。
首先,让我们导入一些有用的库。
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.neural_network import MLPClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.metrics import roc_auc_score
然后,我们可以加载我们的数据集,并将其分成训练集和测试集。
X,y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
现在,我们必须定义我们的模型。在本例中,我将使用一个简单的带有单个隐藏层的多层感知器。为了简单起见,构造函数的所有参数都保留在它们的标准值中。我只是设置随机状态,以确保结果的可重复性。
在将数据集提供给神经网络之前,不要忘记缩放特征。为简单起见,我将在 scikit-learn 中使用 Pipeline 对象,然后应用标准化。
model = Pipeline([
('scaler',StandardScaler()),
('model',MLPClassifier(random_state=0))
])
现在,我们必须通过搜索最佳神经元数量来优化我们的网络。请记住,我们尝试了几种可能的数字并计算交叉验证中性能指标的平均值。最大化这样一个值的神经元数量就是我们正在寻找的数量。
为此,我们可以使用 GridSearchCV 对象。由于我们正在处理二元分类问题,因此我们要最大化的指标是 AUROC。我们将以 2 的步长跨越 5 到 100 个神经元。
search = GridSearchCV(model,
{'model__hidden_layer_sizes':[(x,) for x in np.arange(5,100,2)]},
cv = 5, scoring = "roc_auc", verbose=3, n_jobs = -1
)
最后,我们可以寻找最佳的神经元数量。
search.fit(X_train, y_train)
搜索结束后,我们会得到最好的平均分,即:
search.best_score_
# 0.9947175348495965
神经元的最佳数量是:
search.best_params_
# {'model__hidden_layer_sizes': (75,)}
最后,我们可以在测试数据集上计算这样一个模型的 AUROC,以确保我们没有对数据集进行过多的处理。
roc_auc_score(y_test,search.predict_proba(X_test)[:,1])
# 0.9982730973233008
我们得到的值仍然很高,所以我们很确定优化后的模型已经泛化了训练数据集,从它携带的信息中学习。