【问题标题】:How to use OpenCV functions in Keras Lambda Layer?如何在 Keras Lambda 层中使用 OpenCV 函数?
【发布时间】:2017-08-10 13:04:23
【问题描述】:

我正在尝试使用在图像上使用某些 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)))

当我运行这个 sn-p 时,它会在 cvtColor 函数中抛出一个错误,指出 img 不是一个 numpy 数组。我打印出img,它似乎是一个张量。

我不知道如何将张量更改为图像,然后也返回张量。我希望模型具有这一层。

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

【问题讨论】:

  • 您使用的是 Theano 还是 Tensorflow 的哪个后端?请注意,默认情况下 tensorflow 是后端。因此,如果您没有更改任何内容,那么您正在使用的是 tensorflow。
  • 我正在使用张量流
  • 你解决了这个问题吗?我也遇到了类似的问题

标签: python opencv keras keras-layer


【解决方案1】:

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

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

使用keras后端模块的get_session()方法来抓取当前的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.
    """

那就试试吧:

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

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

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

我看到 lambda 本质上是在改变颜色和调整图像大小,你为什么不在预处理步骤中这样做呢?

【讨论】:

  • 我测试过了。但是 lambda 层需要一个张量对象。具体来说,它应该是占位符。但是您正在返回图像。应该怎么改?
【解决方案2】:

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

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

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

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()

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

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

model.compile('sgd',loss='mse')
model.fit(a,b)

【讨论】:

  • 很好的例子,认为这对我有很大帮助,即使现在 tf 2.0 已经发布了哈哈。但我认为你可能有一个打字错误并且根本没有使用你的自定义层(f),因为你定义了 outputs=y ,事先只是将 x 传递给 y ,所以只是跳过了你的自定义层。也许我说的是bul *****,但无论如何感谢您的解释^^
  • 这是对 Keras 和 Tensorflow 新手的绝佳解释。只需在最新版本的 Tensorflow 中将 tf.py_func 更改为 tf.py_function(删除有状态参数)。谢谢!!
  • 我按照您的模板处理了一个类似的情况,其中图像张量必须通过转换(颜色空间等),并且一直在用一个玩具示例对其进行训练。如果没有自定义层,模型可以很好地训练和泛化,但是当我使用自定义层时,损失永远不会减少。可能是什么问题呢?也许与自定义层中的渐变流动有关?有什么建议吗?谢谢
  • 不确定发生了什么,但除非您感兴趣的功能是某种预处理,否则您不应使用此技巧,即可以将某些东西放在原始 RGB 图像和 DNN 之间。如果您的任务是关于颜色空间的,您总是可以学习一个简单的 1x1 Conv2D 层来进行颜色变换,例如YUV RGB。
猜你喜欢
  • 2017-12-06
  • 2019-09-10
  • 2018-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-09
相关资源
最近更新 更多