在用Keras编写自己的层的时候,需要得到两个输出,困扰了好一会,上网查资料也没有找到满意的答案,然后就根据错误提示查看源码解决问题。
C:\Anaconda3\python.exe D:/yangzhaolu/KERAS/Keras-Segmentation/test.py
Using TensorFlow backend.
Traceback (most recent call last):
File "D:/yangzhaolu/KERAS/Keras-Segmentation/test.py", line 22, in <module>
avgpool()
File "D:/yangzhaolu/KERAS/Keras-Segmentation/test.py", line 15, in avgpool
x, ind= MaxPooling2DWithArgmax(pool_size=(2,2))(img_input)
File "C:\Anaconda3\lib\site-packages\keras\engine\topology.py", line 655, in __call__
arguments=user_kwargs)
File "C:\Anaconda3\lib\site-packages\keras\engine\topology.py", line 717, in _add_inbound_node
output_tensors[i]._keras_shape = output_shapes[i]
AttributeError: 'tuple' object has no attribute '_keras_shape'
以上代码是在编写MaxPooling2DWithArgmax层时遇到错误,MaxPooling2DWithArgmax层是用来实现语义分割SegNet网络中记录最大池化位置的一个网络层,我需要得到池化的结果pool以及池化结果的位置indices两个输出。以上是一个简单的介绍下面是解决方法:
根据错误提示找到源码:
File "C:\Anaconda3\lib\site-packages\keras\engine\topology.py", line 717, in _add_inbound_node
output_tensors[i]._keras_shape = output_shapes[i]
AttributeError: 'tuple' object has no attribute '_keras_shape'
源码:
# Update tensor history, _keras_shape and _uses_learning_phase.
for i in range(len(output_tensors)):
output_tensors[i]._keras_shape = output_shapes[i]
uses_lp = any([getattr(x, '_uses_learning_phase', False) for x in input_tensors])
uses_lp = getattr(self, 'uses_learning_phase', False) or uses_lp
output_tensors[i]._uses_learning_phase = getattr(output_tensors[i], '_uses_learning_phase', False) or uses_lp
output_tensors[i]._keras_history = (self, len(self._inbound_nodes) - 1, i)
然后顺着代码往上找:
# Arguments
input_tensors: list of input tensors.
output_tensors: list of output tensors.
这里的参数要求的是输出向量应该是列表类型,因此需要将输出向量的output_shape以及输出向量都放在一个list列表里面。
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
rows = input_shape[2]
cols = input_shape[3]
elif self.data_format == 'channels_last':
rows = input_shape[1]
cols = input_shape[2]
rows = conv_utils.conv_output_length(rows, self.pool_size[0], self.padding, self.strides[0])
cols = conv_utils.conv_output_length(cols, self.pool_size[1], self.padding, self.strides[1])
if self.data_format == 'channels_first':
return [(input_shape[0], input_shape[1], rows, cols), (input_shape[0], input_shape[1], rows, cols)] # 转换成列表
elif self.data_format == 'channels_last':
return [(input_shape[0], rows, cols, input_shape[3]), (input_shape[0], rows, cols, input_shape[3])] # 转换成列表
def _pooling_function(self, inputs, pool_size, strides,
padding, data_format):
raise NotImplementedError
def call(self, inputs):
output, indices = self._pooling_function(inputs=inputs,
pool_size=self.pool_size,
strides=self.strides,
padding=self.padding,
data_format=self.data_format)
return [output, indices] # 转换成列表
多输入的情况,同样道理,例如两个tensor相加,直接用Add() 层
Add()([x1, x2])