堆叠RBM以在sklearn中创建深度信仰网络

时间:2018-09-04 12:24:38

标签: python machine-learning scikit-learn deep-learning

根据此website,深度信任网络只是使用前一个RBM的输出作为下一个RBM的输入,将多个RBM堆叠在一起。 enter image description here

在scikit-learn documentation中,有一个使用RBM对MNIST数据集进行分类的示例。他们将RBMLogisticRegression放入管道中,以获得更高的准确性。

因此,我想知道是否可以在该管道中添加多个RBM来创建深度信任网络,如以下代码所示。

from sklearn.neural_network import BernoulliRBM
import numpy as np
from sklearn import linear_model, datasets, metrics
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline

digits = datasets.load_digits()
X = np.asarray(digits.data, 'float32')
Y = digits.target
X = (X - np.min(X, 0)) / (np.max(X, 0) + 0.0001)  # 0-1 scaling

X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
                                                    test_size=0.2,
                                                    random_state=0)

logistic = linear_model.LogisticRegression(C=100)
rbm1 = BernoulliRBM(n_components=100, learning_rate=0.06, n_iter=100, verbose=1, random_state=101)
rbm2 = BernoulliRBM(n_components=80, learning_rate=0.06, n_iter=100, verbose=1, random_state=101)
rbm3 = BernoulliRBM(n_components=60, learning_rate=0.06, n_iter=100, verbose=1, random_state=101)
DBN3 = Pipeline(steps=[('rbm1', rbm1),('rbm2', rbm2), ('rbm3', rbm3), ('logistic', logistic)])

DBN3.fit(X_train, Y_train)

print("Logistic regression using RBM features:\n%s\n" % (
    metrics.classification_report(
        Y_test,
        DBN3.predict(X_test))))

但是,我发现添加到管道中的RBM越多,准确性越低。

管道中有1个RBM –> 95%

2个RBM即将发布-> 93%

3个RBM即将发布-> 89%

下面的训练曲线表明100次迭代恰好是收敛的。更多的迭代将导致过度拟合,并且可能性再次降低。

批量大小= 10

enter image description here

批量大小= 256或以上

我注意到一件有趣的事情。如果我使用较大的批处理大小,则网络性能会大大降低。当批次大小大于256时,准确度仅会降低到10%以下。训练曲线对我来说毫无意义,因为第一和第二个RBM并没有学到很多,但是第三个RBM突然学习很快。 enter image description here

对于具有3个RBM的网络来说,似乎有89%的瓶颈。

我想知道我在这里做错了什么吗?我对深度信仰网络的理解正确吗?

1 个答案:

答案 0 :(得分:5)

由于缺乏统计上的严格性,以下内容并不是一个明确的答案。 但是,必要的参数优化和评估仍将花费几天的CPU时间。在此之前,我将提交以下原理证明作为答案。

Tl; dr

更大的层+更长的训练=>逻辑回归本身的表现<+ 1个RBM层<+ RBM堆栈/ DBN

简介

正如我在OP帖子中的评论之一中所述,Erhan et al. (2010)中已系统地探索了使用堆叠式RBM / DBN进行无监督的预训练。确切地说,它们的设置与OP的设置不同之处在于,在训练DBN之后,他们添加了输出神经元的最后一层,并使用反向传播技术对整个网络进行微调。 OP使用对最后一层的输出进行逻辑回归的性能来评估添加一个或多个RBM层的好处。 此外,Erhan等。也不使用scikit-learn中设置的64像素digits数据集,而是使用784像素的MNIST图像(及其变体)。

话虽这么说,相似性足够大,足以将他们的发现作为评估DBN的scikit学习实现的起点,这正是我所做的事情:我还使用MNIST数据集,并且我使用Erhan等人的最佳参数(在报告的地方)。这些参数与OP实例中给出的参数大不相同,并且可能是OP模型性能不佳的根源:特别是,层大小更大,训练样本的数量大几个数量级。但是,作为OP,我在管道的最后一步中使用逻辑回归来评估RBM或RBM堆栈/ DBN的图像转换是否可以改善分类。

顺便说一句,RBM层中的单元数(大约为800个)与原始图像(784个像素)一样多,这也使对原始图像像素的纯逻辑回归成为合适的基准模型。

因此,我比较以下三种模型:

  1. 逻辑回归本身(即基准/基准模型)

  2. RBM输出的逻辑回归,

  3. 一堆RBM / DBN的输出的逻辑回归。

结果

与先前的文献一致,我的初步结果确实表明,与仅使用原始像素值本身相比,使用RBM的输出进行逻辑回归可以提高性能,并且DBN变换在RBM上仍然有所改善较小。

逻辑回归本身:

Model performance:
             precision    recall  f1-score   support

        0.0       0.95      0.97      0.96       995
        1.0       0.96      0.98      0.97      1121
        2.0       0.91      0.90      0.90      1015
        3.0       0.90      0.89      0.89      1033
        4.0       0.93      0.92      0.92       976
        5.0       0.90      0.88      0.89       884
        6.0       0.94      0.94      0.94       999
        7.0       0.92      0.93      0.93      1034
        8.0       0.89      0.87      0.88       923
        9.0       0.89      0.90      0.89      1020

avg / total       0.92      0.92      0.92     10000

基于结果的管理的逻辑回归:

Model performance:
             precision    recall  f1-score   support

        0.0       0.98      0.98      0.98       995
        1.0       0.98      0.99      0.99      1121
        2.0       0.95      0.97      0.96      1015
        3.0       0.97      0.96      0.96      1033
        4.0       0.98      0.97      0.97       976
        5.0       0.97      0.96      0.96       884
        6.0       0.98      0.98      0.98       999
        7.0       0.96      0.97      0.97      1034
        8.0       0.96      0.94      0.95       923
        9.0       0.96      0.96      0.96      1020

avg / total       0.97      0.97      0.97     10000

成堆的RBM / DBN的输出的逻辑回归:

Model performance:
             precision    recall  f1-score   support

        0.0       0.99      0.99      0.99       995
        1.0       0.99      0.99      0.99      1121
        2.0       0.97      0.98      0.98      1015
        3.0       0.98      0.97      0.97      1033
        4.0       0.98      0.97      0.98       976
        5.0       0.96      0.97      0.97       884
        6.0       0.99      0.98      0.98       999
        7.0       0.98      0.98      0.98      1034
        8.0       0.98      0.97      0.97       923
        9.0       0.96      0.97      0.96      1020

avg / total       0.98      0.98      0.98     10000

代码

#!/usr/bin/env python

"""
Using MNIST, compare classification performance of:
1) logistic regression by itself,
2) logistic regression on outputs of an RBM, and
3) logistic regression on outputs of a stacks of RBMs / a DBN.
"""

import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import fetch_mldata
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.neural_network import BernoulliRBM
from sklearn.base import clone
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report


def norm(arr):
    arr = arr.astype(np.float)
    arr -= arr.min()
    arr /= arr.max()
    return arr


if __name__ == '__main__':

    # load MNIST data set
    mnist = fetch_mldata('MNIST original')
    X, Y = mnist.data, mnist.target

    # normalize inputs to 0-1 range
    X = norm(X)

    # split into train, validation, and test data sets
    X_train, X_test, Y_train, Y_test = train_test_split(X,       Y,       test_size=10000, random_state=0)
    X_train, X_val,  Y_train, Y_val  = train_test_split(X_train, Y_train, test_size=10000, random_state=0)

    # --------------------------------------------------------------------------------
    # set hyperparameters

    learning_rate = 0.02 # from Erhan et el. (2010): median value in grid-search
    total_units   =  800 # from Erhan et el. (2010): optimal for MNIST / only slightly worse than 1200 units when using InfiniteMNIST
    total_epochs  =   50 # from Erhan et el. (2010): optimal for MNIST
    batch_size    =  128 # seems like a representative sample; backprop literature often uses 256 or 512 samples

    C = 100. # optimum for benchmark model according to sklearn docs: https://scikit-learn.org/stable/auto_examples/neural_networks/plot_rbm_logistic_classification.html#sphx-glr-auto-examples-neural-networks-plot-rbm-logistic-classification-py)

    # TODO optimize using grid search, etc

    # --------------------------------------------------------------------------------
    # construct models

    # RBM
    rbm = BernoulliRBM(n_components=total_units, learning_rate=learning_rate, batch_size=batch_size, n_iter=total_epochs, verbose=1)

    # "output layer"
    logistic = LogisticRegression(C=C, solver='lbfgs', multi_class='multinomial', max_iter=200, verbose=1)

    models = []
    models.append(Pipeline(steps=[('logistic', clone(logistic))]))                                              # base model / benchmark
    models.append(Pipeline(steps=[('rbm1', clone(rbm)), ('logistic', clone(logistic))]))                        # single RBM
    models.append(Pipeline(steps=[('rbm1', clone(rbm)), ('rbm2', clone(rbm)), ('logistic', clone(logistic))]))  # RBM stack / DBN

    # --------------------------------------------------------------------------------
    # train and evaluate models

    for model in models:
        # train
        model.fit(X_train, Y_train)

        # evaluate using validation set
        print("Model performance:\n%s\n" % (
            classification_report(Y_val, model.predict(X_val))))

    # TODO: after parameter optimization, evaluate on test set