├── ContextNet ├── ContextNet.py ├── bottleneck_residual_blocks.py ├── convolutional.py ├── data │ ├── gtFine │ │ └── CityScapes.txt │ └── leftImg8bit │ │ └── CityScapes.txt ├── data_processing.py └── train_test.py └── README.md /ContextNet/ContextNet.py: -------------------------------------------------------------------------------- 1 | import keras 2 | from keras.models import Model, load_model 3 | from keras.layers.convolutional import Conv2D, UpSampling2D, SeparableConv2D 4 | from keras.layers import Input, add, Reshape, Activation, BatchNormalization 5 | from bottleneck_residual_blocks import _inverted_residual_block 6 | from keras.applications.mobilenet import relu6 7 | 8 | class ContextNet(): 9 | """ 10 | Provides the main structure of contextnet 11 | """ 12 | def __init__(self, n_labels, image_shape, target_shape): 13 | self.n_labels = n_labels 14 | self.image_shape = image_shape 15 | self.target_shape = target_shape 16 | pass 17 | 18 | def deep_net(self, x): 19 | #x = Conv2D(32, (3, 3), strides = (2, 2), activation = 'relu', padding = 'same', name = 'conv1', data_format = 'channels_last')(x) 20 | x = Conv2D(32, (3, 3), strides = (2, 2), padding = 'same', name = 'conv1', data_format = 'channels_last')(x) 21 | x = BatchNormalization()(x) 22 | x = Activation(relu6)(x) 23 | 24 | x = _inverted_residual_block(x, 32, (3, 3), t = 1, strides = 1, n = 1) 25 | x = _inverted_residual_block(x, 32, (3, 3), t = 6, strides = 1, n = 1) 26 | x = _inverted_residual_block(x, 48, (3, 3), t = 6, strides = 2, n = 3) 27 | x = _inverted_residual_block(x, 64, (3, 3), t = 6, strides = 2, n =3) 28 | x = _inverted_residual_block(x, 96, (3, 3), t = 6, strides = 1, n = 2) 29 | x = _inverted_residual_block(x, 128, (3, 3), t = 6, strides = 1, n = 1) 30 | #x = Conv2D(128, (3, 3), activation = 'relu', padding = 'same', name = 'conv2')(x) 31 | x = Conv2D(128, (3, 3), padding = 'same', name = 'conv2')(x) 32 | x = BatchNormalization()(x) 33 | x = Activation(relu6)(x) 34 | 35 | return x 36 | 37 | def shallow_net(self, x): 38 | """ 39 | x = Conv2D(32, (3, 3), strides = (2, 2), activation = 'relu', padding = 'same', name = 'sep_conv1', data_format = 'channels_last')(x) 40 | x = SeparableConv2D(64, (3, 3), strides = (2, 2), activation = 'relu', padding = 'same', name = 'sep_conv2')(x) 41 | x = SeparableConv2D(128, (3, 3), strides = (2, 2), activation = 'relu', padding = 'same', name = 'sep_conv3')(x) 42 | x = SeparableConv2D(128, (3, 3), activation = 'relu', padding = 'same', name = 'sep_conv4')(x) 43 | """ 44 | x = Conv2D(32, (3, 3), strides = (2, 2), padding = 'same', name = 'sep_conv1', data_format = 'channels_last')(x) 45 | x = BatchNormalization()(x) 46 | x = Activation(relu6)(x) 47 | 48 | x = SeparableConv2D(64, (3, 3), strides = (2, 2), padding = 'same', name = 'sep_conv2')(x) 49 | x = BatchNormalization()(x) 50 | x = Activation(relu6)(x) 51 | 52 | x = SeparableConv2D(128, (3, 3), strides = (2, 2), padding = 'same', name = 'sep_conv3')(x) 53 | x = BatchNormalization()(x) 54 | x = Activation(relu6)(x) 55 | 56 | x = SeparableConv2D(128, (3, 3), padding = 'same', name = 'sep_conv4')(x) 57 | x = BatchNormalization()(x) 58 | x = Activation(relu6)(x) 59 | 60 | return x 61 | 62 | def feature_fusion_unit(self, input_tensor1, input_tensor2): 63 | 64 | input1 = Conv2D(128, (1, 1), strides=(1, 1), padding = 'same', name = 'unit_conv1')(input_tensor1) 65 | input2 = UpSampling2D((4, 4))(input_tensor2) 66 | #input2 = SeparableConv2D(128, (3, 3), strides = (1, 1), dilation_rate=(4, 4), activation = 'relu', padding = 'same')(input2) 67 | input2 = SeparableConv2D(128, (3, 3), strides = (1, 1), dilation_rate=(4, 4), padding = 'same')(input2) 68 | input2 = BatchNormalization()(input2) 69 | input2 = Activation(relu6)(input2) 70 | 71 | input2 = Conv2D(128, (1, 1), strides=(1, 1), padding = 'same', name = 'unit_conv2')(input2) 72 | input_tensors = add([input1, input2]) 73 | 74 | 75 | result = Conv2D(self.n_labels, (1, 1), strides = (1, 1), activation = 'softmax', padding = 'same', name = 'conv_last')(input_tensors) 76 | 77 | return result 78 | 79 | def init_model(self): 80 | 81 | h, w, d = self.image_shape 82 | input1 = Input(shape=(h, w, d), name = 'input1') 83 | output_d = self.deep_net(input1) 84 | 85 | input2 = Input(shape=(int(h/4), int(w/4), d), name = 'input2') 86 | output_s = self.shallow_net(input2) 87 | 88 | print(f'output1,2: {output_d.shape, output_s.shape}') 89 | output = self.feature_fusion_unit(output_d, output_s) 90 | context_net = Model(inputs = [input1, input2], outputs = output, name = 'context_model') 91 | opt = keras.optimizers.RMSprop(lr = 1e-4, rho=0.9, epsilon=1e-08, decay=0.0) 92 | context_net.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) 93 | 94 | return context_net 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /ContextNet/bottleneck_residual_blocks.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reference: 3 | https://github.com/xiaochus/MobileNetV2/blob/master/mobilenet_v2.py 4 | 5 | """ 6 | 7 | from keras.layers import Conv2D 8 | from keras.layers import Activation, BatchNormalization, add 9 | from keras.applications.mobilenet import relu6, DepthwiseConv2D 10 | from keras import backend as K 11 | 12 | def _conv_block(inputs, filters, kernel, strides): 13 | """Convolution Block 14 | This function defines a 2D convolution operation with BN and relu6. 15 | # Arguments 16 | inputs: Tensor, input tensor of conv layer. 17 | filters: Integer, the dimensionality of the output space. 18 | kernel: An integer or tuple/list of 2 integers, specifying the 19 | width and height of the 2D convolution window. 20 | strides: An integer or tuple/list of 2 integers, 21 | specifying the strides of the convolution along the width and height. 22 | Can be a single integer to specify the same value for 23 | all spatial dimensions. 24 | # Returns 25 | Output tensor. 26 | """ 27 | 28 | channel_axis = 1 if K.image_data_format() == 'channels_first' else -1 29 | 30 | x = Conv2D(filters, kernel, padding='same', strides=strides)(inputs) 31 | x = BatchNormalization(axis=channel_axis)(x) 32 | return Activation(relu6)(x) 33 | 34 | 35 | def _bottleneck(inputs, filters, kernel, t, s, r=False): 36 | """Bottleneck 37 | This function defines a basic bottleneck structure. 38 | # Arguments 39 | inputs: Tensor, input tensor of conv layer. 40 | filters: Integer, the dimensionality of the output space. 41 | kernel: An integer or tuple/list of 2 integers, specifying the 42 | width and height of the 2D convolution window. 43 | t: Integer, expansion factor. 44 | t is always applied to the input size. 45 | s: An integer or tuple/list of 2 integers,specifying the strides 46 | of the convolution along the width and height.Can be a single 47 | integer to specify the same value for all spatial dimensions. 48 | r: Boolean, Whether to use the residuals. 49 | # Returns 50 | Output tensor. 51 | """ 52 | 53 | channel_axis = 1 if K.image_data_format() == 'channels_first' else -1 54 | tchannel = K.int_shape(inputs)[channel_axis] * t 55 | 56 | x = _conv_block(inputs, tchannel, (1, 1), (1, 1)) 57 | 58 | x = DepthwiseConv2D(kernel, strides=(s, s), depth_multiplier=1, padding='same')(x) 59 | x = BatchNormalization(axis=channel_axis)(x) 60 | x = Activation(relu6)(x) 61 | 62 | x = Conv2D(filters, (1, 1), strides=(1, 1), padding='same')(x) 63 | x = BatchNormalization(axis=channel_axis)(x) 64 | 65 | if r: 66 | x = add([x, inputs]) 67 | return x 68 | 69 | 70 | def _inverted_residual_block(inputs, filters, kernel, t, strides, n): 71 | """Inverted Residual Block 72 | This function defines a sequence of 1 or more identical layers. 73 | # Arguments 74 | inputs: Tensor, input tensor of conv layer. 75 | filters: Integer, the dimensionality of the output space. 76 | kernel: An integer or tuple/list of 2 integers, specifying the 77 | width and height of the 2D convolution window. 78 | t: Integer, expansion factor. 79 | t is always applied to the input size. 80 | s: An integer or tuple/list of 2 integers,specifying the strides 81 | of the convolution along the width and height.Can be a single 82 | integer to specify the same value for all spatial dimensions. 83 | n: Integer, layer repeat times. 84 | # Returns 85 | Output tensor. 86 | """ 87 | 88 | x = _bottleneck(inputs, filters, kernel, t, strides) 89 | 90 | for i in range(1, n): 91 | x = _bottleneck(x, filters, kernel, t, 1, True) 92 | 93 | return x -------------------------------------------------------------------------------- /ContextNet/convolutional.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import 3 | 4 | from .. import backend as K 5 | from .. import activations 6 | from .. import initializers 7 | from .. import regularizers 8 | from .. import constraints 9 | from ..engine import Layer 10 | from ..engine import InputSpec 11 | from ..utils import conv_utils 12 | from ..legacy import interfaces 13 | 14 | # imports for backwards namespace compatibility 15 | from .pooling import AveragePooling1D 16 | from .pooling import AveragePooling2D 17 | from .pooling import AveragePooling3D 18 | from .pooling import MaxPooling1D 19 | from .pooling import MaxPooling2D 20 | from .pooling import MaxPooling3D 21 | 22 | from ..legacy.layers import AtrousConvolution1D 23 | from ..legacy.layers import AtrousConvolution2D 24 | 25 | 26 | class _Conv(Layer): 27 | """Abstract nD convolution layer (private, used as implementation base). 28 | 29 | This layer creates a convolution kernel that is convolved 30 | with the layer input to produce a tensor of outputs. 31 | If `use_bias` is True, a bias vector is created and added to the outputs. 32 | Finally, if `activation` is not `None`, 33 | it is applied to the outputs as well. 34 | 35 | # Arguments 36 | rank: An integer, the rank of the convolution, 37 | e.g. "2" for 2D convolution. 38 | filters: Integer, the dimensionality of the output space 39 | (i.e. the number output of filters in the convolution). 40 | kernel_size: An integer or tuple/list of n integers, specifying the 41 | dimensions of the convolution window. 42 | strides: An integer or tuple/list of n integers, 43 | specifying the strides of the convolution. 44 | Specifying any stride value != 1 is incompatible with specifying 45 | any `dilation_rate` value != 1. 46 | padding: One of `"valid"` or `"same"` (case-insensitive). 47 | data_format: A string, 48 | one of `channels_last` (default) or `channels_first`. 49 | The ordering of the dimensions in the inputs. 50 | `channels_last` corresponds to inputs with shape 51 | `(batch, ..., channels)` while `channels_first` corresponds to 52 | inputs with shape `(batch, channels, ...)`. 53 | It defaults to the `image_data_format` value found in your 54 | Keras config file at `~/.keras/keras.json`. 55 | If you never set it, then it will be "channels_last". 56 | dilation_rate: An integer or tuple/list of n integers, specifying 57 | the dilation rate to use for dilated convolution. 58 | Currently, specifying any `dilation_rate` value != 1 is 59 | incompatible with specifying any `strides` value != 1. 60 | activation: Activation function to use 61 | (see [activations](../activations.md)). 62 | If you don't specify anything, no activation is applied 63 | (ie. "linear" activation: `a(x) = x`). 64 | use_bias: Boolean, whether the layer uses a bias vector. 65 | kernel_initializer: Initializer for the `kernel` weights matrix 66 | (see [initializers](../initializers.md)). 67 | bias_initializer: Initializer for the bias vector 68 | (see [initializers](../initializers.md)). 69 | kernel_regularizer: Regularizer function applied to 70 | the `kernel` weights matrix 71 | (see [regularizer](../regularizers.md)). 72 | bias_regularizer: Regularizer function applied to the bias vector 73 | (see [regularizer](../regularizers.md)). 74 | activity_regularizer: Regularizer function applied to 75 | the output of the layer (its "activation"). 76 | (see [regularizer](../regularizers.md)). 77 | kernel_constraint: Constraint function applied to the kernel matrix 78 | (see [constraints](../constraints.md)). 79 | bias_constraint: Constraint function applied to the bias vector 80 | (see [constraints](../constraints.md)). 81 | """ 82 | 83 | def __init__(self, rank, 84 | filters, 85 | kernel_size, 86 | strides=1, 87 | padding='valid', 88 | data_format=None, 89 | dilation_rate=1, 90 | activation=None, 91 | use_bias=True, 92 | kernel_initializer='glorot_uniform', 93 | bias_initializer='zeros', 94 | kernel_regularizer=None, 95 | bias_regularizer=None, 96 | activity_regularizer=None, 97 | kernel_constraint=None, 98 | bias_constraint=None, 99 | **kwargs): 100 | super(_Conv, self).__init__(**kwargs) 101 | self.rank = rank 102 | self.filters = filters 103 | self.kernel_size = conv_utils.normalize_tuple(kernel_size, rank, 'kernel_size') 104 | self.strides = conv_utils.normalize_tuple(strides, rank, 'strides') 105 | self.padding = conv_utils.normalize_padding(padding) 106 | self.data_format = conv_utils.normalize_data_format(data_format) 107 | self.dilation_rate = conv_utils.normalize_tuple(dilation_rate, rank, 'dilation_rate') 108 | self.activation = activations.get(activation) 109 | self.use_bias = use_bias 110 | self.kernel_initializer = initializers.get(kernel_initializer) 111 | self.bias_initializer = initializers.get(bias_initializer) 112 | self.kernel_regularizer = regularizers.get(kernel_regularizer) 113 | self.bias_regularizer = regularizers.get(bias_regularizer) 114 | self.activity_regularizer = regularizers.get(activity_regularizer) 115 | self.kernel_constraint = constraints.get(kernel_constraint) 116 | self.bias_constraint = constraints.get(bias_constraint) 117 | self.input_spec = InputSpec(ndim=self.rank + 2) 118 | 119 | def build(self, input_shape): 120 | if self.data_format == 'channels_first': 121 | channel_axis = 1 122 | else: 123 | channel_axis = -1 124 | if input_shape[channel_axis] is None: 125 | raise ValueError('The channel dimension of the inputs ' 126 | 'should be defined. Found `None`.') 127 | input_dim = input_shape[channel_axis] 128 | kernel_shape = self.kernel_size + (input_dim, self.filters) 129 | 130 | self.kernel = self.add_weight(shape=kernel_shape, 131 | initializer=self.kernel_initializer, 132 | name='kernel', 133 | regularizer=self.kernel_regularizer, 134 | constraint=self.kernel_constraint) 135 | if self.use_bias: 136 | self.bias = self.add_weight(shape=(self.filters,), 137 | initializer=self.bias_initializer, 138 | name='bias', 139 | regularizer=self.bias_regularizer, 140 | constraint=self.bias_constraint) 141 | else: 142 | self.bias = None 143 | # Set input spec. 144 | self.input_spec = InputSpec(ndim=self.rank + 2, 145 | axes={channel_axis: input_dim}) 146 | self.built = True 147 | 148 | def call(self, inputs): 149 | if self.rank == 1: 150 | outputs = K.conv1d( 151 | inputs, 152 | self.kernel, 153 | strides=self.strides[0], 154 | padding=self.padding, 155 | data_format=self.data_format, 156 | dilation_rate=self.dilation_rate[0]) 157 | if self.rank == 2: 158 | outputs = K.conv2d( 159 | inputs, 160 | self.kernel, 161 | strides=self.strides, 162 | padding=self.padding, 163 | data_format=self.data_format, 164 | dilation_rate=self.dilation_rate) 165 | if self.rank == 3: 166 | outputs = K.conv3d( 167 | inputs, 168 | self.kernel, 169 | strides=self.strides, 170 | padding=self.padding, 171 | data_format=self.data_format, 172 | dilation_rate=self.dilation_rate) 173 | 174 | if self.use_bias: 175 | outputs = K.bias_add( 176 | outputs, 177 | self.bias, 178 | data_format=self.data_format) 179 | 180 | if self.activation is not None: 181 | return self.activation(outputs) 182 | return outputs 183 | 184 | def compute_output_shape(self, input_shape): 185 | if self.data_format == 'channels_last': 186 | space = input_shape[1:-1] 187 | new_space = [] 188 | for i in range(len(space)): 189 | new_dim = conv_utils.conv_output_length( 190 | space[i], 191 | self.kernel_size[i], 192 | padding=self.padding, 193 | stride=self.strides[i], 194 | dilation=self.dilation_rate[i]) 195 | new_space.append(new_dim) 196 | return (input_shape[0],) + tuple(new_space) + (self.filters,) 197 | if self.data_format == 'channels_first': 198 | space = input_shape[2:] 199 | new_space = [] 200 | for i in range(len(space)): 201 | new_dim = conv_utils.conv_output_length( 202 | space[i], 203 | self.kernel_size[i], 204 | padding=self.padding, 205 | stride=self.strides[i], 206 | dilation=self.dilation_rate[i]) 207 | new_space.append(new_dim) 208 | return (input_shape[0], self.filters) + tuple(new_space) 209 | 210 | def get_config(self): 211 | config = { 212 | 'rank': self.rank, 213 | 'filters': self.filters, 214 | 'kernel_size': self.kernel_size, 215 | 'strides': self.strides, 216 | 'padding': self.padding, 217 | 'data_format': self.data_format, 218 | 'dilation_rate': self.dilation_rate, 219 | 'activation': activations.serialize(self.activation), 220 | 'use_bias': self.use_bias, 221 | 'kernel_initializer': initializers.serialize(self.kernel_initializer), 222 | 'bias_initializer': initializers.serialize(self.bias_initializer), 223 | 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer), 224 | 'bias_regularizer': regularizers.serialize(self.bias_regularizer), 225 | 'activity_regularizer': regularizers.serialize(self.activity_regularizer), 226 | 'kernel_constraint': constraints.serialize(self.kernel_constraint), 227 | 'bias_constraint': constraints.serialize(self.bias_constraint) 228 | } 229 | base_config = super(_Conv, self).get_config() 230 | return dict(list(base_config.items()) + list(config.items())) 231 | 232 | 233 | class Conv1D(_Conv): 234 | """1D convolution layer (e.g. temporal convolution). 235 | 236 | This layer creates a convolution kernel that is convolved 237 | with the layer input over a single spatial (or temporal) dimension 238 | to produce a tensor of outputs. 239 | If `use_bias` is True, a bias vector is created and added to the outputs. 240 | Finally, if `activation` is not `None`, 241 | it is applied to the outputs as well. 242 | 243 | When using this layer as the first layer in a model, 244 | provide an `input_shape` argument 245 | (tuple of integers or `None`, e.g. 246 | `(10, 128)` for sequences of 10 vectors of 128-dimensional vectors, 247 | or `(None, 128)` for variable-length sequences of 128-dimensional vectors. 248 | 249 | # Arguments 250 | filters: Integer, the dimensionality of the output space 251 | (i.e. the number output of filters in the convolution). 252 | kernel_size: An integer or tuple/list of a single integer, 253 | specifying the length of the 1D convolution window. 254 | strides: An integer or tuple/list of a single integer, 255 | specifying the stride length of the convolution. 256 | Specifying any stride value != 1 is incompatible with specifying 257 | any `dilation_rate` value != 1. 258 | padding: One of `"valid"`, `"causal"` or `"same"` (case-insensitive). 259 | `"valid"` means "no padding". 260 | `"same"` results in padding the input such that 261 | the output has the same length as the original input. 262 | `"causal"` results in causal (dilated) convolutions, e.g. output[t] 263 | does not depend on input[t+1:]. Useful when modeling temporal data 264 | where the model should not violate the temporal order. 265 | See [WaveNet: A Generative Model for Raw Audio, section 2.1](https://arxiv.org/abs/1609.03499). 266 | dilation_rate: an integer or tuple/list of a single integer, specifying 267 | the dilation rate to use for dilated convolution. 268 | Currently, specifying any `dilation_rate` value != 1 is 269 | incompatible with specifying any `strides` value != 1. 270 | activation: Activation function to use 271 | (see [activations](../activations.md)). 272 | If you don't specify anything, no activation is applied 273 | (ie. "linear" activation: `a(x) = x`). 274 | use_bias: Boolean, whether the layer uses a bias vector. 275 | kernel_initializer: Initializer for the `kernel` weights matrix 276 | (see [initializers](../initializers.md)). 277 | bias_initializer: Initializer for the bias vector 278 | (see [initializers](../initializers.md)). 279 | kernel_regularizer: Regularizer function applied to 280 | the `kernel` weights matrix 281 | (see [regularizer](../regularizers.md)). 282 | bias_regularizer: Regularizer function applied to the bias vector 283 | (see [regularizer](../regularizers.md)). 284 | activity_regularizer: Regularizer function applied to 285 | the output of the layer (its "activation"). 286 | (see [regularizer](../regularizers.md)). 287 | kernel_constraint: Constraint function applied to the kernel matrix 288 | (see [constraints](../constraints.md)). 289 | bias_constraint: Constraint function applied to the bias vector 290 | (see [constraints](../constraints.md)). 291 | 292 | # Input shape 293 | 3D tensor with shape: `(batch_size, steps, input_dim)` 294 | 295 | # Output shape 296 | 3D tensor with shape: `(batch_size, new_steps, filters)` 297 | `steps` value might have changed due to padding or strides. 298 | """ 299 | 300 | @interfaces.legacy_conv1d_support 301 | def __init__(self, filters, 302 | kernel_size, 303 | strides=1, 304 | padding='valid', 305 | dilation_rate=1, 306 | activation=None, 307 | use_bias=True, 308 | kernel_initializer='glorot_uniform', 309 | bias_initializer='zeros', 310 | kernel_regularizer=None, 311 | bias_regularizer=None, 312 | activity_regularizer=None, 313 | kernel_constraint=None, 314 | bias_constraint=None, 315 | **kwargs): 316 | super(Conv1D, self).__init__( 317 | rank=1, 318 | filters=filters, 319 | kernel_size=kernel_size, 320 | strides=strides, 321 | padding=padding, 322 | data_format='channels_last', 323 | dilation_rate=dilation_rate, 324 | activation=activation, 325 | use_bias=use_bias, 326 | kernel_initializer=kernel_initializer, 327 | bias_initializer=bias_initializer, 328 | kernel_regularizer=kernel_regularizer, 329 | bias_regularizer=bias_regularizer, 330 | activity_regularizer=activity_regularizer, 331 | kernel_constraint=kernel_constraint, 332 | bias_constraint=bias_constraint, 333 | **kwargs) 334 | self.input_spec = InputSpec(ndim=3) 335 | 336 | def get_config(self): 337 | config = super(Conv1D, self).get_config() 338 | config.pop('rank') 339 | config.pop('data_format') 340 | return config 341 | 342 | 343 | class Conv2D(_Conv): 344 | """2D convolution layer (e.g. spatial convolution over images). 345 | 346 | This layer creates a convolution kernel that is convolved 347 | with the layer input to produce a tensor of 348 | outputs. If `use_bias` is True, 349 | a bias vector is created and added to the outputs. Finally, if 350 | `activation` is not `None`, it is applied to the outputs as well. 351 | 352 | When using this layer as the first layer in a model, 353 | provide the keyword argument `input_shape` 354 | (tuple of integers, does not include the sample axis), 355 | e.g. `input_shape=(128, 128, 3)` for 128x128 RGB pictures 356 | in `data_format="channels_last"`. 357 | 358 | # Arguments 359 | filters: Integer, the dimensionality of the output space 360 | (i.e. the number output of filters in the convolution). 361 | kernel_size: An integer or tuple/list of 2 integers, specifying the 362 | width and height of the 2D convolution window. 363 | Can be a single integer to specify the same value for 364 | all spatial dimensions. 365 | strides: An integer or tuple/list of 2 integers, 366 | specifying the strides of the convolution along the width and height. 367 | Can be a single integer to specify the same value for 368 | all spatial dimensions. 369 | Specifying any stride value != 1 is incompatible with specifying 370 | any `dilation_rate` value != 1. 371 | padding: one of `"valid"` or `"same"` (case-insensitive). 372 | data_format: A string, 373 | one of `channels_last` (default) or `channels_first`. 374 | The ordering of the dimensions in the inputs. 375 | `channels_last` corresponds to inputs with shape 376 | `(batch, height, width, channels)` while `channels_first` 377 | corresponds to inputs with shape 378 | `(batch, channels, height, width)`. 379 | It defaults to the `image_data_format` value found in your 380 | Keras config file at `~/.keras/keras.json`. 381 | If you never set it, then it will be "channels_last". 382 | dilation_rate: an integer or tuple/list of 2 integers, specifying 383 | the dilation rate to use for dilated convolution. 384 | Can be a single integer to specify the same value for 385 | all spatial dimensions. 386 | Currently, specifying any `dilation_rate` value != 1 is 387 | incompatible with specifying any stride value != 1. 388 | activation: Activation function to use 389 | (see [activations](../activations.md)). 390 | If you don't specify anything, no activation is applied 391 | (ie. "linear" activation: `a(x) = x`). 392 | use_bias: Boolean, whether the layer uses a bias vector. 393 | kernel_initializer: Initializer for the `kernel` weights matrix 394 | (see [initializers](../initializers.md)). 395 | bias_initializer: Initializer for the bias vector 396 | (see [initializers](../initializers.md)). 397 | kernel_regularizer: Regularizer function applied to 398 | the `kernel` weights matrix 399 | (see [regularizer](../regularizers.md)). 400 | bias_regularizer: Regularizer function applied to the bias vector 401 | (see [regularizer](../regularizers.md)). 402 | activity_regularizer: Regularizer function applied to 403 | the output of the layer (its "activation"). 404 | (see [regularizer](../regularizers.md)). 405 | kernel_constraint: Constraint function applied to the kernel matrix 406 | (see [constraints](../constraints.md)). 407 | bias_constraint: Constraint function applied to the bias vector 408 | (see [constraints](../constraints.md)). 409 | 410 | # Input shape 411 | 4D tensor with shape: 412 | `(samples, channels, rows, cols)` if data_format='channels_first' 413 | or 4D tensor with shape: 414 | `(samples, rows, cols, channels)` if data_format='channels_last'. 415 | 416 | # Output shape 417 | 4D tensor with shape: 418 | `(samples, filters, new_rows, new_cols)` if data_format='channels_first' 419 | or 4D tensor with shape: 420 | `(samples, new_rows, new_cols, filters)` if data_format='channels_last'. 421 | `rows` and `cols` values might have changed due to padding. 422 | """ 423 | 424 | @interfaces.legacy_conv2d_support 425 | def __init__(self, filters, 426 | kernel_size, 427 | strides=(1, 1), 428 | padding='valid', 429 | data_format=None, 430 | dilation_rate=(1, 1), 431 | activation=None, 432 | use_bias=True, 433 | kernel_initializer='glorot_uniform', 434 | bias_initializer='zeros', 435 | kernel_regularizer=None, 436 | bias_regularizer=None, 437 | activity_regularizer=None, 438 | kernel_constraint=None, 439 | bias_constraint=None, 440 | **kwargs): 441 | super(Conv2D, self).__init__( 442 | rank=2, 443 | filters=filters, 444 | kernel_size=kernel_size, 445 | strides=strides, 446 | padding=padding, 447 | data_format=data_format, 448 | dilation_rate=dilation_rate, 449 | activation=activation, 450 | use_bias=use_bias, 451 | kernel_initializer=kernel_initializer, 452 | bias_initializer=bias_initializer, 453 | kernel_regularizer=kernel_regularizer, 454 | bias_regularizer=bias_regularizer, 455 | activity_regularizer=activity_regularizer, 456 | kernel_constraint=kernel_constraint, 457 | bias_constraint=bias_constraint, 458 | **kwargs) 459 | self.input_spec = InputSpec(ndim=4) 460 | 461 | def get_config(self): 462 | config = super(Conv2D, self).get_config() 463 | config.pop('rank') 464 | return config 465 | 466 | 467 | class Conv3D(_Conv): 468 | """3D convolution layer (e.g. spatial convolution over volumes). 469 | 470 | This layer creates a convolution kernel that is convolved 471 | with the layer input to produce a tensor of 472 | outputs. If `use_bias` is True, 473 | a bias vector is created and added to the outputs. Finally, if 474 | `activation` is not `None`, it is applied to the outputs as well. 475 | 476 | When using this layer as the first layer in a model, 477 | provide the keyword argument `input_shape` 478 | (tuple of integers, does not include the sample axis), 479 | e.g. `input_shape=(128, 128, 128, 1)` for 128x128x128 volumes 480 | with a single channel, 481 | in `data_format="channels_last"`. 482 | 483 | # Arguments 484 | filters: Integer, the dimensionality of the output space 485 | (i.e. the number output of filters in the convolution). 486 | kernel_size: An integer or tuple/list of 3 integers, specifying the 487 | depth, height and width of the 3D convolution window. 488 | Can be a single integer to specify the same value for 489 | all spatial dimensions. 490 | strides: An integer or tuple/list of 3 integers, 491 | specifying the strides of the convolution along each spatial dimension. 492 | Can be a single integer to specify the same value for 493 | all spatial dimensions. 494 | Specifying any stride value != 1 is incompatible with specifying 495 | any `dilation_rate` value != 1. 496 | padding: one of `"valid"` or `"same"` (case-insensitive). 497 | data_format: A string, 498 | one of `channels_last` (default) or `channels_first`. 499 | The ordering of the dimensions in the inputs. 500 | `channels_last` corresponds to inputs with shape 501 | `(batch, spatial_dim1, spatial_dim2, spatial_dim3, channels)` 502 | while `channels_first` corresponds to inputs with shape 503 | `(batch, channels, spatial_dim1, spatial_dim2, spatial_dim3)`. 504 | It defaults to the `image_data_format` value found in your 505 | Keras config file at `~/.keras/keras.json`. 506 | If you never set it, then it will be "channels_last". 507 | dilation_rate: an integer or tuple/list of 3 integers, specifying 508 | the dilation rate to use for dilated convolution. 509 | Can be a single integer to specify the same value for 510 | all spatial dimensions. 511 | Currently, specifying any `dilation_rate` value != 1 is 512 | incompatible with specifying any stride value != 1. 513 | activation: Activation function to use 514 | (see [activations](../activations.md)). 515 | If you don't specify anything, no activation is applied 516 | (ie. "linear" activation: `a(x) = x`). 517 | use_bias: Boolean, whether the layer uses a bias vector. 518 | kernel_initializer: Initializer for the `kernel` weights matrix 519 | (see [initializers](../initializers.md)). 520 | bias_initializer: Initializer for the bias vector 521 | (see [initializers](../initializers.md)). 522 | kernel_regularizer: Regularizer function applied to 523 | the `kernel` weights matrix 524 | (see [regularizer](../regularizers.md)). 525 | bias_regularizer: Regularizer function applied to the bias vector 526 | (see [regularizer](../regularizers.md)). 527 | activity_regularizer: Regularizer function applied to 528 | the output of the layer (its "activation"). 529 | (see [regularizer](../regularizers.md)). 530 | kernel_constraint: Constraint function applied to the kernel matrix 531 | (see [constraints](../constraints.md)). 532 | bias_constraint: Constraint function applied to the bias vector 533 | (see [constraints](../constraints.md)). 534 | 535 | # Input shape 536 | 5D tensor with shape: 537 | `(samples, channels, conv_dim1, conv_dim2, conv_dim3)` if data_format='channels_first' 538 | or 5D tensor with shape: 539 | `(samples, conv_dim1, conv_dim2, conv_dim3, channels)` if data_format='channels_last'. 540 | 541 | # Output shape 542 | 5D tensor with shape: 543 | `(samples, filters, new_conv_dim1, new_conv_dim2, new_conv_dim3)` if data_format='channels_first' 544 | or 5D tensor with shape: 545 | `(samples, new_conv_dim1, new_conv_dim2, new_conv_dim3, filters)` if data_format='channels_last'. 546 | `new_conv_dim1`, `new_conv_dim2` and `new_conv_dim3` values might have changed due to padding. 547 | """ 548 | 549 | @interfaces.legacy_conv3d_support 550 | def __init__(self, filters, 551 | kernel_size, 552 | strides=(1, 1, 1), 553 | padding='valid', 554 | data_format=None, 555 | dilation_rate=(1, 1, 1), 556 | activation=None, 557 | use_bias=True, 558 | kernel_initializer='glorot_uniform', 559 | bias_initializer='zeros', 560 | kernel_regularizer=None, 561 | bias_regularizer=None, 562 | activity_regularizer=None, 563 | kernel_constraint=None, 564 | bias_constraint=None, 565 | **kwargs): 566 | super(Conv3D, self).__init__( 567 | rank=3, 568 | filters=filters, 569 | kernel_size=kernel_size, 570 | strides=strides, 571 | padding=padding, 572 | data_format=data_format, 573 | dilation_rate=dilation_rate, 574 | activation=activation, 575 | use_bias=use_bias, 576 | kernel_initializer=kernel_initializer, 577 | bias_initializer=bias_initializer, 578 | kernel_regularizer=kernel_regularizer, 579 | bias_regularizer=bias_regularizer, 580 | activity_regularizer=activity_regularizer, 581 | kernel_constraint=kernel_constraint, 582 | bias_constraint=bias_constraint, 583 | **kwargs) 584 | self.input_spec = InputSpec(ndim=5) 585 | 586 | def get_config(self): 587 | config = super(Conv3D, self).get_config() 588 | config.pop('rank') 589 | return config 590 | 591 | 592 | class Conv2DTranspose(Conv2D): 593 | """Transposed convolution layer (sometimes called Deconvolution). 594 | 595 | The need for transposed convolutions generally arises 596 | from the desire to use a transformation going in the opposite direction 597 | of a normal convolution, i.e., from something that has the shape of the 598 | output of some convolution to something that has the shape of its input 599 | while maintaining a connectivity pattern that is compatible with 600 | said convolution. 601 | 602 | When using this layer as the first layer in a model, 603 | provide the keyword argument `input_shape` 604 | (tuple of integers, does not include the sample axis), 605 | e.g. `input_shape=(128, 128, 3)` for 128x128 RGB pictures 606 | in `data_format="channels_last"`. 607 | 608 | # Arguments 609 | filters: Integer, the dimensionality of the output space 610 | (i.e. the number of output filters in the convolution). 611 | kernel_size: An integer or tuple/list of 2 integers, specifying the 612 | width and height of the 2D convolution window. 613 | Can be a single integer to specify the same value for 614 | all spatial dimensions. 615 | strides: An integer or tuple/list of 2 integers, 616 | specifying the strides of the convolution along the width and height. 617 | Can be a single integer to specify the same value for 618 | all spatial dimensions. 619 | Specifying any stride value != 1 is incompatible with specifying 620 | any `dilation_rate` value != 1. 621 | padding: one of `"valid"` or `"same"` (case-insensitive). 622 | data_format: A string, 623 | one of `channels_last` (default) or `channels_first`. 624 | The ordering of the dimensions in the inputs. 625 | `channels_last` corresponds to inputs with shape 626 | `(batch, height, width, channels)` while `channels_first` 627 | corresponds to inputs with shape 628 | `(batch, channels, height, width)`. 629 | It defaults to the `image_data_format` value found in your 630 | Keras config file at `~/.keras/keras.json`. 631 | If you never set it, then it will be "channels_last". 632 | dilation_rate: an integer or tuple/list of 2 integers, specifying 633 | the dilation rate to use for dilated convolution. 634 | Can be a single integer to specify the same value for 635 | all spatial dimensions. 636 | Currently, specifying any `dilation_rate` value != 1 is 637 | incompatible with specifying any stride value != 1. 638 | activation: Activation function to use 639 | (see [activations](../activations.md)). 640 | If you don't specify anything, no activation is applied 641 | (ie. "linear" activation: `a(x) = x`). 642 | use_bias: Boolean, whether the layer uses a bias vector. 643 | kernel_initializer: Initializer for the `kernel` weights matrix 644 | (see [initializers](../initializers.md)). 645 | bias_initializer: Initializer for the bias vector 646 | (see [initializers](../initializers.md)). 647 | kernel_regularizer: Regularizer function applied to 648 | the `kernel` weights matrix 649 | (see [regularizer](../regularizers.md)). 650 | bias_regularizer: Regularizer function applied to the bias vector 651 | (see [regularizer](../regularizers.md)). 652 | activity_regularizer: Regularizer function applied to 653 | the output of the layer (its "activation"). 654 | (see [regularizer](../regularizers.md)). 655 | kernel_constraint: Constraint function applied to the kernel matrix 656 | (see [constraints](../constraints.md)). 657 | bias_constraint: Constraint function applied to the bias vector 658 | (see [constraints](../constraints.md)). 659 | 660 | # Input shape 661 | 4D tensor with shape: 662 | `(batch, channels, rows, cols)` if data_format='channels_first' 663 | or 4D tensor with shape: 664 | `(batch, rows, cols, channels)` if data_format='channels_last'. 665 | 666 | # Output shape 667 | 4D tensor with shape: 668 | `(batch, filters, new_rows, new_cols)` if data_format='channels_first' 669 | or 4D tensor with shape: 670 | `(batch, new_rows, new_cols, filters)` if data_format='channels_last'. 671 | `rows` and `cols` values might have changed due to padding. 672 | 673 | # References 674 | - [A guide to convolution arithmetic for deep learning](https://arxiv.org/abs/1603.07285v1) 675 | - [Deconvolutional Networks](http://www.matthewzeiler.com/pubs/cvpr2010/cvpr2010.pdf) 676 | """ 677 | 678 | @interfaces.legacy_deconv2d_support 679 | def __init__(self, filters, 680 | kernel_size, 681 | strides=(1, 1), 682 | padding='valid', 683 | data_format=None, 684 | activation=None, 685 | use_bias=True, 686 | kernel_initializer='glorot_uniform', 687 | bias_initializer='zeros', 688 | kernel_regularizer=None, 689 | bias_regularizer=None, 690 | activity_regularizer=None, 691 | kernel_constraint=None, 692 | bias_constraint=None, 693 | **kwargs): 694 | super(Conv2DTranspose, self).__init__( 695 | filters, 696 | kernel_size, 697 | strides=strides, 698 | padding=padding, 699 | data_format=data_format, 700 | activation=activation, 701 | use_bias=use_bias, 702 | kernel_initializer=kernel_initializer, 703 | bias_initializer=bias_initializer, 704 | kernel_regularizer=kernel_regularizer, 705 | bias_regularizer=bias_regularizer, 706 | activity_regularizer=activity_regularizer, 707 | kernel_constraint=kernel_constraint, 708 | bias_constraint=bias_constraint, 709 | **kwargs) 710 | self.input_spec = InputSpec(ndim=4) 711 | 712 | def build(self, input_shape): 713 | if len(input_shape) != 4: 714 | raise ValueError('Inputs should have rank ' + 715 | str(4) + 716 | '; Received input shape:', str(input_shape)) 717 | if self.data_format == 'channels_first': 718 | channel_axis = 1 719 | else: 720 | channel_axis = -1 721 | if input_shape[channel_axis] is None: 722 | raise ValueError('The channel dimension of the inputs ' 723 | 'should be defined. Found `None`.') 724 | input_dim = input_shape[channel_axis] 725 | kernel_shape = self.kernel_size + (self.filters, input_dim) 726 | 727 | self.kernel = self.add_weight(shape=kernel_shape, 728 | initializer=self.kernel_initializer, 729 | name='kernel', 730 | regularizer=self.kernel_regularizer, 731 | constraint=self.kernel_constraint) 732 | if self.use_bias: 733 | self.bias = self.add_weight(shape=(self.filters,), 734 | initializer=self.bias_initializer, 735 | name='bias', 736 | regularizer=self.bias_regularizer, 737 | constraint=self.bias_constraint) 738 | else: 739 | self.bias = None 740 | # Set input spec. 741 | self.input_spec = InputSpec(ndim=4, axes={channel_axis: input_dim}) 742 | self.built = True 743 | 744 | def call(self, inputs): 745 | input_shape = K.shape(inputs) 746 | batch_size = input_shape[0] 747 | if self.data_format == 'channels_first': 748 | h_axis, w_axis = 2, 3 749 | else: 750 | h_axis, w_axis = 1, 2 751 | 752 | height, width = input_shape[h_axis], input_shape[w_axis] 753 | kernel_h, kernel_w = self.kernel_size 754 | stride_h, stride_w = self.strides 755 | 756 | # Infer the dynamic output shape: 757 | out_height = conv_utils.deconv_length(height, 758 | stride_h, kernel_h, 759 | self.padding) 760 | out_width = conv_utils.deconv_length(width, 761 | stride_w, kernel_w, 762 | self.padding) 763 | if self.data_format == 'channels_first': 764 | output_shape = (batch_size, self.filters, out_height, out_width) 765 | else: 766 | output_shape = (batch_size, out_height, out_width, self.filters) 767 | 768 | outputs = K.conv2d_transpose( 769 | inputs, 770 | self.kernel, 771 | output_shape, 772 | self.strides, 773 | padding=self.padding, 774 | data_format=self.data_format) 775 | 776 | if self.bias: 777 | outputs = K.bias_add( 778 | outputs, 779 | self.bias, 780 | data_format=self.data_format) 781 | 782 | if self.activation is not None: 783 | return self.activation(outputs) 784 | return outputs 785 | 786 | def compute_output_shape(self, input_shape): 787 | output_shape = list(input_shape) 788 | if self.data_format == 'channels_first': 789 | c_axis, h_axis, w_axis = 1, 2, 3 790 | else: 791 | c_axis, h_axis, w_axis = 3, 1, 2 792 | 793 | kernel_h, kernel_w = self.kernel_size 794 | stride_h, stride_w = self.strides 795 | 796 | output_shape[c_axis] = self.filters 797 | output_shape[h_axis] = conv_utils.deconv_length( 798 | output_shape[h_axis], stride_h, kernel_h, self.padding) 799 | output_shape[w_axis] = conv_utils.deconv_length( 800 | output_shape[w_axis], stride_w, kernel_w, self.padding) 801 | return tuple(output_shape) 802 | 803 | def get_config(self): 804 | config = super(Conv2DTranspose, self).get_config() 805 | config.pop('dilation_rate') 806 | return config 807 | 808 | 809 | class Conv3DTranspose(Conv3D): 810 | """Transposed convolution layer (sometimes called Deconvolution). 811 | 812 | The need for transposed convolutions generally arises 813 | from the desire to use a transformation going in the opposite direction 814 | of a normal convolution, i.e., from something that has the shape of the 815 | output of some convolution to something that has the shape of its input 816 | while maintaining a connectivity pattern that is compatible with 817 | said convolution. 818 | 819 | When using this layer as the first layer in a model, 820 | provide the keyword argument `input_shape` 821 | (tuple of integers, does not include the sample axis), 822 | e.g. `input_shape=(128, 128, 128, 3)` for a 128x128x128 volume with 3 channels 823 | if `data_format="channels_last"`. 824 | 825 | # Arguments 826 | filters: Integer, the dimensionality of the output space 827 | (i.e. the number of output filters in the convolution). 828 | kernel_size: An integer or tuple/list of 3 integers, specifying the 829 | width and height of the 3D convolution window. 830 | Can be a single integer to specify the same value for 831 | all spatial dimensions. 832 | strides: An integer or tuple/list of 3 integers, 833 | specifying the strides of the convolution along the width and height. 834 | Can be a single integer to specify the same value for 835 | all spatial dimensions. 836 | Specifying any stride value != 1 is incompatible with specifying 837 | any `dilation_rate` value != 1. 838 | padding: one of `"valid"` or `"same"` (case-insensitive). 839 | data_format: A string, 840 | one of `channels_last` (default) or `channels_first`. 841 | The ordering of the dimensions in the inputs. 842 | `channels_last` corresponds to inputs with shape 843 | `(batch, depth, height, width, channels)` while `channels_first` 844 | corresponds to inputs with shape 845 | `(batch, channels, depth, height, width)`. 846 | It defaults to the `image_data_format` value found in your 847 | Keras config file at `~/.keras/keras.json`. 848 | If you never set it, then it will be "channels_last". 849 | dilation_rate: an integer or tuple/list of 3 integers, specifying 850 | the dilation rate to use for dilated convolution. 851 | Can be a single integer to specify the same value for 852 | all spatial dimensions. 853 | Currently, specifying any `dilation_rate` value != 1 is 854 | incompatible with specifying any stride value != 1. 855 | activation: Activation function to use 856 | (see [activations](../activations.md)). 857 | If you don't specify anything, no activation is applied 858 | (ie. "linear" activation: `a(x) = x`). 859 | use_bias: Boolean, whether the layer uses a bias vector. 860 | kernel_initializer: Initializer for the `kernel` weights matrix 861 | (see [initializers](../initializers.md)). 862 | bias_initializer: Initializer for the bias vector 863 | (see [initializers](../initializers.md)). 864 | kernel_regularizer: Regularizer function applied to 865 | the `kernel` weights matrix 866 | (see [regularizer](../regularizers.md)). 867 | bias_regularizer: Regularizer function applied to the bias vector 868 | (see [regularizer](../regularizers.md)). 869 | activity_regularizer: Regularizer function applied to 870 | the output of the layer (its "activation"). 871 | (see [regularizer](../regularizers.md)). 872 | kernel_constraint: Constraint function applied to the kernel matrix 873 | (see [constraints](../constraints.md)). 874 | bias_constraint: Constraint function applied to the bias vector 875 | (see [constraints](../constraints.md)). 876 | 877 | # Input shape 878 | 5D tensor with shape: 879 | `(batch, channels, depth, rows, cols)` if data_format='channels_first' 880 | or 5D tensor with shape: 881 | `(batch, depth, rows, cols, channels)` if data_format='channels_last'. 882 | 883 | # Output shape 884 | 5D tensor with shape: 885 | `(batch, filters, new_depth, new_rows, new_cols)` if data_format='channels_first' 886 | or 5D tensor with shape: 887 | `(batch, new_depth, new_rows, new_cols, filters)` if data_format='channels_last'. 888 | `depth` and `rows` and `cols` values might have changed due to padding. 889 | 890 | # References 891 | - [A guide to convolution arithmetic for deep learning](https://arxiv.org/abs/1603.07285v1) 892 | - [Deconvolutional Networks](http://www.matthewzeiler.com/pubs/cvpr2010/cvpr2010.pdf) 893 | """ 894 | 895 | def __init__(self, filters, 896 | kernel_size, 897 | strides=(1, 1, 1), 898 | padding='valid', 899 | data_format=None, 900 | activation=None, 901 | use_bias=True, 902 | kernel_initializer='glorot_uniform', 903 | bias_initializer='zeros', 904 | kernel_regularizer=None, 905 | bias_regularizer=None, 906 | activity_regularizer=None, 907 | kernel_constraint=None, 908 | bias_constraint=None, 909 | **kwargs): 910 | super(Conv3DTranspose, self).__init__( 911 | filters, 912 | kernel_size, 913 | strides=strides, 914 | padding=padding, 915 | data_format=data_format, 916 | activation=activation, 917 | use_bias=use_bias, 918 | kernel_initializer=kernel_initializer, 919 | bias_initializer=bias_initializer, 920 | kernel_regularizer=kernel_regularizer, 921 | bias_regularizer=bias_regularizer, 922 | activity_regularizer=activity_regularizer, 923 | kernel_constraint=kernel_constraint, 924 | bias_constraint=bias_constraint, 925 | **kwargs) 926 | self.input_spec = InputSpec(ndim=5) 927 | 928 | def build(self, input_shape): 929 | if len(input_shape) != 5: 930 | raise ValueError('Inputs should have rank ' + 931 | str(5) + 932 | '; Received input shape:', str(input_shape)) 933 | if self.data_format == 'channels_first': 934 | channel_axis = 1 935 | else: 936 | channel_axis = -1 937 | if input_shape[channel_axis] is None: 938 | raise ValueError('The channel dimension of the inputs ' 939 | 'should be defined. Found `None`.') 940 | input_dim = input_shape[channel_axis] 941 | kernel_shape = self.kernel_size + (self.filters, input_dim) 942 | 943 | self.kernel = self.add_weight(shape=kernel_shape, 944 | initializer=self.kernel_initializer, 945 | name='kernel', 946 | regularizer=self.kernel_regularizer, 947 | constraint=self.kernel_constraint) 948 | if self.use_bias: 949 | self.bias = self.add_weight(shape=(self.filters,), 950 | initializer=self.bias_initializer, 951 | name='bias', 952 | regularizer=self.bias_regularizer, 953 | constraint=self.bias_constraint) 954 | else: 955 | self.bias = None 956 | # Set input spec. 957 | self.input_spec = InputSpec(ndim=5, axes={channel_axis: input_dim}) 958 | self.built = True 959 | 960 | def call(self, inputs): 961 | input_shape = K.shape(inputs) 962 | batch_size = input_shape[0] 963 | if self.data_format == 'channels_first': 964 | d_axis, h_axis, w_axis = 2, 3, 4 965 | else: 966 | d_axis, h_axis, w_axis = 1, 2, 3 967 | 968 | depth = input_shape[d_axis] 969 | height = input_shape[h_axis] 970 | width = input_shape[w_axis] 971 | 972 | kernel_d, kernel_h, kernel_w = self.kernel_size 973 | stride_d, stride_h, stride_w = self.strides 974 | 975 | # Infer the dynamic output shape: 976 | out_depth = conv_utils.deconv_length(depth, 977 | stride_d, kernel_d, 978 | self.padding) 979 | out_height = conv_utils.deconv_length(height, 980 | stride_h, kernel_h, 981 | self.padding) 982 | out_width = conv_utils.deconv_length(width, 983 | stride_w, kernel_w, 984 | self.padding) 985 | 986 | if self.data_format == 'channels_first': 987 | output_shape = (batch_size, self.filters, out_depth, out_height, out_width) 988 | else: 989 | output_shape = (batch_size, out_depth, out_height, out_width, self.filters) 990 | 991 | outputs = K.conv3d_transpose(inputs, 992 | self.kernel, 993 | output_shape, 994 | self.strides, 995 | padding=self.padding, 996 | data_format=self.data_format) 997 | 998 | if self.bias: 999 | outputs = K.bias_add( 1000 | outputs, 1001 | self.bias, 1002 | data_format=self.data_format) 1003 | 1004 | if self.activation is not None: 1005 | return self.activation(outputs) 1006 | return outputs 1007 | 1008 | def compute_output_shape(self, input_shape): 1009 | output_shape = list(input_shape) 1010 | if self.data_format == 'channels_first': 1011 | c_axis, d_axis, h_axis, w_axis = 1, 2, 3, 4 1012 | else: 1013 | c_axis, d_axis, h_axis, w_axis = 4, 1, 2, 3 1014 | 1015 | kernel_d, kernel_h, kernel_w = self.kernel_size 1016 | stride_d, stride_h, stride_w = self.strides 1017 | 1018 | output_shape[c_axis] = self.filters 1019 | output_shape[d_axis] = conv_utils.deconv_length(output_shape[d_axis], 1020 | stride_d, 1021 | kernel_d, 1022 | self.padding) 1023 | output_shape[h_axis] = conv_utils.deconv_length(output_shape[h_axis], 1024 | stride_h, 1025 | kernel_h, 1026 | self.padding) 1027 | output_shape[w_axis] = conv_utils.deconv_length(output_shape[w_axis], 1028 | stride_w, 1029 | kernel_w, 1030 | self.padding) 1031 | 1032 | return tuple(output_shape) 1033 | 1034 | def get_config(self): 1035 | config = super(Conv3DTranspose, self).get_config() 1036 | config.pop('dilation_rate') 1037 | return config 1038 | 1039 | ################################################################################################ 1040 | # original 1041 | ################################################################################################ 1042 | class SeparableConv2D(Conv2D): 1043 | """Depthwise separable 2D convolution. 1044 | 1045 | Separable convolutions consist in first performing 1046 | a depthwise spatial convolution 1047 | (which acts on each input channel separately) 1048 | followed by a pointwise convolution which mixes together the resulting 1049 | output channels. The `depth_multiplier` argument controls how many 1050 | output channels are generated per input channel in the depthwise step. 1051 | 1052 | Intuitively, separable convolutions can be understood as 1053 | a way to factorize a convolution kernel into two smaller kernels, 1054 | or as an extreme version of an Inception block. 1055 | 1056 | # Arguments 1057 | filters: Integer, the dimensionality of the output space 1058 | (i.e. the number output of filters in the convolution). 1059 | kernel_size: An integer or tuple/list of 2 integers, specifying the 1060 | width and height of the 2D convolution window. 1061 | Can be a single integer to specify the same value for 1062 | all spatial dimensions. 1063 | strides: An integer or tuple/list of 2 integers, 1064 | specifying the strides of the convolution along the width and height. 1065 | Can be a single integer to specify the same value for 1066 | all spatial dimensions. 1067 | Specifying any stride value != 1 is incompatible with specifying 1068 | any `dilation_rate` value != 1. 1069 | padding: one of `"valid"` or `"same"` (case-insensitive). 1070 | data_format: A string, 1071 | one of `channels_last` (default) or `channels_first`. 1072 | The ordering of the dimensions in the inputs. 1073 | `channels_last` corresponds to inputs with shape 1074 | `(batch, height, width, channels)` while `channels_first` 1075 | corresponds to inputs with shape 1076 | `(batch, channels, height, width)`. 1077 | It defaults to the `image_data_format` value found in your 1078 | Keras config file at `~/.keras/keras.json`. 1079 | If you never set it, then it will be "channels_last". 1080 | depth_multiplier: The number of depthwise convolution output channels 1081 | for each input channel. 1082 | The total number of depthwise convolution output 1083 | channels will be equal to `filterss_in * depth_multiplier`. 1084 | activation: Activation function to use 1085 | (see [activations](../activations.md)). 1086 | If you don't specify anything, no activation is applied 1087 | (ie. "linear" activation: `a(x) = x`). 1088 | use_bias: Boolean, whether the layer uses a bias vector. 1089 | depthwise_initializer: Initializer for the depthwise kernel matrix 1090 | (see [initializers](../initializers.md)). 1091 | pointwise_initializer: Initializer for the pointwise kernel matrix 1092 | (see [initializers](../initializers.md)). 1093 | bias_initializer: Initializer for the bias vector 1094 | (see [initializers](../initializers.md)). 1095 | depthwise_regularizer: Regularizer function applied to 1096 | the depthwise kernel matrix 1097 | (see [regularizer](../regularizers.md)). 1098 | pointwise_regularizer: Regularizer function applied to 1099 | the depthwise kernel matrix 1100 | (see [regularizer](../regularizers.md)). 1101 | bias_regularizer: Regularizer function applied to the bias vector 1102 | (see [regularizer](../regularizers.md)). 1103 | activity_regularizer: Regularizer function applied to 1104 | the output of the layer (its "activation"). 1105 | (see [regularizer](../regularizers.md)). 1106 | depthwise_constraint: Constraint function applied to 1107 | the depthwise kernel matrix 1108 | (see [constraints](../constraints.md)). 1109 | pointwise_constraint: Constraint function applied to 1110 | the pointwise kernel matrix 1111 | (see [constraints](../constraints.md)). 1112 | bias_constraint: Constraint function applied to the bias vector 1113 | (see [constraints](../constraints.md)). 1114 | 1115 | # Input shape 1116 | 4D tensor with shape: 1117 | `(batch, channels, rows, cols)` if data_format='channels_first' 1118 | or 4D tensor with shape: 1119 | `(batch, rows, cols, channels)` if data_format='channels_last'. 1120 | 1121 | # Output shape 1122 | 4D tensor with shape: 1123 | `(batch, filters, new_rows, new_cols)` if data_format='channels_first' 1124 | or 4D tensor with shape: 1125 | `(batch, new_rows, new_cols, filters)` if data_format='channels_last'. 1126 | `rows` and `cols` values might have changed due to padding. 1127 | """ 1128 | 1129 | @interfaces.legacy_separable_conv2d_support 1130 | def __init__(self, filters, 1131 | kernel_size, 1132 | strides=(1, 1), 1133 | padding='valid', 1134 | data_format=None, 1135 | dilation_rate=(1, 1), 1136 | depth_multiplier=1, 1137 | activation=None, 1138 | use_bias=True, 1139 | depthwise_initializer='glorot_uniform', 1140 | pointwise_initializer='glorot_uniform', 1141 | bias_initializer='zeros', 1142 | depthwise_regularizer=None, 1143 | pointwise_regularizer=None, 1144 | bias_regularizer=None, 1145 | activity_regularizer=None, 1146 | depthwise_constraint=None, 1147 | pointwise_constraint=None, 1148 | bias_constraint=None, 1149 | **kwargs): 1150 | super(SeparableConv2D, self).__init__( 1151 | filters=filters, 1152 | kernel_size=kernel_size, 1153 | strides=strides, 1154 | padding=padding, 1155 | data_format=data_format, 1156 | dilation_rate=dilation_rate, 1157 | activation=activation, 1158 | use_bias=use_bias, 1159 | bias_regularizer=bias_regularizer, 1160 | activity_regularizer=activity_regularizer, 1161 | bias_constraint=bias_constraint, 1162 | **kwargs) 1163 | self.depth_multiplier = depth_multiplier 1164 | self.depthwise_initializer = initializers.get(depthwise_initializer) 1165 | self.pointwise_initializer = initializers.get(pointwise_initializer) 1166 | self.depthwise_regularizer = regularizers.get(depthwise_regularizer) 1167 | self.pointwise_regularizer = regularizers.get(pointwise_regularizer) 1168 | self.depthwise_constraint = constraints.get(depthwise_constraint) 1169 | self.pointwise_constraint = constraints.get(pointwise_constraint) 1170 | 1171 | def build(self, input_shape): 1172 | if len(input_shape) < 4: 1173 | raise ValueError('Inputs to `SeparableConv2D` should have rank 4. ' 1174 | 'Received input shape:', str(input_shape)) 1175 | if self.data_format == 'channels_first': 1176 | channel_axis = 1 1177 | else: 1178 | channel_axis = 3 1179 | if input_shape[channel_axis] is None: 1180 | raise ValueError('The channel dimension of the inputs to ' 1181 | '`SeparableConv2D` ' 1182 | 'should be defined. Found `None`.') 1183 | input_dim = int(input_shape[channel_axis]) 1184 | depthwise_kernel_shape = (self.kernel_size[0], 1185 | self.kernel_size[1], 1186 | input_dim, 1187 | self.depth_multiplier) 1188 | pointwise_kernel_shape = (1, 1, 1189 | self.depth_multiplier * input_dim, 1190 | self.filters) 1191 | 1192 | self.depthwise_kernel = self.add_weight( 1193 | shape=depthwise_kernel_shape, 1194 | initializer=self.depthwise_initializer, 1195 | name='depthwise_kernel', 1196 | regularizer=self.depthwise_regularizer, 1197 | constraint=self.depthwise_constraint) 1198 | self.pointwise_kernel = self.add_weight( 1199 | shape=pointwise_kernel_shape, 1200 | initializer=self.pointwise_initializer, 1201 | name='pointwise_kernel', 1202 | regularizer=self.pointwise_regularizer, 1203 | constraint=self.pointwise_constraint) 1204 | 1205 | if self.use_bias: 1206 | self.bias = self.add_weight(shape=(self.filters,), 1207 | initializer=self.bias_initializer, 1208 | name='bias', 1209 | regularizer=self.bias_regularizer, 1210 | constraint=self.bias_constraint) 1211 | else: 1212 | self.bias = None 1213 | # Set input spec. 1214 | self.input_spec = InputSpec(ndim=4, axes={channel_axis: input_dim}) 1215 | self.built = True 1216 | 1217 | def call(self, inputs): 1218 | outputs = K.separable_conv2d( 1219 | inputs, 1220 | self.depthwise_kernel, 1221 | self.pointwise_kernel, 1222 | data_format=self.data_format, 1223 | dilation_rate= self.dilation_rate, 1224 | strides=self.strides, 1225 | padding=self.padding) 1226 | 1227 | if self.bias: 1228 | outputs = K.bias_add( 1229 | outputs, 1230 | self.bias, 1231 | data_format=self.data_format) 1232 | 1233 | if self.activation is not None: 1234 | return self.activation(outputs) 1235 | return outputs 1236 | 1237 | def compute_output_shape(self, input_shape): 1238 | if self.data_format == 'channels_first': 1239 | rows = input_shape[2] 1240 | cols = input_shape[3] 1241 | elif self.data_format == 'channels_last': 1242 | rows = input_shape[1] 1243 | cols = input_shape[2] 1244 | 1245 | rows = conv_utils.conv_output_length(rows, self.kernel_size[0], 1246 | self.padding, 1247 | self.strides[0], 1248 | self.dilation_rate[0]) 1249 | cols = conv_utils.conv_output_length(cols, self.kernel_size[1], 1250 | self.padding, 1251 | self.strides[1], 1252 | self.dilation_rate[1]) 1253 | if self.data_format == 'channels_first': 1254 | return (input_shape[0], self.filters, rows, cols) 1255 | elif self.data_format == 'channels_last': 1256 | return (input_shape[0], rows, cols, self.filters) 1257 | 1258 | def get_config(self): 1259 | config = super(SeparableConv2D, self).get_config() 1260 | config.pop('kernel_initializer') 1261 | config.pop('kernel_regularizer') 1262 | config.pop('kernel_constraint') 1263 | config['depth_multiplier'] = self.depth_multiplier 1264 | config['depthwise_initializer'] = initializers.serialize(self.depthwise_initializer) 1265 | config['pointwise_initializer'] = initializers.serialize(self.pointwise_initializer) 1266 | config['depthwise_regularizer'] = regularizers.serialize(self.depthwise_regularizer) 1267 | config['pointwise_regularizer'] = regularizers.serialize(self.pointwise_regularizer) 1268 | config['depthwise_constraint'] = constraints.serialize(self.depthwise_constraint) 1269 | config['pointwise_constraint'] = constraints.serialize(self.pointwise_constraint) 1270 | return config 1271 | ################################################################################################ 1272 | class DepthwiseConv2D(Conv2D): 1273 | """Depthwise separable 2D convolution. 1274 | Depthwise Separable convolutions consists in performing 1275 | just the first step in a depthwise spatial convolution 1276 | (which acts on each input channel separately). 1277 | The `depth_multiplier` argument controls how many 1278 | output channels are generated per input channel in the depthwise step. 1279 | # Arguments 1280 | kernel_size: An integer or tuple/list of 2 integers, specifying the 1281 | height and width of the 2D convolution window. 1282 | Can be a single integer to specify the same value for 1283 | all spatial dimensions. 1284 | strides: An integer or tuple/list of 2 integers, 1285 | specifying the strides of the convolution 1286 | along the height and width. 1287 | Can be a single integer to specify the same value for 1288 | all spatial dimensions. 1289 | Specifying any stride value != 1 is incompatible with specifying 1290 | any `dilation_rate` value != 1. 1291 | padding: one of `'valid'` or `'same'` (case-insensitive). 1292 | depth_multiplier: The number of depthwise convolution output channels 1293 | for each input channel. 1294 | The total number of depthwise convolution output 1295 | channels will be equal to `filters_in * depth_multiplier`. 1296 | data_format: A string, 1297 | one of `"channels_last"` or `"channels_first"`. 1298 | The ordering of the dimensions in the inputs. 1299 | `"channels_last"` corresponds to inputs with shape 1300 | `(batch, height, width, channels)` while `"channels_first"` 1301 | corresponds to inputs with shape 1302 | `(batch, channels, height, width)`. 1303 | It defaults to the `image_data_format` value found in your 1304 | Keras config file at `~/.keras/keras.json`. 1305 | If you never set it, then it will be 'channels_last'. 1306 | activation: Activation function to use 1307 | (see [activations](../activations.md)). 1308 | If you don't specify anything, no activation is applied 1309 | (ie. 'linear' activation: `a(x) = x`). 1310 | use_bias: Boolean, whether the layer uses a bias vector. 1311 | depthwise_initializer: Initializer for the depthwise kernel matrix 1312 | (see [initializers](../initializers.md)). 1313 | bias_initializer: Initializer for the bias vector 1314 | (see [initializers](../initializers.md)). 1315 | depthwise_regularizer: Regularizer function applied to 1316 | the depthwise kernel matrix 1317 | (see [regularizer](../regularizers.md)). 1318 | bias_regularizer: Regularizer function applied to the bias vector 1319 | (see [regularizer](../regularizers.md)). 1320 | activity_regularizer: Regularizer function applied to 1321 | the output of the layer (its 'activation'). 1322 | (see [regularizer](../regularizers.md)). 1323 | depthwise_constraint: Constraint function applied to 1324 | the depthwise kernel matrix 1325 | (see [constraints](../constraints.md)). 1326 | bias_constraint: Constraint function applied to the bias vector 1327 | (see [constraints](../constraints.md)). 1328 | # Input shape 1329 | 4D tensor with shape: 1330 | `[batch, channels, rows, cols]` 1331 | if `data_format` is `"channels_first"` 1332 | or 4D tensor with shape: 1333 | `[batch, rows, cols, channels]` 1334 | if `data_format` is `"channels_last"`. 1335 | # Output shape 1336 | 4D tensor with shape: 1337 | `[batch, filters, new_rows, new_cols]` 1338 | if `data_format` is `"channels_first"` 1339 | or 4D tensor with shape: 1340 | `[batch, new_rows, new_cols, filters]` 1341 | if `data_format` is `"channels_last"`. 1342 | `rows` and `cols` values might have changed due to padding. 1343 | """ 1344 | 1345 | def __init__(self, 1346 | kernel_size, 1347 | strides=(1, 1), 1348 | padding='valid', 1349 | depth_multiplier=1, 1350 | data_format=None, 1351 | activation=None, 1352 | use_bias=True, 1353 | depthwise_initializer='glorot_uniform', 1354 | bias_initializer='zeros', 1355 | depthwise_regularizer=None, 1356 | bias_regularizer=None, 1357 | activity_regularizer=None, 1358 | depthwise_constraint=None, 1359 | bias_constraint=None, 1360 | **kwargs): 1361 | super(DepthwiseConv2D, self).__init__( 1362 | filters=None, 1363 | kernel_size=kernel_size, 1364 | strides=strides, 1365 | padding=padding, 1366 | data_format=data_format, 1367 | activation=activation, 1368 | use_bias=use_bias, 1369 | bias_regularizer=bias_regularizer, 1370 | activity_regularizer=activity_regularizer, 1371 | bias_constraint=bias_constraint, 1372 | **kwargs) 1373 | self.depth_multiplier = depth_multiplier 1374 | self.depthwise_initializer = initializers.get(depthwise_initializer) 1375 | self.depthwise_regularizer = regularizers.get(depthwise_regularizer) 1376 | self.depthwise_constraint = constraints.get(depthwise_constraint) 1377 | self.bias_initializer = initializers.get(bias_initializer) 1378 | 1379 | def build(self, input_shape): 1380 | if len(input_shape) < 4: 1381 | raise ValueError('Inputs to `DepthwiseConv2D` should have rank 4. ' 1382 | 'Received input shape:', str(input_shape)) 1383 | if self.data_format == 'channels_first': 1384 | channel_axis = 1 1385 | else: 1386 | channel_axis = 3 1387 | if input_shape[channel_axis] is None: 1388 | raise ValueError('The channel dimension of the inputs to ' 1389 | '`DepthwiseConv2D` ' 1390 | 'should be defined. Found `None`.') 1391 | input_dim = int(input_shape[channel_axis]) 1392 | depthwise_kernel_shape = (self.kernel_size[0], 1393 | self.kernel_size[1], 1394 | input_dim, 1395 | self.depth_multiplier) 1396 | 1397 | self.depthwise_kernel = self.add_weight( 1398 | shape=depthwise_kernel_shape, 1399 | initializer=self.depthwise_initializer, 1400 | name='depthwise_kernel', 1401 | regularizer=self.depthwise_regularizer, 1402 | constraint=self.depthwise_constraint) 1403 | 1404 | if self.use_bias: 1405 | self.bias = self.add_weight(shape=(input_dim * self.depth_multiplier,), 1406 | initializer=self.bias_initializer, 1407 | name='bias', 1408 | regularizer=self.bias_regularizer, 1409 | constraint=self.bias_constraint) 1410 | else: 1411 | self.bias = None 1412 | # Set input spec. 1413 | self.input_spec = InputSpec(ndim=4, axes={channel_axis: input_dim}) 1414 | self.built = True 1415 | 1416 | def call(self, inputs, training=None): 1417 | outputs = K.depthwise_conv2d( 1418 | inputs, 1419 | self.depthwise_kernel, 1420 | strides=self.strides, 1421 | padding=self.padding, 1422 | data_format=self.data_format) 1423 | 1424 | if self.use_bias: 1425 | outputs = K.bias_add( 1426 | outputs, 1427 | self.bias, 1428 | data_format=self.data_format) 1429 | 1430 | if self.activation is not None: 1431 | return self.activation(outputs) 1432 | 1433 | return outputs 1434 | 1435 | def compute_output_shape(self, input_shape): 1436 | if self.data_format == 'channels_first': 1437 | rows = input_shape[2] 1438 | cols = input_shape[3] 1439 | out_filters = input_shape[1] * self.depth_multiplier 1440 | elif self.data_format == 'channels_last': 1441 | rows = input_shape[1] 1442 | cols = input_shape[2] 1443 | out_filters = input_shape[3] * self.depth_multiplier 1444 | 1445 | rows = conv_utils.conv_output_length(rows, self.kernel_size[0], 1446 | self.padding, 1447 | self.strides[0]) 1448 | cols = conv_utils.conv_output_length(cols, self.kernel_size[1], 1449 | self.padding, 1450 | self.strides[1]) 1451 | if self.data_format == 'channels_first': 1452 | return (input_shape[0], out_filters, rows, cols) 1453 | elif self.data_format == 'channels_last': 1454 | return (input_shape[0], rows, cols, out_filters) 1455 | 1456 | def get_config(self): 1457 | config = super(DepthwiseConv2D, self).get_config() 1458 | config.pop('filters') 1459 | config.pop('kernel_initializer') 1460 | config.pop('kernel_regularizer') 1461 | config.pop('kernel_constraint') 1462 | config['depth_multiplier'] = self.depth_multiplier 1463 | config['depthwise_initializer'] = initializers.serialize(self.depthwise_initializer) 1464 | config['depthwise_regularizer'] = regularizers.serialize(self.depthwise_regularizer) 1465 | config['depthwise_constraint'] = constraints.serialize(self.depthwise_constraint) 1466 | return config 1467 | 1468 | ################################################################################################ 1469 | 1470 | class UpSampling1D(Layer): 1471 | """Upsampling layer for 1D inputs. 1472 | 1473 | Repeats each temporal step `size` times along the time axis. 1474 | 1475 | # Arguments 1476 | size: integer. Upsampling factor. 1477 | 1478 | # Input shape 1479 | 3D tensor with shape: `(batch, steps, features)`. 1480 | 1481 | # Output shape 1482 | 3D tensor with shape: `(batch, upsampled_steps, features)`. 1483 | """ 1484 | 1485 | @interfaces.legacy_upsampling1d_support 1486 | def __init__(self, size=2, **kwargs): 1487 | super(UpSampling1D, self).__init__(**kwargs) 1488 | self.size = int(size) 1489 | self.input_spec = InputSpec(ndim=3) 1490 | 1491 | def compute_output_shape(self, input_shape): 1492 | size = self.size * input_shape[1] if input_shape[1] is not None else None 1493 | return (input_shape[0], size, input_shape[2]) 1494 | 1495 | def call(self, inputs): 1496 | output = K.repeat_elements(inputs, self.size, axis=1) 1497 | return output 1498 | 1499 | def get_config(self): 1500 | config = {'size': self.size} 1501 | base_config = super(UpSampling1D, self).get_config() 1502 | return dict(list(base_config.items()) + list(config.items())) 1503 | 1504 | 1505 | class UpSampling2D(Layer): 1506 | """Upsampling layer for 2D inputs. 1507 | 1508 | Repeats the rows and columns of the data 1509 | by size[0] and size[1] respectively. 1510 | 1511 | # Arguments 1512 | size: int, or tuple of 2 integers. 1513 | The upsampling factors for rows and columns. 1514 | data_format: A string, 1515 | one of `channels_last` (default) or `channels_first`. 1516 | The ordering of the dimensions in the inputs. 1517 | `channels_last` corresponds to inputs with shape 1518 | `(batch, height, width, channels)` while `channels_first` 1519 | corresponds to inputs with shape 1520 | `(batch, channels, height, width)`. 1521 | It defaults to the `image_data_format` value found in your 1522 | Keras config file at `~/.keras/keras.json`. 1523 | If you never set it, then it will be "channels_last". 1524 | 1525 | # Input shape 1526 | 4D tensor with shape: 1527 | - If `data_format` is `"channels_last"`: 1528 | `(batch, rows, cols, channels)` 1529 | - If `data_format` is `"channels_first"`: 1530 | `(batch, channels, rows, cols)` 1531 | 1532 | # Output shape 1533 | 4D tensor with shape: 1534 | - If `data_format` is `"channels_last"`: 1535 | `(batch, upsampled_rows, upsampled_cols, channels)` 1536 | - If `data_format` is `"channels_first"`: 1537 | `(batch, channels, upsampled_rows, upsampled_cols)` 1538 | """ 1539 | 1540 | @interfaces.legacy_upsampling2d_support 1541 | def __init__(self, size=(2, 2), data_format=None, **kwargs): 1542 | super(UpSampling2D, self).__init__(**kwargs) 1543 | self.data_format = conv_utils.normalize_data_format(data_format) 1544 | self.size = conv_utils.normalize_tuple(size, 2, 'size') 1545 | self.input_spec = InputSpec(ndim=4) 1546 | 1547 | def compute_output_shape(self, input_shape): 1548 | if self.data_format == 'channels_first': 1549 | height = self.size[0] * input_shape[2] if input_shape[2] is not None else None 1550 | width = self.size[1] * input_shape[3] if input_shape[3] is not None else None 1551 | return (input_shape[0], 1552 | input_shape[1], 1553 | height, 1554 | width) 1555 | elif self.data_format == 'channels_last': 1556 | height = self.size[0] * input_shape[1] if input_shape[1] is not None else None 1557 | width = self.size[1] * input_shape[2] if input_shape[2] is not None else None 1558 | return (input_shape[0], 1559 | height, 1560 | width, 1561 | input_shape[3]) 1562 | 1563 | def call(self, inputs): 1564 | return K.resize_images(inputs, self.size[0], self.size[1], 1565 | self.data_format) 1566 | 1567 | def get_config(self): 1568 | config = {'size': self.size, 1569 | 'data_format': self.data_format} 1570 | base_config = super(UpSampling2D, self).get_config() 1571 | return dict(list(base_config.items()) + list(config.items())) 1572 | 1573 | class MyUpSampling2D(Layer): 1574 | 1575 | @interfaces.legacy_upsampling2d_support 1576 | def __init__(self, size=(2, 2), num_pixels = (0, 0), data_format=None, **kwargs): 1577 | super(MyUpSampling2D, self).__init__(**kwargs) 1578 | self.data_format = conv_utils.normalize_data_format(data_format) 1579 | self.size = conv_utils.normalize_tuple(size, 2, 'size') 1580 | self.input_spec = InputSpec(ndim=4) 1581 | self.num_pixels = num_pixels 1582 | 1583 | def compute_output_shape(self, input_shape): 1584 | if self.data_format == 'channels_first': 1585 | height = self.size[0] * input_shape[2] + self.num_pixels[0] if input_shape[2] is not None else None 1586 | width = self.size[1] * input_shape[3] + self.num_pixels[1] if input_shape[3] is not None else None 1587 | return (input_shape[0], 1588 | input_shape[1], 1589 | height, 1590 | width) 1591 | elif self.data_format == 'channels_last': 1592 | height = self.size[0] * input_shape[1] + self.num_pixels[0] if input_shape[1] is not None else None 1593 | width = self.size[1] * input_shape[2] + self.num_pixels[1] if input_shape[2] is not None else None 1594 | return (input_shape[0], 1595 | height, 1596 | width, 1597 | input_shape[3]) 1598 | 1599 | def call(self, inputs): 1600 | return K.resize_images(inputs, self.size[0], self.size[1], 1601 | self.data_format, self.num_pixels) 1602 | 1603 | def get_config(self): 1604 | config = {'size': self.size, 1605 | 'data_format': self.data_format, 1606 | 'num_pixels': self.num_pixels} 1607 | base_config = super(MyUpSampling2D, self).get_config() 1608 | return dict(list(base_config.items()) + list(config.items())) 1609 | 1610 | class UpSampling3D(Layer): 1611 | """Upsampling layer for 3D inputs. 1612 | 1613 | Repeats the 1st, 2nd and 3rd dimensions 1614 | of the data by size[0], size[1] and size[2] respectively. 1615 | 1616 | # Arguments 1617 | size: int, or tuple of 3 integers. 1618 | The upsampling factors for dim1, dim2 and dim3. 1619 | data_format: A string, 1620 | one of `channels_last` (default) or `channels_first`. 1621 | The ordering of the dimensions in the inputs. 1622 | `channels_last` corresponds to inputs with shape 1623 | `(batch, spatial_dim1, spatial_dim2, spatial_dim3, channels)` 1624 | while `channels_first` corresponds to inputs with shape 1625 | `(batch, channels, spatial_dim1, spatial_dim2, spatial_dim3)`. 1626 | It defaults to the `image_data_format` value found in your 1627 | Keras config file at `~/.keras/keras.json`. 1628 | If you never set it, then it will be "channels_last". 1629 | 1630 | # Input shape 1631 | 5D tensor with shape: 1632 | - If `data_format` is `"channels_last"`: 1633 | `(batch, dim1, dim2, dim3, channels)` 1634 | - If `data_format` is `"channels_first"`: 1635 | `(batch, channels, dim1, dim2, dim3)` 1636 | 1637 | # Output shape 1638 | 5D tensor with shape: 1639 | - If `data_format` is `"channels_last"`: 1640 | `(batch, upsampled_dim1, upsampled_dim2, upsampled_dim3, channels)` 1641 | - If `data_format` is `"channels_first"`: 1642 | `(batch, channels, upsampled_dim1, upsampled_dim2, upsampled_dim3)` 1643 | """ 1644 | 1645 | @interfaces.legacy_upsampling3d_support 1646 | def __init__(self, size=(2, 2, 2), data_format=None, **kwargs): 1647 | self.data_format = conv_utils.normalize_data_format(data_format) 1648 | self.size = conv_utils.normalize_tuple(size, 3, 'size') 1649 | self.input_spec = InputSpec(ndim=5) 1650 | super(UpSampling3D, self).__init__(**kwargs) 1651 | 1652 | def compute_output_shape(self, input_shape): 1653 | if self.data_format == 'channels_first': 1654 | dim1 = self.size[0] * input_shape[2] if input_shape[2] is not None else None 1655 | dim2 = self.size[1] * input_shape[3] if input_shape[3] is not None else None 1656 | dim3 = self.size[2] * input_shape[4] if input_shape[4] is not None else None 1657 | return (input_shape[0], 1658 | input_shape[1], 1659 | dim1, 1660 | dim2, 1661 | dim3) 1662 | elif self.data_format == 'channels_last': 1663 | dim1 = self.size[0] * input_shape[1] if input_shape[1] is not None else None 1664 | dim2 = self.size[1] * input_shape[2] if input_shape[2] is not None else None 1665 | dim3 = self.size[2] * input_shape[3] if input_shape[3] is not None else None 1666 | return (input_shape[0], 1667 | dim1, 1668 | dim2, 1669 | dim3, 1670 | input_shape[4]) 1671 | 1672 | def call(self, inputs): 1673 | return K.resize_volumes(inputs, 1674 | self.size[0], self.size[1], self.size[2], 1675 | self.data_format) 1676 | 1677 | def get_config(self): 1678 | config = {'size': self.size, 1679 | 'data_format': self.data_format} 1680 | base_config = super(UpSampling3D, self).get_config() 1681 | return dict(list(base_config.items()) + list(config.items())) 1682 | 1683 | 1684 | class ZeroPadding1D(Layer): 1685 | """Zero-padding layer for 1D input (e.g. temporal sequence). 1686 | 1687 | # Arguments 1688 | padding: int, or tuple of int (length 2), or dictionary. 1689 | - If int: 1690 | How many zeros to add at the beginning and end of 1691 | the padding dimension (axis 1). 1692 | - If tuple of int (length 2): 1693 | How many zeros to add at the beginning and at the end of 1694 | the padding dimension (`(left_pad, right_pad)`). 1695 | 1696 | # Input shape 1697 | 3D tensor with shape `(batch, axis_to_pad, features)` 1698 | 1699 | # Output shape 1700 | 3D tensor with shape `(batch, padded_axis, features)` 1701 | """ 1702 | 1703 | def __init__(self, padding=1, **kwargs): 1704 | super(ZeroPadding1D, self).__init__(**kwargs) 1705 | self.padding = conv_utils.normalize_tuple(padding, 2, 'padding') 1706 | self.input_spec = InputSpec(ndim=3) 1707 | 1708 | def compute_output_shape(self, input_shape): 1709 | if input_shape[1] is not None: 1710 | length = input_shape[1] + self.padding[0] + self.padding[1] 1711 | else: 1712 | length = None 1713 | return (input_shape[0], 1714 | length, 1715 | input_shape[2]) 1716 | 1717 | def call(self, inputs): 1718 | return K.temporal_padding(inputs, padding=self.padding) 1719 | 1720 | def get_config(self): 1721 | config = {'padding': self.padding} 1722 | base_config = super(ZeroPadding1D, self).get_config() 1723 | return dict(list(base_config.items()) + list(config.items())) 1724 | 1725 | 1726 | class ZeroPadding2D(Layer): 1727 | """Zero-padding layer for 2D input (e.g. picture). 1728 | 1729 | This layer can add rows and columns of zeros 1730 | at the top, bottom, left and right side of an image tensor. 1731 | 1732 | # Arguments 1733 | padding: int, or tuple of 2 ints, or tuple of 2 tuples of 2 ints. 1734 | - If int: the same symmetric padding 1735 | is applied to width and height. 1736 | - If tuple of 2 ints: 1737 | interpreted as two different 1738 | symmetric padding values for height and width: 1739 | `(symmetric_height_pad, symmetric_width_pad)`. 1740 | - If tuple of 2 tuples of 2 ints: 1741 | interpreted as 1742 | `((top_pad, bottom_pad), (left_pad, right_pad))` 1743 | data_format: A string, 1744 | one of `channels_last` (default) or `channels_first`. 1745 | The ordering of the dimensions in the inputs. 1746 | `channels_last` corresponds to inputs with shape 1747 | `(batch, height, width, channels)` while `channels_first` 1748 | corresponds to inputs with shape 1749 | `(batch, channels, height, width)`. 1750 | It defaults to the `image_data_format` value found in your 1751 | Keras config file at `~/.keras/keras.json`. 1752 | If you never set it, then it will be "channels_last". 1753 | 1754 | # Input shape 1755 | 4D tensor with shape: 1756 | - If `data_format` is `"channels_last"`: 1757 | `(batch, rows, cols, channels)` 1758 | - If `data_format` is `"channels_first"`: 1759 | `(batch, channels, rows, cols)` 1760 | 1761 | # Output shape 1762 | 4D tensor with shape: 1763 | - If `data_format` is `"channels_last"`: 1764 | `(batch, padded_rows, padded_cols, channels)` 1765 | - If `data_format` is `"channels_first"`: 1766 | `(batch, channels, padded_rows, padded_cols)` 1767 | """ 1768 | 1769 | @interfaces.legacy_zeropadding2d_support 1770 | def __init__(self, 1771 | padding=(1, 1), 1772 | data_format=None, 1773 | **kwargs): 1774 | super(ZeroPadding2D, self).__init__(**kwargs) 1775 | self.data_format = conv_utils.normalize_data_format(data_format) 1776 | if isinstance(padding, int): 1777 | self.padding = ((padding, padding), (padding, padding)) 1778 | elif hasattr(padding, '__len__'): 1779 | if len(padding) != 2: 1780 | raise ValueError('`padding` should have two elements. ' 1781 | 'Found: ' + str(padding)) 1782 | height_padding = conv_utils.normalize_tuple(padding[0], 2, 1783 | '1st entry of padding') 1784 | width_padding = conv_utils.normalize_tuple(padding[1], 2, 1785 | '2nd entry of padding') 1786 | self.padding = (height_padding, width_padding) 1787 | else: 1788 | raise ValueError('`padding` should be either an int, ' 1789 | 'a tuple of 2 ints ' 1790 | '(symmetric_height_pad, symmetric_width_pad), ' 1791 | 'or a tuple of 2 tuples of 2 ints ' 1792 | '((top_pad, bottom_pad), (left_pad, right_pad)). ' 1793 | 'Found: ' + str(padding)) 1794 | self.input_spec = InputSpec(ndim=4) 1795 | 1796 | def compute_output_shape(self, input_shape): 1797 | if self.data_format == 'channels_first': 1798 | if input_shape[2] is not None: 1799 | rows = input_shape[2] + self.padding[0][0] + self.padding[0][1] 1800 | else: 1801 | rows = None 1802 | if input_shape[3] is not None: 1803 | cols = input_shape[3] + self.padding[1][0] + self.padding[1][1] 1804 | else: 1805 | cols = None 1806 | return (input_shape[0], 1807 | input_shape[1], 1808 | rows, 1809 | cols) 1810 | elif self.data_format == 'channels_last': 1811 | if input_shape[1] is not None: 1812 | rows = input_shape[1] + self.padding[0][0] + self.padding[0][1] 1813 | else: 1814 | rows = None 1815 | if input_shape[2] is not None: 1816 | cols = input_shape[2] + self.padding[1][0] + self.padding[1][1] 1817 | else: 1818 | cols = None 1819 | return (input_shape[0], 1820 | rows, 1821 | cols, 1822 | input_shape[3]) 1823 | 1824 | def call(self, inputs): 1825 | return K.spatial_2d_padding(inputs, 1826 | padding=self.padding, 1827 | data_format=self.data_format) 1828 | 1829 | def get_config(self): 1830 | config = {'padding': self.padding, 1831 | 'data_format': self.data_format} 1832 | base_config = super(ZeroPadding2D, self).get_config() 1833 | return dict(list(base_config.items()) + list(config.items())) 1834 | 1835 | 1836 | class ZeroPadding3D(Layer): 1837 | """Zero-padding layer for 3D data (spatial or spatio-temporal). 1838 | 1839 | # Arguments 1840 | padding: int, or tuple of 2 ints, or tuple of 2 tuples of 2 ints. 1841 | - If int: the same symmetric padding 1842 | is applied to width and height. 1843 | - If tuple of 2 ints: 1844 | interpreted as two different 1845 | symmetric padding values for height and width: 1846 | `(symmetric_dim1_pad, symmetric_dim2_pad, symmetric_dim3_pad)`. 1847 | - If tuple of 2 tuples of 2 ints: 1848 | interpreted as 1849 | `((left_dim1_pad, right_dim1_pad), (left_dim2_pad, right_dim2_pad), (left_dim3_pad, right_dim3_pad))` 1850 | data_format: A string, 1851 | one of `channels_last` (default) or `channels_first`. 1852 | The ordering of the dimensions in the inputs. 1853 | `channels_last` corresponds to inputs with shape 1854 | `(batch, spatial_dim1, spatial_dim2, spatial_dim3, channels)` 1855 | while `channels_first` corresponds to inputs with shape 1856 | `(batch, channels, spatial_dim1, spatial_dim2, spatial_dim3)`. 1857 | It defaults to the `image_data_format` value found in your 1858 | Keras config file at `~/.keras/keras.json`. 1859 | If you never set it, then it will be "channels_last". 1860 | 1861 | # Input shape 1862 | 5D tensor with shape: 1863 | - If `data_format` is `"channels_last"`: 1864 | `(batch, first_axis_to_pad, second_axis_to_pad, third_axis_to_pad, depth)` 1865 | - If `data_format` is `"channels_first"`: 1866 | `(batch, depth, first_axis_to_pad, second_axis_to_pad, third_axis_to_pad)` 1867 | 1868 | # Output shape 1869 | 5D tensor with shape: 1870 | - If `data_format` is `"channels_last"`: 1871 | `(batch, first_padded_axis, second_padded_axis, third_axis_to_pad, depth)` 1872 | - If `data_format` is `"channels_first"`: 1873 | `(batch, depth, first_padded_axis, second_padded_axis, third_axis_to_pad)` 1874 | """ 1875 | 1876 | @interfaces.legacy_zeropadding3d_support 1877 | def __init__(self, padding=(1, 1, 1), data_format=None, **kwargs): 1878 | super(ZeroPadding3D, self).__init__(**kwargs) 1879 | self.data_format = conv_utils.normalize_data_format(data_format) 1880 | if isinstance(padding, int): 1881 | self.padding = ((padding, padding), (padding, padding), (padding, padding)) 1882 | elif hasattr(padding, '__len__'): 1883 | if len(padding) != 3: 1884 | raise ValueError('`padding` should have 3 elements. ' 1885 | 'Found: ' + str(padding)) 1886 | dim1_padding = conv_utils.normalize_tuple(padding[0], 2, 1887 | '1st entry of padding') 1888 | dim2_padding = conv_utils.normalize_tuple(padding[1], 2, 1889 | '2nd entry of padding') 1890 | dim3_padding = conv_utils.normalize_tuple(padding[2], 2, 1891 | '3rd entry of padding') 1892 | self.padding = (dim1_padding, dim2_padding, dim3_padding) 1893 | else: 1894 | raise ValueError('`padding` should be either an int, ' 1895 | 'a tuple of 3 ints ' 1896 | '(symmetric_dim1_pad, symmetric_dim2_pad, symmetric_dim3_pad), ' 1897 | 'or a tuple of 3 tuples of 2 ints ' 1898 | '((left_dim1_pad, right_dim1_pad),' 1899 | ' (left_dim2_pad, right_dim2_pad),' 1900 | ' (left_dim3_pad, right_dim2_pad)). ' 1901 | 'Found: ' + str(padding)) 1902 | self.input_spec = InputSpec(ndim=5) 1903 | 1904 | def compute_output_shape(self, input_shape): 1905 | if self.data_format == 'channels_first': 1906 | if input_shape[2] is not None: 1907 | dim1 = input_shape[2] + self.padding[0][0] + self.padding[0][1] 1908 | else: 1909 | dim1 = None 1910 | if input_shape[3] is not None: 1911 | dim2 = input_shape[3] + self.padding[1][0] + self.padding[1][1] 1912 | else: 1913 | dim2 = None 1914 | if input_shape[4] is not None: 1915 | dim3 = input_shape[4] + self.padding[2][0] + self.padding[2][1] 1916 | else: 1917 | dim3 = None 1918 | return (input_shape[0], 1919 | input_shape[1], 1920 | dim1, 1921 | dim2, 1922 | dim3) 1923 | elif self.data_format == 'channels_last': 1924 | if input_shape[1] is not None: 1925 | dim1 = input_shape[1] + self.padding[0][0] + self.padding[0][1] 1926 | else: 1927 | dim1 = None 1928 | if input_shape[2] is not None: 1929 | dim2 = input_shape[2] + self.padding[1][0] + self.padding[1][1] 1930 | else: 1931 | dim2 = None 1932 | if input_shape[3] is not None: 1933 | dim3 = input_shape[3] + self.padding[2][0] + self.padding[2][1] 1934 | else: 1935 | dim3 = None 1936 | return (input_shape[0], 1937 | dim1, 1938 | dim2, 1939 | dim3, 1940 | input_shape[4]) 1941 | 1942 | def call(self, inputs): 1943 | return K.spatial_3d_padding(inputs, 1944 | padding=self.padding, 1945 | data_format=self.data_format) 1946 | 1947 | def get_config(self): 1948 | config = {'padding': self.padding, 1949 | 'data_format': self.data_format} 1950 | base_config = super(ZeroPadding3D, self).get_config() 1951 | return dict(list(base_config.items()) + list(config.items())) 1952 | 1953 | 1954 | class Cropping1D(Layer): 1955 | """Cropping layer for 1D input (e.g. temporal sequence). 1956 | 1957 | It crops along the time dimension (axis 1). 1958 | 1959 | # Arguments 1960 | cropping: int or tuple of int (length 2) 1961 | How many units should be trimmed off at the beginning and end of 1962 | the cropping dimension (axis 1). 1963 | If a single int is provided, 1964 | the same value will be used for both. 1965 | 1966 | # Input shape 1967 | 3D tensor with shape `(batch, axis_to_crop, features)` 1968 | 1969 | # Output shape 1970 | 3D tensor with shape `(batch, cropped_axis, features)` 1971 | """ 1972 | 1973 | def __init__(self, cropping=(1, 1), **kwargs): 1974 | super(Cropping1D, self).__init__(**kwargs) 1975 | self.cropping = conv_utils.normalize_tuple(cropping, 2, 'cropping') 1976 | self.input_spec = InputSpec(ndim=3) 1977 | 1978 | def compute_output_shape(self, input_shape): 1979 | if input_shape[1] is not None: 1980 | length = input_shape[1] - self.cropping[0] - self.cropping[1] 1981 | else: 1982 | length = None 1983 | return (input_shape[0], 1984 | length, 1985 | input_shape[2]) 1986 | 1987 | def call(self, inputs): 1988 | if self.cropping[1] == 0: 1989 | return inputs[:, self.cropping[0]:, :] 1990 | else: 1991 | return inputs[:, self.cropping[0]: -self.cropping[1], :] 1992 | 1993 | def get_config(self): 1994 | config = {'cropping': self.cropping} 1995 | base_config = super(Cropping1D, self).get_config() 1996 | return dict(list(base_config.items()) + list(config.items())) 1997 | 1998 | 1999 | class Cropping2D(Layer): 2000 | """Cropping layer for 2D input (e.g. picture). 2001 | 2002 | It crops along spatial dimensions, i.e. width and height. 2003 | 2004 | # Arguments 2005 | cropping: int, or tuple of 2 ints, or tuple of 2 tuples of 2 ints. 2006 | - If int: the same symmetric cropping 2007 | is applied to width and height. 2008 | - If tuple of 2 ints: 2009 | interpreted as two different 2010 | symmetric cropping values for height and width: 2011 | `(symmetric_height_crop, symmetric_width_crop)`. 2012 | - If tuple of 2 tuples of 2 ints: 2013 | interpreted as 2014 | `((top_crop, bottom_crop), (left_crop, right_crop))` 2015 | data_format: A string, 2016 | one of `channels_last` (default) or `channels_first`. 2017 | The ordering of the dimensions in the inputs. 2018 | `channels_last` corresponds to inputs with shape 2019 | `(batch, height, width, channels)` while `channels_first` 2020 | corresponds to inputs with shape 2021 | `(batch, channels, height, width)`. 2022 | It defaults to the `image_data_format` value found in your 2023 | Keras config file at `~/.keras/keras.json`. 2024 | If you never set it, then it will be "channels_last". 2025 | 2026 | # Input shape 2027 | 4D tensor with shape: 2028 | - If `data_format` is `"channels_last"`: 2029 | `(batch, rows, cols, channels)` 2030 | - If `data_format` is `"channels_first"`: 2031 | `(batch, channels, rows, cols)` 2032 | 2033 | # Output shape 2034 | 4D tensor with shape: 2035 | - If `data_format` is `"channels_last"`: 2036 | `(batch, cropped_rows, cropped_cols, channels)` 2037 | - If `data_format` is `"channels_first"`: 2038 | `(batch, channels, cropped_rows, cropped_cols)` 2039 | 2040 | # Examples 2041 | 2042 | ```python 2043 | # Crop the input 2D images or feature maps 2044 | model = Sequential() 2045 | model.add(Cropping2D(cropping=((2, 2), (4, 4)), 2046 | input_shape=(28, 28, 3))) 2047 | # now model.output_shape == (None, 24, 20, 3) 2048 | model.add(Conv2D(64, (3, 3), padding='same')) 2049 | model.add(Cropping2D(cropping=((2, 2), (2, 2)))) 2050 | # now model.output_shape == (None, 20, 16. 64) 2051 | ``` 2052 | """ 2053 | 2054 | @interfaces.legacy_cropping2d_support 2055 | def __init__(self, cropping=((0, 0), (0, 0)), 2056 | data_format=None, **kwargs): 2057 | super(Cropping2D, self).__init__(**kwargs) 2058 | self.data_format = conv_utils.normalize_data_format(data_format) 2059 | if isinstance(cropping, int): 2060 | self.cropping = ((cropping, cropping), (cropping, cropping)) 2061 | elif hasattr(cropping, '__len__'): 2062 | if len(cropping) != 2: 2063 | raise ValueError('`cropping` should have two elements. ' 2064 | 'Found: ' + str(cropping)) 2065 | height_cropping = conv_utils.normalize_tuple( 2066 | cropping[0], 2, 2067 | '1st entry of cropping') 2068 | width_cropping = conv_utils.normalize_tuple( 2069 | cropping[1], 2, 2070 | '2nd entry of cropping') 2071 | self.cropping = (height_cropping, width_cropping) 2072 | else: 2073 | raise ValueError('`cropping` should be either an int, ' 2074 | 'a tuple of 2 ints ' 2075 | '(symmetric_height_crop, symmetric_width_crop), ' 2076 | 'or a tuple of 2 tuples of 2 ints ' 2077 | '((top_crop, bottom_crop), (left_crop, right_crop)). ' 2078 | 'Found: ' + str(cropping)) 2079 | self.input_spec = InputSpec(ndim=4) 2080 | 2081 | def compute_output_shape(self, input_shape): 2082 | if self.data_format == 'channels_first': 2083 | return (input_shape[0], 2084 | input_shape[1], 2085 | input_shape[2] - self.cropping[0][0] - self.cropping[0][1] if input_shape[2] else None, 2086 | input_shape[3] - self.cropping[1][0] - self.cropping[1][1] if input_shape[3] else None) 2087 | elif self.data_format == 'channels_last': 2088 | return (input_shape[0], 2089 | input_shape[1] - self.cropping[0][0] - self.cropping[0][1] if input_shape[1] else None, 2090 | input_shape[2] - self.cropping[1][0] - self.cropping[1][1] if input_shape[2] else None, 2091 | input_shape[3]) 2092 | 2093 | def call(self, inputs): 2094 | if self.data_format == 'channels_first': 2095 | if self.cropping[0][1] == self.cropping[1][1] == 0: 2096 | return inputs[:, 2097 | :, 2098 | self.cropping[0][0]:, 2099 | self.cropping[1][0]:] 2100 | elif self.cropping[0][1] == 0: 2101 | return inputs[:, 2102 | :, 2103 | self.cropping[0][0]:, 2104 | self.cropping[1][0]: -self.cropping[1][1]] 2105 | elif self.cropping[1][1] == 0: 2106 | return inputs[:, 2107 | :, 2108 | self.cropping[0][0]: -self.cropping[0][1], 2109 | self.cropping[1][0]:] 2110 | return inputs[:, 2111 | :, 2112 | self.cropping[0][0]: -self.cropping[0][1], 2113 | self.cropping[1][0]: -self.cropping[1][1]] 2114 | elif self.data_format == 'channels_last': 2115 | if self.cropping[0][1] == self.cropping[1][1] == 0: 2116 | return inputs[:, 2117 | self.cropping[0][0]:, 2118 | self.cropping[1][0]:, 2119 | :] 2120 | elif self.cropping[0][1] == 0: 2121 | return inputs[:, 2122 | self.cropping[0][0]:, 2123 | self.cropping[1][0]: -self.cropping[1][1], 2124 | :] 2125 | elif self.cropping[1][1] == 0: 2126 | return inputs[:, 2127 | self.cropping[0][0]: -self.cropping[0][1], 2128 | self.cropping[1][0]:, 2129 | :] 2130 | return inputs[:, 2131 | self.cropping[0][0]: -self.cropping[0][1], 2132 | self.cropping[1][0]: -self.cropping[1][1], 2133 | :] 2134 | 2135 | def get_config(self): 2136 | config = {'cropping': self.cropping, 2137 | 'data_format': self.data_format} 2138 | base_config = super(Cropping2D, self).get_config() 2139 | return dict(list(base_config.items()) + list(config.items())) 2140 | 2141 | 2142 | class Cropping3D(Layer): 2143 | """Cropping layer for 3D data (e.g. spatial or spatio-temporal). 2144 | 2145 | # Arguments 2146 | cropping: int, or tuple of 2 ints, or tuple of 2 tuples of 2 ints. 2147 | - If int: the same symmetric cropping 2148 | is applied to width and height. 2149 | - If tuple of 2 ints: 2150 | interpreted as two different 2151 | symmetric cropping values for height and width: 2152 | `(symmetric_dim1_crop, symmetric_dim2_crop, symmetric_dim3_crop)`. 2153 | - If tuple of 2 tuples of 2 ints: 2154 | interpreted as 2155 | `((left_dim1_crop, right_dim1_crop), (left_dim2_crop, right_dim2_crop), (left_dim3_crop, right_dim3_crop))` 2156 | data_format: A string, 2157 | one of `channels_last` (default) or `channels_first`. 2158 | The ordering of the dimensions in the inputs. 2159 | `channels_last` corresponds to inputs with shape 2160 | `(batch, spatial_dim1, spatial_dim2, spatial_dim3, channels)` 2161 | while `channels_first` corresponds to inputs with shape 2162 | `(batch, channels, spatial_dim1, spatial_dim2, spatial_dim3)`. 2163 | It defaults to the `image_data_format` value found in your 2164 | Keras config file at `~/.keras/keras.json`. 2165 | If you never set it, then it will be "channels_last". 2166 | 2167 | # Input shape 2168 | 5D tensor with shape: 2169 | - If `data_format` is `"channels_last"`: 2170 | `(batch, first_axis_to_crop, second_axis_to_crop, third_axis_to_crop, depth)` 2171 | - If `data_format` is `"channels_first"`: 2172 | `(batch, depth, first_axis_to_crop, second_axis_to_crop, third_axis_to_crop)` 2173 | 2174 | # Output shape 2175 | 5D tensor with shape: 2176 | - If `data_format` is `"channels_last"`: 2177 | `(batch, first_cropped_axis, second_cropped_axis, third_cropped_axis, depth)` 2178 | - If `data_format` is `"channels_first"`: 2179 | `(batch, depth, first_cropped_axis, second_cropped_axis, third_cropped_axis)` 2180 | """ 2181 | 2182 | @interfaces.legacy_cropping3d_support 2183 | def __init__(self, cropping=((1, 1), (1, 1), (1, 1)), 2184 | data_format=None, **kwargs): 2185 | super(Cropping3D, self).__init__(**kwargs) 2186 | self.data_format = conv_utils.normalize_data_format(data_format) 2187 | if isinstance(cropping, int): 2188 | self.cropping = ((cropping, cropping), 2189 | (cropping, cropping), 2190 | (cropping, cropping)) 2191 | elif hasattr(cropping, '__len__'): 2192 | if len(cropping) != 3: 2193 | raise ValueError('`cropping` should have 3 elements. ' 2194 | 'Found: ' + str(cropping)) 2195 | dim1_cropping = conv_utils.normalize_tuple(cropping[0], 2, 2196 | '1st entry of cropping') 2197 | dim2_cropping = conv_utils.normalize_tuple(cropping[1], 2, 2198 | '2nd entry of cropping') 2199 | dim3_cropping = conv_utils.normalize_tuple(cropping[2], 2, 2200 | '3rd entry of cropping') 2201 | self.cropping = (dim1_cropping, dim2_cropping, dim3_cropping) 2202 | else: 2203 | raise ValueError('`cropping` should be either an int, ' 2204 | 'a tuple of 3 ints ' 2205 | '(symmetric_dim1_crop, symmetric_dim2_crop, symmetric_dim3_crop), ' 2206 | 'or a tuple of 3 tuples of 2 ints ' 2207 | '((left_dim1_crop, right_dim1_crop),' 2208 | ' (left_dim2_crop, right_dim2_crop),' 2209 | ' (left_dim3_crop, right_dim2_crop)). ' 2210 | 'Found: ' + str(cropping)) 2211 | self.input_spec = InputSpec(ndim=5) 2212 | 2213 | def compute_output_shape(self, input_shape): 2214 | if self.data_format == 'channels_first': 2215 | if input_shape[2] is not None: 2216 | dim1 = input_shape[2] - self.cropping[0][0] - self.cropping[0][1] 2217 | else: 2218 | dim1 = None 2219 | if input_shape[3] is not None: 2220 | dim2 = input_shape[3] - self.cropping[1][0] - self.cropping[1][1] 2221 | else: 2222 | dim2 = None 2223 | if input_shape[4] is not None: 2224 | dim3 = input_shape[4] - self.cropping[2][0] - self.cropping[2][1] 2225 | else: 2226 | dim3 = None 2227 | return (input_shape[0], 2228 | input_shape[1], 2229 | dim1, 2230 | dim2, 2231 | dim3) 2232 | elif self.data_format == 'channels_last': 2233 | if input_shape[1] is not None: 2234 | dim1 = input_shape[1] - self.cropping[0][0] - self.cropping[0][1] 2235 | else: 2236 | dim1 = None 2237 | if input_shape[2] is not None: 2238 | dim2 = input_shape[2] - self.cropping[1][0] - self.cropping[1][1] 2239 | else: 2240 | dim2 = None 2241 | if input_shape[3] is not None: 2242 | dim3 = input_shape[3] - self.cropping[2][0] - self.cropping[2][1] 2243 | else: 2244 | dim3 = None 2245 | return (input_shape[0], 2246 | dim1, 2247 | dim2, 2248 | dim3, 2249 | input_shape[4]) 2250 | 2251 | def call(self, inputs): 2252 | if self.data_format == 'channels_first': 2253 | if self.cropping[0][1] == self.cropping[1][1] == self.cropping[2][1] == 0: 2254 | return inputs[:, 2255 | :, 2256 | self.cropping[0][0]:, 2257 | self.cropping[1][0]:, 2258 | self.cropping[2][0]:] 2259 | elif self.cropping[0][1] == self.cropping[1][1] == 0: 2260 | return inputs[:, 2261 | :, 2262 | self.cropping[0][0]:, 2263 | self.cropping[1][0]:, 2264 | self.cropping[2][0]: -self.cropping[2][1]] 2265 | elif self.cropping[1][1] == self.cropping[2][1] == 0: 2266 | return inputs[:, 2267 | :, 2268 | self.cropping[0][0]: -self.cropping[0][1], 2269 | self.cropping[1][0]:, 2270 | self.cropping[2][0]:] 2271 | elif self.cropping[0][1] == self.cropping[2][1] == 0: 2272 | return inputs[:, 2273 | :, 2274 | self.cropping[0][0]:, 2275 | self.cropping[1][0]: -self.cropping[1][1], 2276 | self.cropping[2][0]:] 2277 | elif self.cropping[0][1] == 0: 2278 | return inputs[:, 2279 | :, 2280 | self.cropping[0][0]:, 2281 | self.cropping[1][0]: -self.cropping[1][1], 2282 | self.cropping[2][0]: -self.cropping[2][1]] 2283 | elif self.cropping[1][1] == 0: 2284 | return inputs[:, 2285 | :, 2286 | self.cropping[0][0]: -self.cropping[0][1], 2287 | self.cropping[1][0]:, 2288 | self.cropping[2][0]: -self.cropping[2][1]] 2289 | elif self.cropping[2][1] == 0: 2290 | return inputs[:, 2291 | :, 2292 | self.cropping[0][0]: -self.cropping[0][1], 2293 | self.cropping[1][0]: -self.cropping[1][1], 2294 | self.cropping[2][0]:] 2295 | return inputs[:, 2296 | :, 2297 | self.cropping[0][0]: -self.cropping[0][1], 2298 | self.cropping[1][0]: -self.cropping[1][1], 2299 | self.cropping[2][0]: -self.cropping[2][1]] 2300 | 2301 | elif self.data_format == 'channels_last': 2302 | if self.cropping[0][1] == self.cropping[1][1] == self.cropping[2][1] == 0: 2303 | return inputs[:, 2304 | self.cropping[0][0]:, 2305 | self.cropping[1][0]:, 2306 | self.cropping[2][0]:, 2307 | :] 2308 | elif self.cropping[0][1] == self.cropping[1][1] == 0: 2309 | return inputs[:, 2310 | self.cropping[0][0]:, 2311 | self.cropping[1][0]:, 2312 | self.cropping[2][0]: -self.cropping[2][1], 2313 | :] 2314 | elif self.cropping[1][1] == self.cropping[2][1] == 0: 2315 | return inputs[:, 2316 | self.cropping[0][0]: -self.cropping[0][1], 2317 | self.cropping[1][0]:, 2318 | self.cropping[2][0]:, 2319 | :] 2320 | elif self.cropping[0][1] == self.cropping[2][1] == 0: 2321 | return inputs[:, 2322 | self.cropping[0][0]:, 2323 | self.cropping[1][0]:-self.cropping[1][1], 2324 | self.cropping[2][0]:, 2325 | :] 2326 | elif self.cropping[0][1] == 0: 2327 | return inputs[:, 2328 | self.cropping[0][0]:, 2329 | self.cropping[1][0]: -self.cropping[1][1], 2330 | self.cropping[2][0]: -self.cropping[2][1], 2331 | :] 2332 | elif self.cropping[1][1] == 0: 2333 | return inputs[:, 2334 | self.cropping[0][0]: -self.cropping[0][1], 2335 | self.cropping[1][0]:, 2336 | self.cropping[2][0]: -self.cropping[2][1], 2337 | :] 2338 | elif self.cropping[2][1] == 0: 2339 | return inputs[:, 2340 | self.cropping[0][0]: -self.cropping[0][1], 2341 | self.cropping[1][0]: -self.cropping[1][1], 2342 | self.cropping[2][0]:, 2343 | :] 2344 | return inputs[:, 2345 | self.cropping[0][0]: -self.cropping[0][1], 2346 | self.cropping[1][0]: -self.cropping[1][1], 2347 | self.cropping[2][0]: -self.cropping[2][1], 2348 | :] 2349 | 2350 | def get_config(self): 2351 | config = {'cropping': self.cropping, 2352 | 'data_format': self.data_format} 2353 | base_config = super(Cropping3D, self).get_config() 2354 | return dict(list(base_config.items()) + list(config.items())) 2355 | 2356 | 2357 | # Aliases 2358 | 2359 | Convolution1D = Conv1D 2360 | Convolution2D = Conv2D 2361 | Convolution3D = Conv3D 2362 | SeparableConvolution2D = SeparableConv2D 2363 | Convolution2DTranspose = Conv2DTranspose 2364 | Deconvolution2D = Deconv2D = Conv2DTranspose 2365 | Deconvolution3D = Deconv3D = Conv3DTranspose 2366 | 2367 | # Legacy aliases 2368 | AtrousConv1D = AtrousConvolution1D 2369 | AtrousConv2D = AtrousConvolution2D 2370 | -------------------------------------------------------------------------------- /ContextNet/data/gtFine/CityScapes.txt: -------------------------------------------------------------------------------- 1 | download cityscapes "gtFine_trainvaltest" -------------------------------------------------------------------------------- /ContextNet/data/leftImg8bit/CityScapes.txt: -------------------------------------------------------------------------------- 1 | download CityScapes "leftImg8bit_trainvaltest" -------------------------------------------------------------------------------- /ContextNet/data_processing.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reference: 3 | https://github.com/ooleksyuk/CarND-Semantic-Segmentation/blob/master/helper_cityscapes.py 4 | 5 | """ 6 | 7 | import random 8 | import numpy as np 9 | import os.path 10 | import scipy.misc 11 | import shutil 12 | import time 13 | import tensorflow as tf 14 | from glob import glob 15 | import matplotlib.pyplot as plt 16 | 17 | 18 | from collections import namedtuple 19 | from timeit import default_timer as timer 20 | 21 | Label = namedtuple('Label', ['name', 'color']) 22 | """ 23 | # in case you would use cv2 24 | def rgb2bgr(tpl): 25 | return (tpl[2], tpl[1], tpl[0]) 26 | """ 27 | # cf https://github.com/mcordts/cityscapesScripts/blob/master/cityscapesscripts/helpers/labels.py 28 | 29 | # num_classes 20 30 | # background (unlabeled) + 19 classes as per official benchmark 31 | # cf "The Cityscapes Dataset for Semantic Urban Scene Understanding" 32 | label_defs = [ 33 | Label('unlabeled', (0, 0, 0)), 34 | Label('dynamic', (111, 74, 0)), 35 | Label('ground', ( 81, 0, 81)), 36 | Label('road', (128, 64, 128)), 37 | Label('sidewalk', (244, 35, 232)), 38 | Label('parking', (250, 170, 160)), 39 | Label('rail track', (230, 150, 140)), 40 | Label('building', ( 70, 70, 70)), 41 | Label('wall', (102, 102, 156)), 42 | Label('fence', (190, 153, 153)), 43 | Label('guard rail', (180, 165, 180)), 44 | Label('bridge', (150, 100, 100)), 45 | Label('tunnel', (150, 120, 90)), 46 | Label('pole', (153, 153, 153)), 47 | Label('traffic light', (250, 170, 30)), 48 | Label('traffic sign', (220, 220, 0)), 49 | Label('vegetation', (107, 142, 35)), 50 | Label('terrain', (152, 251, 152)), 51 | Label('sky', ( 70, 130, 180)), 52 | Label('person', (220, 20, 60)), 53 | Label('rider', (255, 0, 0)), 54 | Label('car', ( 0, 0, 142)), 55 | Label('truck', ( 0, 0, 70)), 56 | Label('bus', ( 0, 60, 100)), 57 | Label('caravan', ( 0, 0, 90)), 58 | Label('trailer', ( 0, 0, 110)), 59 | Label('train', ( 0, 80, 100)), 60 | Label('motorcycle', ( 0, 0, 230)), 61 | Label('bicycle', (119, 11, 32))] 62 | 63 | 64 | def build_file_list(images_root, labels_root, sample_name): 65 | image_sample_root = images_root + '/' + sample_name 66 | image_root_len = len(image_sample_root) 67 | label_sample_root = labels_root + '/' + sample_name 68 | image_files = glob(image_sample_root + '/**/*png') 69 | file_list = [] 70 | for f in image_files: 71 | f_relative = f[image_root_len:] 72 | f_dir = os.path.dirname(f_relative) 73 | f_base = os.path.basename(f_relative) 74 | f_base_gt = f_base.replace('leftImg8bit', 'gtFine_color') 75 | f_label = label_sample_root + f_dir + '/' + f_base_gt 76 | if os.path.exists(f_label): 77 | file_list.append((f, f_label)) 78 | return file_list 79 | 80 | 81 | def load_data(data_folder): 82 | 83 | images_root = os.path.join(data_folder, 'leftImg8bit') 84 | labels_root = os.path.join(data_folder, 'gtFine') 85 | 86 | train_images = build_file_list(images_root, labels_root, 'train') 87 | valid_images = build_file_list(images_root, labels_root, 'val') 88 | test_images = build_file_list(images_root, labels_root, 'test') 89 | num_classes = len(label_defs) 90 | label_colors = {i: np.array(l.color) for i, l in enumerate(label_defs)} 91 | #image_shape = (256, 512) 92 | 93 | return train_images, valid_images, test_images, num_classes, label_colors #, image_shape 94 | 95 | 96 | def bc_img(img, s=1.0, m=0.0): 97 | img = img.astype(np.int) 98 | img = img * s + m 99 | img[img > 255] = 255 100 | img[img < 0] = 0 101 | img = img.astype(np.uint8) 102 | return img 103 | 104 | 105 | def gen_batch_function(image_paths, image_shape, test = False): 106 | """ 107 | Generate function to create batches of training data 108 | :param data_folder: Path to folder that contains all the datasets 109 | :param image_shape: Tuple - Shape of image 110 | :return: 111 | """ 112 | def get_batches_fn(batch_size): 113 | """ 114 | Create batches of training data 115 | :param batch_size: Batch Size 116 | :return: Batches of training data 117 | """ 118 | random.shuffle(image_paths) 119 | 120 | while True: 121 | 122 | for batch_i in range(0, len(image_paths), batch_size): 123 | image_files = image_paths[batch_i:batch_i+batch_size] 124 | 125 | images = [] 126 | images_lowR = [] 127 | labels = [] 128 | 129 | for f in image_files: 130 | image_file = f[0] 131 | gt_image_file = f[1] 132 | 133 | image = scipy.misc.imresize(scipy.misc.imread(image_file), image_shape) 134 | #gt_image = scipy.misc.imresize(scipy.misc.imread(gt_image_file, mode='RGB'), image_shape) 135 | gt_image = scipy.misc.imresize(scipy.misc.imread(gt_image_file, mode='RGB'), (int(image_shape[0]/8), int(image_shape[1]/8))) 136 | 137 | contrast = random.uniform(0.85, 1.15) # Contrast augmentation 138 | bright = random.randint(-45, 30) # Brightness augmentation 139 | image = bc_img(image, contrast, bright) 140 | 141 | #label_bg = np.zeros([image_shape[0], image_shape[1]], dtype=bool) 142 | label_bg = np.zeros([int(image_shape[0]/8), int(image_shape[1]/8)], dtype=bool) 143 | label_list = [] 144 | for ldef in label_defs[1:]: 145 | label_current = np.all(gt_image == np.array(ldef.color), axis=2) 146 | label_bg |= label_current 147 | label_list.append(label_current) 148 | 149 | label_bg = ~label_bg 150 | label_all = np.dstack([label_bg, *label_list]) 151 | 152 | label_all = label_all.astype(np.float32) 153 | image_resize = scipy.misc.imresize(image, (int(image_shape[0]/4), int(image_shape[1]/4))) 154 | 155 | images.append(image) 156 | images_lowR.append(image_resize) 157 | labels.append(label_all) 158 | 159 | image_set = [np.array(images), np.array(images_lowR)] 160 | if not test: 161 | yield image_set, np.array(labels) 162 | else: 163 | yield image_set 164 | return get_batches_fn 165 | 166 | -------------------------------------------------------------------------------- /ContextNet/train_test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import keras 4 | import data_processing 5 | from keras.models import load_model 6 | import os 7 | from skimage import io 8 | import scipy 9 | from keras.utils.generic_utils import CustomObjectScope 10 | import ContextNet as cn 11 | 12 | def train(n_labels, batch_size, epochs, train_steps, val_steps, saved_weight, input_shape, target_shape, train_generator, valid_generator): 13 | """ 14 | Train the model 15 | """ 16 | if not os.path.exists(saved_weight): 17 | #os.makedirs(saved_weight) 18 | pass 19 | 20 | context_Net = cn.ContextNet(n_labels=n_labels, image_shape=input_shape, target_shape = target_shape) 21 | model = context_Net.init_model() 22 | 23 | chk = keras.callbacks.ModelCheckpoint(saved_weight + '/weight.h5', monitor='val_loss', verbose=0, save_best_only=True, 24 | save_weights_only=False, mode='auto', period=1) 25 | 26 | model.fit_generator(train_generator(batch_size), steps_per_epoch=train_steps, epochs=epochs, verbose=1, callbacks=[chk], 27 | validation_data = valid_generator(batch_size), validation_steps=train_steps) 28 | 29 | def build_pridictor(output_last, label_colors, image_shape): 30 | """ 31 | Get the predicted color map from the output of the model 32 | """ 33 | labels = np.argmax(output_last, axis=-1) 34 | labels = labels.reshape(image_shape[0], image_shape[1]) 35 | labels_colored = np.zeros((image_shape[0], image_shape[1], 3)) 36 | 37 | for label, color in label_colors.items(): 38 | labels_colored[labels == label] = color 39 | 40 | #mask = scipy.misc.toimage(labels_colored, mode="RGBA") 41 | #pred_image = scipy.misc.toimage(image) 42 | #pred_image.paste(mask, box=None, mask=mask) 43 | 44 | return labels_colored 45 | 46 | def test(batch_size, test_steps, target_shape, saved_preImage, saved_weight, label_colors, test_generator): 47 | """ 48 | Test the model 49 | """ 50 | 51 | if not os.path.exists(saved_preImage): 52 | os.makedirs(saved_preImage) 53 | #pass 54 | 55 | with CustomObjectScope({'relu6': keras.applications.mobilenet.relu6,'DepthwiseConv2D': keras.applications.mobilenet.DepthwiseConv2D}): 56 | model = load_model(saved_weight) 57 | predicted = model.predict_generator(test_generator(batch_size), steps=test_steps) 58 | for index, image in enumerate(predicted): 59 | saved_images = os.path.join(saved_preImage, str(index)+'.png') 60 | pred_image = build_pridictor(image, label_colors, target_shape) 61 | pred_image = scipy.misc.imresize(pred_image, (256, 512)) 62 | cv2.imwrite(saved_images, pred_image) 63 | 64 | def run(): 65 | 66 | data_dir = './data' #'D:/DeepLearning' # the path of the dataset 67 | saved_weight = data_dir + '/weight.h5' # the path to save the weight of the model 68 | saved_preImage = os.path.join(data_dir, 'test') # the path to save the predicted results 69 | 70 | image_shape = (256, 512, 3) # the shape of the input images of the model 71 | target_shape = (32, 64) # the shape of outshape of the model 72 | #train_steps, val_steps = 2500, 450 73 | batch_size = 1 74 | epochs = 3 75 | 76 | 77 | train_images, valid_images, test_images, num_classes, label_colors = data_processing.load_data(data_dir) 78 | 79 | train_steps = 5 #int(len(train_images)/batch_size-5) 80 | val_steps = 5 #int(len(valid_images)/batch_size-5) 81 | test_steps = 5 #int(len(test_images)/batch_size-5) 82 | print(train_steps, val_steps, test_steps) 83 | 84 | get_train_image = data_processing.gen_batch_function(train_images, image_shape[0:2]) 85 | get_val_image = data_processing.gen_batch_function(valid_images, image_shape[0:2]) 86 | get_test_image = data_processing.gen_batch_function(test_images, image_shape[0:2], test=True) 87 | 88 | train(num_classes, batch_size, epochs, train_steps, val_steps, data_dir, image_shape, target_shape, get_train_image, get_val_image) 89 | test(batch_size, test_steps, target_shape, saved_preImage, saved_weight, label_colors, get_test_image) 90 | 91 | if __name__ == "__main__": 92 | run() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ContextNet (Ongoing) 2 | Code of the paper "ContextNet: Exploring Context and Detail for Semantic Segmentation in Real-time" 3 | Dataset: Cityscapes 4 | --------------------------------------------------------------------------------