有没有办法将时间权重传递给损失函数?
Is there a way to pass along temporal weights to a loss function?
背景
目前,我正在使用 LSTM 执行回归。我使用的是具有相当大的时间步长的小批量大小(但比我拥有的时间步长数量少得多)。
我正在尝试过渡到具有更少时间步长的更大批次,但启用有状态,以允许使用更大量的生成训练数据。
但是,我目前正在使用基于 sqrt(timestep) 的正则化,(这是消融测试并有助于提高收敛速度,由于问题的统计性质,它起作用,预期误差减少了一个因子平方根(时间步长))。这是通过使用 tf.range
在损失函数中生成适当大小的列表来执行的。当启用有状态时,此方法将不正确,因为它会计算错误的时间步数(此批次中的时间步数,而不是目前为止看到的整体时间步数)。
问题
有没有办法将偏移量或整数或浮点数列表传递给损失函数?最好不要修改模型,但我认识到可能需要这种性质的 hack。
代码
简化模型:
def create_model():
inputs = Input(shape=(None,input_nodes))
next_input = inputs
for i in range(dense_layers):
dense = TimeDistributed(Dense(units=dense_nodes,
activation='relu',
kernel_regularizer=l2(regularization_weight),
activity_regularizer=l2(regularization_weight)))\
(next_input)
next_input = TimeDistributed(Dropout(dropout_dense))(dense)
for i in range(lstm_layers):
prev_input = next_input
next_input = LSTM(units=lstm_nodes,
dropout=dropout_lstm,
recurrent_dropout=dropout_lstm,
kernel_regularizer=l2(regularization_weight),
recurrent_regularizer=l2(regularization_weight),
activity_regularizer=l2(regularization_weight),
stateful=True,
return_sequences=True)\
(prev_input)
next_input = add([prev_input, next_input])
outputs = TimeDistributed(Dense(output_nodes,
kernel_regularizer=l2(regularization_weight),
activity_regularizer=l2(regularization_weight)))\
(next_input)
model = Model(inputs=inputs, outputs=outputs)
损失函数
def loss_function(y_true, y_pred):
length = K.shape(y_pred)[1]
seq = K.ones(shape=(length,))
if use_sqrt_loss_scaling:
seq = tf.range(1, length+1, dtype='int32')
seq = K.sqrt(tf.cast(seq, tf.float32))
seq = K.reshape(seq, (-1, 1))
if separate_theta_phi:
angle_loss = phi_loss_weight * phi_metric(y_true, y_pred, angle_loss_fun)
angle_loss += theta_loss_weight * theta_metric(y_true, y_pred, angle_loss_fun)
else:
angle_loss = angle_loss_weight * total_angle_metric(y_true, y_pred, angle_loss_fun)
norm_loss = norm_loss_weight * norm_loss_fun(y_true, y_pred)
energy_loss = energy_loss_weight * energy_metric(y_true, y_pred)
stability_loss = stability_loss_weight * stab_loss_fun(y_true, y_pred)
act_loss = act_loss_weight * act_loss_fun(y_true, y_pred)
return K.sum(K.dot(0
+ angle_loss
+ norm_loss
+ energy_loss
+ stability_loss
+ act_loss
, seq))
(计算损失函数片段的函数应该不是超级相关的。简单地说,它们也是损失函数。)
为此,您可以使用 fit
方法的 sample_weight
参数并将 sample_weight_mode='temporal'
传递给 compile
方法,以便您可以为每个时间步分配权重批次中的每个样本:
model.compile(..., sample_weight_mode='temporal')
model.fit(..., sample_weight=sample_weight)
sample_weight
应该是一个形状为 (num_samples, num_timesteps)
的数组。
请注意,如果您使用的是输入数据生成器或 Sequence
的实例,则需要将样本权重作为生成器中生成的 tuple/list 的第三个元素或 Sequence
实例。
背景
目前,我正在使用 LSTM 执行回归。我使用的是具有相当大的时间步长的小批量大小(但比我拥有的时间步长数量少得多)。
我正在尝试过渡到具有更少时间步长的更大批次,但启用有状态,以允许使用更大量的生成训练数据。
但是,我目前正在使用基于 sqrt(timestep) 的正则化,(这是消融测试并有助于提高收敛速度,由于问题的统计性质,它起作用,预期误差减少了一个因子平方根(时间步长))。这是通过使用 tf.range
在损失函数中生成适当大小的列表来执行的。当启用有状态时,此方法将不正确,因为它会计算错误的时间步数(此批次中的时间步数,而不是目前为止看到的整体时间步数)。
问题
有没有办法将偏移量或整数或浮点数列表传递给损失函数?最好不要修改模型,但我认识到可能需要这种性质的 hack。
代码
简化模型:
def create_model():
inputs = Input(shape=(None,input_nodes))
next_input = inputs
for i in range(dense_layers):
dense = TimeDistributed(Dense(units=dense_nodes,
activation='relu',
kernel_regularizer=l2(regularization_weight),
activity_regularizer=l2(regularization_weight)))\
(next_input)
next_input = TimeDistributed(Dropout(dropout_dense))(dense)
for i in range(lstm_layers):
prev_input = next_input
next_input = LSTM(units=lstm_nodes,
dropout=dropout_lstm,
recurrent_dropout=dropout_lstm,
kernel_regularizer=l2(regularization_weight),
recurrent_regularizer=l2(regularization_weight),
activity_regularizer=l2(regularization_weight),
stateful=True,
return_sequences=True)\
(prev_input)
next_input = add([prev_input, next_input])
outputs = TimeDistributed(Dense(output_nodes,
kernel_regularizer=l2(regularization_weight),
activity_regularizer=l2(regularization_weight)))\
(next_input)
model = Model(inputs=inputs, outputs=outputs)
损失函数
def loss_function(y_true, y_pred):
length = K.shape(y_pred)[1]
seq = K.ones(shape=(length,))
if use_sqrt_loss_scaling:
seq = tf.range(1, length+1, dtype='int32')
seq = K.sqrt(tf.cast(seq, tf.float32))
seq = K.reshape(seq, (-1, 1))
if separate_theta_phi:
angle_loss = phi_loss_weight * phi_metric(y_true, y_pred, angle_loss_fun)
angle_loss += theta_loss_weight * theta_metric(y_true, y_pred, angle_loss_fun)
else:
angle_loss = angle_loss_weight * total_angle_metric(y_true, y_pred, angle_loss_fun)
norm_loss = norm_loss_weight * norm_loss_fun(y_true, y_pred)
energy_loss = energy_loss_weight * energy_metric(y_true, y_pred)
stability_loss = stability_loss_weight * stab_loss_fun(y_true, y_pred)
act_loss = act_loss_weight * act_loss_fun(y_true, y_pred)
return K.sum(K.dot(0
+ angle_loss
+ norm_loss
+ energy_loss
+ stability_loss
+ act_loss
, seq))
(计算损失函数片段的函数应该不是超级相关的。简单地说,它们也是损失函数。)
为此,您可以使用 fit
方法的 sample_weight
参数并将 sample_weight_mode='temporal'
传递给 compile
方法,以便您可以为每个时间步分配权重批次中的每个样本:
model.compile(..., sample_weight_mode='temporal')
model.fit(..., sample_weight=sample_weight)
sample_weight
应该是一个形状为 (num_samples, num_timesteps)
的数组。
请注意,如果您使用的是输入数据生成器或 Sequence
的实例,则需要将样本权重作为生成器中生成的 tuple/list 的第三个元素或 Sequence
实例。