模型不使用稀疏数据集学习(LSTM with Keras)

数据挖掘 Python 神经网络 深度学习 喀拉斯 lstm
2022-03-05 00:40:57

这个分类问题显然很简单,我不知道为什么它不起作用,也许我在做一个概念错误。我正在尝试制作一个预测器,它将时钟上的分钟分类0为无请求或1该时间瞬间的请求。到目前为止,该模型似乎无法学会0在所有请求发生之前给出一切或置零。到目前为止,我得到的最好的情况是:

在此处输入图像描述

我一直在尝试实现我学到的与神经网络相关的所有东西,我的代码以下列方式工作:

  1. 创建时钟。
  2. 创建一些请求(我使它们持续更长时间,因此数据集不那么稀疏)。
  3. 缩放(MinMax)自变量(时钟)。
  4. 为稀疏数据集创建一个自定义损失函数(我已经使用常规 logits 进行了尝试,但它只能对几乎所有内容进行归零;所以我惩罚了在请求瞬间犯下的错误)。
  5. 创建由 3 个堆叠的 LSTM 层组成的模型(已尝试过常规 NN 和 LSTM)。

其他也尝试过的技术是 Dropout、Gradient Clipping(用于爆炸梯度)和 ADAM 的极小学习率(大约)。基本上,我只能达到 73.33% 左右的准确率。105

下面的代码确实比我想的要长,但我希望它也很容易阅读。谢谢你试图帮助我。

# Data Pre-processing

## The Clock

clock = []
for i in range(0,24):
    for j in range(0,60):
        if i < 10:
            if j < 10:
                clock.append('0' + str(i) + '0' + str(j))
            else:
                clock.append('0' + str(i) + str(j))
        else:
            if j < 10:
                clock.append(str(i) + '0' + str(j))
            else:
                clock.append(str(i) + str(j))

## Requests

levels = 2
request_full = [0]*len(clock)
request_1300 = []
request_1500 = []
request_1800 = []
request_2100 = []
request_2300 = []
for i in range(0,60):
    if i < 10:
        request_1300.append(['13' + '0' + str(i), 1])
        request_1500.append(['15' + '0' + str(i), 1])
        request_1800.append(['18' + '0' + str(i), 1])
        request_2100.append(['21' + '0' + str(i), 1])
        request_2300.append(['23' + '0' + str(i), 1])
    else:
        request_1300.append(['13' + str(i), 1])
        request_1500.append(['15' + str(i), 1])
        request_1800.append(['18' + str(i), 1])
        request_2100.append(['21' + str(i), 1])
        request_2300.append(['23' + str(i), 1])

request_list = [i for i in 
                request_1300 + 
                request_1500 + 
                request_1800 + 
                request_2100 + 
                request_2300]

for i,j in request_list:
    idx = clock.index(i)
    request_full[idx] = j

import numpy as np
import pandas as pd

df = pd.DataFrame({'clock': clock, 'requests': request_full})

df.to_csv('test1.csv', sep = ',')

clock = df['clock'].values
clock = np.reshape(clock, (len(clock), 1))
requests = df['requests'].values
requests = np.reshape(requests, (len(requests), 1))

## Feature Scaling
from sklearn.preprocessing import MinMaxScaler

sc = MinMaxScaler(feature_range = (0, 1))
training_set_scaled = sc.fit_transform(clock)

X_train = []
y_train = []
for i in range(60, len(clock)):
    X_train.append(training_set_scaled[i-60:i, 0])
    y_train.append(requests[i, 0])
X_train, y_train = np.array(X_train), np.array(y_train)

X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
from keras import optimizers
import tensorflow as tf

def sparse_penalty_logits(y_true, y_pred):
    penalty = 10

    loss = tf.where(tf.greater(y_true, 0),
                    penalty*tf.nn.sigmoid_cross_entropy_with_logits(logits = y_pred,
                                                                    labels = y_true),
                    tf.nn.sigmoid_cross_entropy_with_logits(logits = y_pred,
                                                            labels = y_true))

    return loss

# Initialising the RNN
classifier = Sequential()

# Adding the first LSTM layer and some Dropout regularisation
classifier.add(LSTM(units = 60, 
                    return_sequences = True,
                    input_shape = (X_train.shape[1], 1)))
classifier.add(Dropout(0.2))


# 2nd Layer
classifier.add(LSTM(units = 60, 
                    return_sequences = True))
#classifier.add(Dropout(0.2))

# 3rd Layer
classifier.add(LSTM(units = 60, 
                    return_sequences = False))
#classifier.add(Dropout(0.2))

# Adding the output layer
classifier.add(Dense(units = 1, 
                     activation = 'sigmoid'))

# Compiling the RNN
adam = optimizers.Adam(lr = 10**(-5), 
                       clipnorm = 1, 
                       clipvalue = 0.5)

classifier.compile(optimizer = adam, 
                   loss = sparse_penalty_logits,
                   metrics = ['binary_accuracy'])

# Fitting the RNN to the Training set
classifier.fit(X_train, 
               y_train, 
               epochs = 100)


# Making the predictions with the dataset
y_pred = classifier.predict(X_train)
y_pred_bin = (y_pred > 0.5)

from sklearn.metrics import confusion_matrix

cm = confusion_matrix(y_train, y_pred_bin)

# Plotting
import matplotlib.pyplot as plt

plt.plot(y_pred, color = 'green', label = 'model')
plt.plot(y_pred_bin, color = 'red', label = 'model binary')
plt.plot(y_train, color = 'blue', label = 'training')
plt.legend()
plt.show()
plt.close()
2个回答

首先,这是一个相当长的解决过程。我不得不请求朋友的帮助,而后者又把我介绍给了他的一个朋友。解决方案对我来说似乎有些直观,但是,我根本没有注意到。

基本上,由于我们只有一行数据要查看,因此对于 NN 而言,拟合将过于尖锐,因此它很可能始终处于平稳状态并坚持只吐出零。为了让神经网络更容易,建议的解决方案是对我们的数据应用一些噪声,这样系统就不会认为它需要非常精确的拟合才能完成工作。

尽管有这个小技巧,神经网络仍然很难很好地拟合,因为它仍然是一行,所以,现在,如果我们使用 ADAM(它动态降低学习率),它可能会陷入局部最小值并且永远不会出来。最后一个技巧是使用非常高的学习率,在我的例子中,在 0.2 到 0.3 之间。学习过程也将不稳定,因此,最后,有必要使用带有回调的荒谬数量的 epoch(20,000)来注册最佳权重。这样,我朋友的朋友解决方案让我们达到了 99.8% 的准确率。

尽管性能很好,但坦率地说,他和我都同意这个问题最可靠和最快速的解决方案实际上是使用决策树类型的算法。

由于作者的要求,我无法在此处提供该解决方案的源代码。

我建议您尝试神经泊松过程。您尝试预测的是具有固定(或霍克斯过程中的变量)密度函数的点过程。因此,我不确定将其简单地建模为一个序列能否为您提供合理的性能。