使用Keras进行标准偏差合并

时间:2018-11-08 16:55:38

标签: python python-2.7 tensorflow keras

我正在尝试使用keras实现标准偏差合并层。这个想法类似于用功能类似于AveragePooling1D的层来实现,但是要计算标准偏差。

我的第一步是尝试将其实现为Lambda层。它应该使用3d张量,例如(batch_size,time,features)和一个跨度整数(指示窗口的大小)。它应该返回一个形状为(batch_size,time,features)的张量。

我的实现如下:

import tensorflow
import keras
from keras.layers import Dense, TimeDistributed, Lambda, Input
import numpy as np
import keras.backend as K

def stdev_pooling(inputs):
    data, stride = inputs

    stride = K.cast(stride, dtype='int32')

    print K.dtype(stride), K.dtype(data), '---'

    num_windows = K.shape(data)[1] / stride

    idxs = K.arange(num_windows) * stride

    windows = K.map_fn(lambda w: data[:, w: (w + stride), :], idxs, dtype=K.floatx())

    windows = K.permute_dimensions(windows, (1,0,2,3))

    stds = K.map_fn(lambda w: K.std(w, axis=1), windows)

    return stds

ipt = Input(shape=(None,10))
d = TimeDistributed(Dense(10))(ipt)
out = Lambda(stdev_pooling)([d,K.variable(20, dtype='int32', name='stride_var')])

m = keras.Model(inputs=ipt, outputs=out)
x = np.arange(1000).reshape(1,-1,10)
m.predict(x).shape

但是,我的输出(按顺序显示了步幅和数据张量的数据类型)是

int32 float32 ---
float32 float32 ---

堆栈跟踪是这样的:



    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
     in ()
          1 ipt = Input(shape=(None,10))
          2 d = TimeDistributed(Dense(10))(ipt)
    ----> 3 out = Lambda(stdev_pooling)([d,K.variable(20, dtype='int32', name='stride_var')])

    /home/juliano/.local/lib/python2.7/site-packages/keras/engine/base_layer.pyc in __call__(self, inputs, **kwargs)
        472             if all([s is not None
        473                     for s in to_list(input_shape)]):
    --> 474                 output_shape = self.compute_output_shape(input_shape)
        475             else:
        476                 if isinstance(input_shape, list):

    /home/juliano/.local/lib/python2.7/site-packages/keras/layers/core.pyc in compute_output_shape(self, input_shape)
        643                 if isinstance(input_shape, list):
        644                     xs = [K.placeholder(shape=shape) for shape in input_shape]
    --> 645                     x = self.call(xs)
        646                 else:
        647                     x = K.placeholder(shape=input_shape)

    /home/juliano/.local/lib/python2.7/site-packages/keras/layers/core.pyc in call(self, inputs, mask)
        680         if has_arg(self.function, 'mask'):
        681             arguments['mask'] = mask
    --> 682         return self.function(inputs, **arguments)
        683 
        684     def compute_mask(self, inputs, mask=None):

     in stdev_pooling(inputs)
          5     print K.dtype(stride), K.dtype(data), '---'
          6 
    ----> 7     num_windows = K.shape(data)[1] / stride
          8 
          9     idxs = K.arange(num_windows-1) * stride

    /home/juliano/.local/lib/python2.7/site-packages/tensorflow/python/ops/math_ops.pyc in binary_op_wrapper(x, y)
        848     with ops.name_scope(None, op_name, [x, y]) as name:
        849       if isinstance(x, ops.Tensor) and isinstance(y, ops.Tensor):
    --> 850         return func(x, y, name=name)
        851       elif not isinstance(y, sparse_tensor.SparseTensor):
        852         try:

    /home/juliano/.local/lib/python2.7/site-packages/tensorflow/python/ops/math_ops.pyc in _div_python2(x, y, name)
        972   with ops.name_scope(name, "div", [x, y]) as name:
        973     x = ops.convert_to_tensor(x, name="x")
    --> 974     y = ops.convert_to_tensor(y, name="y", dtype=x.dtype.base_dtype)
        975     x_dtype = x.dtype.base_dtype
        976     y_dtype = y.dtype.base_dtype

    /home/juliano/.local/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in convert_to_tensor(value, dtype, name, preferred_dtype)
        996       name=name,
        997       preferred_dtype=preferred_dtype,
    --> 998       as_ref=False)
        999 
       1000 

    /home/juliano/.local/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in internal_convert_to_tensor(value, dtype, name, as_ref, preferred_dtype, ctx)
       1092 
       1093     if ret is None:
    -> 1094       ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
       1095 
       1096     if ret is NotImplemented:

    /home/juliano/.local/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in _TensorTensorConversionFunction(t, dtype, name, as_ref)
        929     raise ValueError(
        930         "Tensor conversion requested dtype %s for Tensor with dtype %s: %r" %
    --> 931         (dtype.name, t.dtype.name, str(t)))
        932   return t
        933 

    ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("lambda_9/Placeholder_1:0", shape=(), dtype=float32)'

有趣的是,据我了解,它表示stride变量是float32,尽管它被声明为int32,但应将其转换为int32。变量K.variable(20, dtype='int32', name='stride_var')

这是怎么了?任何帮助将非常感激!谢谢!

编辑:

正如@BlackBear所建议的,我添加了一个显式的强制转换,看来已经解决了部分问题:

def stdev_pooling(inputs):
    data, stride = inputs

    stride = K.cast(stride, dtype='int32')

    print K.dtype(stride), K.dtype(data), '---'

    num_windows = K.shape(data)[1] / stride

    idxs = K.arange(num_windows) * stride

    windows = K.map_fn(lambda w: data[:, w: (w + stride), :], idxs, dtype=K.floatx())

    windows = K.permute_dimensions(windows, (1,0,2,3))

    stds = K.map_fn(lambda w: K.std(w, axis=1), windows)

    return stds

输出:

int32 float32 ---
int32 float32 ---

但是,现在我有一个新错误,我不知道它来自哪里!

这是堆栈跟踪:



    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
     in ()
          3 x = np.arange(2000).reshape(2,-1,10)
          4 
    ----> 5 m = keras.Model(inputs=ipt, outputs=out)
          6 
          7 m.predict(x).shape

    /home/juliano/.local/lib/python2.7/site-packages/keras/legacy/interfaces.pyc in wrapper(*args, **kwargs)
         89                 warnings.warn('Update your `' + object_name +
         90                               '` call to the Keras 2 API: ' + signature, stacklevel=2)
    ---> 91             return func(*args, **kwargs)
         92         wrapper._original_function = func
         93         return wrapper

    /home/juliano/.local/lib/python2.7/site-packages/keras/engine/network.pyc in __init__(self, *args, **kwargs)
         91                 'inputs' in kwargs and 'outputs' in kwargs):
         92             # Graph network
    ---> 93             self._init_graph_network(*args, **kwargs)
         94         else:
         95             # Subclassed network

    /home/juliano/.local/lib/python2.7/site-packages/keras/engine/network.pyc in _init_graph_network(self, inputs, outputs, name)
        235         # Keep track of the network's nodes and layers.
        236         nodes, nodes_by_depth, layers, layers_by_depth = _map_graph_network(
    --> 237             self.inputs, self.outputs)
        238         self._network_nodes = nodes
        239         self._nodes_by_depth = nodes_by_depth

    /home/juliano/.local/lib/python2.7/site-packages/keras/engine/network.pyc in _map_graph_network(inputs, outputs)
       1351                   layer=layer,
       1352                   node_index=node_index,
    -> 1353                   tensor_index=tensor_index)
       1354 
       1355     for node in reversed(nodes_in_decreasing_depth):

    /home/juliano/.local/lib/python2.7/site-packages/keras/engine/network.pyc in build_map(tensor, finished_nodes, nodes_in_progress, layer, node_index, tensor_index)
       1338             tensor_index = node.tensor_indices[i]
       1339             build_map(x, finished_nodes, nodes_in_progress, layer,
    -> 1340                       node_index, tensor_index)
       1341 
       1342         finished_nodes.add(node)

    /home/juliano/.local/lib/python2.7/site-packages/keras/engine/network.pyc in build_map(tensor, finished_nodes, nodes_in_progress, layer, node_index, tensor_index)
       1310             ValueError: if a cycle is detected.
       1311         """
    -> 1312         node = layer._inbound_nodes[node_index]
       1313 
       1314         # Prevent cycles.

    AttributeError: 'NoneType' object has no attribute '_inbound_nodes'

编辑:我已经更新了stdev_pooling函数,它现在返回正确的输出。但是,我仍然遇到AttributeError: 'NoneType' object has no attribute '_inbound_nodes'错误...

1 个答案:

答案 0 :(得分:1)

在对代码进行了更多摆弄并阅读了keras如何与tensorflow交互之后(在许多不同的地方,包括tensorflow和keras的源代码),我发现了哪里出了问题。

首先,这是我想要做的一个最小的工作示例:

import tensorflow
import keras
from keras.layers import Dense, TimeDistributed, Lambda, Input
import numpy as np
import keras.backend as K


def stdev_pooling(inputs, stride):

    data = inputs

    padding = K.shape(data)[1] % stride

    data = K.switch(padding > 0, K.temporal_padding(data, padding=(0,stride-padding)), data )

    num_windows = K.shape(data)[1] / stride

    idxs = K.arange(num_windows) * stride

    windows = K.map_fn(lambda w: data[:, w: (w + stride), :], idxs, dtype=K.floatx())

    windows = K.permute_dimensions(windows, (1,0,2,3))

    stds = K.map_fn(lambda w: K.std(w, axis=1), windows)

    return stds

ipt = Input(shape=(None,10))
d = TimeDistributed(Dense(10))(ipt)
#stride is an argument to stdev_pooling, not a signal coming from
#a previous layer. Thus it must be passed in the `arguments`
#dictionary of the `Lambda` layer.
out = Lambda(stdev_pooling, arguments={'stride':15})(d)

x = np.arange(2000).reshape(2,-1,10)    
m = keras.Model(inputs=ipt, outputs=out)    
y = m.predict(x)
print y
print y.shape

问题出在先前代码中的out = Lambda(stdev_pooling)([d,K.variable(20, dtype='int32', name='stride_var')])行。

当提供信号(例如K.variable(...))作为Lambda层的输入时,keras希望将其连接到Input层。因此,错误AttributeError: 'NoneType' object has no attribute '_inbound_nodes'

解决方案只是通过Lambda层构造函数的arguments字典提供stride参数:

out = Lambda(stdev_pooling, arguments={'stride':15})(d)

我希望这段代码可以帮助所有人尝试在keras中构建某种池化层。有空的时候,我会将其写为适当的池化层。目前,此Lambda版本应该可以。