【问题标题】:How to implement mid-model loss function with both true and pred values?如何实现具有真实值和预测值的中间模型损失函数?
【发布时间】:2021-09-05 10:26:40
【问题描述】:

我想要做的是从这个paper 实现损失函数。

损失函数利用串联和并联链接的多个独立模型。第一个模型是低保真模型,第二个模型是一组两个并行模型,最后一个模型是物理信息神经网络 (PINN)。我的具体实现不会使用 PINN。

规定的损失函数需要低保真输出的MSE和低保真输出的梯度(至少我是这样理解公式的)以及高保真输出的MSE,即PINN 输出,最后是正则化项。

所以,

  1. 如何获得中间模型输出的 MSE?

  2. 如何计算 y* 和 y 的梯度项?

  3. 鉴于可能有几种不同的方法可以实现这一点, 就清晰度而言,哪种方法最好? (我意识到这有点主观)

我自己的搜索得出的结论是,我需要通过将 Model.add_loss() 函数添加到子类层或通过 tf.keras.Model API 添加它来使用它。这一切都说得通。我遇到问题的部分是将y_true 带到我实现损失函数的位置。到目前为止我发现的最好的事情是在模型声明输入和输出中使用字典:

model = tf.keras.Model( inputs = some_dict{'input_name':input_name}, 
            outputs = another_dict{'output_name0': output_name0, 
            'output_name1': output_name1, name = 'my_name' }

我找到了大致思路here。在阅读本文之前,我什至不知道 tf.keras.Model 输入甚至可以使用字典。我的问题是作者最终使用一些“输出”作为评估的输入。我现在的框架看起来有点像这样

    def load_model0():
        init_model = [ *Load model of choice* ]
        input0 = tf.keras.Input((size,),name = 'input_zero')
        x = input0
        model0_out = init_model(x)

        model = tf.keras.Model( inputs=input0, outputs = {'model0_out': model0_out}, 
                name = "model0")
        return model

    def load_model1():
        init_model = [ *Load model of choice* ]
        input1 = tf.keras.Input((size,),name = 'input_one')
        x = input0
        model1_out = init_model(x)

        model = tf.keras.Model( inputs=input1, outputs = {'model1_out': model1_out}, 
                name = "model1")
        return model

    def link_models(model0,model1):
        input0 = tf.keras.Input((size0,), name = "first_input")
        input1 = tf.keras.Input((size1,), name = "second_input")

        first_model_out = model0(input0)
        x = tf.keras.layers.Concatenate([first_model_out,input1])
        linked_out = model1(x)

        linked_model = tf.keras.Model( intputs = {'input0': input0, 'input1': input1},
                        outputs = {"linked_out": linked_out, [ *insert confusion* ]}

        loss_function0 = tf.keras.losses.MSE([*insert model0 true values here*],first_model_out)
        linked_model.add_loss(loss_function0)
        loss_function1 = tf.keras.losses.MSE([*insert model1 true values here*], linked_out )
        linked_model.add_loss(loss_function1) 

截至目前,我不知道model.add_loss() 损失函数是否可以与Model.compile() 中的常规损失函数/类一起使用。我如何获得真正的价值?如何运行 Model.fit() 来完成这项工作?

编辑:回应拉普拉斯瑞奇。 我有一组端到端连接的三个网络。第一个网络在这里无关紧要。第二个网络输出维度 15。第三个网络输出维度 40。最终模型的设置如下所示:

# top/first model takes input dimension of (40,)
inputs = tf.keras.Input((40,))

# middle_out dimension is (size,15)
middle_out = middle_model(top_model(inputs))

linked_model = tf.keras.Model( inputs = inputs,
                   outputs = [bottom_model(middle_out),middle_out],
                   name = 'linked_model' )

我这样设置损失和优化器:

opt = tf.keras.optimizers.Adam()
loss = [ tf.keras.losses.MSE, tf.keras.losses.MSE ] 
linked_model.compile(optimizer = opt, loss = losses)

适合

y_list = [data0,data1]
linked_model.fit(x,y_list, epoch = 10, batch_size = 32 )

其中 data0 是维度 (size,40),并且 data1 是维度 (size,15)。

这会产生错误:

ValueError: Dimensions must be equal, but are 15 and 40 for '{{node Mul_6}} = Mul[T=DT_FLOAT](IteratorGetNext:3, Cast_4)' with input shapes: [160,15], [40].

我也尝试过 dict 替代方法(对model.fit() 中的预期输出进行必要的更改):

 loss = {'middle_model': tf.keras.losses.MSE,
         'bottom_model': tf.keras.losses.MSE}
        # Tensorflow gave me a very explicit error saying I need 
        # the name of the bottom model as opposed to the name of the
        # linked model

【问题讨论】:

  • 请在这里找到我的 colab:colab.research.google.com/drive/…
  • 在您提供的信息中很难判断形状错误来自何处。错误不在于您提供的内容。 colab 有一个顶部模型、一个中间模型(输出形状 15)和一个底部模型(输出形状 40)以及您指定的初始输入形状 40,现在它正在工作。希望它可以帮助您调试。
  • @LaplaceRicky 问题已解决。我遇到了维度受限度量的问题,并且我没有区分具有单独度量的两个输出。谢谢!!

标签: python tensorflow keras loss-function


【解决方案1】:

add_loss() 用于不需要数据(y_true)信息的损失,例如正则化损失。

实现您想要的一种方法是创建具有多个输出的模型。

示例代码:

tf.random.set_seed(88883)
np.random.seed(88883)
#defining toy example model0 and model1
inputs=tf.keras.Input((10,))
model0=tf.keras.Model(inputs,Dense(5)(inputs),name='outputs_0')
inputs=tf.keras.Input((15,))
model1=tf.keras.Model(inputs,Dense(7)(inputs),name='outputs_1')

#define the big model
inputs_0=tf.keras.Input((10,),name='inputs_0')
inputs_1=tf.keras.Input((10,),name='inputs_1')
first_model_output=model0(inputs_0)
x=tf.keras.layers.Concatenate(axis=-1)([first_model_output,inputs_1])
second_model_output=model1(x)

bigmodel=tf.keras.Model([inputs_0,inputs_1],[first_model_output,second_model_output])

bigmodel.compile(loss=tf.keras.losses.MeanSquaredError(),optimizer=tf.keras.optimizers.SGD())

#generating data
x0=tf.data.Dataset.from_tensor_slices(np.random.rand(64,10))
x1=tf.data.Dataset.from_tensor_slices(np.random.rand(64,10))
y0=tf.data.Dataset.from_tensor_slices(np.random.rand(64,5))
y1=tf.data.Dataset.from_tensor_slices(np.random.rand(64,7))
ds=tf.data.Dataset.zip(({'inputs_0':x0,'inputs_1':x1},{'outputs_0':y0,'outputs_1':y1}))
ds=ds.batch(4)

bigmodel.fit(ds,epochs=5)
'''
Epoch 1/5
16/16 [==============================] - 0s 2ms/step - loss: 0.7648 - outputs_0_loss: 0.4287 - outputs_1_loss: 0.3361
Epoch 2/5
16/16 [==============================] - 0s 1ms/step - loss: 0.5918 - outputs_0_loss: 0.3294 - outputs_1_loss: 0.2625
Epoch 3/5
16/16 [==============================] - 0s 2ms/step - loss: 0.5036 - outputs_0_loss: 0.2728 - outputs_1_loss: 0.2308
Epoch 4/5
16/16 [==============================] - 0s 1ms/step - loss: 0.4530 - outputs_0_loss: 0.2388 - outputs_1_loss: 0.2142
Epoch 5/5
16/16 [==============================] - 0s 2ms/step - loss: 0.4214 - outputs_0_loss: 0.2172 - outputs_1_loss: 0.2042
'''

bigmodel.fit() 将优化first_model_outputy0 的MSE 和second_model_outputy1 的MSE 的sum

【讨论】:

  • 你知道我如何能够添加第一个模型(即论文中的低保真模型)输出梯度的 MSE,同时对第二个模型做同样的事情。这就是为什么这里可能需要add_loss() 函数的部分原因。它可能不是为此目的而设计的,但它可以用作 article 中的引用。
  • 在您的问题中显示的示例中,没有必要使用add_loss()。如果您使用add_loss(),则必须将标签作为 输入 传递给模型,该模型的工作方式相同,但会造成混淆并降低清晰度。在必须使用add_loss() 来使用model.fit() 的情况下,我什至更喜欢使用自定义训练循环,其中损失函数和训练过程获得最大清晰度。 add_loss() 只是一种快捷方式,仅在损失函数和训练过程简单时推荐使用。
  • @"Laplace Ricky" - 除非两组输出的维度相同,否则这将不起作用。我目前正试图弄清楚那部分。您能否更新您的答案以提供一个应该如何完成的示例。
  • 您能否更清楚地描述您遇到的问题以及您想要什么示例?
  • 我已更新我的原始帖子以反映我的错误。
猜你喜欢
  • 1970-01-01
  • 2022-10-08
  • 2020-10-12
  • 1970-01-01
  • 1970-01-01
  • 2018-11-04
  • 1970-01-01
  • 2018-11-20
  • 2014-03-31
相关资源
最近更新 更多