Train
Contents
Train#
This notebooks trains a convolutional neural network (CNN) to segment UAV
imagery into ground
, water
, and building
classes. This process is called
semantic segmentation.
For a demonstration of the models that are trained in this notebook, see inference.ipynb instead.
The purpose of this functionality for the Lakehopper system is twofold:
Provide awareness of the situation under the drone at the moment of flight (‘in-situ’). This is as opposed to beforehand (when a certain dataset was captured or when the drone previously collected data). A lake might have dried up or a boat might be present where it wasn’t previously.
Provide a wide-area map based on orthographic imagery with features that are relevant to lakehopper. Other maps do not necessarily have the same feature definitions as lakehopper. The
water
class for Lakehopper refers to a body of surface water where autonomous landing is possible. Swamps or water obscured by bridges or vegetation do not fit this definition. They are however still classified as ‘water’ on most topographic maps.
More information on everything from the model architecture to the motivation for using a CNN can be found in my 2022 master’s dissertation Autonomous Path Planning and Landing Site Selection for Aquatic UAV.
The dataset is too large to upload via cloud storage (58.6 GiB). Please contact pieter@pfiers.net for a copy.
Google Colaboratory Setup#
Running in Google Colab is useful to inspect the models and preview the dataset. To train the model however, a more powerful runtime is necessary (like a GCE VPS with a TPU).
import sys
IN_COLAB = 'google.colab' in sys.modules
if IN_COLAB:
sys.path.insert(0, "/content/drive/MyDrive/lh-train/lakehopper_semseg")
from google.colab import drive
drive.mount('/content/drive')
Jupyter Notebook Setup#
from env_utils import is_notebook, find_repo
from pathlib import Path
IS_NOTEBOOK = is_notebook()
REPO_ROOT = find_repo(Path.cwd())
if IS_NOTEBOOK:
%load_ext autoreload
%autoreload 2
Imports#
from datetime import datetime
from itertools import islice
import sys, os, csv, json
from IPython.display import clear_output
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow.keras.metrics as k_metrics
import tensorflow.keras.activations as k_activations
from tensorflow.python.distribute.tpu_strategy import TPUStrategy
2022-09-24 11:11:41.863570: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2022-09-24 11:11:42.856209: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory
2022-09-24 11:11:42.856230: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
2022-09-24 11:11:42.970985: E tensorflow/stream_executor/cuda/cuda_blas.cc:2981] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
2022-09-24 11:11:45.044104: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory
2022-09-24 11:11:45.044291: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory
2022-09-24 11:11:45.044304: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.
# Convenience methods
from visualize import show
from tpu import resolve_tpu_strategy, get_tpu_devices
from dataset import load_dataset, split_dataset_paths, read_metadata, has_all_classes, has_any_of_classes, categorical_to_single_label_mask_tf, read_metadata, categorical_to_one_hot_label_mask, single_hot_to_categorical
from masks import colorize_byte_mask
from augment import Augment
from models.create import create_model, compile_model
TPU Setup#
To speed up model training, we use Google Cloud Platform’s “TPU’s”. TPU’s use a machine learning ASIC.
USE_TPU = os.environ.get('USE_TPU', False)
if os.environ.get('USE_TPU', False):
PARALLEL_OPS = tf.data.AUTOTUNE
tpu_strategy = resolve_tpu_strategy('us-node')
nbro_tpu_devices = len(get_tpu_devices())
print(f"{nbro_tpu_devices} TPU devices connected!")
else:
PARALLEL_OPS = None
tpu_strategy = None
Dataset Preparation#
CLASSES = ["water", "building"]
IMAGE_SIZE = (224, 224)
if IN_COLAB:
DATASET_FOLDER = "/content/drive/MyDrive/lh-train/tfr"
elif USE_TPU:
DATASET_FOLDER = "gs://semseg-data-aggregated-1/tfr"
elif REPO_ROOT is not None:
DATASET_FOLDER = str(REPO_ROOT / "vision/datasets/aggregated/tfr")
metadata_file_path = DATASET_FOLDER + "/metadata.json"
metadata = read_metadata(metadata_file_path)
TFR_PATTERN = DATASET_FOLDER + "/*.tfr"
if len(CLASSES) == 1:
def should_include_chip(chip_classes):
return all(class_ in chip_classes for class_ in CLASSES)
else:
def should_include_chip(chip_classes):
return any(class_ in chip_classes for class_ in CLASSES)
stem_nbro_label_pixels = metadata["nbroLabelPixels"]
chip_w, chip_h = tuple(metadata["size"])
chip_nro_pixels = chip_w * chip_h
total_nbro_label_pixels = {}
applicable_chips = set()
for stem, nbro_label_pixels in stem_nbro_label_pixels.items():
if should_include_chip(nbro_label_pixels.keys()):
applicable_chips.add(stem)
for class_, nbro_pixels in nbro_label_pixels.items():
total_nbro_label_pixels[class_] = total_nbro_label_pixels.get(class_, 0) + nbro_pixels
nbro_labelled_pixels = sum(nbro_label_pixels.values())
nbro_unlabelled_pixels = chip_nro_pixels - nbro_labelled_pixels
total_nbro_label_pixels["background"] = total_nbro_label_pixels.get("background", 0) + nbro_unlabelled_pixels
print(total_nbro_label_pixels)
tfr_paths = list(filter(
lambda p: Path(p).stem in applicable_chips,
tf.io.gfile.glob(TFR_PATTERN)
))
{'building': 25987352, 'background': 173127015, 'water': 52975633}
TRAIN_RATIO = 0.75
VALIDATION_RATIO = 0.24 # Remaining 6% is test
train_paths, validate_paths, test_paths = split_dataset_paths(tfr_paths, TRAIN_RATIO, VALIDATION_RATIO)
print(f"Found {len(tfr_paths)} tfrs. Splitting into {len(train_paths)} training, {len(validate_paths)} validation, and {len(test_paths)} test tfrs")
Found 2801 tfrs. Splitting into 2100 training, 672 validation, and 29 test tfrs
Load dataset#
# The weights for each class are inversely proportional to the number of pixels
# of that class present in the dataset, thereby making correct predictions for
# underrepresented classes more important
CLASS_WEIGHTS = 1 / tf.constant([total_nbro_label_pixels["background"], *(total_nbro_label_pixels[_class] for _class in CLASSES)])
# Normalize the weights so that they sum to 1
CLASS_WEIGHTS = CLASS_WEIGHTS/tf.reduce_sum(CLASS_WEIGHTS)
print(f"Class weights: {CLASS_WEIGHTS.numpy()} for classes: {['background', *CLASSES]}")
def add_sample_weights(image, label):
# Create an image of `sample_weights` by using the label at each pixel as an
# index into the `class weights`
sample_weights = tf.gather(CLASS_WEIGHTS, indices=tf.cast(label, tf.int32))
return image, label, sample_weights
Class weights: [0.09149112 0.29899756 0.60951132] for classes: ['background', 'water', 'building']
2022-09-24 11:11:47.847361: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:980] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2022-09-24 11:11:47.848697: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.849289: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcublas.so.11'; dlerror: libcublas.so.11: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.849524: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcublasLt.so.11'; dlerror: libcublasLt.so.11: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.849649: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcufft.so.10'; dlerror: libcufft.so.10: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.849777: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcurand.so.10'; dlerror: libcurand.so.10: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.849886: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcusolver.so.11'; dlerror: libcusolver.so.11: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.850007: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcusparse.so.11'; dlerror: libcusparse.so.11: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.850103: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudnn.so.8'; dlerror: libcudnn.so.8: cannot open shared object file: No such file or directory
2022-09-24 11:11:47.850126: W tensorflow/core/common_runtime/gpu/gpu_device.cc:1934] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.
Skipping registering GPU devices...
2022-09-24 11:11:47.857365: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
BATCH_SIZE = 64 # Using TPU v3-8 device => must be divisible by 8 for sharding
BUFFER_SIZE = 1000
def transform_mask(img, mask, weights = None):
if len(CLASSES) == 1:
mask_transformed = categorical_to_single_label_mask_tf(CLASSES.index("water") + 1, mask)
else:
mask_transformed = categorical_to_one_hot_label_mask(len(CLASSES) + 1, mask)
if weights is None:
return img, mask_transformed
else:
return img, categorical_to_one_hot_label_mask(len(CLASSES) + 1, mask), weights
# Dataset generation *must* come after tpu resolution
training_dataset = (
load_dataset(train_paths, IMAGE_SIZE, PARALLEL_OPS)
.map(add_sample_weights)
.map(transform_mask)
.cache()
.shuffle(BUFFER_SIZE)
.batch(BATCH_SIZE)
.repeat()
.map(Augment())
.prefetch(buffer_size=tf.data.AUTOTUNE)
)
validation_dataset = (
load_dataset(validate_paths, IMAGE_SIZE, PARALLEL_OPS)
.map(transform_mask)
.cache()
.batch(BATCH_SIZE)
.repeat()
.prefetch(buffer_size=tf.data.AUTOTUNE)
)
test_dataset = (
load_dataset(test_paths, IMAGE_SIZE, PARALLEL_OPS)
.map(transform_mask)
.prefetch(buffer_size=tf.data.AUTOTUNE)
)
Visualise Training Data#
if IS_NOTEBOOK:
sample_images_batch, sample_labels_batch, _ = next(iter(training_dataset))
sample_images = iter(sample_images_batch)
sample_labels = iter(sample_labels_batch)
show([(next(sample_images), single_hot_to_categorical(len(CLASSES), 1, next(sample_labels)))])
2022-09-24 11:11:53.957437: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Create model#
input_shape = IMAGE_SIZE + (3,)
print(f"Input shape: {input_shape}")
def create_and_compile(encoder, decoder):
model = create_model(CLASSES, input_shape, encoder, decoder)
model = compile_model(model, CLASSES)
return model
encoder = os.environ.get('ENCODER', 'EfficientNetB3')
decoder = os.environ.get('DECODER', 'FCN')
if tpu_strategy is not None:
with tpu_strategy.scope():
model = create_and_compile(encoder, decoder)
else:
model = create_and_compile(encoder, decoder)
print(f"Model created with encoder: {encoder} and decoder: {decoder}")
if IS_NOTEBOOK:
model.summary()
Input shape: (224, 224, 3)
Got kwargs: {}
Model created with encoder: EfficientNetB3 and decoder: FCN
Model: "FCN_EfficientNetB3"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_2 (InputLayer) [(None, 224, 224, 3 0 []
)]
rescaling_2 (Rescaling) (None, 224, 224, 3) 0 ['input_2[0][0]']
normalization_1 (Normalization (None, 224, 224, 3) 7 ['rescaling_2[0][0]']
)
rescaling_3 (Rescaling) (None, 224, 224, 3) 0 ['normalization_1[0][0]']
stem_conv_pad (ZeroPadding2D) (None, 225, 225, 3) 0 ['rescaling_3[0][0]']
stem_conv (Conv2D) (None, 112, 112, 40 1080 ['stem_conv_pad[0][0]']
)
stem_bn (BatchNormalization) (None, 112, 112, 40 160 ['stem_conv[0][0]']
)
stem_activation (Activation) (None, 112, 112, 40 0 ['stem_bn[0][0]']
)
block1a_dwconv (DepthwiseConv2 (None, 112, 112, 40 360 ['stem_activation[0][0]']
D) )
block1a_bn (BatchNormalization (None, 112, 112, 40 160 ['block1a_dwconv[0][0]']
) )
block1a_activation (Activation (None, 112, 112, 40 0 ['block1a_bn[0][0]']
) )
block1a_se_squeeze (GlobalAver (None, 40) 0 ['block1a_activation[0][0]']
agePooling2D)
block1a_se_reshape (Reshape) (None, 1, 1, 40) 0 ['block1a_se_squeeze[0][0]']
block1a_se_reduce (Conv2D) (None, 1, 1, 10) 410 ['block1a_se_reshape[0][0]']
block1a_se_expand (Conv2D) (None, 1, 1, 40) 440 ['block1a_se_reduce[0][0]']
block1a_se_excite (Multiply) (None, 112, 112, 40 0 ['block1a_activation[0][0]',
) 'block1a_se_expand[0][0]']
block1a_project_conv (Conv2D) (None, 112, 112, 24 960 ['block1a_se_excite[0][0]']
)
block1a_project_bn (BatchNorma (None, 112, 112, 24 96 ['block1a_project_conv[0][0]']
lization) )
block1b_dwconv (DepthwiseConv2 (None, 112, 112, 24 216 ['block1a_project_bn[0][0]']
D) )
block1b_bn (BatchNormalization (None, 112, 112, 24 96 ['block1b_dwconv[0][0]']
) )
block1b_activation (Activation (None, 112, 112, 24 0 ['block1b_bn[0][0]']
) )
block1b_se_squeeze (GlobalAver (None, 24) 0 ['block1b_activation[0][0]']
agePooling2D)
block1b_se_reshape (Reshape) (None, 1, 1, 24) 0 ['block1b_se_squeeze[0][0]']
block1b_se_reduce (Conv2D) (None, 1, 1, 6) 150 ['block1b_se_reshape[0][0]']
block1b_se_expand (Conv2D) (None, 1, 1, 24) 168 ['block1b_se_reduce[0][0]']
block1b_se_excite (Multiply) (None, 112, 112, 24 0 ['block1b_activation[0][0]',
) 'block1b_se_expand[0][0]']
block1b_project_conv (Conv2D) (None, 112, 112, 24 576 ['block1b_se_excite[0][0]']
)
block1b_project_bn (BatchNorma (None, 112, 112, 24 96 ['block1b_project_conv[0][0]']
lization) )
block1b_drop (Dropout) (None, 112, 112, 24 0 ['block1b_project_bn[0][0]']
)
block1b_add (Add) (None, 112, 112, 24 0 ['block1b_drop[0][0]',
) 'block1a_project_bn[0][0]']
block2a_expand_conv (Conv2D) (None, 112, 112, 14 3456 ['block1b_add[0][0]']
4)
block2a_expand_bn (BatchNormal (None, 112, 112, 14 576 ['block2a_expand_conv[0][0]']
ization) 4)
block2a_expand_activation (Act (None, 112, 112, 14 0 ['block2a_expand_bn[0][0]']
ivation) 4)
block2a_dwconv_pad (ZeroPaddin (None, 113, 113, 14 0 ['block2a_expand_activation[0][0]
g2D) 4) ']
block2a_dwconv (DepthwiseConv2 (None, 56, 56, 144) 1296 ['block2a_dwconv_pad[0][0]']
D)
block2a_bn (BatchNormalization (None, 56, 56, 144) 576 ['block2a_dwconv[0][0]']
)
block2a_activation (Activation (None, 56, 56, 144) 0 ['block2a_bn[0][0]']
)
block2a_se_squeeze (GlobalAver (None, 144) 0 ['block2a_activation[0][0]']
agePooling2D)
block2a_se_reshape (Reshape) (None, 1, 1, 144) 0 ['block2a_se_squeeze[0][0]']
block2a_se_reduce (Conv2D) (None, 1, 1, 6) 870 ['block2a_se_reshape[0][0]']
block2a_se_expand (Conv2D) (None, 1, 1, 144) 1008 ['block2a_se_reduce[0][0]']
block2a_se_excite (Multiply) (None, 56, 56, 144) 0 ['block2a_activation[0][0]',
'block2a_se_expand[0][0]']
block2a_project_conv (Conv2D) (None, 56, 56, 32) 4608 ['block2a_se_excite[0][0]']
block2a_project_bn (BatchNorma (None, 56, 56, 32) 128 ['block2a_project_conv[0][0]']
lization)
block2b_expand_conv (Conv2D) (None, 56, 56, 192) 6144 ['block2a_project_bn[0][0]']
block2b_expand_bn (BatchNormal (None, 56, 56, 192) 768 ['block2b_expand_conv[0][0]']
ization)
block2b_expand_activation (Act (None, 56, 56, 192) 0 ['block2b_expand_bn[0][0]']
ivation)
block2b_dwconv (DepthwiseConv2 (None, 56, 56, 192) 1728 ['block2b_expand_activation[0][0]
D) ']
block2b_bn (BatchNormalization (None, 56, 56, 192) 768 ['block2b_dwconv[0][0]']
)
block2b_activation (Activation (None, 56, 56, 192) 0 ['block2b_bn[0][0]']
)
block2b_se_squeeze (GlobalAver (None, 192) 0 ['block2b_activation[0][0]']
agePooling2D)
block2b_se_reshape (Reshape) (None, 1, 1, 192) 0 ['block2b_se_squeeze[0][0]']
block2b_se_reduce (Conv2D) (None, 1, 1, 8) 1544 ['block2b_se_reshape[0][0]']
block2b_se_expand (Conv2D) (None, 1, 1, 192) 1728 ['block2b_se_reduce[0][0]']
block2b_se_excite (Multiply) (None, 56, 56, 192) 0 ['block2b_activation[0][0]',
'block2b_se_expand[0][0]']
block2b_project_conv (Conv2D) (None, 56, 56, 32) 6144 ['block2b_se_excite[0][0]']
block2b_project_bn (BatchNorma (None, 56, 56, 32) 128 ['block2b_project_conv[0][0]']
lization)
block2b_drop (Dropout) (None, 56, 56, 32) 0 ['block2b_project_bn[0][0]']
block2b_add (Add) (None, 56, 56, 32) 0 ['block2b_drop[0][0]',
'block2a_project_bn[0][0]']
block2c_expand_conv (Conv2D) (None, 56, 56, 192) 6144 ['block2b_add[0][0]']
block2c_expand_bn (BatchNormal (None, 56, 56, 192) 768 ['block2c_expand_conv[0][0]']
ization)
block2c_expand_activation (Act (None, 56, 56, 192) 0 ['block2c_expand_bn[0][0]']
ivation)
block2c_dwconv (DepthwiseConv2 (None, 56, 56, 192) 1728 ['block2c_expand_activation[0][0]
D) ']
block2c_bn (BatchNormalization (None, 56, 56, 192) 768 ['block2c_dwconv[0][0]']
)
block2c_activation (Activation (None, 56, 56, 192) 0 ['block2c_bn[0][0]']
)
block2c_se_squeeze (GlobalAver (None, 192) 0 ['block2c_activation[0][0]']
agePooling2D)
block2c_se_reshape (Reshape) (None, 1, 1, 192) 0 ['block2c_se_squeeze[0][0]']
block2c_se_reduce (Conv2D) (None, 1, 1, 8) 1544 ['block2c_se_reshape[0][0]']
block2c_se_expand (Conv2D) (None, 1, 1, 192) 1728 ['block2c_se_reduce[0][0]']
block2c_se_excite (Multiply) (None, 56, 56, 192) 0 ['block2c_activation[0][0]',
'block2c_se_expand[0][0]']
block2c_project_conv (Conv2D) (None, 56, 56, 32) 6144 ['block2c_se_excite[0][0]']
block2c_project_bn (BatchNorma (None, 56, 56, 32) 128 ['block2c_project_conv[0][0]']
lization)
block2c_drop (Dropout) (None, 56, 56, 32) 0 ['block2c_project_bn[0][0]']
block2c_add (Add) (None, 56, 56, 32) 0 ['block2c_drop[0][0]',
'block2b_add[0][0]']
block3a_expand_conv (Conv2D) (None, 56, 56, 192) 6144 ['block2c_add[0][0]']
block3a_expand_bn (BatchNormal (None, 56, 56, 192) 768 ['block3a_expand_conv[0][0]']
ization)
block3a_expand_activation (Act (None, 56, 56, 192) 0 ['block3a_expand_bn[0][0]']
ivation)
block3a_dwconv_pad (ZeroPaddin (None, 59, 59, 192) 0 ['block3a_expand_activation[0][0]
g2D) ']
block3a_dwconv (DepthwiseConv2 (None, 28, 28, 192) 4800 ['block3a_dwconv_pad[0][0]']
D)
block3a_bn (BatchNormalization (None, 28, 28, 192) 768 ['block3a_dwconv[0][0]']
)
block3a_activation (Activation (None, 28, 28, 192) 0 ['block3a_bn[0][0]']
)
block3a_se_squeeze (GlobalAver (None, 192) 0 ['block3a_activation[0][0]']
agePooling2D)
block3a_se_reshape (Reshape) (None, 1, 1, 192) 0 ['block3a_se_squeeze[0][0]']
block3a_se_reduce (Conv2D) (None, 1, 1, 8) 1544 ['block3a_se_reshape[0][0]']
block3a_se_expand (Conv2D) (None, 1, 1, 192) 1728 ['block3a_se_reduce[0][0]']
block3a_se_excite (Multiply) (None, 28, 28, 192) 0 ['block3a_activation[0][0]',
'block3a_se_expand[0][0]']
block3a_project_conv (Conv2D) (None, 28, 28, 48) 9216 ['block3a_se_excite[0][0]']
block3a_project_bn (BatchNorma (None, 28, 28, 48) 192 ['block3a_project_conv[0][0]']
lization)
block3b_expand_conv (Conv2D) (None, 28, 28, 288) 13824 ['block3a_project_bn[0][0]']
block3b_expand_bn (BatchNormal (None, 28, 28, 288) 1152 ['block3b_expand_conv[0][0]']
ization)
block3b_expand_activation (Act (None, 28, 28, 288) 0 ['block3b_expand_bn[0][0]']
ivation)
block3b_dwconv (DepthwiseConv2 (None, 28, 28, 288) 7200 ['block3b_expand_activation[0][0]
D) ']
block3b_bn (BatchNormalization (None, 28, 28, 288) 1152 ['block3b_dwconv[0][0]']
)
block3b_activation (Activation (None, 28, 28, 288) 0 ['block3b_bn[0][0]']
)
block3b_se_squeeze (GlobalAver (None, 288) 0 ['block3b_activation[0][0]']
agePooling2D)
block3b_se_reshape (Reshape) (None, 1, 1, 288) 0 ['block3b_se_squeeze[0][0]']
block3b_se_reduce (Conv2D) (None, 1, 1, 12) 3468 ['block3b_se_reshape[0][0]']
block3b_se_expand (Conv2D) (None, 1, 1, 288) 3744 ['block3b_se_reduce[0][0]']
block3b_se_excite (Multiply) (None, 28, 28, 288) 0 ['block3b_activation[0][0]',
'block3b_se_expand[0][0]']
block3b_project_conv (Conv2D) (None, 28, 28, 48) 13824 ['block3b_se_excite[0][0]']
block3b_project_bn (BatchNorma (None, 28, 28, 48) 192 ['block3b_project_conv[0][0]']
lization)
block3b_drop (Dropout) (None, 28, 28, 48) 0 ['block3b_project_bn[0][0]']
block3b_add (Add) (None, 28, 28, 48) 0 ['block3b_drop[0][0]',
'block3a_project_bn[0][0]']
block3c_expand_conv (Conv2D) (None, 28, 28, 288) 13824 ['block3b_add[0][0]']
block3c_expand_bn (BatchNormal (None, 28, 28, 288) 1152 ['block3c_expand_conv[0][0]']
ization)
block3c_expand_activation (Act (None, 28, 28, 288) 0 ['block3c_expand_bn[0][0]']
ivation)
block3c_dwconv (DepthwiseConv2 (None, 28, 28, 288) 7200 ['block3c_expand_activation[0][0]
D) ']
block3c_bn (BatchNormalization (None, 28, 28, 288) 1152 ['block3c_dwconv[0][0]']
)
block3c_activation (Activation (None, 28, 28, 288) 0 ['block3c_bn[0][0]']
)
block3c_se_squeeze (GlobalAver (None, 288) 0 ['block3c_activation[0][0]']
agePooling2D)
block3c_se_reshape (Reshape) (None, 1, 1, 288) 0 ['block3c_se_squeeze[0][0]']
block3c_se_reduce (Conv2D) (None, 1, 1, 12) 3468 ['block3c_se_reshape[0][0]']
block3c_se_expand (Conv2D) (None, 1, 1, 288) 3744 ['block3c_se_reduce[0][0]']
block3c_se_excite (Multiply) (None, 28, 28, 288) 0 ['block3c_activation[0][0]',
'block3c_se_expand[0][0]']
block3c_project_conv (Conv2D) (None, 28, 28, 48) 13824 ['block3c_se_excite[0][0]']
block3c_project_bn (BatchNorma (None, 28, 28, 48) 192 ['block3c_project_conv[0][0]']
lization)
block3c_drop (Dropout) (None, 28, 28, 48) 0 ['block3c_project_bn[0][0]']
block3c_add (Add) (None, 28, 28, 48) 0 ['block3c_drop[0][0]',
'block3b_add[0][0]']
block4a_expand_conv (Conv2D) (None, 28, 28, 288) 13824 ['block3c_add[0][0]']
block4a_expand_bn (BatchNormal (None, 28, 28, 288) 1152 ['block4a_expand_conv[0][0]']
ization)
block4a_expand_activation (Act (None, 28, 28, 288) 0 ['block4a_expand_bn[0][0]']
ivation)
block4a_dwconv_pad (ZeroPaddin (None, 29, 29, 288) 0 ['block4a_expand_activation[0][0]
g2D) ']
block4a_dwconv (DepthwiseConv2 (None, 14, 14, 288) 2592 ['block4a_dwconv_pad[0][0]']
D)
block4a_bn (BatchNormalization (None, 14, 14, 288) 1152 ['block4a_dwconv[0][0]']
)
block4a_activation (Activation (None, 14, 14, 288) 0 ['block4a_bn[0][0]']
)
block4a_se_squeeze (GlobalAver (None, 288) 0 ['block4a_activation[0][0]']
agePooling2D)
block4a_se_reshape (Reshape) (None, 1, 1, 288) 0 ['block4a_se_squeeze[0][0]']
block4a_se_reduce (Conv2D) (None, 1, 1, 12) 3468 ['block4a_se_reshape[0][0]']
block4a_se_expand (Conv2D) (None, 1, 1, 288) 3744 ['block4a_se_reduce[0][0]']
block4a_se_excite (Multiply) (None, 14, 14, 288) 0 ['block4a_activation[0][0]',
'block4a_se_expand[0][0]']
block4a_project_conv (Conv2D) (None, 14, 14, 96) 27648 ['block4a_se_excite[0][0]']
block4a_project_bn (BatchNorma (None, 14, 14, 96) 384 ['block4a_project_conv[0][0]']
lization)
block4b_expand_conv (Conv2D) (None, 14, 14, 576) 55296 ['block4a_project_bn[0][0]']
block4b_expand_bn (BatchNormal (None, 14, 14, 576) 2304 ['block4b_expand_conv[0][0]']
ization)
block4b_expand_activation (Act (None, 14, 14, 576) 0 ['block4b_expand_bn[0][0]']
ivation)
block4b_dwconv (DepthwiseConv2 (None, 14, 14, 576) 5184 ['block4b_expand_activation[0][0]
D) ']
block4b_bn (BatchNormalization (None, 14, 14, 576) 2304 ['block4b_dwconv[0][0]']
)
block4b_activation (Activation (None, 14, 14, 576) 0 ['block4b_bn[0][0]']
)
block4b_se_squeeze (GlobalAver (None, 576) 0 ['block4b_activation[0][0]']
agePooling2D)
block4b_se_reshape (Reshape) (None, 1, 1, 576) 0 ['block4b_se_squeeze[0][0]']
block4b_se_reduce (Conv2D) (None, 1, 1, 24) 13848 ['block4b_se_reshape[0][0]']
block4b_se_expand (Conv2D) (None, 1, 1, 576) 14400 ['block4b_se_reduce[0][0]']
block4b_se_excite (Multiply) (None, 14, 14, 576) 0 ['block4b_activation[0][0]',
'block4b_se_expand[0][0]']
block4b_project_conv (Conv2D) (None, 14, 14, 96) 55296 ['block4b_se_excite[0][0]']
block4b_project_bn (BatchNorma (None, 14, 14, 96) 384 ['block4b_project_conv[0][0]']
lization)
block4b_drop (Dropout) (None, 14, 14, 96) 0 ['block4b_project_bn[0][0]']
block4b_add (Add) (None, 14, 14, 96) 0 ['block4b_drop[0][0]',
'block4a_project_bn[0][0]']
block4c_expand_conv (Conv2D) (None, 14, 14, 576) 55296 ['block4b_add[0][0]']
block4c_expand_bn (BatchNormal (None, 14, 14, 576) 2304 ['block4c_expand_conv[0][0]']
ization)
block4c_expand_activation (Act (None, 14, 14, 576) 0 ['block4c_expand_bn[0][0]']
ivation)
block4c_dwconv (DepthwiseConv2 (None, 14, 14, 576) 5184 ['block4c_expand_activation[0][0]
D) ']
block4c_bn (BatchNormalization (None, 14, 14, 576) 2304 ['block4c_dwconv[0][0]']
)
block4c_activation (Activation (None, 14, 14, 576) 0 ['block4c_bn[0][0]']
)
block4c_se_squeeze (GlobalAver (None, 576) 0 ['block4c_activation[0][0]']
agePooling2D)
block4c_se_reshape (Reshape) (None, 1, 1, 576) 0 ['block4c_se_squeeze[0][0]']
block4c_se_reduce (Conv2D) (None, 1, 1, 24) 13848 ['block4c_se_reshape[0][0]']
block4c_se_expand (Conv2D) (None, 1, 1, 576) 14400 ['block4c_se_reduce[0][0]']
block4c_se_excite (Multiply) (None, 14, 14, 576) 0 ['block4c_activation[0][0]',
'block4c_se_expand[0][0]']
block4c_project_conv (Conv2D) (None, 14, 14, 96) 55296 ['block4c_se_excite[0][0]']
block4c_project_bn (BatchNorma (None, 14, 14, 96) 384 ['block4c_project_conv[0][0]']
lization)
block4c_drop (Dropout) (None, 14, 14, 96) 0 ['block4c_project_bn[0][0]']
block4c_add (Add) (None, 14, 14, 96) 0 ['block4c_drop[0][0]',
'block4b_add[0][0]']
block4d_expand_conv (Conv2D) (None, 14, 14, 576) 55296 ['block4c_add[0][0]']
block4d_expand_bn (BatchNormal (None, 14, 14, 576) 2304 ['block4d_expand_conv[0][0]']
ization)
block4d_expand_activation (Act (None, 14, 14, 576) 0 ['block4d_expand_bn[0][0]']
ivation)
block4d_dwconv (DepthwiseConv2 (None, 14, 14, 576) 5184 ['block4d_expand_activation[0][0]
D) ']
block4d_bn (BatchNormalization (None, 14, 14, 576) 2304 ['block4d_dwconv[0][0]']
)
block4d_activation (Activation (None, 14, 14, 576) 0 ['block4d_bn[0][0]']
)
block4d_se_squeeze (GlobalAver (None, 576) 0 ['block4d_activation[0][0]']
agePooling2D)
block4d_se_reshape (Reshape) (None, 1, 1, 576) 0 ['block4d_se_squeeze[0][0]']
block4d_se_reduce (Conv2D) (None, 1, 1, 24) 13848 ['block4d_se_reshape[0][0]']
block4d_se_expand (Conv2D) (None, 1, 1, 576) 14400 ['block4d_se_reduce[0][0]']
block4d_se_excite (Multiply) (None, 14, 14, 576) 0 ['block4d_activation[0][0]',
'block4d_se_expand[0][0]']
block4d_project_conv (Conv2D) (None, 14, 14, 96) 55296 ['block4d_se_excite[0][0]']
block4d_project_bn (BatchNorma (None, 14, 14, 96) 384 ['block4d_project_conv[0][0]']
lization)
block4d_drop (Dropout) (None, 14, 14, 96) 0 ['block4d_project_bn[0][0]']
block4d_add (Add) (None, 14, 14, 96) 0 ['block4d_drop[0][0]',
'block4c_add[0][0]']
block4e_expand_conv (Conv2D) (None, 14, 14, 576) 55296 ['block4d_add[0][0]']
block4e_expand_bn (BatchNormal (None, 14, 14, 576) 2304 ['block4e_expand_conv[0][0]']
ization)
block4e_expand_activation (Act (None, 14, 14, 576) 0 ['block4e_expand_bn[0][0]']
ivation)
block4e_dwconv (DepthwiseConv2 (None, 14, 14, 576) 5184 ['block4e_expand_activation[0][0]
D) ']
block4e_bn (BatchNormalization (None, 14, 14, 576) 2304 ['block4e_dwconv[0][0]']
)
block4e_activation (Activation (None, 14, 14, 576) 0 ['block4e_bn[0][0]']
)
block4e_se_squeeze (GlobalAver (None, 576) 0 ['block4e_activation[0][0]']
agePooling2D)
block4e_se_reshape (Reshape) (None, 1, 1, 576) 0 ['block4e_se_squeeze[0][0]']
block4e_se_reduce (Conv2D) (None, 1, 1, 24) 13848 ['block4e_se_reshape[0][0]']
block4e_se_expand (Conv2D) (None, 1, 1, 576) 14400 ['block4e_se_reduce[0][0]']
block4e_se_excite (Multiply) (None, 14, 14, 576) 0 ['block4e_activation[0][0]',
'block4e_se_expand[0][0]']
block4e_project_conv (Conv2D) (None, 14, 14, 96) 55296 ['block4e_se_excite[0][0]']
block4e_project_bn (BatchNorma (None, 14, 14, 96) 384 ['block4e_project_conv[0][0]']
lization)
block4e_drop (Dropout) (None, 14, 14, 96) 0 ['block4e_project_bn[0][0]']
block4e_add (Add) (None, 14, 14, 96) 0 ['block4e_drop[0][0]',
'block4d_add[0][0]']
block5a_expand_conv (Conv2D) (None, 14, 14, 576) 55296 ['block4e_add[0][0]']
block5a_expand_bn (BatchNormal (None, 14, 14, 576) 2304 ['block5a_expand_conv[0][0]']
ization)
block5a_expand_activation (Act (None, 14, 14, 576) 0 ['block5a_expand_bn[0][0]']
ivation)
block5a_dwconv (DepthwiseConv2 (None, 14, 14, 576) 14400 ['block5a_expand_activation[0][0]
D) ']
block5a_bn (BatchNormalization (None, 14, 14, 576) 2304 ['block5a_dwconv[0][0]']
)
block5a_activation (Activation (None, 14, 14, 576) 0 ['block5a_bn[0][0]']
)
block5a_se_squeeze (GlobalAver (None, 576) 0 ['block5a_activation[0][0]']
agePooling2D)
block5a_se_reshape (Reshape) (None, 1, 1, 576) 0 ['block5a_se_squeeze[0][0]']
block5a_se_reduce (Conv2D) (None, 1, 1, 24) 13848 ['block5a_se_reshape[0][0]']
block5a_se_expand (Conv2D) (None, 1, 1, 576) 14400 ['block5a_se_reduce[0][0]']
block5a_se_excite (Multiply) (None, 14, 14, 576) 0 ['block5a_activation[0][0]',
'block5a_se_expand[0][0]']
block5a_project_conv (Conv2D) (None, 14, 14, 136) 78336 ['block5a_se_excite[0][0]']
block5a_project_bn (BatchNorma (None, 14, 14, 136) 544 ['block5a_project_conv[0][0]']
lization)
block5b_expand_conv (Conv2D) (None, 14, 14, 816) 110976 ['block5a_project_bn[0][0]']
block5b_expand_bn (BatchNormal (None, 14, 14, 816) 3264 ['block5b_expand_conv[0][0]']
ization)
block5b_expand_activation (Act (None, 14, 14, 816) 0 ['block5b_expand_bn[0][0]']
ivation)
block5b_dwconv (DepthwiseConv2 (None, 14, 14, 816) 20400 ['block5b_expand_activation[0][0]
D) ']
block5b_bn (BatchNormalization (None, 14, 14, 816) 3264 ['block5b_dwconv[0][0]']
)
block5b_activation (Activation (None, 14, 14, 816) 0 ['block5b_bn[0][0]']
)
block5b_se_squeeze (GlobalAver (None, 816) 0 ['block5b_activation[0][0]']
agePooling2D)
block5b_se_reshape (Reshape) (None, 1, 1, 816) 0 ['block5b_se_squeeze[0][0]']
block5b_se_reduce (Conv2D) (None, 1, 1, 34) 27778 ['block5b_se_reshape[0][0]']
block5b_se_expand (Conv2D) (None, 1, 1, 816) 28560 ['block5b_se_reduce[0][0]']
block5b_se_excite (Multiply) (None, 14, 14, 816) 0 ['block5b_activation[0][0]',
'block5b_se_expand[0][0]']
block5b_project_conv (Conv2D) (None, 14, 14, 136) 110976 ['block5b_se_excite[0][0]']
block5b_project_bn (BatchNorma (None, 14, 14, 136) 544 ['block5b_project_conv[0][0]']
lization)
block5b_drop (Dropout) (None, 14, 14, 136) 0 ['block5b_project_bn[0][0]']
block5b_add (Add) (None, 14, 14, 136) 0 ['block5b_drop[0][0]',
'block5a_project_bn[0][0]']
block5c_expand_conv (Conv2D) (None, 14, 14, 816) 110976 ['block5b_add[0][0]']
block5c_expand_bn (BatchNormal (None, 14, 14, 816) 3264 ['block5c_expand_conv[0][0]']
ization)
block5c_expand_activation (Act (None, 14, 14, 816) 0 ['block5c_expand_bn[0][0]']
ivation)
block5c_dwconv (DepthwiseConv2 (None, 14, 14, 816) 20400 ['block5c_expand_activation[0][0]
D) ']
block5c_bn (BatchNormalization (None, 14, 14, 816) 3264 ['block5c_dwconv[0][0]']
)
block5c_activation (Activation (None, 14, 14, 816) 0 ['block5c_bn[0][0]']
)
block5c_se_squeeze (GlobalAver (None, 816) 0 ['block5c_activation[0][0]']
agePooling2D)
block5c_se_reshape (Reshape) (None, 1, 1, 816) 0 ['block5c_se_squeeze[0][0]']
block5c_se_reduce (Conv2D) (None, 1, 1, 34) 27778 ['block5c_se_reshape[0][0]']
block5c_se_expand (Conv2D) (None, 1, 1, 816) 28560 ['block5c_se_reduce[0][0]']
block5c_se_excite (Multiply) (None, 14, 14, 816) 0 ['block5c_activation[0][0]',
'block5c_se_expand[0][0]']
block5c_project_conv (Conv2D) (None, 14, 14, 136) 110976 ['block5c_se_excite[0][0]']
block5c_project_bn (BatchNorma (None, 14, 14, 136) 544 ['block5c_project_conv[0][0]']
lization)
block5c_drop (Dropout) (None, 14, 14, 136) 0 ['block5c_project_bn[0][0]']
block5c_add (Add) (None, 14, 14, 136) 0 ['block5c_drop[0][0]',
'block5b_add[0][0]']
block5d_expand_conv (Conv2D) (None, 14, 14, 816) 110976 ['block5c_add[0][0]']
block5d_expand_bn (BatchNormal (None, 14, 14, 816) 3264 ['block5d_expand_conv[0][0]']
ization)
block5d_expand_activation (Act (None, 14, 14, 816) 0 ['block5d_expand_bn[0][0]']
ivation)
block5d_dwconv (DepthwiseConv2 (None, 14, 14, 816) 20400 ['block5d_expand_activation[0][0]
D) ']
block5d_bn (BatchNormalization (None, 14, 14, 816) 3264 ['block5d_dwconv[0][0]']
)
block5d_activation (Activation (None, 14, 14, 816) 0 ['block5d_bn[0][0]']
)
block5d_se_squeeze (GlobalAver (None, 816) 0 ['block5d_activation[0][0]']
agePooling2D)
block5d_se_reshape (Reshape) (None, 1, 1, 816) 0 ['block5d_se_squeeze[0][0]']
block5d_se_reduce (Conv2D) (None, 1, 1, 34) 27778 ['block5d_se_reshape[0][0]']
block5d_se_expand (Conv2D) (None, 1, 1, 816) 28560 ['block5d_se_reduce[0][0]']
block5d_se_excite (Multiply) (None, 14, 14, 816) 0 ['block5d_activation[0][0]',
'block5d_se_expand[0][0]']
block5d_project_conv (Conv2D) (None, 14, 14, 136) 110976 ['block5d_se_excite[0][0]']
block5d_project_bn (BatchNorma (None, 14, 14, 136) 544 ['block5d_project_conv[0][0]']
lization)
block5d_drop (Dropout) (None, 14, 14, 136) 0 ['block5d_project_bn[0][0]']
block5d_add (Add) (None, 14, 14, 136) 0 ['block5d_drop[0][0]',
'block5c_add[0][0]']
block5e_expand_conv (Conv2D) (None, 14, 14, 816) 110976 ['block5d_add[0][0]']
block5e_expand_bn (BatchNormal (None, 14, 14, 816) 3264 ['block5e_expand_conv[0][0]']
ization)
block5e_expand_activation (Act (None, 14, 14, 816) 0 ['block5e_expand_bn[0][0]']
ivation)
block5e_dwconv (DepthwiseConv2 (None, 14, 14, 816) 20400 ['block5e_expand_activation[0][0]
D) ']
block5e_bn (BatchNormalization (None, 14, 14, 816) 3264 ['block5e_dwconv[0][0]']
)
block5e_activation (Activation (None, 14, 14, 816) 0 ['block5e_bn[0][0]']
)
block5e_se_squeeze (GlobalAver (None, 816) 0 ['block5e_activation[0][0]']
agePooling2D)
block5e_se_reshape (Reshape) (None, 1, 1, 816) 0 ['block5e_se_squeeze[0][0]']
block5e_se_reduce (Conv2D) (None, 1, 1, 34) 27778 ['block5e_se_reshape[0][0]']
block5e_se_expand (Conv2D) (None, 1, 1, 816) 28560 ['block5e_se_reduce[0][0]']
block5e_se_excite (Multiply) (None, 14, 14, 816) 0 ['block5e_activation[0][0]',
'block5e_se_expand[0][0]']
block5e_project_conv (Conv2D) (None, 14, 14, 136) 110976 ['block5e_se_excite[0][0]']
block5e_project_bn (BatchNorma (None, 14, 14, 136) 544 ['block5e_project_conv[0][0]']
lization)
block5e_drop (Dropout) (None, 14, 14, 136) 0 ['block5e_project_bn[0][0]']
block5e_add (Add) (None, 14, 14, 136) 0 ['block5e_drop[0][0]',
'block5d_add[0][0]']
block6a_expand_conv (Conv2D) (None, 14, 14, 816) 110976 ['block5e_add[0][0]']
block6a_expand_bn (BatchNormal (None, 14, 14, 816) 3264 ['block6a_expand_conv[0][0]']
ization)
block6a_expand_activation (Act (None, 14, 14, 816) 0 ['block6a_expand_bn[0][0]']
ivation)
block6a_dwconv_pad (ZeroPaddin (None, 17, 17, 816) 0 ['block6a_expand_activation[0][0]
g2D) ']
block6a_dwconv (DepthwiseConv2 (None, 7, 7, 816) 20400 ['block6a_dwconv_pad[0][0]']
D)
block6a_bn (BatchNormalization (None, 7, 7, 816) 3264 ['block6a_dwconv[0][0]']
)
block6a_activation (Activation (None, 7, 7, 816) 0 ['block6a_bn[0][0]']
)
block6a_se_squeeze (GlobalAver (None, 816) 0 ['block6a_activation[0][0]']
agePooling2D)
block6a_se_reshape (Reshape) (None, 1, 1, 816) 0 ['block6a_se_squeeze[0][0]']
block6a_se_reduce (Conv2D) (None, 1, 1, 34) 27778 ['block6a_se_reshape[0][0]']
block6a_se_expand (Conv2D) (None, 1, 1, 816) 28560 ['block6a_se_reduce[0][0]']
block6a_se_excite (Multiply) (None, 7, 7, 816) 0 ['block6a_activation[0][0]',
'block6a_se_expand[0][0]']
block6a_project_conv (Conv2D) (None, 7, 7, 232) 189312 ['block6a_se_excite[0][0]']
block6a_project_bn (BatchNorma (None, 7, 7, 232) 928 ['block6a_project_conv[0][0]']
lization)
block6b_expand_conv (Conv2D) (None, 7, 7, 1392) 322944 ['block6a_project_bn[0][0]']
block6b_expand_bn (BatchNormal (None, 7, 7, 1392) 5568 ['block6b_expand_conv[0][0]']
ization)
block6b_expand_activation (Act (None, 7, 7, 1392) 0 ['block6b_expand_bn[0][0]']
ivation)
block6b_dwconv (DepthwiseConv2 (None, 7, 7, 1392) 34800 ['block6b_expand_activation[0][0]
D) ']
block6b_bn (BatchNormalization (None, 7, 7, 1392) 5568 ['block6b_dwconv[0][0]']
)
block6b_activation (Activation (None, 7, 7, 1392) 0 ['block6b_bn[0][0]']
)
block6b_se_squeeze (GlobalAver (None, 1392) 0 ['block6b_activation[0][0]']
agePooling2D)
block6b_se_reshape (Reshape) (None, 1, 1, 1392) 0 ['block6b_se_squeeze[0][0]']
block6b_se_reduce (Conv2D) (None, 1, 1, 58) 80794 ['block6b_se_reshape[0][0]']
block6b_se_expand (Conv2D) (None, 1, 1, 1392) 82128 ['block6b_se_reduce[0][0]']
block6b_se_excite (Multiply) (None, 7, 7, 1392) 0 ['block6b_activation[0][0]',
'block6b_se_expand[0][0]']
block6b_project_conv (Conv2D) (None, 7, 7, 232) 322944 ['block6b_se_excite[0][0]']
block6b_project_bn (BatchNorma (None, 7, 7, 232) 928 ['block6b_project_conv[0][0]']
lization)
block6b_drop (Dropout) (None, 7, 7, 232) 0 ['block6b_project_bn[0][0]']
block6b_add (Add) (None, 7, 7, 232) 0 ['block6b_drop[0][0]',
'block6a_project_bn[0][0]']
block6c_expand_conv (Conv2D) (None, 7, 7, 1392) 322944 ['block6b_add[0][0]']
block6c_expand_bn (BatchNormal (None, 7, 7, 1392) 5568 ['block6c_expand_conv[0][0]']
ization)
block6c_expand_activation (Act (None, 7, 7, 1392) 0 ['block6c_expand_bn[0][0]']
ivation)
block6c_dwconv (DepthwiseConv2 (None, 7, 7, 1392) 34800 ['block6c_expand_activation[0][0]
D) ']
block6c_bn (BatchNormalization (None, 7, 7, 1392) 5568 ['block6c_dwconv[0][0]']
)
block6c_activation (Activation (None, 7, 7, 1392) 0 ['block6c_bn[0][0]']
)
block6c_se_squeeze (GlobalAver (None, 1392) 0 ['block6c_activation[0][0]']
agePooling2D)
block6c_se_reshape (Reshape) (None, 1, 1, 1392) 0 ['block6c_se_squeeze[0][0]']
block6c_se_reduce (Conv2D) (None, 1, 1, 58) 80794 ['block6c_se_reshape[0][0]']
block6c_se_expand (Conv2D) (None, 1, 1, 1392) 82128 ['block6c_se_reduce[0][0]']
block6c_se_excite (Multiply) (None, 7, 7, 1392) 0 ['block6c_activation[0][0]',
'block6c_se_expand[0][0]']
block6c_project_conv (Conv2D) (None, 7, 7, 232) 322944 ['block6c_se_excite[0][0]']
block6c_project_bn (BatchNorma (None, 7, 7, 232) 928 ['block6c_project_conv[0][0]']
lization)
block6c_drop (Dropout) (None, 7, 7, 232) 0 ['block6c_project_bn[0][0]']
block6c_add (Add) (None, 7, 7, 232) 0 ['block6c_drop[0][0]',
'block6b_add[0][0]']
block6d_expand_conv (Conv2D) (None, 7, 7, 1392) 322944 ['block6c_add[0][0]']
block6d_expand_bn (BatchNormal (None, 7, 7, 1392) 5568 ['block6d_expand_conv[0][0]']
ization)
block6d_expand_activation (Act (None, 7, 7, 1392) 0 ['block6d_expand_bn[0][0]']
ivation)
block6d_dwconv (DepthwiseConv2 (None, 7, 7, 1392) 34800 ['block6d_expand_activation[0][0]
D) ']
block6d_bn (BatchNormalization (None, 7, 7, 1392) 5568 ['block6d_dwconv[0][0]']
)
block6d_activation (Activation (None, 7, 7, 1392) 0 ['block6d_bn[0][0]']
)
block6d_se_squeeze (GlobalAver (None, 1392) 0 ['block6d_activation[0][0]']
agePooling2D)
block6d_se_reshape (Reshape) (None, 1, 1, 1392) 0 ['block6d_se_squeeze[0][0]']
block6d_se_reduce (Conv2D) (None, 1, 1, 58) 80794 ['block6d_se_reshape[0][0]']
block6d_se_expand (Conv2D) (None, 1, 1, 1392) 82128 ['block6d_se_reduce[0][0]']
block6d_se_excite (Multiply) (None, 7, 7, 1392) 0 ['block6d_activation[0][0]',
'block6d_se_expand[0][0]']
block6d_project_conv (Conv2D) (None, 7, 7, 232) 322944 ['block6d_se_excite[0][0]']
block6d_project_bn (BatchNorma (None, 7, 7, 232) 928 ['block6d_project_conv[0][0]']
lization)
block6d_drop (Dropout) (None, 7, 7, 232) 0 ['block6d_project_bn[0][0]']
block6d_add (Add) (None, 7, 7, 232) 0 ['block6d_drop[0][0]',
'block6c_add[0][0]']
block6e_expand_conv (Conv2D) (None, 7, 7, 1392) 322944 ['block6d_add[0][0]']
block6e_expand_bn (BatchNormal (None, 7, 7, 1392) 5568 ['block6e_expand_conv[0][0]']
ization)
block6e_expand_activation (Act (None, 7, 7, 1392) 0 ['block6e_expand_bn[0][0]']
ivation)
block6e_dwconv (DepthwiseConv2 (None, 7, 7, 1392) 34800 ['block6e_expand_activation[0][0]
D) ']
block6e_bn (BatchNormalization (None, 7, 7, 1392) 5568 ['block6e_dwconv[0][0]']
)
block6e_activation (Activation (None, 7, 7, 1392) 0 ['block6e_bn[0][0]']
)
block6e_se_squeeze (GlobalAver (None, 1392) 0 ['block6e_activation[0][0]']
agePooling2D)
block6e_se_reshape (Reshape) (None, 1, 1, 1392) 0 ['block6e_se_squeeze[0][0]']
block6e_se_reduce (Conv2D) (None, 1, 1, 58) 80794 ['block6e_se_reshape[0][0]']
block6e_se_expand (Conv2D) (None, 1, 1, 1392) 82128 ['block6e_se_reduce[0][0]']
block6e_se_excite (Multiply) (None, 7, 7, 1392) 0 ['block6e_activation[0][0]',
'block6e_se_expand[0][0]']
block6e_project_conv (Conv2D) (None, 7, 7, 232) 322944 ['block6e_se_excite[0][0]']
block6e_project_bn (BatchNorma (None, 7, 7, 232) 928 ['block6e_project_conv[0][0]']
lization)
block6e_drop (Dropout) (None, 7, 7, 232) 0 ['block6e_project_bn[0][0]']
block6e_add (Add) (None, 7, 7, 232) 0 ['block6e_drop[0][0]',
'block6d_add[0][0]']
block6f_expand_conv (Conv2D) (None, 7, 7, 1392) 322944 ['block6e_add[0][0]']
block6f_expand_bn (BatchNormal (None, 7, 7, 1392) 5568 ['block6f_expand_conv[0][0]']
ization)
block6f_expand_activation (Act (None, 7, 7, 1392) 0 ['block6f_expand_bn[0][0]']
ivation)
block6f_dwconv (DepthwiseConv2 (None, 7, 7, 1392) 34800 ['block6f_expand_activation[0][0]
D) ']
block6f_bn (BatchNormalization (None, 7, 7, 1392) 5568 ['block6f_dwconv[0][0]']
)
block6f_activation (Activation (None, 7, 7, 1392) 0 ['block6f_bn[0][0]']
)
block6f_se_squeeze (GlobalAver (None, 1392) 0 ['block6f_activation[0][0]']
agePooling2D)
block6f_se_reshape (Reshape) (None, 1, 1, 1392) 0 ['block6f_se_squeeze[0][0]']
block6f_se_reduce (Conv2D) (None, 1, 1, 58) 80794 ['block6f_se_reshape[0][0]']
block6f_se_expand (Conv2D) (None, 1, 1, 1392) 82128 ['block6f_se_reduce[0][0]']
block6f_se_excite (Multiply) (None, 7, 7, 1392) 0 ['block6f_activation[0][0]',
'block6f_se_expand[0][0]']
block6f_project_conv (Conv2D) (None, 7, 7, 232) 322944 ['block6f_se_excite[0][0]']
block6f_project_bn (BatchNorma (None, 7, 7, 232) 928 ['block6f_project_conv[0][0]']
lization)
block6f_drop (Dropout) (None, 7, 7, 232) 0 ['block6f_project_bn[0][0]']
block6f_add (Add) (None, 7, 7, 232) 0 ['block6f_drop[0][0]',
'block6e_add[0][0]']
block7a_expand_conv (Conv2D) (None, 7, 7, 1392) 322944 ['block6f_add[0][0]']
block7a_expand_bn (BatchNormal (None, 7, 7, 1392) 5568 ['block7a_expand_conv[0][0]']
ization)
block7a_expand_activation (Act (None, 7, 7, 1392) 0 ['block7a_expand_bn[0][0]']
ivation)
block7a_dwconv (DepthwiseConv2 (None, 7, 7, 1392) 12528 ['block7a_expand_activation[0][0]
D) ']
block7a_bn (BatchNormalization (None, 7, 7, 1392) 5568 ['block7a_dwconv[0][0]']
)
block7a_activation (Activation (None, 7, 7, 1392) 0 ['block7a_bn[0][0]']
)
block7a_se_squeeze (GlobalAver (None, 1392) 0 ['block7a_activation[0][0]']
agePooling2D)
block7a_se_reshape (Reshape) (None, 1, 1, 1392) 0 ['block7a_se_squeeze[0][0]']
block7a_se_reduce (Conv2D) (None, 1, 1, 58) 80794 ['block7a_se_reshape[0][0]']
block7a_se_expand (Conv2D) (None, 1, 1, 1392) 82128 ['block7a_se_reduce[0][0]']
block7a_se_excite (Multiply) (None, 7, 7, 1392) 0 ['block7a_activation[0][0]',
'block7a_se_expand[0][0]']
block7a_project_conv (Conv2D) (None, 7, 7, 384) 534528 ['block7a_se_excite[0][0]']
block7a_project_bn (BatchNorma (None, 7, 7, 384) 1536 ['block7a_project_conv[0][0]']
lization)
block7b_expand_conv (Conv2D) (None, 7, 7, 2304) 884736 ['block7a_project_bn[0][0]']
block7b_expand_bn (BatchNormal (None, 7, 7, 2304) 9216 ['block7b_expand_conv[0][0]']
ization)
block7b_expand_activation (Act (None, 7, 7, 2304) 0 ['block7b_expand_bn[0][0]']
ivation)
block7b_dwconv (DepthwiseConv2 (None, 7, 7, 2304) 20736 ['block7b_expand_activation[0][0]
D) ']
block7b_bn (BatchNormalization (None, 7, 7, 2304) 9216 ['block7b_dwconv[0][0]']
)
block7b_activation (Activation (None, 7, 7, 2304) 0 ['block7b_bn[0][0]']
)
block7b_se_squeeze (GlobalAver (None, 2304) 0 ['block7b_activation[0][0]']
agePooling2D)
block7b_se_reshape (Reshape) (None, 1, 1, 2304) 0 ['block7b_se_squeeze[0][0]']
block7b_se_reduce (Conv2D) (None, 1, 1, 96) 221280 ['block7b_se_reshape[0][0]']
block7b_se_expand (Conv2D) (None, 1, 1, 2304) 223488 ['block7b_se_reduce[0][0]']
block7b_se_excite (Multiply) (None, 7, 7, 2304) 0 ['block7b_activation[0][0]',
'block7b_se_expand[0][0]']
block7b_project_conv (Conv2D) (None, 7, 7, 384) 884736 ['block7b_se_excite[0][0]']
block7b_project_bn (BatchNorma (None, 7, 7, 384) 1536 ['block7b_project_conv[0][0]']
lization)
block7b_drop (Dropout) (None, 7, 7, 384) 0 ['block7b_project_bn[0][0]']
block7b_add (Add) (None, 7, 7, 384) 0 ['block7b_drop[0][0]',
'block7a_project_bn[0][0]']
top_conv (Conv2D) (None, 7, 7, 1536) 589824 ['block7b_add[0][0]']
top_bn (BatchNormalization) (None, 7, 7, 1536) 6144 ['top_conv[0][0]']
fcn_stage_1_skip_conv (Conv2D) (None, 14, 14, 256) 1880064 ['block6a_expand_activation[0][0]
']
top_activation (Activation) (None, 7, 7, 1536) 0 ['top_bn[0][0]']
fcn_stage_1_skip_bn (BatchNorm (None, 14, 14, 256) 1024 ['fcn_stage_1_skip_conv[0][0]']
alization)
fcn_stage_1_upsample (Conv2DTr (None, 14, 14, 256) 6291712 ['top_activation[0][0]']
anspose)
fcn_stage_1_skip_relu (Activat (None, 14, 14, 256) 0 ['fcn_stage_1_skip_bn[0][0]']
ion)
fcn_stage_1_add (Add) (None, 14, 14, 256) 0 ['fcn_stage_1_upsample[0][0]',
'fcn_stage_1_skip_relu[0][0]']
fcn_stage_1_conv (Conv2D) (None, 14, 14, 256) 589824 ['fcn_stage_1_add[0][0]']
fcn_stage_1_bn (BatchNormaliza (None, 14, 14, 256) 1024 ['fcn_stage_1_conv[0][0]']
tion)
fcn_stage_2_skip_conv (Conv2D) (None, 28, 28, 128) 331776 ['block4a_expand_activation[0][0]
']
fcn_stage_1_relu (Activation) (None, 14, 14, 256) 0 ['fcn_stage_1_bn[0][0]']
fcn_stage_2_skip_bn (BatchNorm (None, 28, 28, 128) 512 ['fcn_stage_2_skip_conv[0][0]']
alization)
fcn_stage_2_upsample (Conv2DTr (None, 28, 28, 128) 524416 ['fcn_stage_1_relu[0][0]']
anspose)
fcn_stage_2_skip_relu (Activat (None, 28, 28, 128) 0 ['fcn_stage_2_skip_bn[0][0]']
ion)
fcn_stage_2_add (Add) (None, 28, 28, 128) 0 ['fcn_stage_2_upsample[0][0]',
'fcn_stage_2_skip_relu[0][0]']
fcn_stage_2_conv (Conv2D) (None, 28, 28, 128) 147456 ['fcn_stage_2_add[0][0]']
fcn_stage_2_bn (BatchNormaliza (None, 28, 28, 128) 512 ['fcn_stage_2_conv[0][0]']
tion)
fcn_stage_3_skip_conv (Conv2D) (None, 56, 56, 64) 110592 ['block3a_expand_activation[0][0]
']
fcn_stage_2_relu (Activation) (None, 28, 28, 128) 0 ['fcn_stage_2_bn[0][0]']
fcn_stage_3_skip_bn (BatchNorm (None, 56, 56, 64) 256 ['fcn_stage_3_skip_conv[0][0]']
alization)
fcn_stage_3_upsample (Conv2DTr (None, 56, 56, 64) 131136 ['fcn_stage_2_relu[0][0]']
anspose)
fcn_stage_3_skip_relu (Activat (None, 56, 56, 64) 0 ['fcn_stage_3_skip_bn[0][0]']
ion)
fcn_stage_3_add (Add) (None, 56, 56, 64) 0 ['fcn_stage_3_upsample[0][0]',
'fcn_stage_3_skip_relu[0][0]']
fcn_stage_3_conv (Conv2D) (None, 56, 56, 64) 36864 ['fcn_stage_3_add[0][0]']
fcn_stage_3_bn (BatchNormaliza (None, 56, 56, 64) 256 ['fcn_stage_3_conv[0][0]']
tion)
fcn_stage_4_skip_conv (Conv2D) (None, 112, 112, 32 41472 ['block2a_expand_activation[0][0]
) ']
fcn_stage_3_relu (Activation) (None, 56, 56, 64) 0 ['fcn_stage_3_bn[0][0]']
fcn_stage_4_skip_bn (BatchNorm (None, 112, 112, 32 128 ['fcn_stage_4_skip_conv[0][0]']
alization) )
fcn_stage_4_upsample (Conv2DTr (None, 112, 112, 32 32800 ['fcn_stage_3_relu[0][0]']
anspose) )
fcn_stage_4_skip_relu (Activat (None, 112, 112, 32 0 ['fcn_stage_4_skip_bn[0][0]']
ion) )
fcn_stage_4_add (Add) (None, 112, 112, 32 0 ['fcn_stage_4_upsample[0][0]',
) 'fcn_stage_4_skip_relu[0][0]']
fcn_stage_4_conv (Conv2D) (None, 112, 112, 32 9216 ['fcn_stage_4_add[0][0]']
)
fcn_stage_4_bn (BatchNormaliza (None, 112, 112, 32 128 ['fcn_stage_4_conv[0][0]']
tion) )
fcn_stage_4_relu (Activation) (None, 112, 112, 32 0 ['fcn_stage_4_bn[0][0]']
)
fcn8 (Conv2DTranspose) (None, 896, 896, 21 172053 ['fcn_stage_4_relu[0][0]']
)
head_conv (Conv2DTranspose) (None, 896, 896, 3) 570 ['fcn8[0][0]']
==================================================================================================
Total params: 21,087,326
Trainable params: 20,998,103
Non-trainable params: 89,223
__________________________________________________________________________________________________
PLOT_MODEL = os.environ.get('PLOT_MODEL', False)
if PLOT_MODEL:
plot_file_path = f"{encoder}_{decoder}.png"
tf.keras.utils.plot_model(model, to_file=plot_file_path, show_shapes=True)
print(f"Model plot saved to {plot_file_path}")
def predict_single(image):
prediction = model.predict(image[tf.newaxis, ...], verbose=0)[0]
return prediction
def show_predictions(dataset=None):
if dataset is None:
dataset = test_dataset
rows = [
(
image,
single_hot_to_categorical(len(CLASSES), 1, label),
single_hot_to_categorical(len(CLASSES), 0.8, tf.convert_to_tensor(predict_single(image)))
)
for image, label in dataset
]
show(rows)
class DisplayCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs=None):
clear_output(wait=True)
show_predictions(test_dataset.take(1))
print ('\nSample Prediction after epoch {}\n'.format(epoch+1))
if IS_NOTEBOOK:
show_predictions(test_dataset.take(1))
# tf.keras.utils.plot_model(model, to_file="own-mobilenetv2-fcn-2.png", show_shapes=True)
Train model#
EPOCHS = 40 # Actual number of training epochs will be lower because of early stopping
VAL_SUBSPLITS = 2
MODELS_PATH = "models"
BEST_MODEL_PATH = MODELS_PATH + f"/{model.name}_best.h5" # TensorFlow SavedModel
FINAL_MODEL_PATH = MODELS_PATH + f"/{model.name}_final.h5"
# Because of augmentations + shuffle, using len(train) // BATCH_SIZE is not
# strictly necessary, we can go smaller if epochs take too long or we're OOM,
# and we can conversely go larger.
steps_per_epoch = int(min(len(train_paths) // BATCH_SIZE // 1.25, 15))
validation_steps = len(validate_paths) // BATCH_SIZE // VAL_SUBSPLITS
print(f"With a batch size of {BATCH_SIZE}, there will be {steps_per_epoch} batches per training epoch and {validation_steps} batches per validation run.")
With a batch size of 64, there will be 7 batches per training epoch and 1 batches per validation run.
# tensorboard_log_dir = "gs://lakehopper-semseg-data/model/" + datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
callbacks = [
tf.keras.callbacks.ModelCheckpoint(BEST_MODEL_PATH, save_best_only=True, save_weights_only=True, mode='min'),
tf.keras.callbacks.ReduceLROnPlateau(),
# tf.keras.callbacks.TensorBoard(log_dir=tensorboard_log_dir, histogram_freq=1),
tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0.001, patience=5),
]
if IS_NOTEBOOK:
callbacks.append(DisplayCallback())
else:
callbacks.append(tf.keras.callbacks.ProgbarLogger(count_mode='steps'))
print("Training model...")
history = model.fit(
x=training_dataset,
epochs=EPOCHS,
steps_per_epoch=steps_per_epoch,
validation_data=validation_dataset,
validation_steps=validation_steps,
callbacks=callbacks,
)
model.save_weights(FINAL_MODEL_PATH)
print(f"Best model (lowest validation loss) saved to {BEST_MODEL_PATH}")
print(f"Final model saved to {FINAL_MODEL_PATH}")
Metrics#
if IS_NOTEBOOK:
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'validation'], loc='upper left')
plt.show()
def json_default(obj):
if type(obj).__module__ == np.__name__:
if isinstance(obj, np.ndarray):
return obj.tolist()
else:
return obj.item()
raise TypeError('Unknown type:', type(obj))
with open(MODELS_PATH + f"/{model.name}_metrics.json", 'w') as f:
json.dump(history.history, f, default=json_default)