簡體   English   中英

TensorFlow 等效於 PyTorch 的 transforms.Normalize()

[英]TensorFlow equivalent of PyTorch's transforms.Normalize()

我正在嘗試推斷最初在 PyTorch 中構建的 TFLite model。 我一直遵循PyTorch 實現的思路,並且必須沿 RGB 通道預處理圖像。 我發現與transforms.Normalize()最接近的 TensorFlow 是tf.image.per_image_standardization()文檔)。 盡管這是一個很好的匹配, tf.image.per_image_standardization()通過在通道中獲取均值和標准並將其應用於它們來做到這一點。 這是他們從這里開始的完整實現

def per_image_standardization(image):
  """Linearly scales `image` to have zero mean and unit norm.
  This op computes `(x - mean) / adjusted_stddev`, where `mean` is the average
  of all values in image, and
  `adjusted_stddev = max(stddev, 1.0/sqrt(image.NumElements()))`.
  `stddev` is the standard deviation of all values in `image`. It is capped
  away from zero to protect against division by 0 when handling uniform images.
  Args:
    image: 3-D tensor of shape `[height, width, channels]`.
  Returns:
    The standardized image with same shape as `image`.
  Raises:
    ValueError: if the shape of 'image' is incompatible with this function.
  """
  image = ops.convert_to_tensor(image, name='image')
  _Check3DImage(image, require_static=False)
  num_pixels = math_ops.reduce_prod(array_ops.shape(image))

  image = math_ops.cast(image, dtype=dtypes.float32)
  image_mean = math_ops.reduce_mean(image)

  variance = (math_ops.reduce_mean(math_ops.square(image)) -
              math_ops.square(image_mean))
  variance = gen_nn_ops.relu(variance)
  stddev = math_ops.sqrt(variance)

  # Apply a minimum normalization that protects us against uniform images.
  min_stddev = math_ops.rsqrt(math_ops.cast(num_pixels, dtypes.float32))
  pixel_value_scale = math_ops.maximum(stddev, min_stddev)
  pixel_value_offset = image_mean

  image = math_ops.subtract(image, pixel_value_offset)
  image = math_ops.div(image, pixel_value_scale)
  return image

而 PyTorch 的transforms.Normalize()允許我們提及要在每個通道中應用的平均值和標准差,如下所示。

# transformation
    pose_transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225]),
    ])

在 TensorFlow 2.x 中獲得此功能的方法是什么?

編輯:我創建了一個快速的 botch,似乎通過定義 function 來解決這個問題:

def normalize_image(image, mean, std):
    for channel in range(3):
        image[:,:,channel] = (image[:,:,channel] - mean[channel])/std[channel]
    
    return image

我不確定這有多有效,但似乎可以完成工作。 在輸入到 model 之前,我仍然需要將 output 轉換為張量。

您提到的解決方法似乎沒問題。 但是,當您處理數據管道( generatortf.data )中的大型數據集時,使用for...loop計算單個圖像每個 RGB通道的歸一化可能會有點問題。 但無論如何沒關系。 這是您的方法的演示,稍后我們將提供兩種可能的替代方案,它們可能很容易為您工作。

from PIL import Image 
from matplotlib.pyplot import imshow, subplot, title, hist

# load image (RGB)
img = Image.open('/content/9.jpg')

def normalize_image(image, mean, std):
    for channel in range(3):
        image[:,:,channel] = (image[:,:,channel] - mean[channel]) / std[channel]
    return image

OP_approach = normalize_image(np.array(img) / 255.0, 
                            mean=[0.485, 0.456, 0.406], 
                            std=[0.229, 0.224, 0.225])

現在,讓我們隨后觀察變換屬性。

plt.figure(figsize=(25,10))
subplot(121); imshow(OP_approach); title(f'Normalized Image \n min-px: \
    {OP_approach.min()} \n max-pix: {OP_approach.max()}')
subplot(122); hist(OP_approach.ravel(), bins=50, density=True); \ 
                                    title('Histogram - pixel distribution')

在此處輸入圖像描述

歸一化后的最小和最大像素范圍分別為( -2.11790393013100432.6399999999999997 )。

選項 2

我們可以使用tf. keras...歸一化預處理層做同樣的事情。 它需要兩個重要的 arguments ,它們是meanvariancestd的平方)。

from tensorflow.keras.experimental.preprocessing import Normalization

input_data = np.array(img)/255
layer = Normalization(mean=[0.485, 0.456, 0.406], 
                      variance=[np.square(0.299), 
                                np.square(0.224), 
                                np.square(0.225)])

plt.figure(figsize=(25,10))
subplot(121); imshow(layer(input_data).numpy()); title(f'Normalized Image \n min-px: \
   {layer(input_data).numpy().min()} \n max-pix: {layer(input_data).numpy().max()}')
subplot(122); hist(layer(input_data).numpy().ravel(), bins=50, density=True);\
   title('Histogram - pixel distribution')

在此處輸入圖像描述

歸一化后的最小和最大像素2.64分別為( -2.0357144 )。

選項 3

這更像是減去平均mean並除以平均std

norm_img = ((tf.cast(np.array(img), tf.float32) / 255.0) - 0.449) / 0.226

plt.figure(figsize=(25,10))
subplot(121); imshow(norm_img.numpy()); title(f'Normalized Image \n min-px: \
{norm_img.numpy().min()} \n max-pix: {norm_img.numpy().max()}')
subplot(122); hist(norm_img.numpy().ravel(), bins=50, density=True); \
title('Histogram - pixel distribution')

在此處輸入圖像描述

歸一化后的最小和最大像素2.4380531 -1.9867257 最后,如果我們與pytorch方式進行比較,這些方法之間並沒有太大區別。

import torchvision.transforms as transforms

transform_norm = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                            std=[0.229, 0.224, 0.225]),
])
norm_pt = transform_norm(img)

plt.figure(figsize=(25,10))
subplot(121); imshow(np.array(norm_pt).transpose(1, 2, 0));\
  title(f'Normalized Image \n min-px: \
  {np.array(norm_pt).min()} \n max-pix: {np.array(norm_pt).max()}')
subplot(122); hist(np.array(norm_pt).ravel(), bins=50, density=True); \
  title('Histogram - pixel distribution')

在此處輸入圖像描述

歸一化后的最小和最大像素2.64分別為( -2.117904 )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM