1.17 神经网络模型(有监督)

警告:此实现不适用于大规模数据应用。 特别是 scikit-learn 不支持 GPU。如果想要提高运行速度并使用基于 GPU 的实现以及为构建深度学习架构提供更多灵活性的框架,请看 Related Projects

1.17.1 多层感知机

多层感知机(MLP)是一种有监督学习算法,通过在数据集上训练来学习函数。其中是输入的维数, 是输出的维数。给定一组特征和标签, 它可以对分类或者回归学习一个非线性函数。与逻辑回归不同,在输入层和输出层之间, 会存在一个层或者多层的非线性层, 称为隐藏层。图1展示了一个带有标量输出的单层隐藏层的MLP。

图1:单隐藏层MLP.

最左边的层叫做输入层, 由一组代表输入特征的神经元组成。每个隐藏层中的神经元将前一层的值进行加权线性求和转换, 接着通过非线性函数, 就像双曲正切函数。输出层接受的值是最后一个隐藏层经过变换输出的值。

该模块下, 包含了公共的属性 coefs_intercepts_coefs_是一个权重矩阵的列表, 其中索引为的权重矩阵表示的第层和第层之间的之间的权重。intercepts_是偏置向量的列表, 其中索引为的向量表示的是添加到底层的偏置值。

多层感知机的优点是:

  • 学习非线性模型的能力。
  • 有使用 partial_fit在实时(在线学习)学习模型的能力。

多层感知机(MLP)的缺点包括:

  • 具有隐藏层的 MLP 具有非凸的损失函数,它有不止一个的局部最小值。 因此不同的随机初始化权重会导致不同的验证集准确率。
  • MLP 需要调试一些超参数,例如隐藏层神经元的数量、层数和迭代轮数。
  • MLP对特征缩放是敏感的。

克服这些缺点的方法请参阅 实用使用技巧 部分。

1.17.2 分类

MLPClassifier类通过使用 Backpropagation进行训练实现了多层感知机(MLP)算法。

MLP 在两个数组上进行训练:大小为 (n_samples, n_features) 的数组 X,用来储存表示训练样本的浮点型特征向量; 大小为 (n_samples,) 的数组 y,用来储存训练样本的目标值(类别标签):

>>> from sklearn.neural_network import MLPClassifier
>>> X = [[0.0.], [1.1.]]
>>> y = [01]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
...                     hidden_layer_sizes=(52), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(alpha=1e-05, hidden_layer_sizes=(52), random_state=1,
              solver='lbfgs')

经过拟合(训练),该模型可以预测新样品的标签:

>>> clf.predict([[2.2.], [-1.-2.]])
array([10])

MLP可以拟合训练数据的非线性模型。clf.coefs_包含构成模型参数的权重矩阵:

>>> [coef.shape for coef in clf.coefs_]
[(25), (52), (21)]

目前, MLPClassifier 只支持交叉熵损失函数( Cross-Entropy loss function),它通过运行 predict_proba 方法进行概率估计。

MLP 算法使用的是反向传播的方式。 更准确地说,它使用了某种形式的梯度下降来进行训练,其中的梯度是通过反向传播计算得到的。 对于分类问题而言,它最小化了交叉熵损失函数,为每个样本 给出一个向量形式的概率估计

>>> clf.predict_proba([[2.2.], [1.2.]])
array([[1.967...e-049.998...-01],
       [1.967...e-049.998...-01]])

MLPClassifier通过应用 Softmax作为输出函数来支持多分类。

此外,该模型支持 multi-label classification,其中一个样本可以属于多个类别。 对于每个种类,原始输出经过 logistic 函数变换后,大于或等于 0.5 的值将为 1,否则为 0。 对于样本的预测输出,值为 1 的索引表示该样本的分类类别:

>>> X = [[0.0.], [1.1.]]
>>> y = [[01], [11]]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
...                     hidden_layer_sizes=(15,), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(alpha=1e-05, hidden_layer_sizes=(15,), random_state=1,
              solver='lbfgs')
>>> clf.predict([[1.2.]])
array([[11]])
>>> clf.predict([[0.0.]])
array([[01]])

更多内容请参阅下面的示例和文档 MLPClassifier.fit

示例
比较MLPClassifier的随机学习策略
MLP权重在MNIST上的可视化

1.17.3 回归

MLPRegressor实现了一个多层感知器(MLP),它使用反向传播来训练, 输出层中没有激活函数,这也可以看作是使用identity function作为激活函数。因此,它使用平方误差作为损失函数,输出是一组连续值。

MLPRegressor 还支持多输出回归,其中一个样本可以有多个目标。

1.17.4 正则化

MLPRegressorMLPClassifier 都使用参数alpha进行正则化(L2正则化),这有助于通过惩罚大规模的权重来避免过度拟合。下面的图显示不同alpha值的决策函数。

有关更多信息,请参见下面的示例。

示例
多层感知器中的正则化

1.17.5 算法

MLP使用随机梯度下降(Stochastic Gradient Descent), Adam或者 L-BFGS来进行训练。随机梯度下降(SGD)根据需要调整的参数使用损失函数的梯度更新参数,即

其中是控制参数空间搜索步长的学习速率。是神经网络的损失函数。

更详细的信息可以在SGD的文档中找到。

ADAM在某种意义上类似于SGD,它是一个随机优化器,但它可以根据对低阶矩的自适应估计自动调整更新参数的数量。

使用 SGD 或 Adam ,训练过程可以支持在线学习模式和小批量学习模式。

L-BFGS是一个近似Hessian矩阵的求解器,它表示函数的二阶偏导数。此外,它逼近Hessian矩阵的逆以执行参数更新。该实现使用了 L-BFGS的Scipy版本。

如果你所选择的方法是 ‘L-BFGS’,训练过程不支持在线学习模式和小批量学习模式。

1.17.6 复杂度

假设有个训练样本,个特征,个隐藏层,每个层都包含神经元--为了简单起见,还有个输出神经元。反向传播的时间复杂度为,其中为迭代次数。由于反向传播具有很高的时间复杂度,最好从较小数量的隐神经元和较少的隐藏层开始进行训练。

1.17.7 数学公式

给定一组训练样本, 其中,一个隐藏层中一个神经元学习函数是,其中是模型的参数。分别表示输入层和隐藏层的权重;分别表示添加到隐藏层和输出层的偏差。是激活函数,默认设置为(双曲正切)tan, 它被给出如下:

对于二分类,通过logistic函数获得0到1之间的输出值。设置阈值为0.5, 会将大于或等于0.5的输出样本分配给正类,其余的分配给负类。

如果有两个以上的类, 本身将是大小为(n_classes)的向量。它不是通过logistic函数,而是通过Softmax函数,该函数被编写为,

其中 表示Softmax输入的第个元素,它对应于第类,是类的数量。结果是包含样本属于每个类的概率的向量。输出是概率最高的类。

在回归中,输出保持为 ;因此,输出激活函数就是恒等函数( identity function)。

MLP根据问题类型使用不同的损失函数。分类损失函数是交叉熵(Cross-Entropy),在二分类情况下给出如下:

其中,是对模型的复杂度进行惩罚的L2正则化项(也称为惩罚项),并且是一个非负的超参数,它控制着惩罚的程度。

对于回归,MLP使用均方误差损失函数, 写成;

从初始随机化权重开始,多层感知机(MLP)通过重复更新这些权重,使损失函数最小化。在计算损失后,反向传递将其从输出层传播到前一层,为每个权重参数提供一个更新值,以减少损失。

在梯度下降中,计算得到损失函数关于每个权重的梯度, 并从减去,这可以表示为:

其中是迭代步骤,是值大于0的学习速率。

该算法在达到预定的最大迭代次数,或者当损失的改进低于某个很小的数时停止。

1.17.8 实用技巧

  • 多层感知机对特征的缩放是敏感的,所以它强烈建议您标准化您的数据。 例如,将输入向量 X 的每个属性放缩到到 [0, 1] 或 [-1,+1] ,或者将其标准化使它具有 0 均值和方差 1。注意,为了得到有意义的结果,您必须对测试集也应用相同的尺度缩放。 您可以使用 StandardScaler 进行标准化。

    >>> from sklearn.preprocessing import StandardScaler  # doctest: +SKIP
    >>> scaler = StandardScaler()  # doctest: +SKIP
    >>> # Don't cheat - fit only on training data
    >>> scaler.fit(X_train)  # doctest: +SKIP
    >>> X_train = scaler.transform(X_train)  # doctest: +SKIP
    >>> # apply same transformation to test data
    >>> X_test = scaler.transform(X_test)  # doctest: +SKIP

    另一个推荐的方法是在 Pipeline 中使用的 StandardScaler

  • 最好使用 GridSearchCV 找到一个合理的正则化参数 ,通常范围是在 10.0 ** -np.arange(1, 7)

  • 据经验可知,我们观察到 L-BFGS是收敛速度更快的且在小数据集上表现更好的解决方案。对于规模相对比较大的数据集, Adam是非常鲁棒的。 它通常会迅速收敛,并得到相当不错的表现。另一方面,如果学习率调整得正确, 使用 momentum 或 nesterov’s momentum 的 SGD可能比这两种算法更好。

1.17.9 warm_start的更多控制

如果您希望更多地控制SGD中的停止标准或学习速率,或者希望进行额外的监视,那么使用warm_start=Truemax_iter=1并迭代自己可能会有帮助:

>>> X = [[0.0.], [1.1.]]
>>> y = [01]
>>> clf = MLPClassifier(hidden_layer_sizes=(15,), random_state=1, max_iter=1, warm_start=True)
>>> for i in range(10):
...     clf.fit(X, y)
...     # additional monitoring / inspection
MLPClassifier(...

参考