自动编码器不学习身份功能

Autoencoder not learning identity function

总的来说,我对机器学习有些陌生,我想做一个简单的实验来更熟悉神经网络自动编码器:制作一个非常基本的自动编码器来学习恒等函数。

我使用 Keras 是为了让生活更轻松,所以我首先这样做以确保它有效:

# Weights are given as [weights, biases], so we give
# the identity matrix for the weights and a vector of zeros for the biases
weights = [np.diag(np.ones(84)), np.zeros(84)]
model = Sequential([Dense(84, input_dim=84, weights=weights)])
model.compile(optimizer='sgd', loss='mean_squared_error')
model.fit(X, X, nb_epoch=10, batch_size=8, validation_split=0.3)

正如预期的那样,训练数据和验证数据中的损失均为零:

Epoch 1/10
97535/97535 [==============================] - 27s - loss: 0.0000e+00 - val_loss: 0.0000e+00
Epoch 2/10
97535/97535 [==============================] - 28s - loss: 0.0000e+00 - val_loss: 0.0000e+00

然后我尝试做同样的事情,但没有初始化身份函数的权重,期望经过一段时间的训练后它会学会它。它没有。我让它 运行 在不同的配置下多次运行 200 个时期,使用不同的优化器、损失函数,并添加 L1 和 L2 activity 正则化器。结果各不相同,但我得到的最好结果仍然很糟糕,看起来与原始数据完全不同,只是在相同的数字范围内。 数据只是一些在 1.1 左右波动的数字。我不知道激活层对这个问题是否有意义,我应该使用一个吗?

如果这一层的 "neural network" 不能学习像恒等函数这样简单的东西,我怎么能指望它学习更复杂的东西呢?我做错了什么?

编辑

为了获得更好的上下文,这里有一种方法可以生成与我正在使用的数据集非常相似的数据集:

X = np.random.normal(1.1090579, 0.0012380764, (139336, 84))

我怀疑这些值之间的差异可能太小了。损失函数最终具有不错的值(大约 1e-6),但其精度不足以使结果具有与原始数据相似的形状。也许我应该 scale/normalize 不知何故?感谢您的任何建议!

更新

最后,正如所建议的那样,问题在于数据集在 84 个值之间的变化太小,因此得到的预测实际上在绝对值(损失函数)上相当不错,但与原始数据相比数据,变化相去甚远。我通过将每个样本中的 84 个值标准化为样本均值并除以样本的标准差来解决这个问题。然后我使用原始均值和标准差对另一端的预测进行非规范化。我想这可以通过几种不同的方式来完成,但我是通过使用一些在张量上运行的 Lambda 层将 normalization/denormalization 添加到模型本身来实现的。这样所有的数据处理都被合并到模型中,这使得它更好用。如果您想查看实际代码,请告诉我。

我认为问题可能出在纪元数或初始化 X 的方式上。 我 运行 你的代码带有我的 X 100 个时期并打印了 argmax() 和权重的最大值,它非常接近恒等函数。

我正在添加我使用的代码片段

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import random
import pandas as pd

X = np.array([[random.random() for r in xrange(84)] for i in xrange(1,100000)])
model = Sequential([Dense(84, input_dim=84)], name="layer1")
model.compile(optimizer='sgd', loss='mean_squared_error')
model.fit(X, X, nb_epoch=100, batch_size=80, validation_split=0.3)

l_weights = np.round(model.layers[0].get_weights()[0],3)

print l_weights.argmax(axis=0)
print l_weights.max(axis=0)

我得到:

Train on 69999 samples, validate on 30000 samples
Epoch 1/100
69999/69999 [==============================] - 1s - loss: 0.2092 - val_loss: 0.1564
Epoch 2/100
69999/69999 [==============================] - 1s - loss: 0.1536 - val_loss: 0.1510
Epoch 3/100
69999/69999 [==============================] - 1s - loss: 0.1484 - val_loss: 0.1459
.
.
.
Epoch 98/100
69999/69999 [==============================] - 1s - loss: 0.0055 - val_loss: 0.0054
Epoch 99/100
69999/69999 [==============================] - 1s - loss: 0.0053 - val_loss: 0.0053
Epoch 100/100
69999/69999 [==============================] - 1s - loss: 0.0051 - val_loss: 0.0051
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83]
[ 0.85000002  0.85100001  0.79799998  0.80500001  0.82700002  0.81900001
  0.792       0.829       0.81099999  0.80800003  0.84899998  0.829       0.852
  0.79500002  0.84100002  0.81099999  0.792       0.80800003  0.85399997
  0.82999998  0.85100001  0.84500003  0.847       0.79699999  0.81400001
  0.84100002  0.81        0.85100001  0.80599999  0.84500003  0.824
  0.81999999  0.82999998  0.79100001  0.81199998  0.829       0.85600001
  0.84100002  0.792       0.847       0.82499999  0.84500003  0.796
  0.82099998  0.81900001  0.84200001  0.83999997  0.815       0.79500002
  0.85100001  0.83700001  0.85000002  0.79900002  0.84100002  0.79699999
  0.838       0.847       0.84899998  0.83700001  0.80299997  0.85399997
  0.84500003  0.83399999  0.83200002  0.80900002  0.85500002  0.83899999
  0.79900002  0.83399999  0.81        0.79100001  0.81800002  0.82200003
  0.79100001  0.83700001  0.83600003  0.824       0.829       0.82800001
  0.83700001  0.85799998  0.81999999  0.84299999  0.83999997]

当我只使用 5 个数字作为输入并打印出实际重量时,我得到了这个:

array([[ 1.,  0., -0.,  0.,  0.],
       [ 0.,  1.,  0., -0., -0.],
       [-0.,  0.,  1.,  0.,  0.],
       [ 0., -0.,  0.,  1., -0.],
       [ 0., -0.,  0., -0.,  1.]], dtype=float32)