Keras 自动编码器

Keras autoencoder

我很久以前在 Java 中使用神经网络,现在我正在尝试学习在 Python 中使用 TFLearn 和 Keras。

我正在尝试构建一个自动编码器,但是当我遇到问题时,我向您展示的代码没有瓶颈特征(这应该会使问题变得更容易)。

在下面的代码中,我创建了网络、数据集(两个随机变量),并在训练后绘制了每个预测变量与其输入之间的相关性。

网络应该学习的是输出与接收到的相同的输入。

import matplotlib.pyplot as plt
import numpy as np
from keras.layers import Input, Dense
from keras.models import Model
from keras.models import load_model
from loaders.nslKddCup99.nslKddCup99Loader import NslKddCup99

def buildMyNetwork(inputs, bottleNeck):
    inputLayer = Input(shape=(inputs,))
    autoencoder = Dense(inputs*2, activation='relu')(inputLayer)
    autoencoder = Dense(inputs*2, activation='relu')(autoencoder)
    autoencoder = Dense(bottleNeck, activation='relu')(autoencoder)
    autoencoder = Dense(inputs*2, activation='relu')(autoencoder)
    autoencoder = Dense(inputs*2, activation='relu')(autoencoder)
    autoencoder = Dense(inputs, activation='sigmoid')(autoencoder)
    autoencoder = Model(input=inputLayer, output=autoencoder)
    autoencoder.compile(optimizer='adadelta', loss='mean_squared_error')
    return autoencoder


dataSize = 1000
variables = 2
data = np.zeros((dataSize,variables))
data[:, 0] = np.random.uniform(0, 0.8, size=dataSize)
data[:, 1] = np.random.uniform(0, 0.1, size=dataSize)

trainData, testData = data[:900], data[900:]

model = buildMyNetwork(variables,2)
model.fit(trainData, trainData, nb_epoch=2000)
predictions = model.predict(testData)

for x in range(variables):
    plt.scatter(testData[:, x], predictions[:, x])
    plt.show()
    plt.close()

尽管有些时候结果是可以接受的,但很多时候不是,我知道神经网络有权重随机初始化,因此它可能会收敛到不同的解决方案,但我认为这太多了,可能会有一些错误在我的代码中。

Sometimes correlation is acceptable

Others is quite lost

**

更新:

**

谢谢 Marcin Możejko!

确实是这个问题,我最初的问题是因为我试图构建一个自动编码器,所以为了与标题保持一致,这里有一个自动编码器的例子(只是制作了一个更复杂的数据集并改变了激活函数) :

import matplotlib.pyplot as plt
import numpy as np
from keras.layers import Input, Dense
from keras.models import Model
from keras.models import load_model
from loaders.nslKddCup99.nslKddCup99Loader import NslKddCup99

def buildMyNetwork(inputs, bottleNeck):
    inputLayer = Input(shape=(inputs,))
    autoencoder = Dense(inputs*2, activation='tanh')(inputLayer)
    autoencoder = Dense(inputs*2, activation='tanh')(autoencoder)
    autoencoder = Dense(bottleNeck, activation='tanh')(autoencoder)
    autoencoder = Dense(inputs*2, activation='tanh')(autoencoder)
    autoencoder = Dense(inputs*2, activation='tanh')(autoencoder)
    autoencoder = Dense(inputs, activation='tanh')(autoencoder)
    autoencoder = Model(input=inputLayer, output=autoencoder)
    autoencoder.compile(optimizer='adadelta', loss='mean_squared_error')
    return autoencoder


dataSize = 1000
variables = 6
data = np.zeros((dataSize,variables))
data[:, 0] = np.random.uniform(0, 0.5, size=dataSize)
data[:, 1] = np.random.uniform(0, 0.5, size=dataSize)
data[:, 2] = data[:, 0] + data[:, 1]
data[:, 3] = data[:, 0] * data[:, 1]
data[:, 4] = data[:, 0] / data[:, 1]
data[:, 5] = data[:, 0] ** data[:, 1]

trainData, testData = data[:900], data[900:]

model = buildMyNetwork(variables,2)
model.fit(trainData, trainData, nb_epoch=2000)
predictions = model.predict(testData)

for x in range(variables):
    plt.scatter(testData[:, x], predictions[:, x])
    plt.show()
    plt.close()

在这个例子中,我使用了 TanH 激活函数,但我尝试了其他函数,效果也很好。 数据集现在有 6 个变量,但自动编码器有 2 个神经元的瓶颈;只要变量 2 到 5 由变量 0 和 1 组合而成,自动编码器只需要传递这两个变量的信息并学习函数以在解码阶段生成其他变量。 上面的例子显示了所有函数是如何学习的,除了一个,除法...我还不知道为什么。

这是一个非常酷的用例,可以了解和研究训练神经网络的困难。

事实上,我看到了多种可能性:

1) 如果 2 个不同的 运行s 之间有非常不同的结果,它可能来自初始化。但它也可能来自您的数据集,每个 运行 都不相同。

2) 使网络难以学习相关性的是你的激活,更准确地说是 sigmoid。我会将非线性更改为另一个 'relu'。没有理由在这里使用 Sigmoid,我知道它在 0 附近看起来是线性的,但实际上并不是线性的。要产生 0.7,原始输出必须相当高。您为该网络想到的 "easy" 关系并不容易,因为您对其进行了约束。

3)如果有时不好,可能需要更多的epochs才能收敛?

4) 也许您需要更大的数据集?理论上你很好,因为你的网络中有 900 个样本 < 200 个参数,但谁知道呢......

我无法尝试所有这些,因为我现在正在使用 phone,但请随意尝试并根据我给您的提示进行故障排除 :) 希望这会有所帮助。

编辑:

经过一些试验,正如 Marcin Możejko 所说,问题出在激活上。您可以阅读他的回答以了解有关问题所在的更多信息。修复它的方法是更改​​您的激活。如果你是'relu'的粉丝,可以使用这个激活的特殊版本。为此,使用 LeakyRelu layer 并且不要为上一层设置激活,如下所示:

    autoencoder = Dense(inputs*2)(inputLayer)
    autoencoder = LeakyReLU(alpha=0.3)(autoencoder)

这将解决您陷入非最佳解决方案的情况。 否则,正如我上面所说,您可以尝试不使用任何非线性。你的损失会下降得更快,不会卡住。

请记住,引入非线性是为了让网络在数据中找到更复杂的模式。在你的情况下,你有最简单的线性模式。

我认为您的案例相对容易解释为什么您的网络可能无法学习身份函数。让我们看一下您的示例:

  1. 您的输入来自 2d space - 由于均匀分布,它不在 1d0d 子流形上。从这里很容易看出,为了从您的自动编码器 每个 层获得一个身份函数,应该能够表示一个函数,其范围至少是 二维 ,因为最后一层的输出也应该位于 2d 流形上。
  2. 让我们检查一下您的网络并检查它是否满足条件需要:

    inputLayer = Input(shape=(2,))
    autoencoder = Dense(4, activation='relu')(inputLayer)
    autoencoder = Dense(4, activation='relu')(autoencoder)
    autoencoder = Dense(2, activation='relu')(autoencoder) # Possible problems here
    

    您可能会看到瓶颈可能会导致问题 - 对于这一层,可能很难满足第一点的条件。对于这一层 - 为了获得二维输出范围,您需要具有权重,这将使所有示例不落入 relu 的饱和区域(在这种情况下,所有这些样本将被压缩为 0 在其中一个单位中 - 是什么使得范围不可能成为 "fully" 2d)。所以基本上 - 这不会发生的可能性相对较小。同样反向传播不会将这个单元移动到这个区域的概率也不能忽略。

更新:

在评论中询问了为什么优化器无法防止或撤消饱和的问题。这是重要 relu 缺点之一的示例 - 一旦示例落入 relu 饱和区域 - 此示例不会直接参与给定单元的学习。它可以通过影响以前的单位来影响它 - 但由于 0 导数 - 这种影响不是直接的。所以基本上 不饱和示例 来自副作用 - 而不是优化器的直接作用。

为了可视化重建,可以使用 MNIST 数字并训练线性自动编码器(这次让我们使用 sigmoid 激活):

from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense, Flatten, Reshape
encoded_dim = 2
encoder = Sequential([
                      Flatten(input_shape=(28,28)),
                      Dense(256, activation='sigmoid'),
                      Dense(64, activation='sigmoid'),
                      Dense(encoded_dim)
])
decoder = Sequential([
                      Dense(64, activation='sigmoid', input_shape=(encoded_dim,)),
                      Dense(256, activation='sigmoid'),
                      Dense(28*28, activation='sigmoid'),
                      Reshape((28,28))
])
autoencoder = Model(inputs=encoder.inputs, outputs=decoder(encoder.outputs))
autoencoder.summary()
#Model: "model"
#_________________________________________________________________
#Layer (type)                 Output Shape              Param #   
#=================================================================
#flatten_2_input (InputLayer) [(None, 28, 28)]          0         
#_________________________________________________________________
#flatten_2 (Flatten)          (None, 784)               0         
#_________________________________________________________________
#dense_12 (Dense)             (None, 256)               200960    
#_________________________________________________________________
#dense_13 (Dense)             (None, 64)                16448     
#_________________________________________________________________
#dense_14 (Dense)             (None, 2)                 130       
#_________________________________________________________________
#sequential_5 (Sequential)    (None, 28, 28)            218320    
#=================================================================
#Total params: 435,858
#Trainable params: 435,858
#Non-trainable params: 0

加载 MNIST 数据:

import tensorflow as tf
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
x_train = x_train.astype('float32')/255.
x_test = x_test.astype('float32')/255.

现在让我们在 MNIST 数据集上训练模型;

autoencoder.compile(loss='binary_crossentropy')
autoencoder.fit(x=x_train, y=x_train, epochs=10, batch_size=32)
# Epoch 1/10
# 1875/1875 [==============================] - 8s 4ms/step - loss: 0.2311
# Epoch 2/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.2009
# Epoch 3/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1911
# Epoch 4/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1864
# Epoch 5/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1832
# Epoch 6/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1807
# Epoch 7/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1786
# Epoch 8/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1771
# Epoch 9/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1757
# Epoch 10/10
# 1875/1875 [==============================] - 7s 4ms/step - loss: 0.1746

下面的动画展示了自动编码器在不同时期重建一些随机选择的图像,正如我们所看到的,随着模型训练的时期越来越多,重建误差变得越来越小: