Understanding neural nets: functional API
... understanding how each layer of a neural network changes the shape of the data as it flows through the network is a key part of truly understanding the mechanics of deep learning ~ David Foster, Generative Deep Learning
In this notebook we look at 3 ways of finding the output shape and number of parameters layer by layer:
Keras’ built-in method: model.summary();
our home-made method: mysummary(model);
manual back-of-the-envelope calculation.
We beginning by defining our home-made method, mysummary(model). Worked examples of different network architectures, of fully connected and 2D convolution layers, will follow later.
This notebook is the function API version, which matches cell-by-cell with the companion sequential class version. Sequential class and functional API are two different ways of defining a neural network architecture in Keras.
def mysummary(model):
PASS0 = True
print('OUTPUT FROM mysummary(model):')
for layer in model.layers:
if PASS0:
if len(layer.input_shape)>2 and layer.input_shape[1] != layer.input_shape[2]:
print('warning: input_shape not square')
# take layer.input_shape[1:] only if this is the first layer, which happens at the first pass
# take just [1:] because [0] is always None
input_shape = layer.input_shape[1:]
PASS0 = False
param = 0
if 'Conv2D' in str(layer.build):
if layer.kernel_size[0] != layer.kernel_size[1]:
print('warning: kernel size not square')
if layer.strides[0] != layer.strides[1]:
print('warning: strides not square')
# strides defaults to 1 and padding defaults to none in Keras
# when strides=1, output dimensions are therefore reduced by 2
# when user specificies strides>1, output dimensions are then reduced by that user-specified factor
if layer.strides[0]==1 and layer.strides[1]==1 and layer.padding=='valid':
output_shape = int(input_shape[0] - 2), int(input_shape[1] - 2), layer.filters
else:
output_shape = int(input_shape[0] // layer.strides[0]), int(input_shape[1] // layer.strides[1]), layer.filters
# the number of parameters from a conv2d layer depends on
# - the shape of conv2d kernel
# - the number of channels of the previous layer (or the input data, if it's the first layer)
# - the number of conv2d filters
# the one in the 'plus one' is for the bias
param = (layer.kernel_size[0] * layer.kernel_size[1] * layer.input_shape[3] + 1 ) * layer.filters
elif 'MaxPooling2D'in str(layer.build):
if layer.pool_size[0] != layer.pool_size[1]:
print('warning: pool size not square')
# maxpooling reduces output_shape[:2] by the user-specified pool sizes, without changing output_shape[2]
output_shape = int(input_shape[0] / layer.pool_size[0]), int(input_shape[1] / layer.pool_size[1]), input_shape[2]
elif 'Flatten' in str(layer.build):
output_shape = (input_shape[0] * input_shape[1] * input_shape[2], )
elif 'Dropout' in str(layer.build) or 'input' in str(layer.build):
output_shape = input_shape
elif 'Dense' in str(layer.build):
# output_shape from dense is the user-specified units
output_shape = (layer.units, )
# the number of parameters is units multiplied by (input shape plus 1), where 1 is for the bias
param = (input_shape[0] + 1) * layer.units
# verify that our formulae produce the same output as those calculated internally by Keras
assert output_shape == layer.output_shape[1:], (output_shape, layer.output_shape[1:])
assert param == layer.count_params()
print('{:29s}(None, '.format(layer.name), end='')
for t in output_shape[:-1]:
print(t, end=', ')
# some alignment cosmetics for printing
print('{})'.format(output_shape[-1]), end='')
if len(output_shape)==1:
print(' ', end='')
print(' '*(20 - len(str(output_shape))), param)
input_shape = output_shape
from keras import models, layersUsing TensorFlow backend.
Worked examples¶
In each cell that follows, we define a network architecture using functional API, and proceed to
call Keras’ built-in method: model.summary();
call mysummary(model) which we just defined;
markup inline with our manual back-of-the-envelop calculation of the output shape and number of parameters layer by layer.
input_layer = layers.Input(shape=(784,))
x = layers.Dense(32)(input_layer)
# Output dimension of a dense layer is the user-defined units, which is 32 in this case
# Number of parameters = (784 + 1) * 32 = 25120
output_layer = layers.Dense(32)(x)
# Output dimension is again 32
# Number of parameters = (32 + 1) * 32 = 1056, where the first '32' is from layer dense_1, and the second '32' is from current layer, dense_2
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 784) 0
_________________________________________________________________
dense_1 (Dense) (None, 32) 25120
_________________________________________________________________
dense_2 (Dense) (None, 32) 1056
=================================================================
Total params: 26,176
Trainable params: 26,176
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_1 (None, 784) 0
dense_1 (None, 32) 25120
dense_2 (None, 32) 1056
input_layer = layers.Input(shape=(10000,))
# activations affect neither the output dimensions nor the number of parameters
x = layers.Dense(16, activation='relu')(input_layer)
# Output shape = (None, user-specified units) = (None, 16)
# Number of parameters = (10000 + 1) * 16 = 160016
x = layers.Dense(16, activation='relu')(x)
# Output shape = (None, user-specified units) = (None, 16)
# Number of parameters = (16 + 1) * 16 = 272, where the first '16' is from layer dense_3 and the second '16' is from the current layer, dense_4
output_layer = layers.Dense(1, activation='sigmoid')(x)
# Output shape = (None, user-specified units) = (None, 1)
# Number of parameters = (16 + 1) * 1 = 17, where the 16 is from the current layer, dense_5, itself
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) (None, 10000) 0
_________________________________________________________________
dense_3 (Dense) (None, 16) 160016
_________________________________________________________________
dense_4 (Dense) (None, 16) 272
_________________________________________________________________
dense_5 (Dense) (None, 1) 17
=================================================================
Total params: 160,305
Trainable params: 160,305
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_2 (None, 10000) 0
dense_3 (None, 16) 160016
dense_4 (None, 16) 272
dense_5 (None, 1) 17
input_layer = layers.Input(shape=(10000,))
x = layers.Dense(64, activation='relu')(input_layer)
# Output shape = (None, user-specified units) = (None, 64)
# Number of parameters = (10000 + 1) * 64 = 640064
x = layers.Dense(64, activation='relu')(x)
# Output shape = (None, user-specified units) = (None, 64)
# Number of parameters = (64 + 1) * 64 = 4160, where the first 64 is from layer dense_6 and the second '64' is from the current layer, dense_7
output_layer = layers.Dense(46, activation='softmax')(x)
# Output shape = (None, user-specified units) = (None, 64)
# Number of parameters = (64 + 1) * 46 = 2990
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_3 (InputLayer) (None, 10000) 0
_________________________________________________________________
dense_6 (Dense) (None, 64) 640064
_________________________________________________________________
dense_7 (Dense) (None, 64) 4160
_________________________________________________________________
dense_8 (Dense) (None, 46) 2990
=================================================================
Total params: 647,214
Trainable params: 647,214
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_3 (None, 10000) 0
dense_6 (None, 64) 640064
dense_7 (None, 64) 4160
dense_8 (None, 46) 2990
input_layer = layers.Input(shape=(28 * 28,))
x = layers.Dense(512, activation='relu')(input_layer)
# Output shape = (None, user-specified units) = (None, 512)
# Number of parameters = (28*28 + 1) * 512 = 401920
output_layer = layers.Dense(10, activation='softmax')(x)
# Output dimension = (None, user-specified units) = (None, 10)
# Number of parameters = (512 + 1) * 10 = 5130
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_4 (InputLayer) (None, 784) 0
_________________________________________________________________
dense_9 (Dense) (None, 512) 401920
_________________________________________________________________
dense_10 (Dense) (None, 10) 5130
=================================================================
Total params: 407,050
Trainable params: 407,050
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_4 (None, 784) 0
dense_9 (None, 512) 401920
dense_10 (None, 10) 5130
input_layer = layers.Input(shape=(28, 28, 1))
x = layers.Conv2D(32, (3, 3), activation='relu')(input_layer)
# Output shape = (None, 28-2, 28-2, 32)
# Number of parameters = (3*3*1 + 1) * 32 = 320
x = layers.Conv2D(64, (3, 3), activation='relu')(x)
# Output shape = (None, 26-2, 26-2, 64
# Number of parameters = (3*3*32 + 1) * 64 = 18496
output_layer = layers.Conv2D(64, (3, 3), activation='relu')(x)
# Output shape = (None, 24-2, 24-2, 64
# Number of parameters = (3*3*64 + 1) * 64 = 36928
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_5 (InputLayer) (None, 28, 28, 1) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
conv2d_2 (Conv2D) (None, 24, 24, 64) 18496
_________________________________________________________________
conv2d_3 (Conv2D) (None, 22, 22, 64) 36928
=================================================================
Total params: 55,744
Trainable params: 55,744
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_5 (None, 28, 28, 1) 0
conv2d_1 (None, 26, 26, 32) 320
conv2d_2 (None, 24, 24, 64) 18496
conv2d_3 (None, 22, 22, 64) 36928
input_layer = layers.Input(shape=(28, 28, 1))
x = layers.Conv2D(32, (3, 3), activation='relu')(input_layer)
# Output shape = (None, 28-2, 28-2, 32)
# Number of parameters = (3*3*1 + 1) * 32 = 320
x = layers.MaxPooling2D(2, 2)(x)
# Output dimensions = 26/2, 26/2, 32
x = layers.Conv2D(64, (3, 3), activation='relu')(x)
# Output shape = (None, 13-2, 13-2, 64)
# Number of parameters = (3*3*32 + 1) * 64 = 18496
x = layers.MaxPooling2D(2, 2)(x)
# Output dimensions = floor(11/2), floor(11/2), 64
x = layers.Conv2D(64, (3, 3), activation='relu')(x)
# Output shape = (None, 5-2, 5-2, 64)
# Number of parameters = (3*3*64 + 1) * 64 = 36928
x = layers.Flatten()(x)
# Output shape = (None, 3 * 3 * 64) = (None, 576)
x = layers.Dense(64, activation='relu')(x)
# Output shape = (None, user-specified units) = (None, 64)
# Number of parameters = (576 + 1) * 64 = 36928
output_layer = layers.Dense(10, activation='relu')(x)
# Output shape = (None, user-specified units) = (None, 10)
# Number of parameters = (64 + 1) * 10 = 650
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_6 (InputLayer) (None, 28, 28, 1) 0
_________________________________________________________________
conv2d_4 (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 13, 13, 32) 0
_________________________________________________________________
conv2d_5 (Conv2D) (None, 11, 11, 64) 18496
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
conv2d_6 (Conv2D) (None, 3, 3, 64) 36928
_________________________________________________________________
flatten_1 (Flatten) (None, 576) 0
_________________________________________________________________
dense_11 (Dense) (None, 64) 36928
_________________________________________________________________
dense_12 (Dense) (None, 10) 650
=================================================================
Total params: 93,322
Trainable params: 93,322
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_6 (None, 28, 28, 1) 0
conv2d_4 (None, 26, 26, 32) 320
max_pooling2d_1 (None, 13, 13, 32) 0
conv2d_5 (None, 11, 11, 64) 18496
max_pooling2d_2 (None, 5, 5, 64) 0
conv2d_6 (None, 3, 3, 64) 36928
flatten_1 (None, 576) 0
dense_11 (None, 64) 36928
dense_12 (None, 10) 650
input_layer = layers.Input(shape=(32, 32, 3))
x = layers.Flatten()(input_layer)
# Output shape = (None, 32 * 32 * 3)
x = layers.Dense(200, activation='relu')(x)
# Output shape = (None, user-defined units) = (None, 200)
# Number of parameters = (3072 + 1 ) * 200 = 614600
x = layers.Dense(150, activation='relu')(x)
# Output shape = (None, user-defined units) = (None, 150)
# Number of parameters = (200 + 1) * 150 = 30150
output_layer = layers.Dense(10, activation='softmax')(x)
# Output shape = (None, user-defined units) = (None, 10)
# Number of parameters = (150 + 1) * 10 = 1510
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_7 (InputLayer) (None, 32, 32, 3) 0
_________________________________________________________________
flatten_2 (Flatten) (None, 3072) 0
_________________________________________________________________
dense_13 (Dense) (None, 200) 614600
_________________________________________________________________
dense_14 (Dense) (None, 150) 30150
_________________________________________________________________
dense_15 (Dense) (None, 10) 1510
=================================================================
Total params: 646,260
Trainable params: 646,260
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_7 (None, 32, 32, 3) 0
flatten_2 (None, 3072) 0
dense_13 (None, 200) 614600
dense_14 (None, 150) 30150
dense_15 (None, 10) 1510
input_layer = layers.Input(shape=(32, 32, 3))
x = layers.Conv2D(10, (4, 4), strides = 2, padding = 'same')(input_layer)
# Output shape = (None, 32/2, 32/2, 10)
# Number of parameters = ( 4*4*3 + 1 ) * 10
x = layers.Conv2D(20, (3, 3), strides = 2, padding = 'same')(x)
# Output shape = (None, 16/2, 16/2, 20)
# Number of parameters = ( 3*3*10 + 1 ) * 20
x = layers.Flatten()(x)
# Output shape = (None, 8 * 8 * 20)
output_layer = layers.Dense(10, activation='softmax')(x)
# Output shape = (None, user-defined units) = (None, 10)
# Number of parameters = ( 1280 + 1 ) * 10
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_8 (InputLayer) (None, 32, 32, 3) 0
_________________________________________________________________
conv2d_7 (Conv2D) (None, 16, 16, 10) 490
_________________________________________________________________
conv2d_8 (Conv2D) (None, 8, 8, 20) 1820
_________________________________________________________________
flatten_3 (Flatten) (None, 1280) 0
_________________________________________________________________
dense_16 (Dense) (None, 10) 12810
=================================================================
Total params: 15,120
Trainable params: 15,120
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_8 (None, 32, 32, 3) 0
conv2d_7 (None, 16, 16, 10) 490
conv2d_8 (None, 8, 8, 20) 1820
flatten_3 (None, 1280) 0
dense_16 (None, 10) 12810
input_layer = layers.Input(shape=(150, 150, 3))
x = layers.Conv2D(32, (3, 3), activation='relu')(input_layer)
# Output shape = (None, 150-2, 150-2, 32)
# Number of parameters = (3*3*3 + 1) * 32 = 896
x = layers.MaxPooling2D(2, 2)(x)
# Output shape = (None, 148/2, 148/2, 32)
x = layers.Conv2D(64, (3, 3), activation='relu')(x)
# Output shape = (None, 74-2, 74-2, 64)
# Number of parameters = (3*3*32 + 1) * 64 = 18496
x = layers.MaxPooling2D(2, 2)(x)
# Output shape = (None, 72/2, 72/2, 64)
x = layers.Conv2D(128, (3, 3), activation='relu')(x)
# Output shape = (None, 36-2, 36-2, 128)
# Number of parameters = (3*3*64 + 1) * 128 = 73856
x = layers.MaxPooling2D(2, 2)(x)
# Output shape = (None, 34/2, 34/2, 128)
x = layers.Conv2D(128, (3, 3), activation='relu')(x)
# Output shape = (None, 17-2, 17-2, 128)
# Number of parameters = (3*3*128 + 1) * 128 = 147584
x = layers.MaxPooling2D(2, 2)(x)
# Output shape = (None, floor(15/2), floor(15/2), 128)
x = layers.Flatten()(x)
# Output shape = (None, 7 * 7 * 128) = (None, 6272)
x = layers.Dropout(.5)(x)
# Output shape unchanged
x = layers.Dense(512, activation='relu')(x)
# Output shape = (None, user-specified units) = (None, 512)
# Number of parameters = (6272 + 1) * 512 = 3211776
output_layer = layers.Dense(1, activation='sigmoid')(x)
# Output shape = (None, user-specified units) = (None, 1)
# Number of parameters = (512 + 1) * 1 = 513
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_9 (InputLayer) (None, 150, 150, 3) 0
_________________________________________________________________
conv2d_9 (Conv2D) (None, 148, 148, 32) 896
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 74, 74, 32) 0
_________________________________________________________________
conv2d_10 (Conv2D) (None, 72, 72, 64) 18496
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 36, 36, 64) 0
_________________________________________________________________
conv2d_11 (Conv2D) (None, 34, 34, 128) 73856
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 17, 17, 128) 0
_________________________________________________________________
conv2d_12 (Conv2D) (None, 15, 15, 128) 147584
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 7, 7, 128) 0
_________________________________________________________________
flatten_4 (Flatten) (None, 6272) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 6272) 0
_________________________________________________________________
dense_17 (Dense) (None, 512) 3211776
_________________________________________________________________
dense_18 (Dense) (None, 1) 513
=================================================================
Total params: 3,453,121
Trainable params: 3,453,121
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_9 (None, 150, 150, 3) 0
conv2d_9 (None, 148, 148, 32) 896
max_pooling2d_3 (None, 74, 74, 32) 0
conv2d_10 (None, 72, 72, 64) 18496
max_pooling2d_4 (None, 36, 36, 64) 0
conv2d_11 (None, 34, 34, 128) 73856
max_pooling2d_5 (None, 17, 17, 128) 0
conv2d_12 (None, 15, 15, 128) 147584
max_pooling2d_6 (None, 7, 7, 128) 0
flatten_4 (None, 6272) 0
dropout_1 (None, 6272) 0
dense_17 (None, 512) 3211776
dense_18 (None, 1) 513
# VGG16 coded manually
input_layer = layers.Input(shape=(150, 150, 3))
x = layers.Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2d_1')(input_layer)
x = layers.Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2d_2')(x)
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block1_max_pooling2d')(x)
x = layers.Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2d_1')(x)
x = layers.Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2d_2')(x)
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block2_max_pooling2d')(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2d_1')(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2d_2')(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2d_3')(x)
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block3_max_pooling2d')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2d_1')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2d_2')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2d_3')(x)
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block4_max_pooling2d')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2d_1')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2d_2')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2d_3')(x)
output_layer = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block5_max_pooling2d')(x)
'''
x = layers.Flatten()(x)
x = layers.Dense(4096, activation='relu')(x)
x = layers.Dense(4096, activation='relu')(x)
output_layer = layers.Dense(10, activation='softmax')(x)
'''
model = models.Model(input_layer, output_layer)
model.summary()
mysummary(model)_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_10 (InputLayer) (None, 150, 150, 3) 0
_________________________________________________________________
block1_conv2d_1 (Conv2D) (None, 150, 150, 64) 1792
_________________________________________________________________
block1_conv2d_2 (Conv2D) (None, 150, 150, 64) 36928
_________________________________________________________________
block1_max_pooling2d (MaxPoo (None, 75, 75, 64) 0
_________________________________________________________________
block2_conv2d_1 (Conv2D) (None, 75, 75, 128) 73856
_________________________________________________________________
block2_conv2d_2 (Conv2D) (None, 75, 75, 128) 147584
_________________________________________________________________
block2_max_pooling2d (MaxPoo (None, 37, 37, 128) 0
_________________________________________________________________
block3_conv2d_1 (Conv2D) (None, 37, 37, 256) 295168
_________________________________________________________________
block3_conv2d_2 (Conv2D) (None, 37, 37, 256) 590080
_________________________________________________________________
block3_conv2d_3 (Conv2D) (None, 37, 37, 256) 590080
_________________________________________________________________
block3_max_pooling2d (MaxPoo (None, 18, 18, 256) 0
_________________________________________________________________
block4_conv2d_1 (Conv2D) (None, 18, 18, 512) 1180160
_________________________________________________________________
block4_conv2d_2 (Conv2D) (None, 18, 18, 512) 2359808
_________________________________________________________________
block4_conv2d_3 (Conv2D) (None, 18, 18, 512) 2359808
_________________________________________________________________
block4_max_pooling2d (MaxPoo (None, 9, 9, 512) 0
_________________________________________________________________
block5_conv2d_1 (Conv2D) (None, 9, 9, 512) 2359808
_________________________________________________________________
block5_conv2d_2 (Conv2D) (None, 9, 9, 512) 2359808
_________________________________________________________________
block5_conv2d_3 (Conv2D) (None, 9, 9, 512) 2359808
_________________________________________________________________
block5_max_pooling2d (MaxPoo (None, 4, 4, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
_________________________________________________________________
OUTPUT FROM mysummary(model):
input_10 (None, 150, 150, 3) 0
block1_conv2d_1 (None, 150, 150, 64) 1792
block1_conv2d_2 (None, 150, 150, 64) 36928
block1_max_pooling2d (None, 75, 75, 64) 0
block2_conv2d_1 (None, 75, 75, 128) 73856
block2_conv2d_2 (None, 75, 75, 128) 147584
block2_max_pooling2d (None, 37, 37, 128) 0
block3_conv2d_1 (None, 37, 37, 256) 295168
block3_conv2d_2 (None, 37, 37, 256) 590080
block3_conv2d_3 (None, 37, 37, 256) 590080
block3_max_pooling2d (None, 18, 18, 256) 0
block4_conv2d_1 (None, 18, 18, 512) 1180160
block4_conv2d_2 (None, 18, 18, 512) 2359808
block4_conv2d_3 (None, 18, 18, 512) 2359808
block4_max_pooling2d (None, 9, 9, 512) 0
block5_conv2d_1 (None, 9, 9, 512) 2359808
block5_conv2d_2 (None, 9, 9, 512) 2359808
block5_conv2d_3 (None, 9, 9, 512) 2359808
block5_max_pooling2d (None, 4, 4, 512) 0