将元数据传递给自定义损失函数

我想创建一个依赖于元数据的自定义损失函数。最简单的形式是希望根据元数据确定的每批次权重来乘以损失值。

为了简化起见,我们可以直接传递所需的权重。以下是两种尝试的损失函数:

def three_arg_loss(loss_func):    """ a loss function that takes 3 args"""    def _loss(target,output,weight):        return weight*loss_func(target,output)    return _lossdef target_list_loss(loss_func):    """ a loss function that expects the target arg to be [target,weight]"""    def _loss(target,output):        weight=target[1]        target=target[0]        return weight*loss_func(target,output)    return _loss

当我尝试训练时,得到以下结果:

  • three_arg_loss: TypeError: tf___loss() missing 1 required positional argument: 'weight'

当然,我已经三次确认确实传递了三个参数

  • target_list_loss: ValueError: Shapes (None, None, None) and (None, None, None, 4) are incompatible

同样,在三次检查后,我确实将[target,weight]作为目标参数传递。我担心这里可能搞错了损失函数参数的顺序,所以我调换了它们以确保,结果得到了ValueError: Shapes (None, None, 4) and (None, None, None, None) are incompatible

有什么想法吗?依赖附加数据(在我这里是地理位置)的损失函数的正确/最佳方法是什么?

根据下面的请求,这里是一个完整的(但愚蠢的)示例,展示了错误

BATCH_SIZE=2SIZE=3STEPS=8EPOCHS=3NB_CLASSES=4def gen_inpt(ch_in):    return tf.random.uniform((BATCH_SIZE,SIZE,SIZE,ch_in))def gen_targ(nb_classes):    t=tf.random.uniform((BATCH_SIZE,SIZE,SIZE),maxval=nb_classes,dtype=tf.int32)    return tf.keras.utils.to_categorical(t,num_classes=nb_classes)def gen(ch_in,ch_out):    return ( ( gen_inpt(ch_in), gen_targ(ch_out) ) for b in range(BATCH_SIZE*STEPS*EPOCHS) )def gen_targ_list(ch_in,ch_out):    return ( ( gen_inpt(ch_in), [gen_targ(ch_out), tf.fill(1,2222)] ) for b in range(BATCH_SIZE*STEPS*EPOCHS) )def gen_3args(ch_in,ch_out):    return ( ( gen_inpt(ch_in), gen_targ(ch_out), tf.fill(1,10000.0) ) for b in range(BATCH_SIZE*STEPS*EPOCHS) )class Toy(tf.keras.Model):        def __init__(self,nb_classes):        super(Toy, self).__init__()        self.l1=layers.Conv2D(32,3,padding='same')        self.l2=layers.Conv2D(nb_classes,3,padding='same')            def call(self,x):        x=self.l1(x)        x=self.l2(x)        return xdef test_loss(loss_func):    def _loss(target,output):        return loss_func(target,output)    return _lossdef target_list_loss(loss_func):    def _loss(target,output):        weight=target[1]        target=target[0]        return weight*loss_func(target,output)    return _lossdef three_arg_loss(loss_func):    def _loss(target,output,weight):        return weight*loss_func(target,output)    return _lossloss_func=tf.keras.losses.CategoricalCrossentropy()loss_test=test_loss(loss_func)loss_targ_list=target_list_loss(loss_func)loss_3arg=three_arg_loss(loss_func)def test_train(loss,gen):    try:         model=Toy(NB_CLASSES)            model.compile(optimizer='adam',                  loss=loss,                  metrics=['accuracy'])        model.fit(gen(6,NB_CLASSES),steps_per_epoch=STEPS,epochs=EPOCHS)    except Exception as e:        print(e)## RUN TESTS#test_train(loss_test,gen)test_train(loss_targ_list,gen_targ_list)test_train(loss_3arg,gen_3args)

扩展损失的示例(给出相同的结果)

class TargListLoss(tf.keras.losses.Loss):        def __init__(self,loss_func):        super(TargListLoss,self).__init__()        self.loss_func=loss_func            def call(self,target,output):        weight=target[1]        target=target[0]        return weight*self.loss_func(target,output)

回答:

样本权重!

我试图构建一个按样本加权损失的自定义损失函数,但这正是sample_weights的用途。

对不起大家提出了愚蠢的问题 – 但希望这能防止其他人重蹈我的覆辙。我认为错过了这一点,因为最初我计划通过直接将元数据传递给损失函数来确定权重。回顾起来,将元数据到权重的逻辑包含在损失函数中是没有意义的,因为它取决于应用场景。

为了完整起见,下面的代码展示了如何从生成器传递第三个参数确实可以对每个样本进行加权:

BATCH_SIZE=2SIZE=3STEPS=8EPOCHS=3NB_CLASSES=4def gen_inpt(ch_in):    return tf.random.uniform((BATCH_SIZE,SIZE,SIZE,ch_in))def gen_targ(nb_classes):    t=tf.random.uniform((BATCH_SIZE,SIZE,SIZE),maxval=nb_classes,dtype=tf.int32)    return tf.keras.utils.to_categorical(t,num_classes=nb_classes)        def gen_3args(ch_in,ch_out,dummy_sw):    if dummy_sw:        return ( ( gen_inpt(ch_in), gen_targ(ch_out), tf.convert_to_tensor(dummy_sw) ) for b in range(BATCH_SIZE*STEPS*EPOCHS) )    else:        return ( ( gen_inpt(ch_in), gen_targ(ch_out) ) for b in range(BATCH_SIZE*STEPS*EPOCHS) )    class Toy(tf.keras.Model):        def __init__(self,nb_classes):        super(Toy, self).__init__()        self.l1=layers.Conv2D(32,3,padding='same')        self.l2=layers.Conv2D(nb_classes,3,padding='same')            def call(self,x):        x=self.l1(x)        x=self.l2(x)        return x    loss_func=tf.keras.losses.CategoricalCrossentropy()def test_train(loss,gen):    try:         model=Toy(NB_CLASSES)            model.compile(optimizer='adam',                  loss='categorical_crossentropy',                  metrics=['accuracy'])        model.fit(gen,steps_per_epoch=STEPS,epochs=EPOCHS)    except Exception as e:        print(e)# ## # RUN TESTS# #print('None: unweighted')test_train(loss_func,gen_3args(6,NB_CLASSES,None))print('ones: same as None')test_train(loss_func,gen_3args(6,NB_CLASSES,[1,1]))print('100s: should be roughly 100 times the loss of None')test_train(loss_func,gen_3args(6,NB_CLASSES,[100,100]))print('[0,10]: should be roughly 1/2 the 100s loss ')test_train(loss_func,gen_3args(6,NB_CLASSES,[0,100]))

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注