由于NaN掩蔽,model.get_weights()在训练后返回NaN数组

时间:2017-05-30 09:28:45

标签: python keras

我正在尝试训练LSTM来对不同长度的序列进行分类。我想得到这个模型的权重,所以我可以在有状态版本的模型中使用它们。在训练之前,重量是正常的。此外,培训似乎成功运行,错误逐渐减少。但是,当我将掩码值从-10更改为np.Nan时,mod.get_weights()开始返回NaN的数组,并且验证错误会突然降至接近零的值。为什么会这样?

from keras import models
from keras.layers import Dense, Masking, LSTM
from keras.optimizers import RMSprop
from keras.losses import categorical_crossentropy
from keras.preprocessing.sequence import pad_sequences

import numpy as np
import matplotlib.pyplot as plt


def gen_noise(noise_len, mag):
    return np.random.uniform(size=noise_len) * mag


def gen_sin(t_val, freq):
    return 2 * np.sin(2 * np.pi * t_val * freq)


def train_rnn(x_train, y_train, max_len, mask, number_of_categories):
    epochs = 3
    batch_size = 100

    # three hidden layers of 256 each
    vec_dims = 1
    hidden_units = 256
    in_shape = (max_len, vec_dims)

    model = models.Sequential()

    model.add(Masking(mask, name="in_layer", input_shape=in_shape,))
    model.add(LSTM(hidden_units, return_sequences=False))
    model.add(Dense(number_of_categories, input_shape=(number_of_categories,),
              activation='softmax', name='output'))

    model.compile(loss=categorical_crossentropy, optimizer=RMSprop())

    model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
              validation_split=0.05)

    return model


def gen_sig_cls_pair(freqs, t_stops, num_examples, noise_magnitude, mask, dt=0.01):
    x = []
    y = []

    num_cat = len(freqs)

    max_t = int(np.max(t_stops) / dt)

    for f_i, f in enumerate(freqs):
        for t_stop in t_stops:
            t_range = np.arange(0, t_stop, dt)
            t_len = t_range.size

            for _ in range(num_examples):
                sig = gen_sin(f, t_range) + gen_noise(t_len, noise_magnitude)
                x.append(sig)

                one_hot = np.zeros(num_cat, dtype=np.bool)
                one_hot[f_i] = 1
                y.append(one_hot)

    pad_kwargs = dict(padding='post', maxlen=max_t, value=mask, dtype=np.float32)
    return pad_sequences(x, **pad_kwargs), np.array(y)


if __name__ == '__main__':
    noise_mag = 0.01
    mask_val = -10
    frequencies = (5, 7, 10)
    signal_lengths = (0.8, 0.9, 1)
    dt_val = 0.01

    x_in, y_in = gen_sig_cls_pair(frequencies, signal_lengths, 50, noise_mag, mask_val)
    mod = train_rnn(x_in[:, :, None], y_in, int(np.max(signal_lengths) / dt_val), mask_val, len(frequencies))

即使我将网络架构更改为return_sequences=True并使用Dense包裹TimeDistributed图层,也不会删除LSTM图层,这种情况仍然存在。

3 个答案:

答案 0 :(得分:3)

我遇到了同样的问题。在你的情况下,我可以看到它可能是不同的,但有人可能有同样的问题,来自谷歌。所以在我的情况下,我将sample_weight参数传递给fit()方法,当样本权重包含一些零时,get_weights()返回一个带有NaN的数组。当我省略sample_weight = 0的样本时(如果sample_weight = 0则它们无用),它开始起作用。

答案 1 :(得分:0)

get_weights()实例的

keras.engine.training.Model方法应检索模型的权重。

这应该是Numpy数组的平面列表,换句话说,这应该是模型中所有权重张量的列表。

mw = model.get_weights()
print(mw)

如果您获得NaN,则有特定含义。您正在处理消失的梯度问题。 (在某些情况下,甚至在爆炸渐变中也是如此。)

我将首先尝试更改模型,以减少渐变消失的机会。尝试先减少hidden_units,然后对您的激活进行标准化。

即使LSTM可以解决梯度消失或爆炸的问题,您也需要从(-1,1)间隔设置正确的激活。

请注意,此间隔是浮点数最精确的地方。

在掩蔽层下使用np.nan是不可预测的操作,因为您无法与np.nan进行比较。

尝试print(np.nan==np.nan),它将返回False。这是IEEE 754标准的一个老问题。

或者实际上可能是基于IEEE 754标准弱点的Tensorflow中的错误。

答案 2 :(得分:0)

权重确实在变化。不变的权重从图像的边缘开始,并且它们可能没有改变,因为边缘对分类数字没有帮助。 检查选择特定的图层并查看结果:

print(model.layers[70].get_weights()[1])

70:是我的情况下最后一层的编号。