如何构建具有多模态输入的 RNN 来对时间序列进行分类
How to build RNN with multimodal input to classify time series
我有每个时间序列 50 个样本的数据。
我想构建一个时间序列分类器。
每个样本有三个输入 - 一个形状为 1X768 的向量,一个形状为 1X25 的向量,一个形状为 1X496 的向量。
每个输入都来自不同的模态,因此在连接所有输入之前需要经过一些特定于输入的层。
数据存储在数据框中:
df = time_series_id timestamp input1 input2 input3 time_series_label
0 0 [x0..x768] [x0..x25] [x0..x496] A
0 1 [x0..x768] [x0..x25] [x0..x496] A
..
0 50 [x0..x768] [x0..x25] [x0..x496] A
1 0 [x0..x768] [x0..x25] [x0..x496] B
1 50 [x0..x768] [x0..x25] [x0..x496] B
我是 DL 的新手,我想构建一个网络,将每 50 个时间戳长的时间序列分类为 2 个 类 之一,但我找不到任何教程来举例说明如何插入多模式数据分为 Conv1d
或 LSTM
层。
我如何构建这样的网络,最好是使用 keras,并在我的数据帧上进行训练以便对时间序列进行分类?
(所以,当我给它一个包含 50 个时间戳的新时间序列时,我将得到整个时间序列的 A/B 预测)?
请注意,具有相同 ID 的所有行的标签都是相同的。所以每次,我只需要给 RNN 提供相同 id 的样本。
使用一些网络(线性、MLP 等)将它们嵌入到同一维度,您可以使用加法、元素乘法、双(三)线性或任何您想要将它们组合到维度统一输入中的方法RNN 或 CNN。
或者你可以只连接每个时间步长,每个时间步长一个数据,这对 CNNs
没问题
我已经为你创建了一个很好的例子:
# Define mini-dataset similar to yours example
df = pd.DataFrame({'A':[np.zeros((768))]*100,'B':[np.ones((25))]*100})
# 100 rows, 2 columns (each value in column A is a list size 768, each value in column B is a list size 25)
预处理数据以匹配 50 个时间戳的滚动 windows
# Create windows of data:
list_of_indexes=[]
df.index.to_series().rolling(50).apply((lambda x: list_of_indexes.append(x.tolist()) or 0), raw=False)
d_A = df.A.apply(list)
d_B = df.B.apply(list)
a = [[d_A[ix] for ix in x] for x in list_of_indexes]
b = [[d_B[ix] for ix in x] for x in list_of_indexes]
a = np.array(a)
b = np.array(b)
print(f'a shape: {a.shape}')
print(f'b shape: {b.shape}')
预处理后的数据:
a shape: (51, 50, 768)
b shape: (51, 50, 25)
解释:
a: 51个样本,每个样本包含50个时间戳,每个时间戳包含768个值。 (b与25个值相同。)
创建一个有两个输入的模型,输入 a 和输入 b,您可以分别处理每个输入,然后连接起来。
# define two sets of inputs
input_A = Input(shape=(50, 768))
input_B = Input(shape=(50, 25))
LSTM_A = Bidirectional(LSTM(32))(input_A)
LSTM_B = Bidirectional(LSTM(32))(input_B)
combined = concatenate([
LSTM_A,
LSTM_B
])
dense1 = Dense(32, activation='relu')(combined)
output = Dense(1, activation='sigmoid')(dense1)
model = Model(inputs=[
input_A,
input_B
], outputs=output)
model.summary()
模型总结:
拟合模型:
adam = Adam(lr=0.00001)
model.compile(loss='binary_crossentropy', optimizer=adam)
history = model.fit([a,b], y, batch_size=2, epochs=2)
当然你可以在 LSTM 之前进行连接:
# define two sets of inputs
input_A = Input(shape=(50, 768))
input_B = Input(shape=(50, 25))
combined = concatenate([
input_A,
input_B
])
LSTM_layer = Bidirectional(LSTM(32))(combined)
dense1 = Dense(32, activation='relu')(LSTM_layer)
output = Dense(1, activation='sigmoid')(dense1)
model = Model(inputs=[
input_A,
input_B
], outputs=output)
model.summary()
编辑:
df:
形状:(100, 4)
预处理代码:
def split_into_inputs(group):
x_data_inp1.append(group.input1)
x_data_inp2.append(group.input2)
# supposing time_series_id have the same label for all of its rows (thats what i understood from the question details)
y_data.append(group.time_series_label.unique()[0])
x_data_inp1 = []
x_data_inp2 = []
y_data = []
df.groupby('time_series_id').apply(lambda group: split_into_inputs(group))
# convert list into array with np.float dtype to match the nn.
x_data_inp1 = np.array(x_data_inp1, dtype=np.float)
x_data_inp2 = np.array(x_data_inp2, dtype=np.float)
# Convert labels from chars into digits
from sklearn.preprocessing import LabelEncoder
# creating instance of labelencoder
labelencoder = LabelEncoder()
# Assigning numerical values. Convert 'A','B' into 0, 1
y_data = labelencoder.fit_transform(y_data)
x_data_inp1.shape, x_data_inp2.shape, y_data.shape
输出:
((2, 50, 768), (2, 50, 25), (2,))
我们的100个样本经过预处理后,根据“time_series_id”列,有2个序列,每个50个样本,有2个标签,第一个序列标签A为0,标签B 为 1 表示第二个序列。
问题:每个 50 个样本序列都有不同的“time_series_id”?
定义模式:
# define two sets of inputs
input_A = Input(shape=(50, 768))
input_B = Input(shape=(50, 25))
LSTM_A = Bidirectional(LSTM(32))(input_A)
LSTM_B = Bidirectional(LSTM(32))(input_B)
combined = concatenate([
LSTM_A,
LSTM_B
])
dense1 = Dense(32, activation='relu')(combined)
output = Dense(1, activation='sigmoid')(dense1)
model = Model(inputs=[
input_A,
input_B
], outputs=output)
model.summary()
拟合模型:
adam = Adam(lr=0.00001)
model.compile(loss='binary_crossentropy', optimizer=adam)
history = model.fit([x_data_inp1, x_data_inp2], y_data, batch_size=2, epochs=2)
我有每个时间序列 50 个样本的数据。 我想构建一个时间序列分类器。
每个样本有三个输入 - 一个形状为 1X768 的向量,一个形状为 1X25 的向量,一个形状为 1X496 的向量。
每个输入都来自不同的模态,因此在连接所有输入之前需要经过一些特定于输入的层。
数据存储在数据框中:
df = time_series_id timestamp input1 input2 input3 time_series_label
0 0 [x0..x768] [x0..x25] [x0..x496] A
0 1 [x0..x768] [x0..x25] [x0..x496] A
..
0 50 [x0..x768] [x0..x25] [x0..x496] A
1 0 [x0..x768] [x0..x25] [x0..x496] B
1 50 [x0..x768] [x0..x25] [x0..x496] B
我是 DL 的新手,我想构建一个网络,将每 50 个时间戳长的时间序列分类为 2 个 类 之一,但我找不到任何教程来举例说明如何插入多模式数据分为 Conv1d
或 LSTM
层。
我如何构建这样的网络,最好是使用 keras,并在我的数据帧上进行训练以便对时间序列进行分类? (所以,当我给它一个包含 50 个时间戳的新时间序列时,我将得到整个时间序列的 A/B 预测)?
请注意,具有相同 ID 的所有行的标签都是相同的。所以每次,我只需要给 RNN 提供相同 id 的样本。
使用一些网络(线性、MLP 等)将它们嵌入到同一维度,您可以使用加法、元素乘法、双(三)线性或任何您想要将它们组合到维度统一输入中的方法RNN 或 CNN。 或者你可以只连接每个时间步长,每个时间步长一个数据,这对 CNNs
没问题我已经为你创建了一个很好的例子:
# Define mini-dataset similar to yours example
df = pd.DataFrame({'A':[np.zeros((768))]*100,'B':[np.ones((25))]*100})
# 100 rows, 2 columns (each value in column A is a list size 768, each value in column B is a list size 25)
预处理数据以匹配 50 个时间戳的滚动 windows
# Create windows of data:
list_of_indexes=[]
df.index.to_series().rolling(50).apply((lambda x: list_of_indexes.append(x.tolist()) or 0), raw=False)
d_A = df.A.apply(list)
d_B = df.B.apply(list)
a = [[d_A[ix] for ix in x] for x in list_of_indexes]
b = [[d_B[ix] for ix in x] for x in list_of_indexes]
a = np.array(a)
b = np.array(b)
print(f'a shape: {a.shape}')
print(f'b shape: {b.shape}')
预处理后的数据:
a shape: (51, 50, 768)
b shape: (51, 50, 25)
解释:
a: 51个样本,每个样本包含50个时间戳,每个时间戳包含768个值。 (b与25个值相同。)
创建一个有两个输入的模型,输入 a 和输入 b,您可以分别处理每个输入,然后连接起来。
# define two sets of inputs
input_A = Input(shape=(50, 768))
input_B = Input(shape=(50, 25))
LSTM_A = Bidirectional(LSTM(32))(input_A)
LSTM_B = Bidirectional(LSTM(32))(input_B)
combined = concatenate([
LSTM_A,
LSTM_B
])
dense1 = Dense(32, activation='relu')(combined)
output = Dense(1, activation='sigmoid')(dense1)
model = Model(inputs=[
input_A,
input_B
], outputs=output)
model.summary()
模型总结:
拟合模型:
adam = Adam(lr=0.00001)
model.compile(loss='binary_crossentropy', optimizer=adam)
history = model.fit([a,b], y, batch_size=2, epochs=2)
当然你可以在 LSTM 之前进行连接:
# define two sets of inputs
input_A = Input(shape=(50, 768))
input_B = Input(shape=(50, 25))
combined = concatenate([
input_A,
input_B
])
LSTM_layer = Bidirectional(LSTM(32))(combined)
dense1 = Dense(32, activation='relu')(LSTM_layer)
output = Dense(1, activation='sigmoid')(dense1)
model = Model(inputs=[
input_A,
input_B
], outputs=output)
model.summary()
编辑:
df:
(100, 4)
预处理代码:
def split_into_inputs(group):
x_data_inp1.append(group.input1)
x_data_inp2.append(group.input2)
# supposing time_series_id have the same label for all of its rows (thats what i understood from the question details)
y_data.append(group.time_series_label.unique()[0])
x_data_inp1 = []
x_data_inp2 = []
y_data = []
df.groupby('time_series_id').apply(lambda group: split_into_inputs(group))
# convert list into array with np.float dtype to match the nn.
x_data_inp1 = np.array(x_data_inp1, dtype=np.float)
x_data_inp2 = np.array(x_data_inp2, dtype=np.float)
# Convert labels from chars into digits
from sklearn.preprocessing import LabelEncoder
# creating instance of labelencoder
labelencoder = LabelEncoder()
# Assigning numerical values. Convert 'A','B' into 0, 1
y_data = labelencoder.fit_transform(y_data)
x_data_inp1.shape, x_data_inp2.shape, y_data.shape
输出:
((2, 50, 768), (2, 50, 25), (2,))
我们的100个样本经过预处理后,根据“time_series_id”列,有2个序列,每个50个样本,有2个标签,第一个序列标签A为0,标签B 为 1 表示第二个序列。 问题:每个 50 个样本序列都有不同的“time_series_id”?
定义模式:
# define two sets of inputs
input_A = Input(shape=(50, 768))
input_B = Input(shape=(50, 25))
LSTM_A = Bidirectional(LSTM(32))(input_A)
LSTM_B = Bidirectional(LSTM(32))(input_B)
combined = concatenate([
LSTM_A,
LSTM_B
])
dense1 = Dense(32, activation='relu')(combined)
output = Dense(1, activation='sigmoid')(dense1)
model = Model(inputs=[
input_A,
input_B
], outputs=output)
model.summary()
拟合模型:
adam = Adam(lr=0.00001)
model.compile(loss='binary_crossentropy', optimizer=adam)
history = model.fit([x_data_inp1, x_data_inp2], y_data, batch_size=2, epochs=2)