IVR*_*IVR 5 time-series lstm keras tensorflow sequence-to-sequence
我正在研究序列预测问题,并且在这方面没有太多经验,因此下面的一些问题可能很幼稚。
仅供参考:我在这里创建了一个重点关注 CRF 的后续问题
我有以下问题:
我想预测多个非独立变量的二元序列。
输入:
我有一个包含以下变量的数据集:
此外,假设以下情况:
binary_signal_group_A和binary_signal_group_B是我想使用(1)它们过去的行为和(2)从每个时间戳提取的附加信息来预测的 2 个非独立变量。
到目前为止我所做的:
# required libraries
import re
import numpy as np
import pandas as pd
from keras import Sequential
from keras.layers import LSTM
data_length = 18 # how long our data series will be
shift_length = 3 # how long of a sequence do we want
df = (pd.DataFrame # create a sample dataframe
.from_records(np.random.randint(2, size=[data_length, 3]))
.rename(columns={0:'a', 1:'b', 2:'extra'}))
# NOTE: the 'extra' variable refers to a generic predictor such as for example 'is_weekend' indicator, it doesn't really matter what it is
# shift so that our sequences are in rows (assuming data is sorted already)
colrange = df.columns
shift_range = [_ for _ in range(-shift_length, shift_length+1) if _ != 0]
for c in colrange:
for s in shift_range:
if not (c == 'extra' and s > 0):
charge = 'next' if s > 0 else 'last' # 'next' variables is what we want to predict
formatted_s = '{0:02d}'.format(abs(s))
new_var = '{var}_{charge}_{n}'.format(var=c, charge=charge, n=formatted_s)
df[new_var] = df[c].shift(s)
# drop unnecessary variables and trim missings generated by the shift operation
df.dropna(axis=0, inplace=True)
df.drop(colrange, axis=1, inplace=True)
df = df.astype(int)
df.head() # check it out
# a_last_03 a_last_02 ... extra_last_02 extra_last_01
# 3 0 1 ... 0 1
# 4 1 0 ... 0 0
# 5 0 1 ... 1 0
# 6 0 0 ... 0 1
# 7 0 0 ... 1 0
# [5 rows x 15 columns]
# separate predictors and response
response_df_dict = {}
for g in ['a','b']:
response_df_dict[g] = df[[c for c in df.columns if 'next' in c and g in c]]
# reformat for LSTM
# the response for every row is a matrix with depth of 2 (the number of groups) and width = shift_length
# the predictors are of the same dimensions except the depth is not 2 but the number of predictors that we have
response_array_list = []
col_prefix = set([re.sub('_\d+$','',c) for c in df.columns if 'next' not in c])
for c in col_prefix:
current_array = df[[z for z in df.columns if z.startswith(c)]].values
response_array_list.append(current_array)
# reshape into samples (1), time stamps (2) and channels/variables (0)
response_array = np.array([response_df_dict['a'].values,response_df_dict['b'].values])
response_array = np.reshape(response_array, (response_array.shape[1], response_array.shape[2], response_array.shape[0]))
predictor_array = np.array(response_array_list)
predictor_array = np.reshape(predictor_array, (predictor_array.shape[1], predictor_array.shape[2], predictor_array.shape[0]))
# feed into the model
model = Sequential()
model.add(LSTM(8, input_shape=(predictor_array.shape[1],predictor_array.shape[2]), return_sequences=True)) # the number of neurons here can be anything
model.add(LSTM(2, return_sequences=True)) # should I use an activation function here? the number of neurons here must be equal to the # of groups we are predicting
model.summary()
# _________________________________________________________________
# Layer (type) Output Shape Param #
# =================================================================
# lstm_62 (LSTM) (None, 3, 8) 384
# _________________________________________________________________
# lstm_63 (LSTM) (None, 3, 2) 88
# =================================================================
# Total params: 472
# Trainable params: 472
# Non-trainable params: 0
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # is it valid to use crossentropy and accuracy as metric?
model.fit(predictor_array, response_array, epochs=10, batch_size=1)
model_preds = model.predict_classes(predictor_array) # not gonna worry about train/test split here
model_preds.shape # should return (12, 3, 2) or (# of records, # of timestamps, # of groups which are a and b)
# (12, 3)
model_preds
# array([[1, 0, 0],
# [0, 0, 0],
# [1, 0, 0],
# [0, 0, 0],
# [1, 0, 0],
# [0, 0, 0],
# [0, 0, 0],
# [0, 0, 0],
# [0, 0, 0],
# [0, 0, 0],
# [1, 0, 0],
# [0, 0, 0]])
Run Code Online (Sandbox Code Playgroud)
问题:
这里的主要问题是:我如何让它工作,以便模型能够预测两组的下一个 N 序列?
另外,我想问以下问题:
非常感谢!
我将按顺序回答所有问题
我如何让它工作,以便模型能够预测两组的下一个 N 序列?
我建议对您的模型进行两处修改。
第一个是对最后一层使用 sigmoid 激活。
为什么??考虑二元交叉熵损失函数(我从这里借用了方程)
其中L是计算损失, p是网络预测,y是目标值。
损失定义为。如果 p 在此开区间范围之外,则损失未定义。keras中 lstm 层的默认激活为 tanh,其输出范围为 (-1, 1)。这意味着模型的输出不适合二元交叉熵损失。如果你尝试训练模型,你最终可能会遭受
nan损失。
第二个修改(是第一个修改的一部分)要么在最后一层之前添加 sigmoid 激活。为此,您有三个选择。
尽管所有情况都可行,但我建议使用带有 sigmoid 激活的密集层,因为它几乎总是效果更好。现在建议更改的模型将是
model = Sequential()
model.add(LSTM(8, input_shape=(predictor_array.shape[1],predictor_array.shape[2]), return_sequences=True))
model.add(LSTM(2, return_sequences=True))
model.add(TimeDistributed(Dense(2, activation="sigmoid")))
model.summary()
Run Code Online (Sandbox Code Playgroud)
...尝试通过单个模型输出 A 和 B 序列是否有效,或者我应该安装 2 个单独的模型...?
理想情况下,这两种情况都可以。但最新的研究表明,前一种情况(对两组使用单一模型)往往表现更好。该方法通常称为多任务学习。多任务学习背后的想法非常广泛,为了简单起见,它可以被认为是通过强制模型学习多个任务常见的隐藏表示来添加归纳偏差。
...预测输出的形状是 (12, 3),而我原本期望它是 (12, 2) - 我在这里做错了什么吗...?
您得到这个是因为您正在使用Predict_classes方法。与预测方法不同,predict_classes 方法返回通道轴的最大索引(在您的情况下是第三个索引)。正如我上面所解释的,如果您对最后一层使用 sigmoid 激活并用 Predict 替换 Predict_classes,您将得到您所期望的结果。
就输出 LSTM 层而言,这里使用激活函数(例如 sigmoid)是个好主意吗?为什么/为什么不呢?
我希望我已经在上面解释了这一点。答案是肯定的。
使用分类类型损失(二元交叉熵)和指标(准确性)来优化序列是否有效?
由于您的目标是二进制信号(分布是 伯努利分布),所以使用二进制损失和准确性指标是有效的。这个答案提供了 更多关于为什么二元交叉熵对于这种类型的目标变量有效的细节。
LSTM 模型是这里的最佳选择吗?有人认为 CRF 或某种 HMM 类型的模型在这里效果更好吗?
这取决于可用数据和您选择的网络的复杂性。CRF 和 HMM 网络很简单,如果可用数据较小,效果会更好。但如果可用数据集很大,LSTM 几乎总是优于 CRF 和 HMM。我的建议是,如果你有大量数据,请使用 LSTM。但如果您的数据较少或正在寻找简单的模型,您可以使用 CRF 或 HMM。
| 归档时间: |
|
| 查看次数: |
2240 次 |
| 最近记录: |