如何在Keras Lambda Layer中使用OpenCV函数?

Kau*_*kar 5 python opencv keras keras-layer

我试图使用一个在图像上使用一些OpenCV函数的函数.但我得到的数据是张量,我无法将其转换为图像.

def image_func(img):
     img=cv2.cvtColor(img,cv2.COLOR_BGR2YUV) 
     img=cv2.resize(img,(200,66))
     return img

model=Sequential()
model.add(Lambda(get_ideal_img,input_shape=(r,c,ch),output_shape=(r,c,ch)))
Run Code Online (Sandbox Code Playgroud)

当我运行这个片段时,它会在cvtColor函数中抛出一个错误,说这img不是一个numpy数组.我打印出来img,似乎是张量.

我不知道如何将张量更改为图像然后返回张量.我希望模型有这个层.

如果我无法通过lambda图层实现这一目标,我还能做些什么?

pit*_*all 5

您将Lambda层中的符号运算与 Python 函数中的数值运算混淆了。

基本上,您的自定义操作接受数字输入但不接受符号输入。为了解决这个问题,你需要的是像py_functensorflow

此外,您还没有考虑反向传播。简而言之,虽然这一层是非参数化和不可学习的,但你也需要注意它的梯度。

import tensorflow as tf
from keras.layers import Input, Conv2D, Lambda
from keras.models import Model
from keras import backend as K
import cv2

def image_func(img):
    img=cv2.cvtColor(img,cv2.COLOR_BGR2YUV) 
    img=cv2.resize(img,(200,66))
    return img.astype('float32')

def image_tensor_func(img4d) :
    results = []
    for img3d in img4d :
        rimg3d = image_func(img3d )
        results.append( np.expand_dims( rimg3d, axis=0 ) )
    return np.concatenate( results, axis = 0 )

class CustomLayer( Layer ) :
    def call( self, xin )  :
        xout = tf.py_func( image_tensor_func, 
                           [xin],
                           'float32',
                           stateful=False,
                           name='cvOpt')
        xout = K.stop_gradient( xout ) # explicitly set no grad
        xout.set_shape( [xin.shape[0], 66, 200, xin.shape[-1]] ) # explicitly set output shape
        return xout
    def compute_output_shape( self, sin ) :
        return ( sin[0], 66, 200, sin[-1] )

x = Input(shape=(None,None,3))
f = CustomLayer(name='custom')(x)
y = Conv2D(1,(1,1), padding='same')(x)

model = Model( inputs=x, outputs=y )
print model.summary()
Run Code Online (Sandbox Code Playgroud)

现在您可以使用一些虚拟数据测试该层。

a = np.random.randn(2,100,200,3)
b = model.predict(a)
print b.shape

model.compile('sgd',loss='mse')
model.fit(a,b)
Run Code Online (Sandbox Code Playgroud)


ors*_*ady -1

我将假设image_func函数可以完成您想要的操作(调整大小)和图像。请注意,图像由 numpy 数组表示。由于您使用的是张量流后端,因此您正在对张量进行操作(这一点您知道)。

现在的工作是将张量转换为 numpy 数组。为此,我们需要使用评估张量来评估张量。但为了做到这一点,我们需要一个来获取张量流会话。

使用get_session()keras后端模块的方法来抓取当前的tensorflow会话。

这是文档字符串get_session()

def get_session():
    """Returns the TF session to be used by the backend.
    If a default TensorFlow session is available, we will return it.
    Else, we will return the global Keras session.
    If no global Keras session exists at this point:
    we will create a new global session.
    Note that you can manually set the global session
    via `K.set_session(sess)`.
    # Returns
        A TensorFlow session.
    """
Run Code Online (Sandbox Code Playgroud)

所以尝试:

def image_func(img)

    from keras import backend as K

    sess  = K.get_session()
    img = sess.run(img) # now img is a proper numpy array 

    img=cv2.cvtColor(img,cv2.COLOR_BGR2YUV) 
    img=cv2.resize(img,(200,66))
    return img
Run Code Online (Sandbox Code Playgroud)

请注意,我无法对此进行测试

编辑:刚刚测试了这个,它不起作用(正如您所注意到的)。lambda函数需要返回Tensor。计算流程会抛出一个张量,因此它也需要在微分意义上是平滑的。

我发现 lambda 本质上是在改变颜色并调整图像大小,为什么不在预处理步骤中执行此操作?