从 2 个自动编码器中提取特征并将它们输入 MLP
Extract features from 2 auto-encoders and feed them into an MLP
我知道从自动编码器中提取的特征可以输入到 mlp 中用于分类或回归目的。这是我之前做过的事情。
但是如果我有 2 个自动编码器呢?我可以从 2 个自动编码器的瓶颈层中提取特征并将它们输入到基于这些特征执行分类的 mlp 中吗?如果是,那么如何?我不确定如何连接这两个功能集。我尝试使用 numpy.hstack() 给我 'unhashable slice' 错误,而使用 tf.concat() 给我错误 'Input tensors to a Model must be Keras tensors.' 两个自动编码器的瓶颈层是每个维度 (None,100)。所以,基本上,如果我水平堆叠它们,我应该得到 (None, 200)。 mlp 的隐藏层可能包含一些 (num_hidden=100) 个神经元。有人可以帮忙吗?
x1 = autoencoder1.get_layer('encoder2').output
x2 = autoencoder2.get_layer('encoder2').output
#inp = np.hstack((x1, x2))
inp = tf.concat([x1, x2], 1)
x = tf.concat([x1, x2], 1)
h = Dense(num_hidden, activation='relu', name='hidden')(x)
y = Dense(1, activation='sigmoid', name='prediction')(h)
mymlp = Model(inputs=inp, outputs=y)
# Compile model
mymlp.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Train model
mymlp.fit(x_train, y_train, epochs=20, batch_size=8)
根据@twolffpiggott 的建议更新:
from keras.layers import Input, Dense, Dropout
from keras import layers
from keras.models import Model
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import numpy as np
x1 = Data1
x2 = Data2
y = Data3
num_neurons1 = x1.shape[1]
num_neurons2 = x2.shape[1]
# Train-test split
x1_train, x1_test, x2_train, x2_test, y_train, y_test = train_test_split(x1, x2, y, test_size=0.2)
# scale data within [0-1] range
scalar = MinMaxScaler()
x1_train = scalar.fit_transform(x1_train)
x1_test = scalar.transform(x1_test)
x2_train = scalar.fit_transform(x2_train)
x2_test = scalar.transform(x2_test)
x_train = np.concatenate([x1_train, x2_train], axis =-1)
x_test = np.concatenate([x1_test, x2_test], axis =-1)
# Auto-encoder1
encoding_dim1 = 500
encoding_dim2 = 100
input_data = Input(shape=(num_neurons1,))
encoded = Dense(encoding_dim1, activation='relu', name='encoder1')(input_data)
encoded1 = Dense(encoding_dim2, activation='relu', name='encoder2')(encoded)
decoded = Dense(encoding_dim2, activation='relu', name='decoder1')(encoded1)
decoded = Dense(num_neurons1, activation='sigmoid', name='decoder2')(decoded)
# this model maps an input to its reconstruction
autoencoder1 = Model(inputs=input_data, outputs=decoded)
autoencoder1.compile(optimizer='sgd', loss='mse')
# training
autoencoder1.fit(x1_train, x1_train,
epochs=100,
batch_size=8,
shuffle=True,
validation_data=(x1_test, x1_test))
# Auto-encoder2
encoding_dim1 = 500
encoding_dim2 = 100
input_data = Input(shape=(num_neurons2,))
encoded = Dense(encoding_dim1, activation='relu', name='encoder1')(input_data)
encoded2 = Dense(encoding_dim2, activation='relu', name='encoder2')(encoded)
decoded = Dense(encoding_dim2, activation='relu', name='decoder1')(encoded2)
decoded = Dense(num_neurons2, activation='sigmoid', name='decoder2')(decoded)
# this model maps an input to its reconstruction
autoencoder2 = Model(inputs=input_data, outputs=decoded)
autoencoder2.compile(optimizer='sgd', loss='mse')
# training
autoencoder2.fit(x2_train, x2_train,
epochs=100,
batch_size=8,
shuffle=True,
validation_data=(x2_test, x2_test))
# MLP
num_hidden = 100
encoded1.trainable = False
encoded2.trainable = False
encoded1 = autoencoder1(autoencoder1.inputs)
encoded2 = autoencoder2(autoencoder2.inputs)
concatenated = layers.concatenate([encoded1, encoded2], axis=-1)
x = Dropout(0.2)(concatenated)
h = Dense(num_hidden, activation='relu', name='hidden')(x)
h = Dropout(0.5)(h)
y = Dense(1, activation='sigmoid', name='prediction')(h)
myMLP = Model(inputs=[autoencoder1.inputs, autoencoder2.inputs], outputs=y)
# Compile model
myMLP.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Training
myMLP.fit(x_train, y_train, epochs=200, batch_size=8)
# Testing
myMLP.predict(x_test)
给我一个错误:无法散列的类型:'list' 来自行:
myMLP = 模型(输入=[autoencoder1.inputs,autoencoder2.inputs],输出=y)
问题是您将 numpy 数组与 keras 张量混合使用。这个去不了
有两种方法。
- 从每个自动编码器预测 numpy 数组,连接数组,将它们发送到第三个模型
- 连接所有模型,可能使自动编码器无法训练,适合每个自动编码器的一个输入。
就我个人而言,我会选择第一个。 (假设自动编码器已经过训练并且不需要更改)。
第一种方法
numpyOutputFromAuto1 = autoencoder1.predict(numpyInputs1)
numpyOutputFromAuto2 = autoencoder2.predict(numpyInputs2)
inputDataForThird = np.concatenate([numpyOutputFromAuto1,numpyOutputFromAuto2],axis=-1)
inputTensorForMlp = Input(inputsForThird.shape[1:])
h = Dense(num_hidden, activation='relu', name='hidden')(inputTensorForMlp)
y = Dense(1, activation='sigmoid', name='prediction')(h)
mymlp = Model(inputs=inputTensorForMlp, outputs=y)
....
mymlp.fit(inputDataForThird ,someY)
第二种方法
这有点复杂,起初我看不出有太多理由这样做。 (但当然也有可能是不错的选择)
现在我们完全忘记了 numpy,转而使用 keras 张量。
自行创建 mlp(如果您稍后在没有自动编码器的情况下使用它则很好):
inputTensorForMlp = Input(input_shape_compatible_with_concatenated_encoder_outputs)
x = Dropout(0.2)(inputTensorForMlp)
h = Dense(num_hidden, activation='relu', name='hidden')(x)
h = Dropout(0.5)(h)
y = Dense(1, activation='sigmoid', name='prediction')(h)
myMLP = Model(inputs=[autoencoder1.inputs, autoencoder2.inputs], outputs=y)
我们可能想要自动编码器的瓶颈功能,对吧?如果您碰巧正确地创建了自动编码器:编码器模型、解码器模型,将两者结合起来,那么只使用编码器模型会更容易。其他:
encodedOutput1 = autoencoder1.layers[bottleneckLayer].outputs #or encoder1.outputs
encodedOutput2 = autoencoder1.layers[bottleneckLayer].outputs #or encoder2.outputs
正在创建连接模型。串联必须使用 keras 层(我们正在使用 keras 张量):
concatenated = Concatenate()([encodedOutput1,encodedOutput2])
output = myMLP(concatenated)
joinedModel = Model([autoencoder1.input,autoencoder2.input],output)
我也会采用 Daniel 的第一种方法(为了简单和高效),但如果您对第二种方法感兴趣;例如,如果您对 运行 网络端到端感兴趣,您可以这样处理:
# make autoencoders not trainable
autoencoder1.trainable = False
autoencoder2.trainable = False
encoded1 = autoencoder1(kerasInputs1)
encoded2 = autoencoder2(kerasInputs2)
concatenated = layers.concatenate([encoded1, encoded2], axis=-1)
h = Dense(num_hidden, activation='relu', name='hidden')(concatenated)
y = Dense(1, activation='sigmoid', name='prediction')(h)
myMLP = Model([input_data1, input_data2], y)
myMLP.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Training
myMLP.fit([x1_train, x2_train], y_train, epochs=200, batch_size=8)
# Testing
myMLP.predict([x1_test, x2_test])
关键编辑
- 两个自动编码器的权重应该被端到端地冻结(否则来自随机初始化的 MLP 的早期梯度更新可能会导致他们学习的大部分损失)。
- 自动编码器输入层应分配给每个自动编码器的单独变量
input_data1
和 input_data2
(而不是同时分配给 input_data
)。尽管 autoencoder1.inputs
returns 是一个 tf 张量,但这是 unhashable type: list
异常的来源,用 [input_data1, input_data2]
替换可以解决问题。
- 为端到端模型拟合 MLP 时,输入应该是
x1_train
和 x2_train
的列表,而不是串联的输入。预测时相同。
我知道从自动编码器中提取的特征可以输入到 mlp 中用于分类或回归目的。这是我之前做过的事情。
但是如果我有 2 个自动编码器呢?我可以从 2 个自动编码器的瓶颈层中提取特征并将它们输入到基于这些特征执行分类的 mlp 中吗?如果是,那么如何?我不确定如何连接这两个功能集。我尝试使用 numpy.hstack() 给我 'unhashable slice' 错误,而使用 tf.concat() 给我错误 'Input tensors to a Model must be Keras tensors.' 两个自动编码器的瓶颈层是每个维度 (None,100)。所以,基本上,如果我水平堆叠它们,我应该得到 (None, 200)。 mlp 的隐藏层可能包含一些 (num_hidden=100) 个神经元。有人可以帮忙吗?
x1 = autoencoder1.get_layer('encoder2').output
x2 = autoencoder2.get_layer('encoder2').output
#inp = np.hstack((x1, x2))
inp = tf.concat([x1, x2], 1)
x = tf.concat([x1, x2], 1)
h = Dense(num_hidden, activation='relu', name='hidden')(x)
y = Dense(1, activation='sigmoid', name='prediction')(h)
mymlp = Model(inputs=inp, outputs=y)
# Compile model
mymlp.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Train model
mymlp.fit(x_train, y_train, epochs=20, batch_size=8)
根据@twolffpiggott 的建议更新:
from keras.layers import Input, Dense, Dropout
from keras import layers
from keras.models import Model
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import numpy as np
x1 = Data1
x2 = Data2
y = Data3
num_neurons1 = x1.shape[1]
num_neurons2 = x2.shape[1]
# Train-test split
x1_train, x1_test, x2_train, x2_test, y_train, y_test = train_test_split(x1, x2, y, test_size=0.2)
# scale data within [0-1] range
scalar = MinMaxScaler()
x1_train = scalar.fit_transform(x1_train)
x1_test = scalar.transform(x1_test)
x2_train = scalar.fit_transform(x2_train)
x2_test = scalar.transform(x2_test)
x_train = np.concatenate([x1_train, x2_train], axis =-1)
x_test = np.concatenate([x1_test, x2_test], axis =-1)
# Auto-encoder1
encoding_dim1 = 500
encoding_dim2 = 100
input_data = Input(shape=(num_neurons1,))
encoded = Dense(encoding_dim1, activation='relu', name='encoder1')(input_data)
encoded1 = Dense(encoding_dim2, activation='relu', name='encoder2')(encoded)
decoded = Dense(encoding_dim2, activation='relu', name='decoder1')(encoded1)
decoded = Dense(num_neurons1, activation='sigmoid', name='decoder2')(decoded)
# this model maps an input to its reconstruction
autoencoder1 = Model(inputs=input_data, outputs=decoded)
autoencoder1.compile(optimizer='sgd', loss='mse')
# training
autoencoder1.fit(x1_train, x1_train,
epochs=100,
batch_size=8,
shuffle=True,
validation_data=(x1_test, x1_test))
# Auto-encoder2
encoding_dim1 = 500
encoding_dim2 = 100
input_data = Input(shape=(num_neurons2,))
encoded = Dense(encoding_dim1, activation='relu', name='encoder1')(input_data)
encoded2 = Dense(encoding_dim2, activation='relu', name='encoder2')(encoded)
decoded = Dense(encoding_dim2, activation='relu', name='decoder1')(encoded2)
decoded = Dense(num_neurons2, activation='sigmoid', name='decoder2')(decoded)
# this model maps an input to its reconstruction
autoencoder2 = Model(inputs=input_data, outputs=decoded)
autoencoder2.compile(optimizer='sgd', loss='mse')
# training
autoencoder2.fit(x2_train, x2_train,
epochs=100,
batch_size=8,
shuffle=True,
validation_data=(x2_test, x2_test))
# MLP
num_hidden = 100
encoded1.trainable = False
encoded2.trainable = False
encoded1 = autoencoder1(autoencoder1.inputs)
encoded2 = autoencoder2(autoencoder2.inputs)
concatenated = layers.concatenate([encoded1, encoded2], axis=-1)
x = Dropout(0.2)(concatenated)
h = Dense(num_hidden, activation='relu', name='hidden')(x)
h = Dropout(0.5)(h)
y = Dense(1, activation='sigmoid', name='prediction')(h)
myMLP = Model(inputs=[autoencoder1.inputs, autoencoder2.inputs], outputs=y)
# Compile model
myMLP.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Training
myMLP.fit(x_train, y_train, epochs=200, batch_size=8)
# Testing
myMLP.predict(x_test)
给我一个错误:无法散列的类型:'list' 来自行: myMLP = 模型(输入=[autoencoder1.inputs,autoencoder2.inputs],输出=y)
问题是您将 numpy 数组与 keras 张量混合使用。这个去不了
有两种方法。
- 从每个自动编码器预测 numpy 数组,连接数组,将它们发送到第三个模型
- 连接所有模型,可能使自动编码器无法训练,适合每个自动编码器的一个输入。
就我个人而言,我会选择第一个。 (假设自动编码器已经过训练并且不需要更改)。
第一种方法
numpyOutputFromAuto1 = autoencoder1.predict(numpyInputs1)
numpyOutputFromAuto2 = autoencoder2.predict(numpyInputs2)
inputDataForThird = np.concatenate([numpyOutputFromAuto1,numpyOutputFromAuto2],axis=-1)
inputTensorForMlp = Input(inputsForThird.shape[1:])
h = Dense(num_hidden, activation='relu', name='hidden')(inputTensorForMlp)
y = Dense(1, activation='sigmoid', name='prediction')(h)
mymlp = Model(inputs=inputTensorForMlp, outputs=y)
....
mymlp.fit(inputDataForThird ,someY)
第二种方法
这有点复杂,起初我看不出有太多理由这样做。 (但当然也有可能是不错的选择)
现在我们完全忘记了 numpy,转而使用 keras 张量。
自行创建 mlp(如果您稍后在没有自动编码器的情况下使用它则很好):
inputTensorForMlp = Input(input_shape_compatible_with_concatenated_encoder_outputs)
x = Dropout(0.2)(inputTensorForMlp)
h = Dense(num_hidden, activation='relu', name='hidden')(x)
h = Dropout(0.5)(h)
y = Dense(1, activation='sigmoid', name='prediction')(h)
myMLP = Model(inputs=[autoencoder1.inputs, autoencoder2.inputs], outputs=y)
我们可能想要自动编码器的瓶颈功能,对吧?如果您碰巧正确地创建了自动编码器:编码器模型、解码器模型,将两者结合起来,那么只使用编码器模型会更容易。其他:
encodedOutput1 = autoencoder1.layers[bottleneckLayer].outputs #or encoder1.outputs
encodedOutput2 = autoencoder1.layers[bottleneckLayer].outputs #or encoder2.outputs
正在创建连接模型。串联必须使用 keras 层(我们正在使用 keras 张量):
concatenated = Concatenate()([encodedOutput1,encodedOutput2])
output = myMLP(concatenated)
joinedModel = Model([autoencoder1.input,autoencoder2.input],output)
我也会采用 Daniel 的第一种方法(为了简单和高效),但如果您对第二种方法感兴趣;例如,如果您对 运行 网络端到端感兴趣,您可以这样处理:
# make autoencoders not trainable
autoencoder1.trainable = False
autoencoder2.trainable = False
encoded1 = autoencoder1(kerasInputs1)
encoded2 = autoencoder2(kerasInputs2)
concatenated = layers.concatenate([encoded1, encoded2], axis=-1)
h = Dense(num_hidden, activation='relu', name='hidden')(concatenated)
y = Dense(1, activation='sigmoid', name='prediction')(h)
myMLP = Model([input_data1, input_data2], y)
myMLP.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Training
myMLP.fit([x1_train, x2_train], y_train, epochs=200, batch_size=8)
# Testing
myMLP.predict([x1_test, x2_test])
关键编辑
- 两个自动编码器的权重应该被端到端地冻结(否则来自随机初始化的 MLP 的早期梯度更新可能会导致他们学习的大部分损失)。
- 自动编码器输入层应分配给每个自动编码器的单独变量
input_data1
和input_data2
(而不是同时分配给input_data
)。尽管autoencoder1.inputs
returns 是一个 tf 张量,但这是unhashable type: list
异常的来源,用[input_data1, input_data2]
替换可以解决问题。 - 为端到端模型拟合 MLP 时,输入应该是
x1_train
和x2_train
的列表,而不是串联的输入。预测时相同。