import tensorflow as tf

input_height = 360
input_width = 480
kernel = 3
filter_size = 64
pad = 1
pool_size = 2

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Layer(input_shape=(3, input_height, input_width)))

# encoder
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(filter_size, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size)))

model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(128, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size)))

model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(256, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size)))

model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(512, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))

# decoder
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(512, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())

model.add(tf.keras.layers.UpSampling2D(size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(256, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())

model.add(tf.keras.layers.UpSampling2D(size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(128, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())

model.add(tf.keras.layers.UpSampling2D(size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(filter_size, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())

model.add(tf.keras.layers.Conv2D(nClasses, 1, 1, border_mode='valid', ))

model.outputHeight = model.output_shape[-2]
model.outputWidth = model.output_shape[-1]

model.add(tf.keras.layers.Reshape((nClasses, model.output_shape[-2] * model.output_shape[-1]),
                  input_shape=(nClasses, model.output_shape[-2], model.output_shape[-1])))

model.add(tf.keras.layers.Permute((2, 1)))
model.add(tf.keras.layers.Activation('softmax'))

model.compile(loss="categorical_crossentropy", optimizer=tf.keras.optimizers.Adam, metrics=['accuracy'])

tensorflow.keras.layers.Activation tensorflow.keras.layers.Conv2D tensorflow.keras.layers.UpSampling2D tensorflow.keras.layers.Layer tensorflow.keras.layers.BatchNormalization tensorflow.keras.layers.Permute tensorflow.keras.layers.ZeroPadding2D tensorflow.keras.layers.Reshape tensorflow.keras.layers.MaxPooling2D tensorflow.keras.models.Sequential
[(10, 'tensorflow.keras.models.Sequential', 'tf.keras.models.Sequential', ([], {}), True, 'import tensorflow as tf\n'), (11, 'tensorflow.keras.layers.Layer', 'tf.keras.layers.Layer', ([], {'input_shape': '(3, input_height, input_width)'}), True, 'import tensorflow as tf\n'), (14, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (15, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['filter_size', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (16, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (17, 'tensorflow.keras.layers.Activation', 'tf.keras.layers.Activation', (['"""relu"""'], {}), True, 'import tensorflow as tf\n'), (18, 'tensorflow.keras.layers.MaxPooling2D', 'tf.keras.layers.MaxPooling2D', ([], {'pool_size': '(pool_size, pool_size)'}), True, 'import tensorflow as tf\n'), (20, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (21, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['(128)', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (22, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (23, 'tensorflow.keras.layers.Activation', 'tf.keras.layers.Activation', (['"""relu"""'], {}), True, 'import tensorflow as tf\n'), (24, 'tensorflow.keras.layers.MaxPooling2D', 'tf.keras.layers.MaxPooling2D', ([], {'pool_size': '(pool_size, pool_size)'}), True, 'import tensorflow as tf\n'), (26, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (27, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['(256)', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (28, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (29, 'tensorflow.keras.layers.Activation', 'tf.keras.layers.Activation', (['"""relu"""'], {}), True, 'import tensorflow as tf\n'), (30, 'tensorflow.keras.layers.MaxPooling2D', 'tf.keras.layers.MaxPooling2D', ([], {'pool_size': '(pool_size, pool_size)'}), True, 'import tensorflow as tf\n'), (32, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (33, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['(512)', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (34, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (35, 'tensorflow.keras.layers.Activation', 'tf.keras.layers.Activation', (['"""relu"""'], {}), True, 'import tensorflow as tf\n'), (38, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (39, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['(512)', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (40, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (42, 'tensorflow.keras.layers.UpSampling2D', 'tf.keras.layers.UpSampling2D', ([], {'size': '(pool_size, pool_size)'}), True, 'import tensorflow as tf\n'), (43, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (44, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['(256)', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (45, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (47, 'tensorflow.keras.layers.UpSampling2D', 'tf.keras.layers.UpSampling2D', ([], {'size': '(pool_size, pool_size)'}), True, 'import tensorflow as tf\n'), (48, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (49, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['(128)', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (50, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (52, 'tensorflow.keras.layers.UpSampling2D', 'tf.keras.layers.UpSampling2D', ([], {'size': '(pool_size, pool_size)'}), True, 'import tensorflow as tf\n'), (53, 'tensorflow.keras.layers.ZeroPadding2D', 'tf.keras.layers.ZeroPadding2D', ([], {'padding': '(pad, pad)'}), True, 'import tensorflow as tf\n'), (54, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['filter_size', 'kernel', 'kernel'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (55, 'tensorflow.keras.layers.BatchNormalization', 'tf.keras.layers.BatchNormalization', ([], {}), True, 'import tensorflow as tf\n'), (57, 'tensorflow.keras.layers.Conv2D', 'tf.keras.layers.Conv2D', (['nClasses', '(1)', '(1)'], {'border_mode': '"""valid"""'}), True, 'import tensorflow as tf\n'), (62, 'tensorflow.keras.layers.Reshape', 'tf.keras.layers.Reshape', (['(nClasses, model.output_shape[-2] * model.output_shape[-1])'], {'input_shape': '(nClasses, model.output_shape[-2], model.output_shape[-1])'}), True, 'import tensorflow as tf\n'), (65, 'tensorflow.keras.layers.Permute', 'tf.keras.layers.Permute', (['(2, 1)'], {}), True, 'import tensorflow as tf\n'), (66, 'tensorflow.keras.layers.Activation', 'tf.keras.layers.Activation', (['"""softmax"""'], {}), True, 'import tensorflow as tf\n')]