-
Notifications
You must be signed in to change notification settings - Fork 0
/
fcn.py
82 lines (69 loc) · 3.47 KB
/
fcn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
"""
File name: fcn
Author: Benjamin Planche
Date created: 17.02.2019
Date last modified: 16:59 17.02.2019
Python Version: "3.6"
Copyright = "Copyright (C) 2018-2019 of Packt"
Credits = ["Eliot Andres, Benjamin Planche"]
License = "MIT"
Version = "1.0.0"
Maintainer = "non"
Status = "Prototype" # "Prototype", "Development", or "Production"
"""
#==============================================================================
# Imported Modules
#==============================================================================
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from tensorflow.keras.models import Model
from tensorflow.keras.layers import *
from tensorflow.keras.applications.vgg16 import *
#==============================================================================
# Function Definitions
#==============================================================================
def fcn_8s(image_size, ch_in=3, ch_out=3):
"""
Build a FCN-8s Keras model, with the VGG-16 layers pretrained on ImageNet.
:param image_size: Image size (H x W)
:param ch_in: Number of input channels
:param ch_out: Number of output channels
:return: Keras model
"""
inputs = Input(shape=(*image_size, ch_in), name='input')
# Building a pre-trained VGG-16 feature extractor (i.e., without the final FC layers)
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=inputs)
# Recovering the feature maps generated by each of the 3 final blocks:
f3 = vgg16.get_layer('block3_pool').output # shape: (28, 28, 256)
f4 = vgg16.get_layer('block4_pool').output # shape: (14, 14, 512)
f5 = vgg16.get_layer('block5_pool').output # shape: ( 7, 7, 512)
# Replacing VGG dense layers by convolutions:
f5_conv1 = Conv2D(filters=4086, kernel_size=7, padding='same',
activation='relu')(f5)
f5_drop1 = Dropout(0.5)(f5_conv1)
f5_conv2 = Conv2D(filters=4086, kernel_size=1, padding='same',
activation='relu')(f5_drop1)
f5_drop2 = Dropout(0.5)(f5_conv2)
f5_conv3 = Conv2D(filters=ch_out, kernel_size=1, padding='same',
activation=None)(f5_drop2)
# Using a transposed conv (w/ s=2) to upscale `f5` into a 14 x 14 map
# so it can be merged with features from `f4_conv1` obtained from `f4`:
f5_conv3_x2 = Conv2DTranspose(filters=ch_out, kernel_size=4, strides=2,
use_bias=False, padding='same', activation='relu')(f5)
f4_conv1 = Conv2D(filters=ch_out, kernel_size=1, padding='same',
activation=None)(f4)
# Merging the 2 feature maps (addition):
merge1 = add([f4_conv1, f5_conv3_x2])
# We repeat the operation to merge `merge1` and `f3` into a 28 x 28 map:
merge1_x2 = Conv2DTranspose(filters=ch_out, kernel_size=4, strides=2,
use_bias=False, padding='same', activation='relu')(merge1)
f3_conv1 = Conv2D(filters=ch_out, kernel_size=1, padding='same',
activation=None)(f3)
merge2 = add([f3_conv1, merge1_x2])
# Finally, we use another transposed conv to decode and up-scale the feature map
# to the original shape, i.e., using a stride 8 to go from 28 x 28 to 224 x 224 here:
outputs = Conv2DTranspose(filters=ch_out, kernel_size=16, strides=8,
padding='same', activation=None)(merge2)
fcn8s_model = Model(inputs, outputs)
return fcn8s_model