简体   繁体   English

在keras自定义层中包括高级计算(类似于scikit)

[英]Including advanced computation (scikit-like) in a keras custom layer

Normally I would preprocess the data before I feed it into my model for classification. 通常,在将数据输入模型进行分类之前,我会对其进行预处理。

This is however not possible and thus am stuck either to enhance the performance of the model further (somehow) or include useful preprocessing steps directly inside the model. 但是,这是不可能的,因此被卡住以进一步(以某种方式)增强模型的性能,或者直接在模型内部包含有用的预处理步骤。

How can I do that? 我怎样才能做到这一点? The best solution I found thus far, included re-implementing the functionality I want using Keras backend. 到目前为止,我找到的最佳解决方案包括使用Keras后端重新实现我想要的功能。 This is far from a good solution and thus I am hoping someone has an idea, how to salavage the situation. 这远不是一个好的解决方案,因此我希望有人对如何解决这种情况有一个想法。

Below are links I found useful + my current code. 以下是我发现有用的链接和当前代码。

Useful links: 有用的链接:

Keras Custom Layer with advanced calculations 具有高级计算功能的Keras自定义图层

How to Switch from Keras Tensortype to numpy array for a custom layer? 如何从Keras Tensortype切换到自定义图层的numpy数组?

How to create a Keras Custom Layer using functions not included in the Backend, to perform tensor sampling? 如何使用后端未包含的功能创建Keras自定义图层以执行张量采样?

My code thus far: 到目前为止,我的代码:

def freezeBaseModelLayers(baseModel):
    for layer in baseModel.layers:
        layer.trainable = False


def preprocess_input(x):
    # TODO: Not working, but intention should be clear
    numpy_array = tf.unstack(tf.unstack(tf.unstack(x, 224, 0), 224, 0), 1, 0)
    from skimage.feature import hog
    from skimage import data, exposure
    img_adapteq = exposure.equalize_adapthist(numpy_array, orientations=8, pixels_per_cell=(3, 3),
                                              cells_per_block=(1, 1), visualize=True, multichannel=False)
    [x1, x2, x3] = tf.constant(img_adapteq), tf.constant(img_adapteq), tf.constant(img_adapteq)
    img_conc = Concatenate([x1, x2, x3])
    return img_conc


def create(x):
    is_training = tf.get_variable('is_training', (), dtype=tf.bool, trainable=False)
    with tf.name_scope('pretrained'):
        # Add preprocess step here...
        input_layer = Lambda(preprocess_input(x), input_shape=(224, 224, 1), output_shape=(224, 224, 3))

        baseModel = vgg16.VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))    
        freezeBaseModelLayers(baseModel)
        layer = baseModel(input_layer)
        layer = GlobalMaxPooling2D()(layer)
        layer = Dense(1024, activation='relu')(layer)
        layer = Dense(2, activation=None)(layer)
        model = Model(input=input_layer.input, output=layer)
        output = model(x)
        return output




I would like to include prepocessing steps inside my model

The models I am working with are receiving noisy data. In order to enhance the performance of the models, I would like to do some preprocessing steps e.g. equalize_adapthist.

A better way to do this is via a custom keras layer. 更好的方法是通过自定义keras层。 Here is an example: 这是一个例子:

import tensorflow as tf
from keras.layers import Layer, Input, Conv2D
from keras.models import Model
from keras import backend as K
from skimage.feature import hog
from skimage import data, exposure

def equalize(img):
  img_adapteq = exposure.equalize_adapthist(img)
  return img_adapteq

def preprocess_input(img):
  return tf.py_func(equalize, 
                     [img],
                     'float32',
                     stateful=False,
                     name='custom_image_op')


class CustomLayer(Layer):
  def __init__(self, output_dim, **kwargs):
    self.output_dim = output_dim
    self.trainable = False
    super(CustomLayer, self).__init__(**kwargs)

  def call(self, x):
    res = tf.map_fn(preprocess_input, x)
    res.set_shape([x.shape[0],
                   self.output_dim[1], 
                   self.output_dim[0],
                   x.shape[-1]])
    return res

output_dim = (224,224)
inputs = Input(shape=(224,224,3))
x = CustomLayer(output_dim)(inputs)
x = Conv2D(32, (3,3))(x)
x = Flatten()(x)
x = Dense(1)(x)

model = Model(inputs, x)
model.summary()

# test
sample = np.random.rand(4, 224,224,3).astype(np.float32)
y = np.random.randint(2, size=(4,))

model.compile("sgd", "mse")
model.fit(sample, y)

To do this with a Lambda layer, you would need to write histogram equalization in pure tensorflow . 要使用Lambda层执行此操作,您需要在纯tensorflow编写直方图均衡化。 Indeed, when building the graph, the function ( preprocess_input ) will be called on tensorflow placeholders which, in the case of this skimage function which expects numpy arrays, will not work. 确实,在构建图形时,将在tensorflow占位符上调用函数( preprocess_input ),对于使用numpy数组的skimage函数,该函数将不起作用。

This question shows how to write it in pure tensorflow . 这个问题说明了如何用纯张量tensorflow编写它。 Copy-pasting here for the sake of redundancy/ease-of-reading (I have not tested it myself but a test is available in the question): 为了冗余/易于阅读而在此处进行复制粘贴(我自己尚未对其进行测试,但是问题中可以进行测试):

def tf_equalize_histogram(image):
    values_range = tf.constant([0., 255.], dtype = tf.float32)
    histogram = tf.histogram_fixed_width(tf.to_float(image), values_range, 256)
    cdf = tf.cumsum(histogram)
    cdf_min = cdf[tf.reduce_min(tf.where(tf.greater(cdf, 0)))]

    img_shape = tf.shape(image)
    pix_cnt = img_shape[-3] * img_shape[-2]
    px_map = tf.round(tf.to_float(cdf - cdf_min) * 255. / tf.to_float(pix_cnt - 1))
    px_map = tf.cast(px_map, tf.uint8)

    eq_hist = tf.expand_dims(tf.gather_nd(px_map, tf.cast(image, tf.int32)), 2)
    return eq_hist

Btw you should write the pre-processing step as (once you made the preprocessing step pure tensorflow ): 顺便说一句,您应该将预处理步骤写为(一旦您使预处理步骤成为纯tensorflow ):

input_layer = Lambda(preprocess_input, input_shape=(224, 224, 1), output_shape=(224, 224, 3))(x)

Another way to do this is to write a custom layer as pointed out by mlRocks. 执行此操作的另一种方法是编写mlRocks指出的自定义层。

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

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