Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Oleh Astappiev
Near-Similar Image Recognition
Commits
72f55184
Commit
72f55184
authored
Jun 01, 2022
by
Oleh Astappiev
Browse files
fix: refactor siamese model
parent
60016a16
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
35 additions
and
28 deletions
+35
-28
src/alexnet.py
src/alexnet.py
+6
-6
src/model/siamese.py
src/model/siamese.py
+29
-22
No files found.
src/alexnet.py
View file @
72f55184
...
...
@@ -16,15 +16,15 @@ model = AlexNetModel()
model
.
compile
()
load_weights_of
(
model
,
dataset
)
emb_vectors
,
emb_labels
=
get_embeddings_of
(
model
.
get_embedding_model
(),
dataset
)
emb_model
=
model
.
get_embedding_model
()
emb_vectors
,
emb_labels
=
get_embeddings_of
(
emb_model
,
dataset
)
emb_ds
=
SiameseModel
.
prepare_dataset
(
emb_vectors
,
emb_labels
)
MARGIN
=
0.5
siamese
=
SiameseModel
(
embedding_model
=
model
.
get_embedding_model
(),
image_vector_dimensions
=
512
)
siamese
.
compile
(
loss_margin
=
MARGIN
)
siamese
=
SiameseModel
(
emb_model
,
image_vector_dimensions
=
512
,
loss_margin
=
1
,
fit_epochs
=
5
)
siamese
.
compile
()
siamese
.
fit
(
emb_ds
,
num_classes
=
dataset
.
num_classes
)
projection_vectors
=
siamese
.
projection_model
.
predict
(
emb_vectors
)
#
save_vectors(projection_vectors, emb_labels, dataset.name + '_' + siamese.name + '_vectors')
project_embeddings
(
projection_vectors
,
emb_labels
,
str
(
MARGIN
)
+
'_'
+
siamese
.
name
+
'_'
+
dataset
.
name
)
save_vectors
(
projection_vectors
,
emb_labels
,
dataset
.
name
+
'_'
+
siamese
.
name
+
'_vectors'
)
project_embeddings
(
projection_vectors
,
emb_labels
,
siamese
.
name
+
'_'
+
dataset
.
name
)
print
(
'Done!'
)
src/model/siamese.py
View file @
72f55184
...
...
@@ -12,7 +12,7 @@ DEFAULT_MARGIN = 0.5
NUM_EPOCHS
=
3
TRAIN_BATCH_SIZE
=
128
STEPS_PER_EPOCH
=
100
# TODO: try restore 1000
STEPS_PER_EPOCH
=
100
class
SiameseModel
(
Model
):
...
...
@@ -25,26 +25,21 @@ class SiameseModel(Model):
calculates the euclidean distance between the two generated image vectors and calculates the contrastive loss.
"""
def
__init__
(
self
,
embedding_model
,
image_vector_dimensions
=
IMAGE_VECTOR_DIMENSIONS
):
super
().
__init__
()
self
.
embedding_model
=
embedding_model
self
.
embedding_vector_dimension
=
embedding_model
.
output_shape
[
1
]
self
.
image_vector_dimensions
=
image_vector_dimensions
emb_input_1
=
layers
.
Input
(
self
.
embedding_vector_dimension
)
emb_input_2
=
layers
.
Input
(
self
.
embedding_vector_dimension
)
def
__init__
(
self
,
embedding_model
,
image_vector_dimensions
=
IMAGE_VECTOR_DIMENSIONS
,
loss_margin
=
DEFAULT_MARGIN
,
fit_epochs
=
NUM_EPOCHS
):
embedding_vector_dimension
=
embedding_model
.
output_shape
[
1
]
emb_input_1
=
layers
.
Input
(
embedding_vector_dimension
)
emb_input_2
=
layers
.
Input
(
embedding_vector_dimension
)
# projection model is the one to use for queries (put in a sequence after the embedding-generator model above)
self
.
projection_model
=
tf
.
keras
.
models
.
Sequential
([
projection_model
=
tf
.
keras
.
models
.
Sequential
([
# layers.Dense(image_vector_dimensions, activation=ACTIVATION_FN, input_shape=(embedding_vector_dimension,))
layers
.
Dense
(
128
,
activation
=
'relu'
,
input_shape
=
(
self
.
embedding_vector_dimension
,)),
layers
.
Dense
(
self
.
image_vector_dimensions
,
activation
=
None
),
layers
.
Dense
(
128
,
activation
=
'relu'
,
input_shape
=
(
embedding_vector_dimension
,)),
layers
.
Dense
(
image_vector_dimensions
,
activation
=
None
),
layers
.
Lambda
(
lambda
x
:
tf
.
keras
.
backend
.
l2_normalize
(
x
,
axis
=
1
)),
],
name
=
'siamese_projection'
)
v1
=
self
.
projection_model
(
emb_input_1
)
v2
=
self
.
projection_model
(
emb_input_2
)
v1
=
projection_model
(
emb_input_1
)
v2
=
projection_model
(
emb_input_2
)
# As a note, [here](https://towardsdatascience.com/contrastive-loss-explaned-159f2d4a87ec) they mention that
# cosine distance is preferable to euclidean distance: in a large dimensional space, all points tend to be far
...
...
@@ -54,20 +49,32 @@ class SiameseModel(Model):
# computed_distance = layers.Lambda(euclidean_distance)([v1, v2])
""" Inference model is a model from image to image vector """
im_input
=
self
.
embedding_model
.
input
embedding
=
self
.
embedding_model
(
im_input
)
image_vector
=
self
.
projection_model
(
embedding
)
self
.
inference_model
=
Model
(
inputs
=
im_input
,
outputs
=
image_vector
,
name
=
'siamese_inference'
)
im_input
=
embedding_model
.
input
embedding
=
embedding_model
(
im_input
)
image_vector
=
projection_model
(
embedding
)
inference_model
=
Model
(
inputs
=
im_input
,
outputs
=
image_vector
,
name
=
'siamese_inference'
)
super
(
SiameseModel
,
self
).
__init__
(
inputs
=
[
emb_input_1
,
emb_input_2
],
outputs
=
computed_distance
,
name
=
embedding_model
.
name
+
'_siamese_'
+
str
(
self
.
image_vector_dimensions
)
name
=
embedding_model
.
name
+
'_siamese_
d
'
+
str
(
image_vector_dimensions
)
+
'_m'
+
str
(
loss_margin
)
+
'_s'
+
str
(
fit_epochs
*
STEPS_PER_EPOCH
)
)
def
compile
(
self
,
optimizer
=
tf
.
keras
.
optimizers
.
RMSprop
(),
loss_margin
=
DEFAULT_MARGIN
,
**
kwargs
):
self
.
loss_margin
=
loss_margin
self
.
fit_epochs
=
fit_epochs
self
.
projection_model
=
projection_model
self
.
inference_model
=
inference_model
def
compile
(
self
,
optimizer
=
tf
.
keras
.
optimizers
.
RMSprop
(),
loss_margin
=
None
,
**
kwargs
):
if
loss_margin
is
None
:
loss_margin
=
self
.
loss_margin
super
().
compile
(
optimizer
=
optimizer
,
loss
=
tfa
.
losses
.
ContrastiveLoss
(
margin
=
loss_margin
),
**
kwargs
)
def
fit
(
self
,
x
=
None
,
y
=
None
,
epochs
=
NUM_EPOCHS
,
steps_per_epoch
=
STEPS_PER_EPOCH
,
num_classes
=
None
,
callbacks
=
[
tensorboard_cb
],
**
kwargs
):
def
fit
(
self
,
x
=
None
,
y
=
None
,
epochs
=
None
,
steps_per_epoch
=
STEPS_PER_EPOCH
,
num_classes
=
None
,
callbacks
=
[
tensorboard_cb
],
**
kwargs
):
if
epochs
is
None
:
epochs
=
self
.
fit_epochs
if
num_classes
is
not
None
and
'class_weight'
not
in
kwargs
:
kwargs
=
dict
(
kwargs
,
class_weight
=
{
0
:
1
/
num_classes
,
1
:
(
num_classes
-
1
)
/
num_classes
})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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