我想在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。
答案 0 :(得分:1)
我被同样的问题困扰了几天。当我们将“标准”损失添加到 add_loss 的损失时,“标准”损失将是一个标量。我让它工作的唯一方法是在计算平均值时再添加一个轴。所以我们会得到一个标量,它会起作用。
tmp = self.rate*K.mean(inputs*inputs, axis=[0, -1])