Keras顺序神经网络无法通过完美解释的变量进行学习-为什么?

时间:2018-12-23 10:36:07

标签: python tensorflow machine-learning keras

我在使用Python中的神经网络进行训练和预测时间序列时遇到一些麻烦。

我正在使用的数据集非常简单:由零和一组成的目标列。只有一个解释变量,它是目标值偏移。也就是说,如果目标在时间t预测为1,则说明性列在时间t-1将为1。因此,我希望这种情况易于预测。要使用等于我的数据,可以执行以下操作:

# Load packages:
import pandas as pd
from pandas import read_csv
from keras.models import Sequential
from keras.layers import Dense
import random
from keras.layers import GRU
from sklearn.utils import class_weight
from matplotlib.patches import Patch
from matplotlib.lines import Line2D
import numpy as np
import matplotlib.pyplot as plt

# Create dataset
a = [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0.,
0., 0., 1., 1., 1., 1., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 1., 1., 0., 0., 0., 0., 0., 1., 0., 1., 1., 1., 1., 1., 1., 1.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0.]
b = [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0.,
 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 1., 1., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 1., 1., 0., 0., 0., 0., 0., 1., 0., 1., 1., 1., 1., 1., 1.,
1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0.]
dataset = pd.DataFrame({'a':a, 'b':b})

# Split into X and y data
class_X, class_y = dataset.values[:, :-1], dataset.values[:, -1]

# Last column in the dataframe should be the one we want to predict
def spitIntoTrainAndTest1(dataFrame):
values = dataFrame.values
# split into input and outputs
train_X, train_y = values[:, :-1], values[:, -1]
# reshape input to be 3D [samples, timesteps, features]
train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))

return train_X, train_y

# Split classification into test and training data
X_clas2, y_clas2 = spitIntoTrainAndTest1(dataset)

# Used in RNN
X_clas_RNN = np.squeeze(X_clas2, axis=1)
y_clas_RNN = np.expand_dims(y_clas2, axis=1)

# Used in GRU
lengthOfDataset = len(X_clas2)
train_X_clas2 = np.squeeze(X_clas2, axis=1)
X_clas_GRU = np.reshape(train_X_clas2, (lengthOfDataset,1,1))
y_clas_GRU = y_clas_RNN

下一部分是关于对数据拟合模型:

# Parameters in the fitting
numberOfEpochs = 100
batchSize = 50
printFit = 1# 1 = true
randomSeedNumber = 164
validationSplitRatio = 0.33

# ORDINARY RNN MODEL:

# create model
random.seed(randomSeedNumber)
model_RNN = Sequential()
model_RNN.add(Dense(32, input_dim=1, activation='relu'))
model_RNN.add(Dense(32, activation='relu'))
model_RNN.add(Dense(1, activation='sigmoid'))
model_RNN.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
RNN_history = model_RNN.fit(X_clas_RNN, y_clas_RNN, 
validation_split=validationSplitRatio, epochs=numberOfEpochs, 
batch_size=batchSize, verbose=1)

# WEIGHTED GRU MODEL:

model_GRU_weight = Sequential()
model_GRU_weight.add(GRU(1, input_shape=(1,1)))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(32, activation='relu'))
model_GRU_weight.add(Dense(1, activation='softmax'))
model_GRU_weight.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
#model_GRU_weight.fit(train_X_clas3, train_y_class, epochs=100, batch_size=500, class_weight = 'auto')
GRU_weight_history = model_GRU_weight.fit(X_clas_GRU, y_clas_GRU, validation_split=validationSplitRatio, 
                                      epochs=numberOfEpochs, batch_size=batchSize, verbose = printFit, 
                                      class_weight = 'auto', shuffle=False)

最后,我要评估结果/预测:

# Combine the predictions on the test dataset

# Predicitons made
firstValObs = round(validationSplitRatio*len(X_clas_RNN))+1
valSet2 = X_clas_RNN[firstValObs:,:]
valSet3 = X_clas_GRU[firstValObs:,:]
actuals = pd.DataFrame(y_clas_RNN[firstValObs:,:])
predictions_RNN = np.round(model_RNN.predict(valSet2))
predictions_GRU_weight = np.round(model_GRU_weight.predict(valSet3))

timeSequence = np.r_[1:(len(predictions_GRU_weight)+1)]
firstValObs = round(validationSplitRatio*len(X_clas_RNN))+1

# Plot predictions
numberOfRows = 3
numberOfCols = 1
minY=-0.1
maxY = 1.1

plt.figure(1)

plt.subplot(numberOfRows, numberOfCols, 1)
plt.plot(timeSequence, actuals)
plt.ylim((minY,maxY))
plt.title('Actuals')
plt.xticks([])
plt.yticks([])
plt.subplot(numberOfRows, numberOfCols, 2)
plt.plot(timeSequence, predictions_RNN)
plt.ylim((minY,maxY))
plt.title('RNN predictions')
plt.xticks([])
plt.yticks([])
plt.subplot(numberOfRows, numberOfCols, 3)
plt.plot(timeSequence, predictions_GRU_weight)
plt.ylim((minY,maxY))
plt.title('GRU weighted predictions')
plt.xticks([])
plt.yticks([])
plt.tight_layout()

plt.show()

获得的绘图如下:

enter image description here

目前,RNN正在做出正确的预测。如果相反,我将代码更改为:

# create model
random.seed(randomSeedNumber)
model_RNN = Sequential()
model_RNN.add(Dense(32, input_dim=1, activation='relu'))
model_RNN.add(Dense(8, activation='relu'))
model_RNN.add(Dense(1, activation='sigmoid'))
model_RNN.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
RNN_history = model_RNN.fit(X_clas_RNN, y_clas_RNN, 
validation_split=validationSplitRatio, epochs=numberOfEpochs, 
batch_size=batchSize, verbose=1)

结果将类似于:

enter image description here

我觉得有些奇怪。

我有点惊讶,因为在我看来它必须在每一层中有足够数量的神经元才能做出这种简单的预测(将序列移动一个周期)。真的可以是第二个代码段中RNN中神经元的数量不够吗?

我不明白为什么加权GRU无法做出更好的预测。如果第一个问题的答案是更多数量的神经元可以改善性能,那么我认为这里应该足够了。另外,我发现很难接受它的过度拟合,因为仅将其过渡一个时期应该非常简单。尽管如此,它始终会预测1-您对此有何解释?

此外,我想知道输入参数的值(历元,批大小,层数,每层神经元数)是否有任何经验法则。我实际上考虑过的数据集具有相同的长度(大约500),但是有5个输入变量(X),而不是上述示例中的一列。

请,如果您对我做错的事情有任何想法或应该考虑,请立即添加评论。

预先感谢

1 个答案:

答案 0 :(得分:0)

首先,感谢您的回答,caseWestern。

我确实做了一些更改:

# ORDINARY RNN MODEL:

# create model
random.seed(randomSeedNumber)
model_RNN = Sequential()
model_RNN.add(Dense(1, input_dim=1, activation='relu'))
model_RNN.add(Dense(1, activation='relu'))
model_RNN.add(Dense(1, activation='sigmoid'))
model_RNN.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
RNN_history = model_RNN.fit(X_clas_RNN, y_clas_RNN, validation_split=validationSplitRatio, epochs=numberOfEpochs, batch_size=batchSize, verbose=1)

# WEIGHTED GRU MODEL:

model_GRU_weight = Sequential()
model_GRU_weight.add(GRU(1, input_shape=(1,1)))
model_GRU_weight.add(Dense(1, activation='relu'))
model_GRU_weight.add(Dense(1, activation='softmax'))
model_GRU_weight.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
#model_GRU_weight.fit(train_X_clas3, train_y_class, epochs=100, batch_size=500, class_weight = 'auto')
GRU_weight_history = model_GRU_weight.fit(X_clas_GRU, y_clas_GRU, validation_split=validationSplitRatio, 
                                          epochs=numberOfEpochs, batch_size=batchSize, verbose = printFit, 
                                          class_weight = 'auto', shuffle=False)

我得到的结果仍然像这样: enter image description here

关于过于复杂的模型:因为数据中没有噪音(因为它只是移位,所以它是完全干净的),我看不到它应该过度拟合。另外,我同意一个简单的模型就足够了,但是我希望一个更加灵活/复杂的模型也能够捕获它,因为没有“干扰它”的噪音。请随时提出您的想法。

如上所述,我的成绩没有改善-我做了,您有何评论?