python 如何在 Tensorflow 中创建我自己的预处理层?

How to create my own preprocessing layer in Tensorflow in python?

我有一个用于预处理数据的特定顺序模型,如下所示:

data_transformation = tf.keras.Sequential([layers.experimental.preprocessing.RandomContrast(factor=(0.7,0.9)),layers.GaussianNoise(stddev=tf.random.uniform(shape=(),minval=0, maxval=1)), layers.experimental.preprocessing.RandomRotation(factor=0.1, fill_mode='reflect', interpolation='bilinear', seed=None, name=None, fill_value=0.0), layers.experimental.preprocessing.RandomZoom(height_factor=(0.1,0.2), width_factor=(0.1,0.2), fill_mode='reflect', interpolation='bilinear', seed=None, name=None, fill_value=0.0),])

但是,我想添加我自己的预处理层,它由下面的 Python 函数定义:

import tensorflow as tf
import random

def my_random_contrast(image_to_be_transformed, contrast_factor):

    #build the contrast factor 
    selected_contrast_factor=random.uniform(1-contrast_factor, 1+contrast_factor)
    
    selected_contrast_factor_c1=selected_contrast_factor
    selected_contrast_factor_c2=selected_contrast_factor-0.01
    selected_contrast_factor_c3=selected_contrast_factor-0.02
    
    
    image_to_be_transformed=image_to_be_transformed.numpy()
    image_to_be_transformed[0,:,:]=((image_to_be_transformed[0,:,:]-tf.reduce_mean(image_to_be_transformed[0,:,:]))*selected_contrast_factor_c1)+tf.reduce_mean(image_to_be_transformed[0,:,:])
    image_to_be_transformed[1,:,:]=((image_to_be_transformed[1,:,:]-tf.reduce_mean(image_to_be_transformed[1,:,:]))*selected_contrast_factor_c2)+tf.reduce_mean(image_to_be_transformed[1,:,:])
    image_to_be_transformed[2,:,:]=((image_to_be_transformed[2,:,:]-tf.reduce_mean(image_to_be_transformed[2,:,:]))*selected_contrast_factor_c3)+tf.reduce_mean(image_to_be_transformed[2,:,:])
    
    image_to_be_transformed=tf.convert_to_tensor(image_to_be_transformed)
    return image_to_be_transformed


x=tf.random.uniform(shape=[3,224,224], minval=0, maxval=1, dtype=tf.float32)
y=my_random_contrast(x, 0.5)

我如何使用 TensorFlow 做到这一点?作为一个新的预处理层,它将接收来自其他层的输入和输出,我是否必须保证输入和输出是给定的类型?

您需要通过子class层class创建自定义层,可以在此处找到示例Making new Layers and Models via subclassing。网上可以找到很多例子。

如果您计划一次预处理多个图像,则需要确保您的方法适用于批量维度。此外,它应该能够在没有任何 numpy 操作的情况下工作,以便在图形模式下 运行。然后,您可以编写自己的自定义图层或简单的 lambda 图层:

import tensorflow as tf
import matplotlib.pyplot as plt
import pathlib

dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)

ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  image_size=(180, 180),
  batch_size=32, shuffle=False)

def my_random_contrast(image_to_be_transformed, contrast_factor):

    #build the contrast factor 
    selected_contrast_factor=tf.random.uniform((), minval=1 - contrast_factor, maxval=1 + contrast_factor)
    
    selected_contrast_factor_c1=selected_contrast_factor
    selected_contrast_factor_c2=selected_contrast_factor-0.01
    selected_contrast_factor_c3=selected_contrast_factor-0.02
    
    c0 = ((image_to_be_transformed[:,:,:, 0]-tf.reduce_mean(image_to_be_transformed[:,:,:, 0]))*selected_contrast_factor_c1)+tf.reduce_mean(image_to_be_transformed[:,:,:, 0])
    c1 = ((image_to_be_transformed[:,:,:, 1]-tf.reduce_mean(image_to_be_transformed[:,:,:, 1]))*selected_contrast_factor_c2)+tf.reduce_mean(image_to_be_transformed[:,:,:, 1])
    c2 = ((image_to_be_transformed[:,:,:, 2]-tf.reduce_mean(image_to_be_transformed[:,:,:, 2]))*selected_contrast_factor_c3)+tf.reduce_mean(image_to_be_transformed[:,:,:, 2])

    image_to_be_transformed = tf.concat([c0[..., tf.newaxis], image_to_be_transformed[:,:,:, 1:]], axis=-1)
    image_to_be_transformed = tf.concat([image_to_be_transformed[:,:,:, 0][..., tf.newaxis], c1[..., tf.newaxis], image_to_be_transformed[:,:,:, 2][..., tf.newaxis]], axis=-1)
    image_to_be_transformed = tf.concat([image_to_be_transformed[:,:,:, :2], c2[..., tf.newaxis]], axis=-1)

    return image_to_be_transformed


images, _ = next(iter(ds.take(1)))
image = images[2]
plt.figure()
f, axarr = plt.subplots(1,2) 
axarr[0].imshow(image / 255)

# After preprocessing dataset:
images, _ = next(iter(ds.map(lambda x, y: (my_random_contrast(x, 0.8), y)).take(1)))
image = images[2]
axarr[1].imshow(image / 255)

用法示例:

model = tf.keras.Sequential()
model.add(tf.keras.layers.Lambda(lambda x: my_random_contrast(x, 0.8)))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(1))
model.compile(optimizer='adam', loss='mse')
model.fit(tf.random.normal((50, 64, 64, 3)), tf.random.normal((50, 1)))