Предварительная обработка изображения для модели Tensorflow вместо предварительной обработки Pytorch

#tensorflow #pytorch #python-imaging-library

#tensorflow #pytorch #python-imaging-library

Вопрос:

У меня была модель кодировщика pytorch resnet101, когда входное изображение получило эту предварительную обработку:

 import torchvision as tv
from PIL import Image

data_transforms = tv.transforms.Compose([
    tv.transforms.Resize((224, 224)),
    tv.transforms.ToTensor(),
    tv.transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])
img = Image.open(img_path)
img = img.convert('RGB')
img = data_transforms(img)
img = torch.FloatTensor(img)
img = img.unsqueeze(0)
print(img)
  

тензор изображения pytorch

Форма ввода для кодировщика в этом случае [1, 3, 224, 224], и это изображение нормализовано со средним значением и стандартным значением ImageNet. Теперь я экспортирую эту модель в tensorflow, итак, как выполнить такую же предварительную обработку изображения для tf-модели?

Я пытался сделать что-то вроде этого:

 from PIL import Image

img = Image.open(img_path)
img = img.convert('RGB')
img = tf.keras.preprocessing.image.img_to_array(img)
img = tf.image.resize(tf_img, (224, 224))
img = tf.keras.applications.resnet.preprocess_input(img)# now shape is [224, 224, 3]
img = tf.reshape(img, [1, 3, 224, 224])
print(img)
  

тензор изображения tensorflow

но я уверен, что я сделал что-то не так, потому что тензоры torch и tf выглядят очень по-разному для одного изображения и дают совершенно разные выходные результаты для одной модели кодера.

Может кто-нибудь помочь, что я должен исправить в предварительной обработке tf?

Ответ №1:

Это:

 img = Image.open(img_path)
img = img.convert('RGB')
  

может быть заменен на

 image = tf.io.read_file(filename=filepath)
image = tf.image.decode_jpeg(image, channels=3) #or decode_png
    
  

Кроме того, противоположность unsqueeze и squeeze является expand_dims :

   img = tf.expand_dims(img,axis=0)
  

Все должно работать хорошо, просто убедитесь, что

 tf.keras.applications.resnet.preprocess_input(img) `and` data.transforms()
  

приведите к желаемым / необходимым преобразованиям.

Что касается фотографий, я совершенно уверен, что вы пропустили / 255.0 в случае PyTorch или добавили деление 255.0 в случае TensorFlow.

Фактически, углубляясь в серверную часть Keras, вы можете видеть, что когда вы вызываете свою функцию предварительной обработки, она вызывает эту функцию здесь:

 def _preprocess_numpy_input(x, data_format, mode):
  """Preprocesses a Numpy array encoding a batch of images.

  Arguments:
    x: Input array, 3D or 4D.
    data_format: Data format of the image array.
    mode: One of "caffe", "tf" or "torch".
      - caffe: will convert the images from RGB to BGR,
          then will zero-center each color channel with
          respect to the ImageNet dataset,
          without scaling.
      - tf: will scale pixels between -1 and 1,
          sample-wise.
      - torch: will scale pixels between 0 and 1 and then
          will normalize each channel with respect to the
          ImageNet dataset.

  Returns:
      Preprocessed Numpy array.
  """
  if not issubclass(x.dtype.type, np.floating):
    x = x.astype(backend.floatx(), copy=False)

  if mode == 'tf':
    x /= 127.5
    x -= 1.
    return x
  elif mode == 'torch':
    x /= 255.
    mean = [0.485, 0.456, 0.406]
    std = [0.229, 0.224, 0.225]
  else:
    if data_format == 'channels_first':
      # 'RGB'->'BGR'
      if x.ndim == 3:
        x = x[::-1, ...]
      else:
        x = x[:, ::-1, ...]
    else:
      # 'RGB'->'BGR'
      x = x[..., ::-1]
    mean = [103.939, 116.779, 123.68]
    std = None

  # Zero-center by mean pixel
  if data_format == 'channels_first':
    if x.ndim == 3:
      x[0, :, :] -= mean[0]
      x[1, :, :] -= mean[1]
      x[2, :, :] -= mean[2]
      if std is not None:
        x[0, :, :] /= std[0]
        x[1, :, :] /= std[1]
        x[2, :, :] /= std[2]
    else:
      x[:, 0, :, :] -= mean[0]
      x[:, 1, :, :] -= mean[1]
      x[:, 2, :, :] -= mean[2]
      if std is not None:
        x[:, 0, :, :] /= std[0]
        x[:, 1, :, :] /= std[1]
        x[:, 2, :, :] /= std[2]
  else:
    x[..., 0] -= mean[0]
    x[..., 1] -= mean[1]
    x[..., 2] -= mean[2]
    if std is not None:
      x[..., 0] /= std[0]
      x[..., 1] /= std[1]
      x[..., 2] /= std[2]
  return x
  

mode Параметр по умолчанию в Keras и TensorFlow для предварительной обработки для ResNet50, на удивление, не tf но caffe .

Таким образом, предварительная обработка, которая выполняется для изображения, находится в этой ветке else (я добавляю ветку else и код после этого, чтобы вы могли следить за преобразованиями и видеть, чего вам не хватает):

  else:
    if data_format == 'channels_first':
      # 'RGB'->'BGR'
      if x.ndim == 3:
        x = x[::-1, ...]
      else:
        x = x[:, ::-1, ...]
    else:
      # 'RGB'->'BGR'
      x = x[..., ::-1]
    mean = [103.939, 116.779, 123.68]
    std = None
# Zero-center by mean pixel
  if data_format == 'channels_first':
    if x.ndim == 3:
      x[0, :, :] -= mean[0]
      x[1, :, :] -= mean[1]
      x[2, :, :] -= mean[2]
      if std is not None:
        x[0, :, :] /= std[0]
        x[1, :, :] /= std[1]
        x[2, :, :] /= std[2]
    else:
      x[:, 0, :, :] -= mean[0]
      x[:, 1, :, :] -= mean[1]
      x[:, 2, :, :] -= mean[2]
      if std is not None:
        x[:, 0, :, :] /= std[0]
        x[:, 1, :, :] /= std[1]
        x[:, 2, :, :] /= std[2]
  else:
    x[..., 0] -= mean[0]
    x[..., 1] -= mean[1]
    x[..., 2] -= mean[2]
    if std is not None:
      x[..., 0] /= std[0]
      x[..., 1] /= std[1]
      x[..., 2] /= std[2]
  return x
  

Описание:

caffe: преобразует изображения из RGB в BGR, затем обнуляет каждый цветовой канал по отношению к набору данных ImageNet без масштабирования.