python - Keras:如何实现 LSTM 的目标复制?
问题描述
使用Lipton 等人 (2016)的示例,目标复制基本上是计算 LSTM(或 GRU)的每个时间步(除了最终时间步)的损失,并在训练时平均该损失并将其添加到主要损失中。在数学上,它由 -
在图形上,它可以表示为 -
那么我该如何在 Keras 中实现这一点呢?说,我有二进制分类任务。假设我的模型是下面给出的简单模型 -
model.add(LSTM(50))
model.add(Dense(1))
model.compile(loss='binary_crossentropy', class_weights={0:0.5, 1:4}, optimizer=Adam(), metrics=['accuracy'])
model.fit(x_train, y_train)
- 我认为
y_train
需要从 (batch_size, 1) 重塑/平铺到 (batch_size, time_step) 对吗? - 设置后需要将密集层
TimeDistributed
正确应用到 LSTMreturn_sequences=True
吗? - 我如何准确地实现上面给出的确切损失函数?
class_weights
需要修改吗? - 目标复制仅在训练期间进行。如何仅使用主要损失来实现验证集评估?
- 我应该如何处理目标复制中的零填充?我的序列被填充为
max_len
15,平均长度为 7。由于目标复制损失在所有步骤中平均,我如何确保它在计算损失时不使用填充词?基本上,动态分配T实际序列长度。
解决方案
问题一:
因此,对于目标,您需要将其塑造为(batch_size, time_steps, 1)
. 只需使用:
y_train = np.stack([y_train]*time_steps, axis=1)
问题2:
你是对的,但TimeDistributed
在 Keras 2 中是可选的。
问题 3:
我不知道类权重会如何表现,但是常规的损失函数应该是这样的:
from keras.losses import binary_crossentropy
def target_replication_loss(alpha):
def inner_loss(true,pred):
losses = binary_crossentropy(true,pred)
return (alpha*K.mean(losses[:,:-1], axis=-1)) + ((1-alpha)*losses[:,-1])
return inner_loss
model.compile(......, loss = target_replication_loss(alpha), ...)
问题 3a:
由于上述方法不适用于类权重,我创建了一个替代方案,其中权重进入损失:
def target_replication_loss(alpha, class_weights):
def get_weights(x):
b = class_weights[0]
a = class_weights[1] - b
return (a*x) + b
def inner_loss(true,pred):
#this will only work for classification with only one class 0 or 1
#and only if the target is the same for all classes
true_classes = true[:,-1,0]
weights = get_weights(true_classes)
losses = binary_crossentropy(true,pred)
return weights*((alpha*K.mean(losses[:,:-1], axis=-1)) + ((1-alpha)*losses[:,-1]))
return inner_loss
问题4:
metric
为避免复杂性,我会说您应该在验证中使用附加功能:
def last_step_BC(true,pred):
return binary_crossentropy(true[:,-1], pred[:,-1])
model.compile(....,
loss = target_replication_loss(alpha),
metrics=[last_step_BC])
问题 5:
这是一个很难的,我需要研究一点....
作为初始解决方法,您可以使用输入形状设置模型(None, features)
,并单独训练每个序列。
没有 class_weight 的工作示例
def target_replication_loss(alpha):
def inner_loss(true,pred):
losses = binary_crossentropy(true,pred)
#print(K.int_shape(losses))
#print(K.int_shape(losses[:,:-1]))
#print(K.int_shape(K.mean(losses[:,:-1], axis=-1)))
#print(K.int_shape(losses[:,-1]))
return (alpha*K.mean(losses[:,:-1], axis=-1)) + ((1-alpha)*losses[:,-1])
return inner_loss
alpha = 0.6
i1 = Input((5,2))
i2 = Input((5,2))
out = LSTM(1, activation='sigmoid', return_sequences=True)(i1)
model = Model(i1, out)
model.compile(optimizer='adam', loss = target_replication_loss(alpha))
model.fit(np.arange(30).reshape((3,5,2)), np.arange(15).reshape((3,5,1)), epochs = 200)
具有类权重的工作示例:
def target_replication_loss(alpha, class_weights):
def get_weights(x):
b = class_weights[0]
a = class_weights[1] - b
return (a*x) + b
def inner_loss(true,pred):
#this will only work for classification with only one class 0 or 1
#and only if the target is the same for all classes
true_classes = true[:,-1,0]
weights = get_weights(true_classes)
losses = binary_crossentropy(true,pred)
print(K.int_shape(losses))
print(K.int_shape(losses[:,:-1]))
print(K.int_shape(K.mean(losses[:,:-1], axis=-1)))
print(K.int_shape(losses[:,-1]))
print(K.int_shape(weights))
return weights*((alpha*K.mean(losses[:,:-1], axis=-1)) + ((1-alpha)*losses[:,-1]))
return inner_loss
alpha = 0.6
class_weights={0: 0.5, 1:4.}
i1 = Input(batch_shape=(3,5,2))
i2 = Input((5,2))
out = LSTM(1, activation='sigmoid', return_sequences=True)(i1)
model = Model(i1, out)
model.compile(optimizer='adam', loss = target_replication_loss(alpha, class_weights))
model.fit(np.arange(30).reshape((3,5,2)), np.arange(15).reshape((3,5,1)), epochs = 200)
推荐阅读
- r - 基于日期时间复制和修改行
- java - 如何在@Around 通知中调用proceed() 方法之前检索方法声明的返回类型(运行时类型)
- java - Gradle任务替换.java文件中的字符串不起作用
- java - Payara 服务器未启动
- c++ - 动态类对象加载
- python - PyCharm 2020.2.1 的全新 Snap 安装无法调试
- node.js - Uncaught (in promise) SyntaxError: Unexpected end of JSON input for large data request
- python - MaxRetryError 与 Spotify API
- c - 作为指针的参数未正确递增
- php - 如何在 Laravel 中显示来自另一个磁盘的图像