【问题标题】:Autoencoder not learning identity function自动编码器不学习身份功能
【发布时间】:2017-05-24 09:17:55
【问题描述】:

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

我使用 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 个 epoch,使用了不同的优化器、损失函数,并添加了 L1 和 L2 活动正则化器。结果各不相同,但我得到的最好的结果仍然很糟糕,看起来与原始数据完全不同,只是在相同的数字范围内。 数据只是一些在 1.1 附近波动的数字。我不知道激活层是否对这个问题有意义,我应该使用一个吗?

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

编辑

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

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

我怀疑这些值之间的差异可能太小了。损失函数最终具有不错的值(大约1e-6),但精度不足以使结果具有与原始数据相似的形状。也许我应该以某种方式对其进行缩放/标准化?感谢您的建议!

更新

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

【问题讨论】:

  • 你用的是什么版本的keras?这个 model = Sequential(Dense(84, input_dim=84, weights=weights)) 在最新 (1.1.2) 中不起作用
  • @y300 对不起,我错过了Dense 层周围的[],因为Sequentiallayers 参数应该是一个可迭代的层。我现在修好了。顺便说一句,我正在使用 keras 1.2.0。
  • 你能分享你的X 吗? optimizer='adam' 对我来说效果很好

标签: machine-learning neural-network keras autoencoder


【解决方案1】:

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

我正在添加我使用的代码 sn-p

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)

【讨论】:

  • 有趣!所以也许更高维度的输入会阻止它正确学习确切的身份函数。除此之外,你对我初始化 X 的方式是什么意思?我在想也许输入的规模不是很好。它们是应该绘制的值,84 个值之间的差异非常小。该模型预测的值“接近”原始值,但变化是无稽之谈。也许我应该以某种方式规范化/缩放输入数据?有什么建议吗?谢谢!!
  • 您没有在原始帖子中写下 X 的外观,所以我无法判断这是否是问题所在。尝试运行我的代码,看看你是否可以让它与你的数据一起工作。我使用随机数进行初始化。如果您觉得此答案有帮助,请考虑接受它作为正确答案。
  • 我在问题中提到 X 是一些在 1.1 附近波动的值。我在问题中添加了一种更具体的生成 X 的方法,所以也许现在您可以更好地了解可能发生的情况。
猜你喜欢
  • 2017-09-03
  • 2019-02-26
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-21
  • 2018-06-12
  • 2018-11-04
相关资源
最近更新 更多