Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
bob
bob.learn.tensorflow
Commits
feff4f40
Commit
feff4f40
authored
Apr 22, 2021
by
Tiago de Freitas Pereira
Browse files
Properly implemented resnet50 and resnet101
parent
5a8c7061
Pipeline
#50087
failed with stage
in 3 minutes and 41 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
bob/learn/tensorflow/models/__init__.py
View file @
feff4f40
...
...
@@ -8,6 +8,8 @@ from .densenet import densenet161 # noqa: F401
from
.embedding_validation
import
EmbeddingValidation
from
.mine
import
MineModel
from
.arcface
import
ArcFaceLayer
,
ArcFaceLayer3Penalties
,
ArcFaceModel
from
.resnet50_modified
import
resnet50_modified
,
resnet101_modified
# gets sphinx autodoc done right - don't remove it
def
__appropriate__
(
*
args
):
...
...
bob/learn/tensorflow/models/resnet50_modified.py
0 → 100644
View file @
feff4f40
# -*- coding: utf-8 -*-
"""
The resnet50 from `tf.keras.applications.Resnet50` has a problem with the convolutional layers.
It basically add bias terms to such layers followed by batch normalizations, which is not correct
https://github.com/tensorflow/tensorflow/issues/37365
This resnet 50 implementation provides a cleaner version
"""
import
tensorflow
as
tf
from
tensorflow.keras
import
layers
from
tensorflow.keras.regularizers
import
l2
from
tensorflow.keras.layers
import
Input
,
Conv2D
,
Activation
,
BatchNormalization
from
tensorflow.keras.layers
import
MaxPooling2D
,
AveragePooling2D
,
Flatten
,
Dense
global
weight_decay
weight_decay
=
1e-4
class
IdentityBlock
(
tf
.
keras
.
layers
.
Layer
):
def
__init__
(
self
,
kernel_size
,
filters
,
stage
,
block
,
weight_decay
=
1e-4
,
name
=
None
,
**
kwargs
):
"""Block that has no convolutianal layer as skip connection
Parameters
----------
kernel_size:
The kernel size of middle conv layer at main path
filters:
list of integers, the filterss of 3 conv layer at main path
stage:
Current stage label, used for generating layer names
block:
'a','b'..., current block label, used for generating layer names
"""
super
().
__init__
(
name
=
name
,
**
kwargs
)
filters1
,
filters2
,
filters3
=
filters
bn_axis
=
3
conv_name_1
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_reduce"
bn_name_1
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_reduce/bn"
layers
=
[
Conv2D
(
filters1
,
(
1
,
1
),
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
kernel_regularizer
=
l2
(
weight_decay
),
name
=
conv_name_1
,
)
]
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
bn_name_1
)]
layers
+=
[
Activation
(
"relu"
)]
conv_name_2
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_3x3"
bn_name_2
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_3x3/bn"
layers
+=
[
Conv2D
(
filters2
,
kernel_size
,
padding
=
"same"
,
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
kernel_regularizer
=
l2
(
weight_decay
),
name
=
conv_name_2
,
)
]
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
bn_name_2
)]
layers
+=
[
Activation
(
"relu"
)]
conv_name_3
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_increase"
bn_name_3
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_increase/bn"
layers
+=
[
Conv2D
(
filters3
,
(
1
,
1
),
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
kernel_regularizer
=
l2
(
weight_decay
),
name
=
conv_name_3
,
)
]
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
bn_name_3
)]
self
.
layers
=
layers
def
call
(
self
,
input_tensor
,
training
=
None
):
x
=
input_tensor
for
l
in
self
.
layers
:
x
=
l
(
x
,
training
=
training
)
x
=
tf
.
keras
.
layers
.
add
([
x
,
input_tensor
])
x
=
Activation
(
"relu"
)(
x
)
return
x
class
ConvBlock
(
tf
.
keras
.
layers
.
Layer
):
def
__init__
(
self
,
kernel_size
,
filters
,
stage
,
block
,
strides
=
(
2
,
2
),
weight_decay
=
1e-4
,
name
=
None
,
**
kwargs
,
):
""" Block that has a conv layer AS shortcut.
Parameters
----------
kernel_size:
The kernel size of middle conv layer at main path
filters:
list of integers, the filterss of 3 conv layer at main path
stage:
Current stage label, used for generating layer names
block:
'a','b'..., current block label, used for generating layer names
"""
super
().
__init__
(
name
=
name
,
**
kwargs
)
filters1
,
filters2
,
filters3
=
filters
bn_axis
=
3
conv_name_1
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_reduce"
bn_name_1
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_reduce/bn"
layers
=
[
Conv2D
(
filters1
,
(
1
,
1
),
strides
=
strides
,
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
kernel_regularizer
=
l2
(
weight_decay
),
name
=
conv_name_1
,
)
]
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
bn_name_1
)]
layers
+=
[
Activation
(
"relu"
)]
conv_name_2
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_3x3"
bn_name_2
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_3x3/bn"
layers
+=
[
Conv2D
(
filters2
,
kernel_size
,
padding
=
"same"
,
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
kernel_regularizer
=
l2
(
weight_decay
),
name
=
conv_name_2
,
)
]
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
bn_name_2
)]
layers
+=
[
Activation
(
"relu"
)]
conv_name_3
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_increase"
bn_name_3
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_increase/bn"
layers
+=
[
Conv2D
(
filters3
,
(
1
,
1
),
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
kernel_regularizer
=
l2
(
weight_decay
),
name
=
conv_name_3
,
)
]
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
bn_name_3
)]
conv_name_4
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_proj"
bn_name_4
=
"conv"
+
str
(
stage
)
+
"_"
+
str
(
block
)
+
"_1x1_proj/bn"
shortcut
=
[
Conv2D
(
filters3
,
(
1
,
1
),
strides
=
strides
,
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
kernel_regularizer
=
l2
(
weight_decay
),
name
=
conv_name_4
,
)
]
shortcut
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
bn_name_4
)]
self
.
layers
=
layers
self
.
shortcut
=
shortcut
def
call
(
self
,
input_tensor
,
training
=
None
):
x
=
input_tensor
for
l
in
self
.
layers
:
x
=
l
(
x
,
training
=
training
)
x_s
=
input_tensor
for
l
in
self
.
shortcut
:
x_s
=
l
(
x_s
,
training
=
training
)
x
=
tf
.
keras
.
layers
.
add
([
x
,
x_s
])
x
=
Activation
(
"relu"
)(
x
)
return
x
def
resnet50_modified
(
input_tensor
=
None
,
input_shape
=
None
,
**
kwargs
):
"""
The resnet50 from `tf.keras.applications.Resnet50` has a problem with the convolutional layers.
It basically add bias terms to such layers followed by batch normalizations, which is not correct
https://github.com/tensorflow/tensorflow/issues/37365
This resnet 50 implementation provides a cleaner version
"""
if
input_tensor
is
None
:
input_tensor
=
tf
.
keras
.
Input
(
shape
=
input_shape
)
else
:
if
not
K
.
is_keras_tensor
(
input_tensor
):
input_tensor
=
tf
.
keras
.
Input
(
tensor
=
input_tensor
,
shape
=
input_shape
)
bn_axis
=
3
# inputs are of size 224 x 224 x 3
layers
=
[
input_tensor
]
layers
+=
[
Conv2D
(
64
,
(
7
,
7
),
strides
=
(
2
,
2
),
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
trainable
=
True
,
kernel_regularizer
=
l2
(
weight_decay
),
padding
=
"same"
,
name
=
"conv1/7x7_s2"
,
)
]
# inputs are of size 112 x 112 x 64
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
"conv1/7x7_s2/bn"
)]
layers
+=
[
Activation
(
"relu"
)]
layers
+=
[
MaxPooling2D
((
3
,
3
),
strides
=
(
2
,
2
))]
# inputs are of size 56 x 56
layers
+=
[
ConvBlock
(
3
,
[
64
,
64
,
256
],
stage
=
2
,
block
=
1
,
strides
=
(
1
,
1
))]
layers
+=
[
IdentityBlock
(
3
,
[
64
,
64
,
256
],
stage
=
2
,
block
=
2
)]
layers
+=
[
IdentityBlock
(
3
,
[
64
,
64
,
256
],
stage
=
2
,
block
=
3
)]
# inputs are of size 28 x 28
layers
+=
[
ConvBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
1
)]
layers
+=
[
IdentityBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
2
)]
layers
+=
[
IdentityBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
3
)]
layers
+=
[
IdentityBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
4
)]
# inputs are of size 14 x 14
layers
+=
[
ConvBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
1
)]
layers
+=
[
IdentityBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
2
)]
layers
+=
[
IdentityBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
3
)]
layers
+=
[
IdentityBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
4
)]
layers
+=
[
IdentityBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
5
)]
layers
+=
[
IdentityBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
6
)]
# inputs are of size 7 x 7
layers
+=
[
ConvBlock
(
3
,
[
512
,
512
,
2048
],
stage
=
5
,
block
=
1
)]
layers
+=
[
IdentityBlock
(
3
,
[
512
,
512
,
2048
],
stage
=
5
,
block
=
2
)]
layers
+=
[
IdentityBlock
(
3
,
[
512
,
512
,
2048
],
stage
=
5
,
block
=
3
)]
return
tf
.
keras
.
Sequential
(
layers
)
def
resnet101_modified
(
input_tensor
=
None
,
input_shape
=
None
,
**
kwargs
):
"""
The resnet101 from `tf.keras.applications.Resnet101` has a problem with the convolutional layers.
It basically add bias terms to such layers followed by batch normalizations, which is not correct
https://github.com/tensorflow/tensorflow/issues/37365
This resnet 10 implementation provides a cleaner version
"""
if
input_tensor
is
None
:
input_tensor
=
tf
.
keras
.
Input
(
shape
=
input_shape
)
else
:
if
not
tf
.
keras
.
backend
.
is_keras_tensor
(
input_tensor
):
input_tensor
=
tf
.
keras
.
Input
(
tensor
=
input_tensor
,
shape
=
input_shape
)
bn_axis
=
3
# inputs are of size 224 x 224 x 3
layers
=
[
input_tensor
]
layers
+=
[
Conv2D
(
64
,
(
7
,
7
),
strides
=
(
2
,
2
),
kernel_initializer
=
"orthogonal"
,
use_bias
=
False
,
trainable
=
True
,
kernel_regularizer
=
l2
(
weight_decay
),
padding
=
"same"
,
name
=
"conv1/7x7_s2"
,
)
]
# inputs are of size 112 x 112 x 64
layers
+=
[
BatchNormalization
(
axis
=
bn_axis
,
name
=
"conv1/7x7_s2/bn"
)]
layers
+=
[
Activation
(
"relu"
)]
layers
+=
[
MaxPooling2D
((
3
,
3
),
strides
=
(
2
,
2
))]
# inputs are of size 56 x 56
layers
+=
[
ConvBlock
(
3
,
[
64
,
64
,
256
],
stage
=
2
,
block
=
1
,
strides
=
(
1
,
1
))]
layers
+=
[
IdentityBlock
(
3
,
[
64
,
64
,
256
],
stage
=
2
,
block
=
2
)]
layers
+=
[
IdentityBlock
(
3
,
[
64
,
64
,
256
],
stage
=
2
,
block
=
3
)]
# inputs are of size 28 x 28
layers
+=
[
ConvBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
1
)]
layers
+=
[
IdentityBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
2
)]
layers
+=
[
IdentityBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
3
)]
layers
+=
[
IdentityBlock
(
3
,
[
128
,
128
,
512
],
stage
=
3
,
block
=
4
)]
# inputs are of size 14 x 14
# 23 blocks here. That's the only difference from
# resnet-101
layers
+=
[
ConvBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
1
)]
for
i
in
range
(
2
,
24
):
layers
+=
[
IdentityBlock
(
3
,
[
256
,
256
,
1024
],
stage
=
4
,
block
=
i
)]
# inputs are of size 7 x 7
layers
+=
[
ConvBlock
(
3
,
[
512
,
512
,
2048
],
stage
=
5
,
block
=
1
)]
layers
+=
[
IdentityBlock
(
3
,
[
512
,
512
,
2048
],
stage
=
5
,
block
=
2
)]
layers
+=
[
IdentityBlock
(
3
,
[
512
,
512
,
2048
],
stage
=
5
,
block
=
3
)]
return
tf
.
keras
.
Sequential
(
layers
)
if
__name__
==
"__main__"
:
input_tensor
=
tf
.
keras
.
layers
.
InputLayer
([
112
,
112
,
3
])
model
=
resnet_50
(
input_tensor
)
print
(
len
(
model
.
variables
))
print
(
model
.
summary
())
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment