python - 使用 Keras 评估滑动窗口中的函数
问题描述
我正在尝试跨序列扩展匹配匹配算法。我的比赛有 20 个单位长,每个时间点有 4 个频道。我已经建立了一个封装匹配的模型,我只是不知道如何在滑动窗口中使用它来将它应用到更长的序列中以找到序列中的匹配。
我有 2 个(20, 4)
输入张量 (query
和target
),我将它们连接、添加、展平,然后应用一个简单的密集层。我在这个阶段有数据可以用 100K 查询、目标对进行训练。
def sum_seqs(seqs):
return K.sum(seqs, axis=3)
def pad_dims(seq):
return K.expand_dims(seq, axis=3)
def pad_outshape(in_shape):
return (in_shape[0], in_shape[1], in_shape[2], 1)
query = Input((20, 4))
query_pad = Lambda(pad_dims, output_shape=pad_outshape, name='gpad')(query)
target = Input((20,4))
target_pad = Lambda(pad_dims, output_shape=pad_outshape)(target)
matching = Concatenate(axis = 3)([query_pad, target_pad])
matching = Lambda(sum_seqs)(matching)
matching = Flatten()(matching)
matching = Dropout(0.1)(matching)
matching = Dense(1, activation = 'sigmoid')(matching)
match_model = Model([query, target], matching)
这完美地工作。现在我想使用这个预训练模型来搜索target
具有不同序列的更长query
序列。
它似乎应该是这样的:
long_target = Input((100, 4))
short_target = Input((20, 4))
choose_query = Input((20, 4))
spec_match = match_model([choose_query, short_target])
mdl = TimeDistributed(spec_match)(long_target)
但TimeDistributed
需要 a Layer
not a Tensor
。有没有我缺少的包装?我会以错误的方式解决这个问题吗?我是否需要以某种方式将其重新表述为卷积问题?
继续实验:在我用键盘敲了一天的头之后,很明显,两者TimeDistributed
都只backend.rnn
允许您将模型/层应用于数据的单个时间片。似乎没有办法做到这一点。看起来唯一可以跨时间维度的多个切片“行走”的是Conv1D
.
所以,我将我的问题重新定义为卷积,但这也不能很好地工作。我能够构建一个Conv1D
过滤器来匹配特定的query
. 这工作得相当好,它确实允许我扫描更长的序列并获得匹配。但是每个过滤器对于每个张量都是唯一的,query
并且似乎没有一种方法可以在query
不训练全新Conv1D
层的情况下从小说到适当的过滤器权重。由于我的目标是找到query
与大多数目标匹配的新 s,因此这并没有多大帮助。
query
由于我的“匹配”需要目标和每个窗口处的查询的交互,因此似乎没有一种方法可以target
通过Conv1D
.
有没有办法在 Keras/tensorflow 中进行这种滑动窗口类型评估?这似乎是一件如此简单却又如此遥远的事情。有没有我找不到的方法可以做到这一点?
响应和进一步的实验。
@today 和 @nuric 的解决方案有效,但它们最终target
以平铺类型的方式复制输入数据。因此,对于长度查询,图表中的输入数据副本m
会少一些。m
我希望找到一种解决方案,可以在target
没有重复的情况下真正“滑动”评估。
Conv1D
这是我想出的几乎解决方案的一个版本。
query_weights = []
for query, (targets, scores) in query_target_gen():
single_query_model = Sequential()
single_query_model.add(Conv1D(1, 20, input_shape = (20, 4)))
single_query_model.add(Flatten())
single_query_model.fit(targets, scores)
query_weights.append(single_query_model.layers[0].get_weights())
multi_query_model_long_targets = Sequential()
multi_query_model_long_targets.add(Conv1D(len(query_weights), 20, input_shape = (100, 4)))
multi_query_model_long_targets.layers[0].set_weights(combine_weights(query_weights))
multi_query_model_long_targets.summary()
该combine_weights
函数只是进行一些拆包和矩阵重新排列,以按照需要的方式堆叠过滤器Conv1D
。
该解决方案解决了数据重复问题,但它以其他方式困扰着我。一个是基于数据的......我的数据包含许多query
,target
对,但它往往是相同的target
many query
s,因为在那个方向上生成真实世界的数据更容易。因此,这样做会使培训变得困难。其次,这假设每个都query
以独立的方式工作,而实际上,我知道query
,target
配对实际上很重要。因此,使用可以查看许多配对示例而不是个人的模型是有意义的。
有没有办法结合这两种方法?有没有办法让它在沿着序列行走时Conv1D
将长target
张量与常数结合起来?query
解决方案
只是为了提供使用 Keras 后端功能的替代解决方案。
您还可以使用K.arange
和生成滑动窗口K.map_fn
:
def sliding_windows(inputs):
target, query = inputs
target_length = K.shape(target)[1] # variable-length sequence, shape is a TF tensor
query_length = K.int_shape(query)[1]
num_windows = target_length - query_length + 1 # number of windows is also variable
# slice the target into consecutive windows
start_indices = K.arange(num_windows)
windows = K.map_fn(lambda t: target[:, t:(t + query_length), :],
start_indices,
dtype=K.floatx())
# `windows` is a tensor of shape (num_windows, batch_size, query_length, ...)
# so we need to change the batch axis back to axis 0
windows = K.permute_dimensions(windows, (1, 0, 2, 3))
# repeat query for `num_windows` times so that it could be merged with `windows` later
query = K.expand_dims(query, 1)
query = K.tile(query, [1, num_windows, 1, 1])
# just a hack to force the dimensions 2 to be known (required by Flatten layer)
windows = K.reshape(windows, shape=K.shape(query))
return [windows, query]
要使用它:
long_target = Input((None, 4))
choose_query = Input((20, 4))
windows, query = Lambda(sliding_windows)([long_target, choose_query])
鉴于您的 pretrained match_model
,问题TimeDistributed
在于它无法包装Model
具有多个输入的 Keras。
但是,由于逻辑匹配target
和query
是在 之后的层中实现的Concatenate
,因此您可以将这些层收集到 中Model
,并应用于TimeDistributed
它:
submodel_input = Input((20, 4, 2))
x = submodel_input
for layer in match_model.layers[-4:]: # the `Lambda(sum_seqs)` layer
x = layer(x)
submodel = Model(submodel_input, x)
现在您只需要以与sliding_windows
以下相同的方式处理和合并 的输出match_model
:
long_target = Input((None, 4))
choose_query = Input((20, 4))
windows, query = Lambda(sliding_windows)([long_target, choose_query])
windows_pad = Lambda(lambda x: K.expand_dims(x))(windows)
query_pad = Lambda(lambda x: K.expand_dims(x))(query)
merged = Concatenate()([windows_pad, query_pad])
match_scores = TimeDistributed(submodel)(merged)
max_score = GlobalMaxPooling1D()(match_scores)
model = Model([long_target, choose_query], max_score)
model
然后可以以端到端的方式用于匹配长目标。
您还可以通过应用于滑动窗口来验证 的输出model
确实是匹配分数的最大值:match_model
target_arr = np.random.rand(32, 100, 4)
query_arr = np.random.rand(32, 20, 4)
match_model_scores = np.array([
match_model.predict([target_arr[:, t:t + 20, :], query_arr])
for t in range(81)
])
scores = model.predict([target_arr, query_arr])
print(np.allclose(scores, match_model_scores.max(axis=0)))
True
推荐阅读
- python - 结合 Pandas 数据框
- amazon-web-services - 将 WorkDocs Sync 安装到 Amazon Workspace
- php - 如何创建与 Sendle API 的 curl 连接
- c++ - 前序遍历(二叉树) - 迭代法
- mongodb - 如何从 mongodb 中的 HH:MM:SS 字符串时间值聚合分钟数据
- javascript - Openweathermap 循环遍历城市 id 以获取当前天气
- templates - 为什么我收到模板类堆栈的分段错误?
- javascript - Javascript:带有数组和超时的承诺函数
- octave - 在程序以八度自动结束后重新运行程序
- javascript - 如何在 React Native 中使用 useState 在 AsyncStorage 中保存数据?