mse损失函数与隐藏层输出上的正则化损失(add_loss)不兼容

时间:2020-07-04 11:40:44

标签: python-3.x neural-network layer tf.keras tensorflow2.x

我想在tf.Keras中编写一个具有几个损失函数的神经网络。一个是带有因子负载的标准mse(均方误差),而另一个基本上是隐藏层输出上的正则项。第二个损失是通过self.add_loss()加在继承自tf.keras.layers.Layer的用户定义的类中的。我有几个问题(尽管第一个更重要)。

1):尝试将两个损失合并在一起时出现的错误如下:

ValueError: Shapes must be equal rank, but are 0 and 1
        From merging shape 0 with other shapes. for '{{node AddN}} = AddN[N=2, T=DT_FLOAT](loss/weighted_loss/value, model/new_layer/mul_1)' with input shapes: [], [100].

因此,来自这样一个事实:应该累加成一个唯一的损耗值的张量具有不同的形状(和等级)。不过,当我尝试在训练过程中打印损失时,我清楚地看到作为损失返回的向量的形状为batch_size且排名为1。难道是当两个损失相加时我必须提供它们(或至少损失了add_loss作为标量?我知道mse通常作为向量返回,其中每个条目都是批次中一个样本的mse,因此具有batch_size作为形状。我想我试图对“常规化”损失做同样的事情。您对此行为有解释吗?

给我错误的示例代码如下:

import numpy as np
import tensorflow as tf
from tensorflow.keras import backend as K
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Input


def rate_mse(rate=1e5):
    @tf.function # also needed for printing
    def loss(y_true, y_pred):
        tmp = rate*K.mean(K.square(y_pred - y_true), axis=-1)
#        tf.print('shape %s and rank %s output in mse'%(K.shape(tmp), tf.rank(tmp)))
        tf.print('shape and rank output in mse',[K.shape(tmp), tf.rank(tmp)])
        tf.print('mse loss:',tmp) # print when I put tf.function
        return tmp
    return loss

class newLayer(tf.keras.layers.Layer):
    def __init__(self, rate=5e-2, **kwargs):
        super(newLayer, self).__init__(**kwargs)
        self.rate = rate
        
#    @tf.function # to be commented for NN training
    def call(self, inputs):
        tmp = self.rate*K.mean(inputs*inputs, axis=-1)
        tf.print('shape and rank output in regularizer',[K.shape(tmp), tf.rank(tmp)])
        tf.print('regularizer loss:',tmp)
        self.add_loss(tmp, inputs=True)
        return inputs



tot_n = 10000
xx = np.random.rand(tot_n,1)
yy = np.pi*xx

train_size = int(0.9*tot_n)
xx_train = xx[:train_size]; xx_val = xx[train_size:]
yy_train = yy[:train_size]; yy_val = yy[train_size:]

reg_layer = newLayer()

input_layer = Input(shape=(1,))                                      # input
hidden = Dense(20, activation='relu', input_shape=(2,))(input_layer) # hidden layer
hidden = reg_layer(hidden)
output_layer = Dense(1, activation='linear')(hidden) 

model = Model(inputs=[input_layer], outputs=[output_layer])
model.compile(optimizer='Adam', loss=rate_mse(), experimental_run_tf_function=False)
#model.compile(optimizer='Adam', loss=None, experimental_run_tf_function=False)
model.fit(xx_train, yy_train, epochs=100, batch_size = 100, 
          validation_data=(xx_val,yy_val), verbose=1)

#new_xx = np.random.rand(10,1); new_yy = np.pi*new_xx
#model.evaluate(new_xx,new_yy)


print(model.predict(np.array([[1]])))

2)我还有一个与此代码有关的第二个问题。我注意到在功能tf.print中使用rate_mse打印仅适用于tf.function。类似地,仅在训练期间评论同一装饰者的情况下才考虑call的{​​{1}}方法。有人可以解释为什么会出现这种情况,还是可以向我介绍可能的解决方案?

在此先感谢谁能为我提供帮助。我目前正在使用Tensorflow 2.2.0,而keras版本是2.3.0-tf。

1 个答案:

答案 0 :(得分:1)

我被同样的问题困扰了几天。当我们将“标准”损失添加到 add_loss 的损失时,“标准”损失将是一个标量。我让它工作的唯一方法是在计算平均值时再添加一个轴。所以我们会得到一个标量,它会起作用。

tmp = self.rate*K.mean(inputs*inputs, axis=[0, -1])