【发布时间】:2020-05-17 22:33:55
【问题描述】:
编辑:请参阅此问题的结尾以获取解决方案
TL;DR:我需要找到一种方法来计算每批的标签分布,并更新学习率。有没有办法访问当前模型的优化器来更新每个批次的 learning_rate?
下面是如何计算标签分布。它可以在损失函数中完成,因为默认情况下,损失是分批计算的。可以在哪里执行还可以访问模型优化器的代码?
def loss(y_true, y_pred):
y = math_ops.argmax(y_true, axis=1)
freqs = tf.gather(lf, y) # equal to lf[y] if `lf` and `y` were numpy array's
inv_freqs = math_ops.pow(freqs, -1)
E = 1 / math_ops.reduce_sum(inv_freqs) # value to use when updating learning rate
更多详情
为了实现学习率计划,如this paper 中所述,我相信我需要一种方法来更新训练期间的学习率,每批,通过从真实标签的标签分布计算的值 在批处理中(y_true 通常在 keras/tensorflow 中表示)
在哪里...
x 模型的输出
y对应的ground truth标签
Β m 个样本的 minibatch(例如 64)
ny 地面实况标签 y 的整个训练样本大小
ny-1逆标签频率
我关注的公式部分是α和Δ之间的部分θ
我可以在自定义损失函数中轻松实现这一点,但我不知道如何从损失函数中更新学习率——如果你可以的话。
def loss(y_true, y_pred):
y = math_ops.argmax(y_true, axis=1)
freqs = tf.gather(lf, y) # equal to lf[y] if `lf` and `y` were numpy array's
inv_freqs = math_ops.pow(freqs, -1)
E = 1 / math_ops.reduce_sum(inv_freqs) # value to use when updating learning rate
在哪里...
lf 每个类的采样频率。例如2 个类,c0 = 10 个示例,c1 = 100 -->
lf == [10, 100]
有什么奇特的方法可以更新优化器的学习率,比如可以从回调中做什么?
def on_batch_begin(self, batch, log):
# note: batch is just an incremented value to indicate batch index
self.model.optimizer.lr # learning rate, can be modified from callback
提前感谢您的帮助!
解决方案
非常感谢 @mrk 推动我朝着正确的方向解决这个问题!
为了计算每批次的标签分布,然后使用该值来更新优化器的学习率,必须...
- 创建一个自定义指标,计算每批次的标签分布,并返回频率数组(默认情况下,keras 是按批次优化的,因此每批次都会计算指标)。
- 通过继承
keras.callbacks.History类创建一个典型的学习率调度程序 - 覆盖调度程序的
on_batch_end函数,logsdict 将包含批处理的所有计算指标包括我们的自定义标签分布指标!
创建自定义指标
class LabelDistribution(tf.keras.metrics.Metric):
"""
Computes the per-batch label distribution (y_true) and stores the array as
a metric which can be accessed via keras CallBack's
:param n_class: int - number of distinct output class(es)
"""
def __init__(self, n_class, name='batch_label_distribution', **kwargs):
super(LabelDistribution, self).__init__(name=name, **kwargs)
self.n_class = n_class
self.label_distribution = self.add_weight(name='ld', initializer='zeros',
aggregation=VariableAggregation.NONE,
shape=(self.n_class, ))
def update_state(self, y_true, y_pred, sample_weight=None):
y_true = mo.cast(y_true, 'int32')
y = mo.argmax(y_true, axis=1)
label_distrib = mo.bincount(mo.cast(y, 'int32'))
self.label_distribution.assign(mo.cast(label_distrib, 'float32'))
def result(self):
return self.label_distribution
def reset_states(self):
self.label_distribution.assign([0]*self.n_class)
创建 DRW 学习率调度器
class DRWLearningRateSchedule(keras.callbacks.History):
"""
Used to implement the Differed Re-weighting strategy from
[Kaidi Cao, et al. "Learning Imbalanced Datasets with Label-Distribution-Aware Margin Loss." (2019)]
(https://arxiv.org/abs/1906.07413)
To be included as a metric to model.compile
`model.compile(..., metrics=[DRWLearningRateSchedule(.01)])`
"""
def __init__(self, base_lr, ld_metric='batch_label_distribution'):
super(DRWLearningRateSchedule, self).__init__()
self.base_lr = base_lr
self.ld_metric = ld_metric # name of the LabelDistribution metric
def on_batch_end(self, batch, logs=None):
ld = logs.get(self.ld_metric) # the per-batch label distribution
current_lr = self.model.optimizer.lr
# example below of updating the optimizers learning rate
K.set_value(self.model.optimizer.lr, current_lr * (1 / math_ops.reduce_sum(ld)))
【问题讨论】:
标签: python tensorflow machine-learning math keras