简体   繁体   English

在 Keras 中使用 SSIM 损失函数

[英]Use SSIM loss function with Keras

I need to use the SSIM from Sewar as a loss function in order to compare images for my model.我需要使用 Sewar 的 SSIM 作为损失函数来比较我的模型的图像。

I am getting errors when I try to compile my model.当我尝试编译我的模型时出现错误。 I import the function and compile the model like this:我导入函数并编译模型,如下所示:

from sewar.full_ref import ssim
...
model.compile('ssim', optimizer=my_optimizer, metrics=[ssim])

and I get this:我明白了:

File "/media/merry/merry32/train.py", line 19, in train
model.compile(loss='ssim', optimizer=opt, metrics=[ssim])
File "/home/merry/anaconda3/envs/merry_env/lib/python3.7/site-packages/keras/engine/training.py", line 451, in compile
handle_metrics(output_metrics)
File "/home/merry/anaconda3/envs/merry_env/lib/python3.7/site-packages/keras/engine/training.py", line 420, in handle_metrics
mask=masks[i])
File "/home/merry/anaconda3/envs/merry_env/lib/python3.7/site-packages/keras/engine/training_utils.py", line 404, in weighted
score_array = fn(y_true, y_pred)
File "/home/merry/anaconda3/envs/merry_env/lib/python3.7/site-packages/sewar/full_ref.py", line 143, in ssim
MAX = np.iinfo(GT.dtype).max
File "/home/merry/anaconda3/envs/merry_env/lib/python3.7/site-packages/numpy/core/getlimits.py", line 506, in __init__
raise ValueError("Invalid integer data type %r." % (self.kind,))
ValueError: Invalid integer data type 'O'.

I could also write something like this:我也可以这样写:

model.compile(ssim(), optimizer=my_optimizer, metrics=[ssim()])

But then I get this error (obviously):但是后来我收到了这个错误(显然):

TypeError: ssim() missing 2 required positional arguments: 'GT' and 'P'

I just wanted to do the same I was doing with mean_sqeared_error but with SSIM, like this (which works perfectly with no need of passing parameters to it):我只是想对 mean_sqeared_error 做同样的事情,但使用 SSIM,就像这样(无需向其传递参数即可完美运行):

model.compile('mean_squared_error', optimizer=my_optimizer, metrics=['mse'])

Any idea on how should I use this function to compile?关于如何使用此函数进行编译的任何想法?

  • You can use tf.image.ssim to compute SSIM index between two images.您可以使用tf.image.ssim计算两个图像之间的 SSIM 索引。
  • Since training happens on batch of images we will use the mean of SSIM values of all the images in the batch as the loss value由于训练是在一批图像上进行的,我们将使用该批次中所有图像的 SSIM 值的平均值作为损失值
  • Our model will return an image (of some size based on the CNN layers used which is again based on input and expected output image dimensions).我们的模型将返回一个图像(基于所使用的 CNN 层的某种大小,这同样基于输入和预期的输出图像尺寸)。

Sample working code示例工作代码

from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten
import numpy as np
import tensorflow as tf

# Loss functtion
def ssim_loss(y_true, y_pred):
  return tf.reduce_mean(tf.image.ssim(y_true, y_pred, 2.0))

# Model: Input Image size: 32X32X1 output Image size: 28X28X1 
# check model.summary
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=(32,32,1)))
model.add(Conv2D(1, kernel_size=(3, 3),
                 activation='relu'))

model.compile(optimizer='adam', loss=ssim_loss, metrics=[ssim_loss, 'accuracy'])

# Train
model.fit(np.random.randn(10,32,32,1), np.random.randn(10,28,28,1))

You need to create your own custom loss function in order to use external losses.您需要创建自己的自定义损失函数才能使用外部损失。 However, these losses must be adapted to use Tensorflow's tensors and not numerical values or matrixes, so it is not so simple.但是,这些损失必须适应使用 Tensorflow 的张量而不是数值或矩阵,所以它不是那么简单。

I suggest you to see how to write a custom loss function, there are a lot of good tutorials about this, like this one .我建议你看看如何编写自定义损失函数,有很多关于这方面的好教程,比如这个

Keras has an implementation of SSIM. Keras 有一个 SSIM 的实现。 You can use it like this:你可以这样使用它:

def SSIMLoss(y_true, y_pred):
  return 1 - tf.reduce_mean(tf.image.ssim(y_true, y_pred, 1.0))

self.model.compile(optimizer=sgd, loss=SSIMLoss)

Use the TensorFlow implementation of SSIM.使用 SSIM 的 TensorFlow 实现。 The correct way to SSIM as training loss is as follows. SSIM 作为训练损失的正确方法如下。 SSIM is defined for positive pixel values only. SSIM 仅针对正像素值定义。 To be able to compute SSIM on the prediction of your network and the (positive only, and preferrably normalized) input tensors, you should restrict your network's top layer to only output numbers in the range [0, inf] by using a "softplus" activation function.为了能够根据网络的预测和(仅正的,最好是归一化的)输入张量计算 SSIM,您应该使用“softplus”将网络的顶层限制为仅输出 [0, inf] 范围内的数字激活函数。

Because SSIM is subject to maximization, invert it to use it as training loss:由于 SSIM 受制于最大化,将其反转以将其用作训练损失:

ssim_loss = 1 - tf.reduce_mean(tf.image.ssim(y_true, y_pred, 1.0))

Adapting the example of mujjiga and implementing all before mentioned changes:改编 mujjiga 的例子并实现所有之前提到的变化:

from keras.models import Sequential
from keras.layers import Conv2D
import numpy as np
import tensorflow as tf
    

# normalize the data in the range [0, 2]
def normalize(data):
    normalized_data = data / np.max(np.abs(data))
    normalized_data += 1
    return normalized_data


# Loss function
def ssim_loss(y_true, y_pred):
    return 1 - tf.reduce_mean(tf.image.ssim(y_true, y_pred, 2.0))


# dummy input data
input_data = np.random.randn(100, 32, 32, 1)
target_data = np.random.randn(100, 28, 28, 1)
normalized_input_data = normalize(input_data)
normalized_target_data = normalize(target_data)

# Model: Input Image size: 32X32X1 output Image size: 28X28X1
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(32, 32, 1)))
model.add(Conv2D(1, kernel_size=(3, 3), activation='softplus'))

model.compile(optimizer='adam', loss=ssim_loss)

# Train
model.fit(normalized_input_data, normalized_target_data, epochs=100)

Now you see a positive loss decreasing现在你看到正损失在减少

Epoch 1/100
4/4 [==============================] - 3s 65ms/step - loss: 0.9300
Epoch 2/100
4/4 [==============================] - 0s 7ms/step - loss: 0.9269
[...]
Epoch 99/100
4/4 [==============================] - 0s 7ms/step - loss: 0.9089
Epoch 100/100
4/4 [==============================] - 0s 6ms/step - loss: 0.9093

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM