Autoencoder不学习身份功能

And*_*ios 7 machine-learning neural-network autoencoder keras

我对机器学习有点新意,我想做一个简单的实验来更熟悉神经网络自动编码器:制作一个非常基本的自动编码器来学习身份功能.

我正在使用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)
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

然后我尝试做同样的事情,但没有初始化身份函数的权重,期望经过一段时间的训练后,它将学习它.它没有.我让它在不同的配置中运行200个时代,使用不同的优化器,丢失函数以及添加L1和L2活动正则化器.结果各不相同,但我得到的最好的仍然非常糟糕,看起来没有原始数据,只是在同一数值范围内.数据只是一些数字在1.1左右振荡.我不知道激活层是否对这个问题有意义,我应该使用它吗?

如果一层的"神经网络"无法学习像身份函数这样简单的东西,我怎么能指望它学习更复杂的东西呢?我究竟做错了什么?

编辑

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

X = np.random.normal(1.1090579, 0.0012380764, (139336, 84))
Run Code Online (Sandbox Code Playgroud)

我怀疑值之间的差异可能太小.损失函数最终具有不错的值(大约1e-6),但结果的精确度不足以使其具有与原始数据类似的形状.也许我应该以某种方式扩展/规范它?谢谢你的建议!

UPDATE

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

Oha*_*dok 3

我相信问题可能是纪元数或初始化 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)
Run Code Online (Sandbox Code Playgroud)

我得到:

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]
Run Code Online (Sandbox Code Playgroud)

当我只使用 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)
Run Code Online (Sandbox Code Playgroud)