如何实现具有真值和预测值的中间模型损失函数?

How to implement mid-model loss function with both true and pred values?

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

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

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

所以,

  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() 中的常规损失 function/class 结合使用。我如何获得真正的价值?我如何 运行 Model.fit() 来完成这项工作?

编辑:回应 Laplace Ricky。 我有一组端到端连接的三个网络。第一个网络在这里无关紧要。第二个网络输出维度 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

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_output 的 MSE 和 y0sumsecond_model_output 的 MSE 的 y1.