Keras可变宽度输入模型添加解码器时的输入尺寸报错求解
问题分析与解决方案
报错原因
这个InvalidArgumentError的核心问题是动态尺寸(输入宽度设为None)下,tf.boolean_mask + K.reshape的组合导致TensorFlow无法正确推断张量形状。
具体来说:
- 你的输入宽度是动态的(
None),所以masked张量的宽度维度在图构建阶段是未知的(静态形状为None)。 - 你用
tf.boolean_mask(masked, tf.not_equal(masked,0))把所有非零元素提取出来后,得到的non_zero是一维张量,此时尝试用K.reshape(non_zero,[-1, masked.shape[1], -1,1])恢复形状时,TensorFlow需要同时推断两个未知维度:第一个-1(batch size)和第三个-1(宽度)。而TensorFlow的reshape规则只允许存在一个未知维度(用-1表示),因此触发了报错。
另外,你的masked张量本身已经是经过掩码处理的结果:只有目标通道有非零值,其余通道全为0。完全没必要用tf.boolean_mask提取非零元素——这反而破坏了原有的空间维度结构,徒增形状推断的麻烦。
解决方案
修改Mask层的call方法,去掉tf.boolean_mask和有问题的reshape逻辑,直接通过通道维度的求和/取最大值来提取目标通道的内容,这样既能保留原有的空间维度(包括动态的宽度),又能避免形状推断错误。
修改后的Mask层call方法如下:
def call(self, inputs, **kwargs): if type(inputs) is list: # 传入了真实标签,形状为[None, n_classes](one-hot编码) assert len(inputs) == 2 inputs, mask = inputs inputs = K.squeeze(inputs, axis=-1) # [batch, input_height, input_width, num_cap, num_atom] -> [batch, input_height, input_width, num_cap] else: # 无真实标签,按胶囊的最大长度掩码,主要用于预测 inputs = K.squeeze(inputs, axis=-1) #[batch, input_height, input_width, num_cap] x = K.softmax(K.sqrt(K.sum(K.square(inputs), axis=(1,2)) + K.epsilon())) # x: [batch, 4] mask = K.one_hot(indices=K.argmax(x, 1), num_classes=x.get_shape().as_list()[1]) # mask: [batch,4] expand_mask = K.reshape(mask,[-1,1,1,mask.shape[1]]) #[batch_size, 1, 1, num_class] masked = inputs * expand_mask # 关键修改:直接对通道维度求和,提取非零通道的内容(其余通道都是0,求和不影响结果) # 输出形状保持为[batch, H, W, 1],完美支持动态宽度 non_zero_masked = K.sum(masked, axis=-1, keepdims=True) return non_zero_masked
为什么这个方案有效?
- 保留空间维度:
K.sum(masked, axis=-1, keepdims=True)会保留原张量的batch、高度、宽度维度,不管宽度是不是动态的(None),TensorFlow都能正确跟踪这些维度的动态变化。 - 逻辑等价:因为
masked只有目标通道有非零值,其余通道全为0,求和操作完全等价于提取目标通道的内容,和你原来用tf.boolean_mask再reshape的结果一致,但避免了形状推断的问题。 - 适配动态输入:修改后的输出形状是
[batch, 50, None, 1],完全符合Conv2DTranspose对输入的要求,转置卷积可以根据动态的宽度维度正确计算输出尺寸,适配任意输入宽度。
额外验证点
确保你的Conv2DTranspose层的配置是正确的:比如第一个转置卷积的strides是(2,2),输入高度是50,那么输出高度会是100;输入宽度是动态的,输出宽度也会是输入的2倍,完全匹配你恢复原输入尺寸的需求。
内容的提问来源于stack exchange,提问作者Jeonghwa Yoo
相关产品推荐
相关产品推荐

