Python 当您需要输入值来计算损失时,如何编写keras自定义损失函数?

Python 当您需要输入值来计算损失时,如何编写keras自定义损失函数?,python,deep-learning,tensorflow2.0,style-transfer,Python,Deep Learning,Tensorflow2.0,Style Transfer,我正在尝试使用中描述的方法复制一张快速样式的转印纸(见上图) 我在理解如何使用自定义损失类(见下文)时遇到问题 为了计算损耗分量,我需要以下信息: y_hat,要获取的生成图像 target\u-style\u-gram是静态的,因此我可以从target\u-style\u-features和缓存中导出一次,(,target\u-style\u-features)=VGG(y\u-s) x,用于获取(目标内容特征)的输入图像(与y\u cContentTarget相同) 我发现我正在对l

我正在尝试使用中描述的方法复制一张快速样式的转印纸(见上图)

我在理解如何使用自定义损失类(见下文)时遇到问题

为了计算损耗分量,我需要以下信息:

  • y_hat
    ,要获取的生成图像
  • target\u-style\u-gram
    是静态的,因此我可以从
    target\u-style\u-features
    和缓存中导出一次,
    ,target\u-style\u-features)=VGG(y\u-s)
  • x
    ,用于获取
    (目标内容特征)的输入图像(与
    y\u c
    ContentTarget相同)
我发现我正在对loss类中的大量内容进行修补,
tf.keras.loss.loss
,以便导出这些值并最终执行损失计算。尤其是
目标内容功能
,它需要输入图像,这是我通过
y\u true
传入的,但这显然是一个黑客行为

y_pred = generated_image # y_hat from diagram, shape=(b,256,256,3)
y_true = x # hack: access the input image here

lossFn = PerceptualLosses_Loss(VGG, target_style_gram)
loss = lossFn(y_true, y_pred)

我还尝试在
tf.data.Dataset
中预先计算
y\u true
,但尽管它在
eager execution
下运行良好,但它在
model.fit()期间导致了一个错误

xy\u true\u数据集=tf.data.Dataset.from\u生成器(
xyGenerator_y_true(图像、VGG、目标样式图),
输出类型=(tf.float32,(tf.float32,tf.float32,tf.float32,tf.float32,tf.float32,tf.float32)),
输出图形=(
(256,256,3),
( (16, 16, 512), (64, 64), (128, 128), (256, 256), (512, 512), (512, 512)) 
),
)
#急切执行,y_true:[TensorShape([4,16,16,512])、TensorShape([4,64,64])、TensorShape([4,128,128])、TensorShape([4,256,256])、TensorShape([4,512,512])、TensorShape([4,512,512])]
#model.fit(),y_true:(无,无,无,无)

ValueError:检查模型目标时出错:传递给模型的Numpy数组列表的大小不是模型预期的大小。对于输入['output_1'],预期会看到1个数组,但得到的是以下6个数组的列表:[,,,根据错误消息,这似乎与您的输入形状不同。1个数组与6个数组的列表不同。急切执行会隐式强制转换哪个model.fit()不会。您尝试过numpy.array()或numpy.asarray()吗要将列表更改为数组吗?根据错误消息,这似乎与您的输入形状不同有关。1个数组与6个数组的列表。急切执行会隐式强制转换哪个模型。fit()不会。您是否尝试过numpy.array()或numpy.asarray()将列表更改为数组?
y_pred = generated_image # y_hat from diagram, shape=(b,256,256,3)
y_true = x # hack: access the input image here

lossFn = PerceptualLosses_Loss(VGG, target_style_gram)
loss = lossFn(y_true, y_pred)


class PerceptualLosses_Loss(tf.losses.Loss):
  name="PerceptualLosses_Loss"
  reduction=tf.keras.losses.Reduction.AUTO
  RGB_MEAN_NORMAL_VGG = tf.constant( [0.48501961, 0.45795686, 0.40760392], dtype=tf.float32)

  def __init__(self, loss_network, target_style_gram, loss_weights=None):
    super(PerceptualLosses_Loss, self).__init__( name=self.name, reduction=self.reduction )
    self.target_style_gram = target_style_gram # repeated in y_true
    print("PerceptualLosses_Loss init()", type(target_style_gram), type(self.target_style_gram))
    self.VGG = loss_network

  def call(self, y_true, y_pred):

    b,h,w,c = y_pred.shape
    #???: y_pred.shape=(None, 256,256,3), need batch dim for utils.gram(value)
    generated_batch = tf.reshape(y_pred, (BATCH_SIZE,h,w,c) )

    # generated_batch: expecting domain=(+-int), mean centered
    generated_batch = tf.nn.tanh(generated_batch) # domain=(-1.,1.), mean centered

    # reverse VGG mean_center
    generated_batch = tf.add( generated_batch, self.RGB_MEAN_NORMAL_VGG) # domain=(0.,1.)
    generated_batch_BGR_centered = tf.keras.applications.vgg19.preprocess_input(generated_batch*255.)/255.
    generated_content_features, generated_style_features = self.VGG( generated_batch_BGR_centered, preprocess=False )
    generated_style_gram = [ utils.gram(value)  for value in generated_style_features ]  # list

    y_pred = generated_content_features + generated_style_gram
    # print("PerceptualLosses_Loss: y_pred, output_shapes=", type(y_pred), [v.shape for v in y_pred])
    # PerceptualLosses_Loss: y_pred, output_shapes= [
    #   TensorShape([4, 16, 16, 512]), 
    #   TensorShape([4, 64, 64]), 
    #   TensorShape([4, 128, 128]), 
    #   TensorShape([4, 256, 256]), 
    #   TensorShape([4, 512, 512]), 
    #   TensorShape([4, 512, 512])
    # ]

    if tf.is_tensor(y_true):
      # print("detect y_true is image", type(y_true), y_true.shape)
      x_train = y_true
      x_train_BGR_centered = tf.keras.applications.vgg19.preprocess_input(x_train*255.)/255.
      target_content_features, _ = self.VGG(x_train_BGR_centered, preprocess=False )
      # ???: target_content_features[0].shape=(None, None, None, 512), should be shape=(4, 16, 16, 512)
      target_content_features = [tf.reshape(v, generated_content_features[i].shape) for i,v in enumerate(target_content_features)]
    elif isinstance(y_true, tuple):
      print("detect y_true is tuple(target_content_features + self.target_style_gram)", y_true[0].shape)
      target_content_features = y_true[:len(generated_content_features)]
      if self.target_style_gram is None:
        self.target_style_gram = y_true[len(generated_content_features):]
    else:
      assert False, "unexpected result for y_true"

    # losses = tf.keras.losses.MSE(y_true, y_pred)
    def batch_reduce_sum(y_true, y_pred, weight, name):
      losses = tf.zeros(BATCH_SIZE)
      for a,b in zip(y_true, y_pred):
        # batch_reduce_sum()
        loss = tf.keras.losses.MSE(a,b)
        loss = tf.reduce_sum(loss, axis=[i for i in range(1,len(loss.shape))] )
        losses = tf.add(losses, loss)
      return tf.multiply(losses, weight, name="{}_loss".format(name)) # shape=(BATCH_SIZE,)

    c_loss = batch_reduce_sum(target_content_features, generated_content_features, CONTENT_WEIGHT, 'content_loss')
    s_loss = batch_reduce_sum(self.target_style_gram, generated_style_gram, STYLE_WEIGHT, 'style_loss')
    return (c_loss, s_loss)
xy_true_Dataset = tf.data.Dataset.from_generator(
    xyGenerator_y_true(image_ds, VGG, target_style_gram),
    output_types=(tf.float32, (tf.float32,  tf.float32,tf.float32,tf.float32,tf.float32,tf.float32) ),
    output_shapes=(
      (256,256,3),
      ( (16, 16, 512), (64, 64), (128, 128), (256, 256), (512, 512), (512, 512)) 
    ),
  )

# eager execution, y_true: <class 'tuple'> [TensorShape([4, 16, 16, 512]), TensorShape([4, 64, 64]), TensorShape([4, 128, 128]), TensorShape([4, 256, 256]), TensorShape([4, 512, 512]), TensorShape([4, 512, 512])]
# model.fit(), y_true: <class 'tensorflow.python.framework.ops.Tensor'> (None, None, None, None)

ValueError: Error when checking model target: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 1 array(s), for inputs ['output_1'] but instead got the following list of 6 arrays: [<tf.Tensor 'args_1:0' shape=(None, 16, 16, 512) dtype=float32>, <tf.Tensor 'args_2:0' shape=(None, 64, 64) dtype=float32>, <tf.Tensor 'args_3:0' shape=(None, 128, 128) dtype=float32>, <tf.Tensor 'arg...