基于自动编码器特征抽取的分类实战

       【翻译自: Autoencoder Feature Extraction for Classification

      【说明:Jason Brownlee PhD大神的文章个人很喜欢,所以闲暇时间里会做一点翻译和学习实践的工作,这里是相应工作的实践记录,希望能帮到有需要的人!】

     自动编码器是一种神经网络,可用于学习原始数据的压缩表示。自动编码器由编码器和解码器子模型组成。编码器压缩输入,而解码器尝试根据编码器提供的压缩版本重新创建输入。训练后,将保存编码器模型,并丢弃解码器。然后,编码器可用作数据准备技术,对原始数据执行特征提取,以用于训练不同的机器学习模型。

     在本教程中,您将发现如何开发和评估用于分类预测建模的自动编码器。完成本教程后,您将知道:

自动编码器是一种神经网络模型,可用于学习原始数据的压缩表示形式。
如何在训练数据集上训练自动编码器模型,并仅保存模型的编码器部分。
训练机器学习模型时如何使用编码器作为数据准备步骤。

教程概述

      本教程分为三个部分: 他们是:

用于特征提取的自动编码器
分类自动编码器
编码器作为预测模型的数据准备


用于特征提取的自动编码器

       自动编码器是一种神经网络模型,旨在学习输入的压缩表示形式。它们是一种无监督的学习方法,尽管从技术上讲,它们是使用有监督的学习方法(称为自我监督)进行训练的。自动编码器通常被训练为尝试重新创建输入的更广泛模型的一部分。

     例如:   X = model.predict(X)

    自动编码器模型的设计通过将体系结构限制在模型中点的瓶颈处来故意使此挑战变得困难,从该瓶颈执行输入数据的重构。自动编码器的类型很多,其用途各不相同,但也许更常见的用途是作为学习型或自动特征提取模型。在这种情况下,一旦模型适合,就可以放弃模型的重构方面,可以使用直至瓶颈的模型。 模型在瓶颈处的输出是固定长度的向量,该向量提供输入数据的压缩表示。

     然后,可以将来自域的输入数据提供给模型,并且可以将瓶颈处的模型输出用作监督学习模型中的特征向量,以进行可视化,或更普遍地用于降维。接下来,让我们探讨如何针对分类预测建模问题开发用于特征提取的自动编码器。

分类自动编码器

    在本节中,我们将开发一种自动编码器,以学习用于分类预测建模问题的输入特征的压缩表示。首先,让我们定义分类预测建模问题。我们将使用make_classification()scikit-learn函数定义具有100个输入要素(列)和1,000个示例(行)的合成二进制(2类)分类任务。 重要的是,我们将以大多数输入变量都是冗余的(100个中的90个或90%)的方式定义问题,以便以后自动编码器可以学习有用的压缩表示形式。

      下面的示例定义了数据集并总结了其形状。

# synthetic classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=100, n_informative=10, n_redundant=90, random_state=1)
# summarize the dataset
print(X.shape, y.shape)

     运行示例将定义数据集并打印数组的形状,从而确认行数和列数。

(1000, 100) (1000,)

      接下来,我们将开发一个多层感知器(MLP)自动编码器模型。该模型将采用所有输入列,然后输出相同的值。它将学习准确地重新创建输入模式。自动编码器由两部分组成:编码器和解码器。编码器学习如何解释输入并将其压缩为瓶颈层定义的内部表示。解码器获取编码器的输出(瓶颈层),并尝试重新创建输入。一旦对自动编码器进行了训练,解码器将被丢弃,我们仅保留编码器并将其用于将输入示例压缩为瓶颈层输出的矢量。在第一个自动编码器中,我们将完全不压缩输入,而将使用与输入大小相同的瓶颈层。这应该是一个容易解决的问题,该模型将几乎完美地学习并且旨在确认我们的模型已正确实现。

     我们将使用功能性API定义模型;如果这对您来说是新手,我建议您学习本教程:

   如何使用Keras功能API进行深度学习
   在定义和拟合模型之前,我们将数据分为训练集和测试集,并通过将值归一化为0-1范围来缩放输入数据,这是MLP的一种良好做法。

# split into train test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# scale data
t = MinMaxScaler()
t.fit(X_train)
X_train = t.transform(X_train)
X_test = t.transform(X_test)

     我们将编码器定义为具有两个隐藏层,第一层具有两倍的输入数量(例如200),第二层具有相同的输入数量(100),其次是瓶颈层,具有与输入相同数量的输入。 数据集(100)。为确保模型学习良好,我们将使用批处理规范化和泄漏性ReLU激活。

# define encoder
visible = Input(shape=(n_inputs,))
# encoder level 1
e = Dense(n_inputs*2)(visible)
e = BatchNormalization()(e)
e = LeakyReLU()(e)
# encoder level 2
e = Dense(n_inputs)(e)
e = BatchNormalization()(e)
e = LeakyReLU()(e)
# bottleneck
n_bottleneck = n_inputs
bottleneck = Dense(n_bottleneck)(e)

      解码器将以类似的结构定义,尽管相反。它将具有两个隐藏层,第一层具有数据集中的输入数量(例如100),第二层具有两倍的输入数量(例如200)。 输出层的节点数与输入数据中的列数相同,并将使用线性激活函数输出数值。

# define decoder, level 1
d = Dense(n_inputs)(bottleneck)
d = BatchNormalization()(d)
d = LeakyReLU()(d)
# decoder level 2
d = Dense(n_inputs*2)(d)
d = BatchNormalization()(d)
d = LeakyReLU()(d)
# output layer
output = Dense(n_inputs, activation='linear')(d)
# define autoencoder model
model = Model(inputs=visible, outputs=output)

        考虑到重构是多输出回归问题的一种,该模型将使用高效的随机随机梯度下降法进行拟合,并最小化均方误差。

# compile autoencoder model
model.compile(optimizer='adam', loss='mse')

      我们可以在自动编码器模型中绘制图层,以了解数据如何流过模型。

# plot the autoencoder
plot_model(model, 'autoencoder_no_compress.png', show_shapes=True)

       下图显示了自动编码器的图。

       接下来,我们可以训练模型以重现输入,并在保持测试集上跟踪模型的性能。

# fit the autoencoder model to reconstruct input
history = model.fit(X_train, X_train, epochs=200, batch_size=16, verbose=2, validation_data=(X_test,X_test))

       训练后,我们可以绘制训练和测试集的学习曲线,以确认模型很好地学习了重建问题。

# plot loss
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

        最后,如果需要,我们可以保存编码器模型供以后使用。

# define an encoder model (without the decoder)
encoder = Model(inputs=visible, outputs=bottleneck)
plot_model(encoder, 'encoder_no_compress.png', show_shapes=True)
# save the encoder to file
encoder.save('encoder.h5')

      作为保存编码器的一部分,我们还将绘制编码器模型,以了解瓶颈层输出的形状,例如 100元素向量。下面提供了该图的示例。

       综上所述,下面列出了自动编码器的完整示例,该示例可用于重构分类数据集的输入数据,而无需在瓶颈层进行任何压缩。

# train autoencoder for classification with no compression in the bottleneck layer
from sklearn.datasets import make_classification
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import LeakyReLU
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.utils import plot_model
from matplotlib import pyplot
# define dataset
X, y = make_classification(n_samples=1000, n_features=100, n_informative=10, n_redundant=90, random_state=1)
# number of input columns
n_inputs = X.shape[1]
# split into train test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# scale data
t = MinMaxScaler()
t.fit(X_train)
X_train = t.transform(X_train)
X_test = t.transform(X_test)
# define encoder
visible = Input(shape=(n_inputs,))
# encoder level 1
e = Dense(n_inputs*2)(visible)
e = BatchNormalization()(e)
e = LeakyReLU()(e)
# encoder level 2
e = Dense(n_inputs)(e)
e = BatchNormalization()(e)
e = LeakyReLU()(e)
# bottleneck
n_bottleneck = n_inputs
bottleneck = Dense(n_bottleneck)(e)
# define decoder, level 1
d = Dense(n_inputs)(bottleneck)
d = BatchNormalization()(d)
d = LeakyReLU()(d)
# decoder level 2
d = Dense(n_inputs*2)(d)
d = BatchNormalization()(d)
d = LeakyReLU()(d)
# output layer
output = Dense(n_inputs, activation='linear')(d)
# define autoencoder model
model = Model(inputs=visible, outputs=output)
# compile autoencoder model
model.compile(optimizer='adam', loss='mse')
# plot the autoencoder
plot_model(model, 'autoencoder_no_compress.png', show_shapes=True)
# fit the autoencoder model to reconstruct input
history = model.fit(X_train, X_train, epochs=200, batch_size=16, verbose=2, validation_data=(X_test,X_test))
# plot loss
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()
# define an encoder model (without the decoder)
encoder = Model(inputs=visible, outputs=bottleneck)
plot_model(encoder, 'encoder_no_compress.png', show_shapes=True)
# save the encoder to file
encoder.save('encoder.h5')

     运行示例符合模型,并报告沿途训练和测试集上的损失。

     注意:如果在创建模型图时遇到问题,可以注释掉导入并调用plot_model()函数。

     注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。 考虑运行该示例几次并比较平均结果。

    在这种情况下,我们看到损失变低了,但是在瓶颈层没有压缩的情况下,损失并没有达到零(正如我们可能预期的那样)。 也许需要进一步调整模型架构或学习超参数。

...
42/42 - 0s - loss: 0.0032 - val_loss: 0.0016
Epoch 196/200
42/42 - 0s - loss: 0.0031 - val_loss: 0.0024
Epoch 197/200
42/42 - 0s - loss: 0.0032 - val_loss: 0.0015
Epoch 198/200
42/42 - 0s - loss: 0.0032 - val_loss: 0.0014
Epoch 199/200
42/42 - 0s - loss: 0.0031 - val_loss: 0.0020
Epoch 200/200
42/42 - 0s - loss: 0.0029 - val_loss: 0.0017

      创建了一条学习曲线图,表明该模型在重构输入时取得了很好的拟合,在整个训练过程中保持稳定,而不是过度拟合。  到现在为止还挺好。 我们知道如何开发无压缩的自动编码器。接下来,让我们更改模型的配置,以使瓶颈层的节点数减少一半(例如50个)。

# bottleneck
n_bottleneck = round(float(n_inputs) / 2.0)
bottleneck = Dense(n_bottleneck)(e)

      完整代码实例如下:

# train autoencoder for classification with with compression in the bottleneck layer
from sklearn.datasets import make_classification
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import LeakyReLU
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.utils import plot_model
from matplotlib import pyplot
# define dataset
X, y = make_classification(n_samples=1000, n_features=100, n_informative=10, n_redundant=90, random_state=1)
# number of input columns
n_inputs = X.shape[1]
# split into train test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# scale data
t = MinMaxScaler()
t.fit(X_train)
X_train = t.transform(X_train)
X_test = t.transform(X_test)
# define encoder
visible = Input(shape=(n_inputs,))
# encoder level 1
e = Dense(n_inputs*2)(visible)
e = BatchNormalization()(e)
e = LeakyReLU()(e)
# encoder level 2
e = Dense(n_inputs)(e)
e = BatchNormalization()(e)
e = LeakyReLU()(e)
# bottleneck
n_bottleneck = round(float(n_inputs) / 2.0)
bottleneck = Dense(n_bottleneck)(e)
# define decoder, level 1
d = Dense(n_inputs)(bottleneck)
d = BatchNormalization()(d)
d = LeakyReLU()(d)
# decoder level 2
d = Dense(n_inputs*2)(d)
d = BatchNormalization()(d)
d = LeakyReLU()(d)
# output layer
output = Dense(n_inputs, activation='linear')(d)
# define autoencoder model
model = Model(inputs=visible, outputs=output)
# compile autoencoder model
model.compile(optimizer='adam', loss='mse')
# plot the autoencoder
plot_model(model, 'autoencoder_compress.png', show_shapes=True)
# fit the autoencoder model to reconstruct input
history = model.fit(X_train, X_train, epochs=200, batch_size=16, verbose=2, validation_data=(X_test,X_test))
# plot loss
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()
# define an encoder model (without the decoder)
encoder = Model(inputs=visible, outputs=bottleneck)
plot_model(encoder, 'encoder_compress.png', show_shapes=True)
# save the encoder to file
encoder.save('encoder.h5')

    运行示例符合模型,并报告沿途训练和测试集上的损失。

   注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。 考虑运行该示例几次并比较平均结果。

    在这种情况下,我们看到的损失与上述示例类似,没有压缩,并且损失很小,这表明该模型在瓶颈只有一半的情况下也能表现出色。

42/42 - 0s - loss: 0.0029 - val_loss: 0.0010
Epoch 196/200
42/42 - 0s - loss: 0.0029 - val_loss: 0.0013
Epoch 197/200
42/42 - 0s - loss: 0.0030 - val_loss: 9.4472e-04
Epoch 198/200
42/42 - 0s - loss: 0.0028 - val_loss: 0.0015
Epoch 199/200
42/42 - 0s - loss: 0.0033 - val_loss: 0.0021
Epoch 200/200
42/42 - 0s - loss: 0.0027 - val_loss: 8.7731e-04

      创建了一条学习曲线图,再次表明该模型在重构输入时取得了很好的拟合,在整个训练过程中保持稳定,而不是过度拟合。

    经过训练的编码器将保存到文件“ encoder.h5”中,我们以后可以加载和使用。接下来,让我们探讨如何使用训练有素的编码器模型。

编码器作为预测模型的数据准备

      在本节中,我们将使用自动编码器中训练有素的编码器来压缩输入数据并训练不同的预测模型。首先,让我们为该问题建立性能基准。 这很重要,因为压缩的编码无法改善模型的性能,那么压缩的编码不会为项目增加价值,因此不应使用。我们可以直接在训练数据集上训练逻辑回归模型,并在保留测试集上评估模型的性能。下面列出了完整的示例。

# baseline in performance with logistic regression model
from sklearn.datasets import make_classification
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# define dataset
X, y = make_classification(n_samples=1000, n_features=100, n_informative=10, n_redundant=90, random_state=1)
# split into train test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# scale data
t = MinMaxScaler()
t.fit(X_train)
X_train = t.transform(X_train)
X_test = t.transform(X_test)
# define model
model = LogisticRegression()
# fit model on training set
model.fit(X_train, y_train)
# make prediction on test set
yhat = model.predict(X_test)
# calculate accuracy
acc = accuracy_score(y_test, yhat)
print(acc)

      运行示例将逻辑回归模型拟合到训练数据集上,并在测试集上对其进行评估。

     注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。 考虑运行该示例几次并比较平均结果。

     在这种情况下,我们可以看到该模型实现了约89.3%的分类精度。

     我们希望并期望逻辑回归模型适合输入的编码版本,从而为认为有用的编码实现更高的准确性。

0.8939393939393939

      我们可以更新示例,以使用上一节中训练的编码器模型首先对数据进行编码。首先,我们可以从文件中加载经过训练的编码器模型。

# load the model from file
encoder = load_model('encoder.h5')

      然后,我们可以使用编码器将原始输入数据(例如100列)转换为瓶颈向量(例如50个元素向量)。该过程可以应用于训练和测试数据集。

# encode the train data
X_train_encode = encoder.predict(X_train)
# encode the test data
X_test_encode = encoder.predict(X_test)

      然后,我们可以像以前一样使用此编码数据来训练和评估逻辑回归模型。

# define the model
model = LogisticRegression()
# fit the model on the training set
model.fit(X_train_encode, y_train)
# make predictions on the test set
yhat = model.predict(X_test_encode)

        完整实例如下所示:

# evaluate logistic regression on encoded input
from sklearn.datasets import make_classification
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from tensorflow.keras.models import load_model
# define dataset
X, y = make_classification(n_samples=1000, n_features=100, n_informative=10, n_redundant=90, random_state=1)
# split into train test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# scale data
t = MinMaxScaler()
t.fit(X_train)
X_train = t.transform(X_train)
X_test = t.transform(X_test)
# load the model from file
encoder = load_model('encoder.h5')
# encode the train data
X_train_encode = encoder.predict(X_train)
# encode the test data
X_test_encode = encoder.predict(X_test)
# define the model
model = LogisticRegression()
# fit the model on the training set
model.fit(X_train_encode, y_train)
# make predictions on the test set
yhat = model.predict(X_test_encode)
# calculate classification accuracy
acc = accuracy_score(y_test, yhat)
print(acc)

      运行示例时,首先使用编码器对数据集进行编码,然后将逻辑回归模型拟合到训练数据集上,并在测试集上进行评估。

     注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。 考虑运行该示例几次并比较平均结果。

     在这种情况下,我们可以看到该模型实现了约93.9%的分类精度。

     这比原始数据集上评估的同一模型具有更好的分类精度,这表明编码对于我们选择的模型和测试工具很有帮助。

0.9393939393939394

 

相关接口参考

 

 

 

 

 

 

 

 

 

评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值