DSP*_*ted 3 concatenation deep-learning conv-neural-network keras tensorflow
我对修改后的 U-Net 架构的输入维度有一两个问题。为了节省您的时间并更好地理解/重现我的结果,我将发布代码和输出尺寸。修改后的U-Net架构是来自https://github.com/nibtehaz/MultiResUNet/blob/master/MultiResUNet.py的MultiResUNet架构。并基于本文https://arxiv.org/abs/1902.04049 请不要因这段代码的长度而关闭。您只需复制粘贴即可,重现我的结果的时间不会超过 10 秒。此外,您不需要为此提供数据集。使用 TF.v1.9 Keras v.2.20 进行测试。
import tensorflow as tf
from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Conv2DTranspose, concatenate, BatchNormalization, Activation, add
from tensorflow.keras.models import Model
from tensorflow.keras.activations import relu
###{ 2D Convolutional layers
# Arguments: ######################################################################
# x {keras layer} -- input layer #
# filters {int} -- number of filters #
# num_row {int} -- number of rows in filters #
# num_col {int} -- number of columns in filters #
# Keyword Arguments:
# padding {str} -- mode of padding (default: {'same'})
# strides {tuple} -- stride of convolution operation (default: {(1, 1)})
# activation {str} -- activation function (default: {'relu'})
# name {str} -- name of the layer (default: {None})
# Returns:
# [keras layer] -- [output layer]}
# # ############################################################################
def conv2d_bn(x, filters ,num_row,num_col, padding = "same", strides = (1,1), activation = 'relu', name = None):
x = Conv2D(filters,(num_row, num_col), strides=strides, padding=padding, use_bias=False)(x)
x = BatchNormalization(axis=3, scale=False)(x)
if(activation == None):
return x
x = Activation(activation, name=name)(x)
return x
# our 2D transposed Convolution with batch normalization
# 2D Transposed Convolutional layers
# Arguments: #############################################################
# x {keras layer} -- input layer #
# filters {int} -- number of filters #
# num_row {int} -- number of rows in filters #
# num_col {int} -- number of columns in filters
# Keyword Arguments:
# padding {str} -- mode of padding (default: {'same'})
# strides {tuple} -- stride of convolution operation (default: {(2, 2)})
# name {str} -- name of the layer (default: {None})
# Returns:
# [keras layer] -- [output layer] ###################################
def trans_conv2d_bn(x, filters, num_row, num_col, padding='same', strides=(2, 2), name=None):
x = Conv2DTranspose(filters, (num_row, num_col), strides=strides, padding=padding)(x)
x = BatchNormalization(axis=3, scale=False)(x)
return x
# Our Multi-Res Block
# Arguments: ############################################################
# U {int} -- Number of filters in a corrsponding UNet stage #
# inp {keras layer} -- input layer #
# Returns: #
# [keras layer] -- [output layer] #
###################################################################
def MultiResBlock(U, inp, alpha = 1.67):
W = alpha * U
shortcut = inp
shortcut = conv2d_bn(shortcut, int(W*0.167) + int(W*0.333) +
int(W*0.5), 1, 1, activation=None, padding='same')
conv3x3 = conv2d_bn(inp, int(W*0.167), 3, 3,
activation='relu', padding='same')
conv5x5 = conv2d_bn(conv3x3, int(W*0.333), 3, 3,
activation='relu', padding='same')
conv7x7 = conv2d_bn(conv5x5, int(W*0.5), 3, 3,
activation='relu', padding='same')
out = concatenate([conv3x3, conv5x5, conv7x7], axis=3)
out = BatchNormalization(axis=3)(out)
out = add([shortcut, out])
out = Activation('relu')(out)
out = BatchNormalization(axis=3)(out)
return out
# Our ResPath:
# ResPath
# Arguments:#######################################
# filters {int} -- [description]
# length {int} -- length of ResPath
# inp {keras layer} -- input layer
# Returns:
# [keras layer] -- [output layer]#############
def ResPath(filters, length, inp):
shortcut = inp
shortcut = conv2d_bn(shortcut, filters, 1, 1,
activation=None, padding='same')
out = conv2d_bn(inp, filters, 3, 3, activation='relu', padding='same')
out = add([shortcut, out])
out = Activation('relu')(out)
out = BatchNormalization(axis=3)(out)
for i in range(length-1):
shortcut = out
shortcut = conv2d_bn(shortcut, filters, 1, 1,
activation=None, padding='same')
out = conv2d_bn(out, filters, 3, 3, activation='relu', padding='same')
out = add([shortcut, out])
out = Activation('relu')(out)
out = BatchNormalization(axis=3)(out)
return out
# MultiResUNet
# Arguments: ############################################
# height {int} -- height of image
# width {int} -- width of image
# n_channels {int} -- number of channels in image
# Returns:
# [keras model] -- MultiResUNet model###############
def MultiResUnet(height, width, n_channels):
inputs = Input((height, width, n_channels))
# downsampling part begins here
mresblock1 = MultiResBlock(32, inputs)
pool1 = MaxPooling2D(pool_size=(2, 2))(mresblock1)
mresblock1 = ResPath(32, 4, mresblock1)
mresblock2 = MultiResBlock(32*2, pool1)
pool2 = MaxPooling2D(pool_size=(2, 2))(mresblock2)
mresblock2 = ResPath(32*2, 3, mresblock2)
mresblock3 = MultiResBlock(32*4, pool2)
pool3 = MaxPooling2D(pool_size=(2, 2))(mresblock3)
mresblock3 = ResPath(32*4, 2, mresblock3)
mresblock4 = MultiResBlock(32*8, pool3)
# Upsampling part
up5 = concatenate([Conv2DTranspose(
32*4, (2, 2), strides=(2, 2), padding='same')(mresblock4), mresblock3], axis=3)
mresblock5 = MultiResBlock(32*8, up5)
up6 = concatenate([Conv2DTranspose(
32*4, (2, 2), strides=(2, 2), padding='same')(mresblock5), mresblock2], axis=3)
mresblock6 = MultiResBlock(32*4, up6)
up7 = concatenate([Conv2DTranspose(
32*2, (2, 2), strides=(2, 2), padding='same')(mresblock6), mresblock1], axis=3)
mresblock7 = MultiResBlock(32*2, up7)
conv8 = conv2d_bn(mresblock7, 1, 1, 1, activation='sigmoid')
model = Model(inputs=[inputs], outputs=[conv8])
return model
Run Code Online (Sandbox Code Playgroud)
现在回到 UNet 架构中输入/输出维度不匹配的问题。
如果我选择过滤器高度/宽度 (128,128) 或 (256,256) 或 (512,512) 并执行以下操作:
model = MultiResUnet(128, 128,3)
display(model.summary())
Run Code Online (Sandbox Code Playgroud)
Tensorflow 为我提供了整个架构的完美结果。现在如果我这样做
model = MultiResUnet(36, 36,3)
display(model.summary())
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
-------------------------------------------------- ------------------------- ----> 1 model = MultiResUnet(36, 36,3) 中的 ValueError Traceback(最近一次调用最后一次) 2 显示(model.summary())
在 MultiResUnet(高度, 宽度, n_channels) 25 26 up5 = concatenate([Conv2DTranspose( ---> 27 32*4, (2, 2), strides=(2, 2), padding='same')(mresblock4) , mresblock3], 轴=3) 28 mresblock5 = MultiResBlock(32*8, up5) 29
~/miniconda3/envs/MastersThenv/lib/python3.6/site-packages/tensorflow/python/keras/layers/merge.py in concatenate(inputs, axis, **kwargs) 682 一个张量,输入的串联轴
axis。第683章 684、第685章 686调用中的〜/miniconda3/envs/MastersThenv/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py (self,inputs,*args,**kwargs)694如果全部(hasattr(x) , 'get_shape') for x in input_list): 695 input_shapes = Nest.map_struct(lambda x: x.get_shape(), input) --> 696 self.build(input_shapes) 697 698 # 检查层构建后设置的输入假设,例如输入形状。
包装器中的〜/ miniconda3 / envs / MastersThenv / lib / python3.6 / site-packages / tensorflow / python / keras / utils / tf_utils.py(实例,input_shape)146其他:147 input_shape = tuple(tensor_shape.TensorShape(input_shape) .as_list()) --> 148 output_shape = fn(instance, input_shape) 149 如果 output_shape 不是 None: 150 如果 isinstance(output_shape, list):
~/miniconda3/envs/MastersTheenv/lib/python3.6/site-packages/tensorflow/python/keras/layers/merge.py in build(self, input_shape) 388 '具有匹配形状' 389 '的输入,除了连接轴。' --> 390 '获得输入形状:%s' % (input_shape)) 391 392 def _merge_function(self, input):
ValueError:
Concatenate图层需要具有匹配形状(连接轴除外)的输入。获得输入形状:[(None, 8, 8, 128), (None, 9, 9, 128)]
为什么 Conv2DTranspose 给我错误的尺寸
(无、8、8、128)
代替
(无、9、9、128)
为什么当我选择像 (128,128)、(256,256) 等过滤器大小(32 的倍数)时 Concat 函数不会抱怨 所以概括这个问题我如何使这个 UNet 架构适用于任何过滤器大小以及如何我处理 Conv2DTranspose 层,生成一个比实际需要的尺寸少一维(宽度/高度)的输出(当过滤器大小不是 32 的倍数或不对称时),为什么其他情况不会发生这种情况过滤器大小是 32 的倍数。如果我有可变的输入大小怎么办?
任何帮助将不胜感激。
干杯,H
U-Net 系列模型(例如上面的 MultiResUNet 模型)遵循编码器-解码器架构。编码器是具有特征提取的下采样路径,而解码器是上采样路径。来自编码器的特征图通过跳跃连接在解码器处连接。这些特征图在最后一个轴“通道”轴处连接(考虑特征的尺寸为[batch_size、高度、宽度、通道])。现在,对于要在任何轴(在我们的例子中为“通道”轴)连接的特征,所有其他轴的尺寸必须匹配。
在上述模型架构中,编码器路径中(通过 )执行了3 个下采样/最大池操作。MaxPooling2D在解码器路径3 处执行上采样/转置卷积操作,旨在将图像恢复到全尺寸。然而,为了发生串联(通过跳过连接),下采样和上采样的高度、宽度和批量大小的特征尺寸应在模型的每个“级别”保持相同。我将用您在问题中提到的示例来说明这一点:
第一种情况:输入尺寸(128,128,3):128 -> 64 -> 32 -> 16 -> 32 -> 64 -> 128
第二种情况:输入尺寸(36,36,3):36 -> 18 -> 9 -> 4 -> 8 -> 16 -> 32
在第二种情况下,当编码器路径中特征图的高度和宽度达到9时,进一步下采样会导致尺寸变化(损失),而在上采样时,该尺寸变化无法在解码器中恢复。因此,由于无法连接维度[(None, 8, 8, 128)]和[(None, 9, 9, 128)]的特征图,它会抛出错误。
一般来说,对于具有“ n ”个下采样 ( MaxPooling2D) 层的简单编码器-解码器模型(具有跳跃连接),输入维度必须是2^n 的倍数,以便能够在解码器处连接模型的编码器特征。在这种情况下n=3,因此输入必须是8的倍数才不会遇到这些维度不匹配错误。
希望这可以帮助!:)
| 归档时间: |
|
| 查看次数: |
2288 次 |
| 最近记录: |