diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..4dabdbe
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,66 @@
+name: Tests and Linting
+
+on:
+ push:
+ paths:
+ - '.github/workflows/tests.yml'
+ - 'retinaface/**'
+ - 'tests/**'
+ - 'requirements.txt'
+ - '.gitignore'
+ - 'setup.py'
+ pull_request:
+ paths:
+ - '.github/workflows/tests.yml'
+ - 'retinaface/**'
+ - 'tests/**'
+ - 'requirements.txt'
+ - '.gitignore'
+ - 'setup.py'
+
+jobs:
+ unit-tests:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: [3.8]
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install pytest
+ pip install .
+
+ - name: Test with pytest
+ run: |
+ python -m pytest tests/ -s --disable-warnings
+ linting:
+ needs: unit-tests
+
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: [3.8]
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install pylint
+ pip install black
+ pip install .
+
+ - name: Lint with pylint
+ run: |
+ python -m pylint retinaface/ --fail-under=10
\ No newline at end of file
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..8c89d8a
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,645 @@
+[MAIN]
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Load and enable all available extensions. Use --list-extensions to see a list
+# all available extensions.
+#enable-all-extensions=
+
+# In error mode, messages with a category besides ERROR or FATAL are
+# suppressed, and no reports are done by default. Error mode is compatible with
+# disabling specific errors.
+#errors-only=
+
+# Always return a 0 (non-error) status code, even if lint errors are found.
+# This is primarily useful in continuous integration scripts.
+#exit-zero=
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code.
+extension-pkg-allow-list=
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
+# for backward compatibility.)
+extension-pkg-whitelist=
+
+# Return non-zero exit code if any of these messages/categories are detected,
+# even if score is above --fail-under value. Syntax same as enable. Messages
+# specified are enabled, while categories only check already-enabled messages.
+fail-on=
+
+# Specify a score threshold under which the program will exit with error.
+fail-under=10
+
+# Interpret the stdin as a python script, whose filename needs to be passed as
+# the module_or_package argument.
+#from-stdin=
+
+# Files or directories to be skipped. They should be base names, not paths.
+ignore=CVS
+
+# Add files or directories matching the regular expressions patterns to the
+# ignore-list. The regex matches against paths and can be in Posix or Windows
+# format. Because '\' represents the directory delimiter on Windows systems, it
+# can't be used as an escape character.
+ignore-paths=
+
+# Files or directories matching the regular expression patterns are skipped.
+# The regex matches against base names, not paths. The default value ignores
+# Emacs file locks
+ignore-patterns=^\.#
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis). It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
+# number of processors available to use, and will cap the count on Windows to
+# avoid hangs.
+jobs=1
+
+# Control the amount of potential inferred values when inferring a single
+# object. This can help the performance when dealing with large functions or
+# complex, nested conditions.
+limit-inference-results=100
+
+# List of plugins (as comma separated values of python module names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Minimum Python version to use for version dependent checks. Will default to
+# the version used to run pylint.
+py-version=3.9
+
+# Discover python modules and packages in the file system subtree.
+recursive=no
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages.
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+# In verbose mode, extra non-checker-related info will be displayed.
+#verbose=
+
+
+[BASIC]
+
+# Naming style matching correct argument names.
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style. If left empty, argument names will be checked with the set
+# naming style.
+#argument-rgx=
+
+# Naming style matching correct attribute names.
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style. If left empty, attribute names will be checked with the set naming
+# style.
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma.
+bad-names=foo,
+ bar,
+ baz,
+ toto,
+ tutu,
+ tata
+
+# Bad variable names regexes, separated by a comma. If names match any regex,
+# they will always be refused
+bad-names-rgxs=
+
+# Naming style matching correct class attribute names.
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style. If left empty, class attribute names will be checked
+# with the set naming style.
+#class-attribute-rgx=
+
+# Naming style matching correct class constant names.
+class-const-naming-style=UPPER_CASE
+
+# Regular expression matching correct class constant names. Overrides class-
+# const-naming-style. If left empty, class constant names will be checked with
+# the set naming style.
+#class-const-rgx=
+
+# Naming style matching correct class names.
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-
+# style. If left empty, class names will be checked with the set naming style.
+#class-rgx=
+
+# Naming style matching correct constant names.
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style. If left empty, constant names will be checked with the set naming
+# style.
+#const-rgx=
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names.
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style. If left empty, function names will be checked with the set
+# naming style.
+#function-rgx=
+
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+ j,
+ k,
+ x1,
+ x2,
+ y1,
+ y2,
+ ex,
+ Run,
+ _
+
+# Good variable names regexes, separated by a comma. If names match any regex,
+# they will always be accepted
+good-names-rgxs=
+
+# Include a hint for the correct naming format with invalid-name.
+include-naming-hint=no
+
+# Naming style matching correct inline iteration names.
+inlinevar-naming-style=any
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style. If left empty, inline iteration names will be checked
+# with the set naming style.
+#inlinevar-rgx=
+
+# Naming style matching correct method names.
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style. If left empty, method names will be checked with the set naming style.
+#method-rgx=
+
+# Naming style matching correct module names.
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style. If left empty, module names will be checked with the set naming style.
+#module-rgx=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+# These decorators are taken in consideration only for invalid-name.
+property-classes=abc.abstractproperty
+
+# Regular expression matching correct type variable names. If left empty, type
+# variable names will be checked with the set naming style.
+#typevar-rgx=
+
+# Naming style matching correct variable names.
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style. If left empty, variable names will be checked with the set
+# naming style.
+#variable-rgx=
+
+
+[CLASSES]
+
+# Warn about protected attribute access inside special methods
+check-protected-access-in-special-methods=no
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp,
+ __post_init__
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=cls
+
+
+[DESIGN]
+
+# List of regular expressions of class ancestor names to ignore when counting
+# public methods (see R0903)
+exclude-too-few-public-methods=
+
+# List of qualified class names to ignore when counting class parents (see
+# R0901)
+ignored-parents=
+
+# Maximum number of arguments for function / method.
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in an if statement (see R0916).
+max-bool-expr=5
+
+# Maximum number of branch for function / method body.
+max-branches=12
+
+# Maximum number of locals for function / method body.
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body.
+max-returns=6
+
+# Maximum number of statements in function / method body.
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when caught.
+overgeneral-exceptions=BaseException,
+ Exception
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )??$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Maximum number of lines in a module.
+max-module-lines=1000
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[IMPORTS]
+
+# List of modules that can be imported at any level, not just the top level
+# one.
+allow-any-import-level=
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Deprecated modules which should not be used, separated by a comma.
+deprecated-modules=
+
+# Output a graph (.gv or any supported image format) of external dependencies
+# to the given file (report RP0402 must not be disabled).
+ext-import-graph=
+
+# Output a graph (.gv or any supported image format) of all (i.e. internal and
+# external) dependencies to the given file (report RP0402 must not be
+# disabled).
+import-graph=
+
+# Output a graph (.gv or any supported image format) of internal dependencies
+# to the given file (report RP0402 must not be disabled).
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+# Couples of modules and preferred modules, separated by a comma.
+preferred-modules=
+
+
+[LOGGING]
+
+# The type of string formatting that logging methods do. `old` means using %
+# formatting, `new` is for `{}` formatting.
+logging-format-style=old
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format.
+logging-modules=logging
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
+# UNDEFINED.
+confidence=HIGH,
+ CONTROL_FLOW,
+ INFERENCE,
+ INFERENCE_FAILURE,
+ UNDEFINED
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then re-enable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=raw-checker-failed,
+ bad-inline-option,
+ locally-disabled,
+ file-ignored,
+ suppressed-message,
+ useless-suppression,
+ deprecated-pragma,
+ use-symbolic-message-instead,
+ import-error,
+ invalid-name,
+ missing-module-docstring,
+ missing-function-docstring,
+ missing-class-docstring,
+ too-many-arguments,
+ too-many-locals,
+ too-many-branches,
+ too-many-statements,
+ global-variable-undefined,
+ import-outside-toplevel,
+ singleton-comparison,
+ too-many-lines,
+ duplicate-code,
+ bare-except,
+ cyclic-import,
+ global-statement,
+ no-member,
+ no-name-in-module,
+ unrecognized-option,
+ consider-using-dict-items,
+ consider-iterating-dictionary,
+ unexpected-keyword-arg
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[METHOD_ARGS]
+
+# List of qualified names (i.e., library.method) which require a timeout
+# parameter e.g. 'requests.api.get,requests.api.post'
+timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+ XXX,
+ TODO
+
+# Regular expression of note tags to take in consideration.
+notes-rgx=
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=sys.exit,argparse.parse_error
+
+
+[REPORTS]
+
+# Python expression which should return a score less than or equal to 10. You
+# have access to the variables 'fatal', 'error', 'warning', 'refactor',
+# 'convention', and 'info' which contain the number of messages in each
+# category, as well as 'statement' which is the total number of statements
+# analyzed. This score is used by the global evaluation report (RP0004).
+evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details.
+msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio). You can also give a reporter class, e.g.
+# mypackage.mymodule.MyReporterClass.
+#output-format=
+
+# Tells whether to display a full report or only the messages.
+reports=no
+
+# Activate the evaluation score.
+score=yes
+
+
+[SIMILARITIES]
+
+# Comments are removed from the similarity computation
+ignore-comments=yes
+
+# Docstrings are removed from the similarity computation
+ignore-docstrings=yes
+
+# Imports are removed from the similarity computation
+ignore-imports=yes
+
+# Signatures are removed from the similarity computation
+ignore-signatures=yes
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes.
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it work,
+# install the 'python-enchant' package.
+spelling-dict=
+
+# List of comma separated words that should be considered directives if they
+# appear at the beginning of a comment and should not be checked.
+spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains the private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to the private dictionary (see the
+# --spelling-private-dict-file option) instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[STRING]
+
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=no
+
+# This flag controls whether the implicit-str-concat should generate a warning
+# on implicit string concatenation in sequences defined over several lines.
+check-str-concat-over-line-jumps=no
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether to warn about missing members when the owner of the attribute
+# is inferred to be None.
+ignore-none=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of symbolic message names to ignore for Mixin members.
+ignored-checks-for-mixins=no-member,
+ not-async-context-manager,
+ not-context-manager,
+ attribute-defined-outside-init
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+# Regex pattern to define which classes are considered mixins.
+mixin-class-rgx=.*[Mm]ixin
+
+# List of decorators that change the signature of a decorated function.
+signature-mutators=
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid defining new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of names allowed to shadow builtins
+allowed-redefined-builtins=
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+ _cb
+
+# A regular expression matching the name of dummy variables (i.e. expected to
+# not be used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored.
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d1857aa
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+test:
+ python -m pytest tests/ -s --disable-warnings
+
+lint:
+ python -m pylint retinaface/ --fail-under=10
\ No newline at end of file
diff --git a/README.md b/README.md
index fb4641c..b961e8e 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-[![PyPI Downloads](https://static.pepy.tech/personalized-badge/retina-face?period=total&units=international_system&left_color=grey&right_color=blue&left_text=pypi%20downloads)](https://pepy.tech/project/retina-face)
+[![PyPI Downloads](https://static.pepy.tech/personalized-badge/retina-face?period=total&units=international_system&left_color=grey&right_color=blue&left_text=pip%20downloads)](https://pepy.tech/project/retina-face)
[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/retina-face?color=green&label=conda%20downloads)](https://anaconda.org/conda-forge/retina-face)
[![Stars](https://img.shields.io/github/stars/serengil/retinaface?color=yellow)](https://github.com/serengil/retinaface)
[![License](http://img.shields.io/:license-MIT-green.svg?style=flat)](https://github.com/serengil/retinaface/blob/master/LICENSE)
@@ -102,6 +102,10 @@ print(obj["verified"])
Notice that ArcFace got 99.40% accuracy on [LFW data set](https://sefiks.com/2020/08/27/labeled-faces-in-the-wild-for-face-recognition/) whereas human beings just have 97.53% confidence.
+## Contribution [![Tests](https://github.com/serengil/retinaface/actions/workflows/tests.yml/badge.svg)](https://github.com/serengil/retinaface/actions/workflows/tests.yml)
+
+Pull requests are more than welcome! You should run the unit tests and linting locally before creating a PR. Commands `make test` and `make lint` will help you to run it locally. Once a PR created, GitHub test workflow will be run automatically and unit test results will be available in [GitHub actions](https://github.com/serengil/retinaface/actions) before approval.
+
## Support
There are many ways to support a project. Starring⭐️ the repo is just one 🙏
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..e5ee965
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+numpy>=1.14.0
+gdown>=3.10.1
+Pillow>=5.2.0
+opencv-python>=3.4.4
+tensorflow>=1.9.0
\ No newline at end of file
diff --git a/retinaface/RetinaFace.py b/retinaface/RetinaFace.py
index d9f1af1..ffd8eb7 100644
--- a/retinaface/RetinaFace.py
+++ b/retinaface/RetinaFace.py
@@ -1,69 +1,82 @@
-import warnings
-warnings.filterwarnings("ignore")
-
import os
-os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
-
-#---------------------------
+import warnings
+import logging
+from typing import Union, Any, Optional, Dict
import numpy as np
import tensorflow as tf
-import cv2
from retinaface.model import retinaface_model
from retinaface.commons import preprocess, postprocess
-#---------------------------
+# pylint: disable=global-variable-undefined, no-name-in-module, unused-import, too-many-locals, redefined-outer-name, too-many-statements, too-many-arguments
-import tensorflow as tf
+# ---------------------------
-#Limit the amount of reserved VRAM so that other scripts can be run in the same GPU as well
-os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true'
+# configurations
+warnings.filterwarnings("ignore")
+os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
+# Limit the amount of reserved VRAM so that other scripts can be run in the same GPU as well
+os.environ["TF_FORCE_GPU_ALLOW_GROWTH"] = "true"
-tf_version = int(tf.__version__.split(".")[0])
+tf_version = int(tf.__version__.split(".", maxsplit=1)[0])
if tf_version == 2:
- import logging
tf.get_logger().setLevel(logging.ERROR)
+ from tensorflow.keras.models import Model
+else:
+ from keras.models import Model
# ---------------------------
-def build_model():
-
+def build_model() -> Any:
+ """
+ Builds retinaface model once and store it into memory
+ """
+ # pylint: disable=invalid-name
global model # singleton design pattern
if not "model" in globals():
-
model = tf.function(
retinaface_model.build_model(),
- input_signature=(tf.TensorSpec(shape=[None, None, None, 3], dtype=np.float32),)
+ input_signature=(tf.TensorSpec(shape=[None, None, None, 3], dtype=np.float32),),
)
return model
-def get_image(img_path):
- if type(img_path) == str: # Load from file path
- if not os.path.isfile(img_path):
- raise ValueError("Input image file path (", img_path, ") does not exist.")
- img = cv2.imread(img_path)
-
- elif isinstance(img_path, np.ndarray): # Use given NumPy array
- img = img_path.copy()
-
- else:
- raise ValueError("Invalid image input. Only file paths or a NumPy array accepted.")
-
- # Validate image shape
- if len(img.shape) != 3 or np.prod(img.shape) == 0:
- raise ValueError("Input image needs to have 3 channels at must not be empty.")
-
- return img
-
-def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
+def detect_faces(
+ img_path: Union[str, np.ndarray],
+ threshold: float = 0.9,
+ model: Optional[Model] = None,
+ allow_upscaling: bool = True,
+) -> Dict[str, Any]:
+ """
+ Detect the facial area for a given image
+ Args:
+ img_path (str or numpy array): given image
+ threshold (float): threshold for detection
+ model (Model): pre-trained model can be given
+ allow_upscaling (bool): allowing up-scaling
+ Returns:
+ detected faces as:
+ {
+ "face_1": {
+ "score": 0.9993440508842468,
+ "facial_area": [155, 81, 434, 443],
+ "landmarks": {
+ "right_eye": [257.82974, 209.64787],
+ "left_eye": [374.93427, 251.78687],
+ "nose": [303.4773, 299.91144],
+ "mouth_right": [228.37329, 338.73193],
+ "mouth_left": [320.21982, 374.58798]
+ }
+ }
+ }
+ """
resp = {}
- img = get_image(img_path)
+ img = preprocess.get_image(img_path)
# ---------------------------
@@ -78,12 +91,16 @@ def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
_feat_stride_fpn = [32, 16, 8]
_anchors_fpn = {
- 'stride32': np.array([[-248., -248., 263., 263.], [-120., -120., 135., 135.]], dtype=np.float32),
- 'stride16': np.array([[-56., -56., 71., 71.], [-24., -24., 39., 39.]], dtype=np.float32),
- 'stride8': np.array([[-8., -8., 23., 23.], [0., 0., 15., 15.]], dtype=np.float32)
+ "stride32": np.array(
+ [[-248.0, -248.0, 263.0, 263.0], [-120.0, -120.0, 135.0, 135.0]], dtype=np.float32
+ ),
+ "stride16": np.array(
+ [[-56.0, -56.0, 71.0, 71.0], [-24.0, -24.0, 39.0, 39.0]], dtype=np.float32
+ ),
+ "stride8": np.array([[-8.0, -8.0, 23.0, 23.0], [0.0, 0.0, 15.0, 15.0]], dtype=np.float32),
}
- _num_anchors = {'stride32': 2, 'stride16': 2, 'stride8': 2}
+ _num_anchors = {"stride32": 2, "stride16": 2, "stride8": 2}
# ---------------------------
@@ -95,24 +112,23 @@ def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
net_out = [elt.numpy() for elt in net_out]
sym_idx = 0
- for _idx, s in enumerate(_feat_stride_fpn):
- _key = 'stride%s' % s
+ for _, s in enumerate(_feat_stride_fpn):
+ # _key = f"stride{s}"
scores = net_out[sym_idx]
- scores = scores[:, :, :, _num_anchors['stride%s' % s]:]
+ scores = scores[:, :, :, _num_anchors[f"stride{s}"] :]
bbox_deltas = net_out[sym_idx + 1]
height, width = bbox_deltas.shape[1], bbox_deltas.shape[2]
- A = _num_anchors['stride%s' % s]
+ A = _num_anchors[f"stride{s}"]
K = height * width
- anchors_fpn = _anchors_fpn['stride%s' % s]
+ anchors_fpn = _anchors_fpn[f"stride{s}"]
anchors = postprocess.anchors_plane(height, width, s, anchors_fpn)
anchors = anchors.reshape((K * A, 4))
scores = scores.reshape((-1, 1))
bbox_stds = [1.0, 1.0, 1.0, 1.0]
- bbox_deltas = bbox_deltas
- bbox_pred_len = bbox_deltas.shape[3]//A
+ bbox_pred_len = bbox_deltas.shape[3] // A
bbox_deltas = bbox_deltas.reshape((-1, bbox_pred_len))
bbox_deltas[:, 0::4] = bbox_deltas[:, 0::4] * bbox_stds[0]
bbox_deltas[:, 1::4] = bbox_deltas[:, 1::4] * bbox_stds[1]
@@ -135,8 +151,8 @@ def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
scores_list.append(scores)
landmark_deltas = net_out[sym_idx + 2]
- landmark_pred_len = landmark_deltas.shape[3]//A
- landmark_deltas = landmark_deltas.reshape((-1, 5, landmark_pred_len//5))
+ landmark_pred_len = landmark_deltas.shape[3] // A
+ landmark_deltas = landmark_deltas.reshape((-1, 5, landmark_pred_len // 5))
landmarks = postprocess.landmark_pred(anchors, landmark_deltas)
landmarks = landmarks[order, :]
@@ -145,8 +161,8 @@ def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
sym_idx += 3
proposals = np.vstack(proposals_list)
-
- if proposals.shape[0]==0:
+
+ if proposals.shape[0] == 0:
return resp
scores = np.vstack(scores_list)
@@ -160,8 +176,8 @@ def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
pre_det = np.hstack((proposals[:, 0:4], scores)).astype(np.float32, copy=False)
- #nms = cpu_nms_wrapper(nms_threshold)
- #keep = nms(pre_det)
+ # nms = cpu_nms_wrapper(nms_threshold)
+ # keep = nms(pre_det)
keep = postprocess.cpu_nms(pre_det, nms_threshold)
det = np.hstack((pre_det, proposals[:, 4:]))
@@ -169,8 +185,7 @@ def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
landmarks = landmarks[keep]
for idx, face in enumerate(det):
-
- label = 'face_'+str(idx+1)
+ label = "face_" + str(idx + 1)
resp[label] = {}
resp[label]["score"] = face[4]
@@ -186,41 +201,57 @@ def detect_faces(img_path, threshold=0.9, model=None, allow_upscaling=True):
return resp
-def extract_faces(img_path, threshold=0.9, model=None, align=True, allow_upscaling=True, expand_face_area: int = 0):
-
+def extract_faces(
+ img_path: Union[str, np.ndarray],
+ threshold: float = 0.9,
+ model: Optional[Model] = None,
+ align: bool = True,
+ allow_upscaling: bool = True,
+ expand_face_area: int = 0,
+) -> list:
+ """
+ Extract detected and aligned faces
+ Args:
+ img_path (str or numpy): given image
+ threshold (float): detection threshold
+ model (Model): pre-trained model can be passed to the function
+ align (bool): enable or disable alignment
+ allow_upscaling (bool)
+ expand_face_area (int): set this to something to expand facial area with given pixels
+ """
resp = []
# ---------------------------
- img = get_image(img_path)
+ img = preprocess.get_image(img_path)
# ---------------------------
- obj = detect_faces(img_path=img, threshold=threshold, model=model, allow_upscaling=allow_upscaling)
-
- if type(obj) == dict:
- for key in obj:
- identity = obj[key]
+ obj = detect_faces(
+ img_path=img, threshold=threshold, model=model, allow_upscaling=allow_upscaling
+ )
+ if isinstance(obj, dict):
+ for _, identity in obj.items():
facial_area = identity["facial_area"]
+
# expand the facial area to be extracted and stay within img.shape limits
x1 = max(0, facial_area[0] - expand_face_area) # expand left
y1 = max(0, facial_area[1] - expand_face_area) # expand top
x2 = min(img.shape[1], facial_area[2] + expand_face_area) # expand right
y2 = min(img.shape[0], facial_area[3] + expand_face_area) # expand bottom
- facial_img = img[y1: y2, x1: x2]
+ facial_img = img[y1:y2, x1:x2]
- if align == True:
+ if align is True:
landmarks = identity["landmarks"]
left_eye = landmarks["left_eye"]
right_eye = landmarks["right_eye"]
nose = landmarks["nose"]
- mouth_right = landmarks["mouth_right"]
- mouth_left = landmarks["mouth_left"]
+ # mouth_right = landmarks["mouth_right"]
+ # mouth_left = landmarks["mouth_left"]
facial_img = postprocess.alignment_procedure(facial_img, right_eye, left_eye, nose)
resp.append(facial_img[:, :, ::-1])
- # elif type(obj) == tuple:
return resp
diff --git a/retinaface/commons/logger.py b/retinaface/commons/logger.py
new file mode 100644
index 0000000..4fd7976
--- /dev/null
+++ b/retinaface/commons/logger.py
@@ -0,0 +1,41 @@
+import os
+import logging
+from datetime import datetime
+
+# pylint: disable=broad-except
+class Logger:
+ def __init__(self, module=None):
+ self.module = module
+ log_level = os.environ.get("RETINAFACE_LOG_LEVEL", str(logging.INFO))
+ try:
+ self.log_level = int(log_level)
+ except Exception as err:
+ self.dump_log(
+ f"Exception while parsing $RETINAFACE_LOG_LEVEL."
+ f"Expected int but it is {log_level} ({str(err)})."
+ "Setting app log level to info."
+ )
+ self.log_level = logging.INFO
+
+ def info(self, message):
+ if self.log_level <= logging.INFO:
+ self.dump_log(f"{message}")
+
+ def debug(self, message):
+ if self.log_level <= logging.DEBUG:
+ self.dump_log(f"🕷️ {message}")
+
+ def warn(self, message):
+ if self.log_level <= logging.WARNING:
+ self.dump_log(f"⚠️ {message}")
+
+ def error(self, message):
+ if self.log_level <= logging.ERROR:
+ self.dump_log(f"🔴 {message}")
+
+ def critical(self, message):
+ if self.log_level <= logging.CRITICAL:
+ self.dump_log(f"💥 {message}")
+
+ def dump_log(self, message):
+ print(f"{str(datetime.now())[2:-7]} - {message}")
diff --git a/retinaface/commons/postprocess.py b/retinaface/commons/postprocess.py
index dbcfb44..12e819f 100644
--- a/retinaface/commons/postprocess.py
+++ b/retinaface/commons/postprocess.py
@@ -1,72 +1,77 @@
+import math
import numpy as np
from PIL import Image
-import math
-import cv2
-def findEuclideanDistance(source_representation, test_representation):
+
+# pylint: disable=unused-argument
+
+
+def findEuclideanDistance(
+ source_representation: np.ndarray, test_representation: np.ndarray
+) -> float:
+ """
+ Find euclidean distance between 2 vectors
+ Args:
+ source_representation (numpy array)
+ test_representation (numpy array)
+ Returns
+ distance
+ """
euclidean_distance = source_representation - test_representation
euclidean_distance = np.sum(np.multiply(euclidean_distance, euclidean_distance))
euclidean_distance = np.sqrt(euclidean_distance)
return euclidean_distance
-#this function copied from the deepface repository: https://github.com/serengil/deepface/blob/master/deepface/commons/functions.py
-def alignment_procedure(img, left_eye, right_eye, nose):
- #this function aligns given face in img based on left and right eye coordinates
-
- #left eye is the eye appearing on the left (right eye of the person)
- #left top point is (0, 0)
+def alignment_procedure(img: np.ndarray, left_eye: tuple, right_eye: tuple, nose: tuple):
+ """
+ Alignma given face with respect to the left and right eye coordinates.
+ Left eye is the eye appearing on the left (right eye of the person). Left top point is (0, 0)
+ Args:
+ img (numpy array): given image
+ left_eye (tuple): left eye coordinates.
+ Left eye is appearing on the left of image (right eye of the person)
+ right_eye (tuple): right eye coordinates.
+ Right eye is appearing on the right of image (left eye of the person)
+ nose (tuple): coordinates of nose
+ """
left_eye_x, left_eye_y = left_eye
right_eye_x, right_eye_y = right_eye
- #-----------------------
- #decide the image is inverse
-
- center_eyes = (int((left_eye_x + right_eye_x) / 2), int((left_eye_y + right_eye_y) / 2))
-
- if False:
-
- img = cv2.circle(img, (int(left_eye[0]), int(left_eye[1])), 2, (0, 255, 255), 2)
- img = cv2.circle(img, (int(right_eye[0]), int(right_eye[1])), 2, (255, 0, 0), 2)
- img = cv2.circle(img, center_eyes, 2, (0, 0, 255), 2)
- img = cv2.circle(img, (int(nose[0]), int(nose[1])), 2, (255, 255, 255), 2)
-
- #-----------------------
- #find rotation direction
-
+ # -----------------------
+ # find rotation direction
if left_eye_y > right_eye_y:
point_3rd = (right_eye_x, left_eye_y)
- direction = -1 #rotate same direction to clock
+ direction = -1 # rotate same direction to clock
else:
point_3rd = (left_eye_x, right_eye_y)
- direction = 1 #rotate inverse direction of clock
+ direction = 1 # rotate inverse direction of clock
- #-----------------------
- #find length of triangle edges
+ # -----------------------
+ # find length of triangle edges
a = findEuclideanDistance(np.array(left_eye), np.array(point_3rd))
b = findEuclideanDistance(np.array(right_eye), np.array(point_3rd))
c = findEuclideanDistance(np.array(right_eye), np.array(left_eye))
- #-----------------------
-
- #apply cosine rule
+ # -----------------------
+ # apply cosine rule
+ if b != 0 and c != 0: # this multiplication causes division by zero in cos_a calculation
- if b != 0 and c != 0: #this multiplication causes division by zero in cos_a calculation
+ cos_a = (b * b + c * c - a * a) / (2 * b * c)
- cos_a = (b*b + c*c - a*a)/(2*b*c)
-
- #PR15: While mathematically cos_a must be within the closed range [-1.0, 1.0], floating point errors would produce cases violating this
- #In fact, we did come across a case where cos_a took the value 1.0000000169176173, which lead to a NaN from the following np.arccos step
+ # PR15: While mathematically cos_a must be within the closed range [-1.0, 1.0],
+ # floating point errors would produce cases violating this
+ # In fact, we did come across a case where cos_a took the value 1.0000000169176173
+ # which lead to a NaN from the following np.arccos step
cos_a = min(1.0, max(-1.0, cos_a))
-
-
- angle = np.arccos(cos_a) #angle in radian
- angle = (angle * 180) / math.pi #radian to degree
- #-----------------------
- #rotate base image
+ angle = np.arccos(cos_a) # angle in radian
+ angle = (angle * 180) / math.pi # radian to degree
+
+ # -----------------------
+ # rotate base image
if direction == -1:
angle = 90 - angle
@@ -74,12 +79,16 @@ def alignment_procedure(img, left_eye, right_eye, nose):
img = Image.fromarray(img)
img = np.array(img.rotate(direction * angle))
- #-----------------------
+ # -----------------------
+
+ return img
- return img #return img anyway
-#this function is copied from the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/retinaface.py
def bbox_pred(boxes, box_deltas):
+ """
+ This function is copied from the following code snippet:
+ https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/retinaface.py
+ """
if boxes.shape[0] == 0:
return np.zeros((0, box_deltas.shape[1]))
@@ -109,15 +118,19 @@ def bbox_pred(boxes, box_deltas):
# y2
pred_boxes[:, 3:4] = pred_ctr_y + 0.5 * (pred_h - 1.0)
- if box_deltas.shape[1]>4:
- pred_boxes[:,4:] = box_deltas[:,4:]
+ if box_deltas.shape[1] > 4:
+ pred_boxes[:, 4:] = box_deltas[:, 4:]
return pred_boxes
-# This function copied from the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/retinaface.py
+
def landmark_pred(boxes, landmark_deltas):
+ """
+ This function copied from the following code snippet
+ https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/retinaface.py
+ """
if boxes.shape[0] == 0:
- return np.zeros((0, landmark_deltas.shape[1]))
+ return np.zeros((0, landmark_deltas.shape[1]))
boxes = boxes.astype(float, copy=False)
widths = boxes[:, 2] - boxes[:, 0] + 1.0
heights = boxes[:, 3] - boxes[:, 1] + 1.0
@@ -125,12 +138,16 @@ def landmark_pred(boxes, landmark_deltas):
ctr_y = boxes[:, 1] + 0.5 * (heights - 1.0)
pred = landmark_deltas.copy()
for i in range(5):
- pred[:,i,0] = landmark_deltas[:,i,0]*widths + ctr_x
- pred[:,i,1] = landmark_deltas[:,i,1]*heights + ctr_y
+ pred[:, i, 0] = landmark_deltas[:, i, 0] * widths + ctr_x
+ pred[:, i, 1] = landmark_deltas[:, i, 1] * heights + ctr_y
return pred
-# This function copied from rcnn module of retinaface-tf2 project: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/processing/bbox_transform.py
+
def clip_boxes(boxes, im_shape):
+ """
+ This function copied from rcnn module of retinaface-tf2 project
+ https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/processing/bbox_transform.py
+ """
# x1 >= 0
boxes[:, 0::4] = np.maximum(np.minimum(boxes[:, 0::4], im_shape[1] - 1), 0)
# y1 >= 0
@@ -141,17 +158,27 @@ def clip_boxes(boxes, im_shape):
boxes[:, 3::4] = np.maximum(np.minimum(boxes[:, 3::4], im_shape[0] - 1), 0)
return boxes
-#this function is mainly based on the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/cython/anchors.pyx
+
def anchors_plane(height, width, stride, base_anchors):
+ """
+ This function is mainly based on the following code snippet
+ https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/cython/anchors.pyx
+ """
A = base_anchors.shape[0]
c_0_2 = np.tile(np.arange(0, width)[np.newaxis, :, np.newaxis, np.newaxis], (height, 1, A, 1))
c_1_3 = np.tile(np.arange(0, height)[:, np.newaxis, np.newaxis, np.newaxis], (1, width, A, 1))
- all_anchors = np.concatenate([c_0_2, c_1_3, c_0_2, c_1_3], axis=-1) * stride + np.tile(base_anchors[np.newaxis, np.newaxis, :, :], (height, width, 1, 1))
+ all_anchors = np.concatenate([c_0_2, c_1_3, c_0_2, c_1_3], axis=-1) * stride + np.tile(
+ base_anchors[np.newaxis, np.newaxis, :, :], (height, width, 1, 1)
+ )
return all_anchors
-#this function is mainly based on the following code snippet: https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/cython/cpu_nms.pyx
-#Fast R-CNN by Ross Girshick
+
def cpu_nms(dets, threshold):
+ """
+ This function is mainly based on the following code snippet
+ https://github.com/StanislasBertrand/RetinaFace-tf2/blob/master/rcnn/cython/cpu_nms.pyx
+ Fast R-CNN by Ross Girshick
+ """
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
@@ -170,14 +197,21 @@ def cpu_nms(dets, threshold):
if suppressed[i] == 1:
continue
keep.append(i)
- ix1 = x1[i]; iy1 = y1[i]; ix2 = x2[i]; iy2 = y2[i]
+ ix1 = x1[i]
+ iy1 = y1[i]
+ ix2 = x2[i]
+ iy2 = y2[i]
iarea = areas[i]
for _j in range(_i + 1, ndets):
j = order[_j]
if suppressed[j] == 1:
continue
- xx1 = max(ix1, x1[j]); yy1 = max(iy1, y1[j]); xx2 = min(ix2, x2[j]); yy2 = min(iy2, y2[j])
- w = max(0.0, xx2 - xx1 + 1); h = max(0.0, yy2 - yy1 + 1)
+ xx1 = max(ix1, x1[j])
+ yy1 = max(iy1, y1[j])
+ xx2 = min(ix2, x2[j])
+ yy2 = min(iy2, y2[j])
+ w = max(0.0, xx2 - xx1 + 1)
+ h = max(0.0, yy2 - yy1 + 1)
inter = w * h
ovr = inter / (iarea + areas[j] - inter)
if ovr >= threshold:
diff --git a/retinaface/commons/preprocess.py b/retinaface/commons/preprocess.py
index ec96902..b3f471f 100644
--- a/retinaface/commons/preprocess.py
+++ b/retinaface/commons/preprocess.py
@@ -1,10 +1,89 @@
+import os
+import base64
+from pathlib import Path
+from typing import Union
+import requests
+from PIL import Image
import numpy as np
import cv2
-# This function is modified from the following code snippet:
-# https://github.com/StanislasBertrand/RetinaFace-tf2/blob/5f68ce8130889384cb8aca937a270cea4ef2d020/retinaface.py#L49-L74
-def resize_image(img, scales, allow_upscaling):
+def get_image(img_uri: Union[str, np.ndarray]) -> np.ndarray:
+ """
+ Load the given image
+ Args:
+ img_path (str or numpy array): exact image path, pre-loaded numpy array (BGR format)
+ , base64 encoded string and urls are welcome
+ Returns:
+ image itself
+ """
+ # if it is pre-loaded numpy array
+ if isinstance(img_uri, np.ndarray): # Use given NumPy array
+ img = img_uri.copy()
+
+ # if it is base64 encoded string
+ elif isinstance(img_uri, str) and img_uri.startswith("data:image/"):
+ img = load_base64_img(img_uri)
+
+ # if it is an external url
+ elif isinstance(img_uri, str) and img_uri.startswith("http"):
+ img = np.array(
+ Image.open(requests.get(img_uri, stream=True, timeout=60).raw).convert("BGR")
+ )
+
+ # then it has to be a path on filesystem
+ elif isinstance(img_uri, str):
+ if isinstance(img_uri, Path):
+ img_uri = str(img_uri)
+
+ if not os.path.isfile(img_uri):
+ raise ValueError(f"Input image file path ({img_uri}) does not exist.")
+
+ # pylint: disable=no-member
+ img = cv2.imread(img_uri)
+
+ else:
+ raise ValueError(
+ f"Invalid image input - {img_uri}."
+ "Exact paths, pre-loaded numpy arrays, base64 encoded "
+ "strings and urls are welcome."
+ )
+
+ # Validate image shape
+ if len(img.shape) != 3 or np.prod(img.shape) == 0:
+ raise ValueError("Input image needs to have 3 channels at must not be empty.")
+
+ return img
+
+
+def load_base64_img(uri) -> np.ndarray:
+ """Load image from base64 string.
+
+ Args:
+ uri: a base64 string.
+
+ Returns:
+ numpy array: the loaded image.
+ """
+ encoded_data = uri.split(",")[1]
+ nparr = np.fromstring(base64.b64decode(encoded_data), np.uint8)
+ img_bgr = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
+ # img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
+ return img_bgr
+
+
+def resize_image(img: np.ndarray, scales: list, allow_upscaling: bool) -> tuple:
+ """
+ This function is modified from the following code snippet:
+ https://github.com/StanislasBertrand/RetinaFace-tf2/blob/5f68ce8130889384cb8aca937a270cea4ef2d020/retinaface.py#L49-L74
+
+ Args:
+ img (numpy array): given image
+ scales (list)
+ allow_upscaling (bool)
+ Returns
+ resized image, im_scale
+ """
img_h, img_w = img.shape[0:2]
target_size = scales[0]
max_size = scales[1]
@@ -22,21 +101,21 @@ def resize_image(img, scales, allow_upscaling):
im_scale = max_size / float(im_size_max)
if im_scale != 1.0:
- img = cv2.resize(
- img,
- None,
- None,
- fx=im_scale,
- fy=im_scale,
- interpolation=cv2.INTER_LINEAR
- )
+ img = cv2.resize(img, None, None, fx=im_scale, fy=im_scale, interpolation=cv2.INTER_LINEAR)
return img, im_scale
-# This function is modified from the following code snippet:
-# https://github.com/StanislasBertrand/RetinaFace-tf2/blob/5f68ce8130889384cb8aca937a270cea4ef2d020/retinaface.py#L76-L96
-def preprocess_image(img, allow_upscaling):
+def preprocess_image(img: np.ndarray, allow_upscaling: bool) -> tuple:
+ """
+ This function is modified from the following code snippet:
+ https://github.com/StanislasBertrand/RetinaFace-tf2/blob/5f68ce8130889384cb8aca937a270cea4ef2d020/retinaface.py#L76-L96
+ Args:
+ img (numpy array): given image
+ allow_upscaling (bool)
+ Returns:
+ tensor, image shape, im_scale
+ """
pixel_means = np.array([0.0, 0.0, 0.0], dtype=np.float32)
pixel_stds = np.array([1.0, 1.0, 1.0], dtype=np.float32)
pixel_scale = float(1.0)
@@ -48,6 +127,8 @@ def preprocess_image(img, allow_upscaling):
# Make image scaling + BGR2RGB conversion + transpose (N,H,W,C) to (N,C,H,W)
for i in range(3):
- im_tensor[0, :, :, i] = (img[:, :, 2 - i] / pixel_scale - pixel_means[2 - i]) / pixel_stds[2 - i]
+ im_tensor[0, :, :, i] = (img[:, :, 2 - i] / pixel_scale - pixel_means[2 - i]) / pixel_stds[
+ 2 - i
+ ]
return im_tensor, img.shape[0:2], im_scale
diff --git a/retinaface/model/retinaface_model.py b/retinaface/model/retinaface_model.py
index a2cc022..881a41a 100644
--- a/retinaface/model/retinaface_model.py
+++ b/retinaface/model/retinaface_model.py
@@ -1,468 +1,1028 @@
-import tensorflow as tf
-import gdown
-from pathlib import Path
import os
+from pathlib import Path
+import gdown
+import tensorflow as tf
+from retinaface.commons.logger import Logger
+
+logger = Logger(module="retinaface/model/retinaface_model.py")
-tf_version = int(tf.__version__.split(".")[0])
+# pylint: disable=too-many-statements, no-name-in-module
+
+# configurations
+
+tf_version = int(tf.__version__.split(".", maxsplit=1)[0])
if tf_version == 1:
from keras.models import Model
- from keras.layers import Input, BatchNormalization, ZeroPadding2D, Conv2D, ReLU, MaxPool2D, Add, UpSampling2D, concatenate, Softmax
+ from keras.layers import (
+ Input,
+ BatchNormalization,
+ ZeroPadding2D,
+ Conv2D,
+ ReLU,
+ MaxPool2D,
+ Add,
+ UpSampling2D,
+ concatenate,
+ Softmax,
+ )
else:
from tensorflow.keras.models import Model
- from tensorflow.keras.layers import Input, BatchNormalization, ZeroPadding2D, Conv2D, ReLU, MaxPool2D, Add, UpSampling2D, concatenate, Softmax
-
-def load_weights(model):
-
- home = str(os.getenv('DEEPFACE_HOME', default=Path.home()))
-
- exact_file = home+'/.deepface/weights/retinaface.h5'
- #url = 'https://drive.google.com/file/d/1K3Eq2k1b9dpKkucZjPAiCCnNzfCMosK4'
- #url = 'https://drive.google.com/uc?id=1K3Eq2k1b9dpKkucZjPAiCCnNzfCMosK4'
- url = 'https://github.com/serengil/deepface_models/releases/download/v1.0/retinaface.h5'
-
- #-----------------------------
-
- if not os.path.exists(home+"/.deepface"):
- os.mkdir(home+"/.deepface")
- print("Directory ",home,"/.deepface created")
-
- if not os.path.exists(home+"/.deepface/weights"):
- os.mkdir(home+"/.deepface/weights")
- print("Directory ",home,"/.deepface/weights created")
-
- #-----------------------------
-
- if os.path.isfile(exact_file) != True:
- print("retinaface.h5 will be downloaded from the url "+url)
+ from tensorflow.keras.layers import (
+ Input,
+ BatchNormalization,
+ ZeroPadding2D,
+ Conv2D,
+ ReLU,
+ MaxPool2D,
+ Add,
+ UpSampling2D,
+ concatenate,
+ Softmax,
+ )
+
+
+def load_weights(model: Model):
+ """
+ Loading pre-trained weights for the RetinaFace model
+ Args:
+ model (Model): retinaface model structure with randon weights
+ Returns:
+ model (Model): retinaface model with its structure and pre-trained weights
+
+ """
+ home = str(os.getenv("DEEPFACE_HOME", default=str(Path.home())))
+
+ exact_file = home + "/.deepface/weights/retinaface.h5"
+ url = "https://github.com/serengil/deepface_models/releases/download/v1.0/retinaface.h5"
+
+ # -----------------------------
+
+ if not os.path.exists(home + "/.deepface"):
+ os.mkdir(home + "/.deepface")
+ logger.info(f"Directory {home}/.deepface created")
+
+ if not os.path.exists(home + "/.deepface/weights"):
+ os.mkdir(home + "/.deepface/weights")
+ logger.info(f"Directory {home}/.deepface/weights created")
+
+ # -----------------------------
+
+ if os.path.isfile(exact_file) is not True:
+ logger.info(f"retinaface.h5 will be downloaded from the url {url}")
gdown.download(url, exact_file, quiet=False)
- #-----------------------------
+ # -----------------------------
- #gdown should download the pretrained weights here. If it does not still exist, then throw an exception.
- if os.path.isfile(exact_file) != True:
- raise ValueError("Pre-trained weight could not be loaded!"
- +" You might try to download the pre-trained weights from the url "+ url
- + " and copy it to the ", exact_file, "manually.")
+ # gdown should download the pretrained weights here.
+ # If it does not still exist, then throw an exception.
+ if os.path.isfile(exact_file) is not True:
+ raise ValueError(
+ "Pre-trained weight could not be loaded!"
+ + " You might try to download the pre-trained weights from the url "
+ + url
+ + " and copy it to the ",
+ exact_file,
+ "manually.",
+ )
model.load_weights(exact_file)
return model
-def build_model():
- data = Input(dtype=tf.float32, shape=(None, None, 3), name='data')
+def build_model() -> Model:
+ """
+ Build RetinaFace model
+ """
+ data = Input(dtype=tf.float32, shape=(None, None, 3), name="data")
- bn_data = BatchNormalization(epsilon=1.9999999494757503e-05, name='bn_data', trainable=False)(data)
+ bn_data = BatchNormalization(epsilon=1.9999999494757503e-05, name="bn_data", trainable=False)(
+ data
+ )
conv0_pad = ZeroPadding2D(padding=tuple([3, 3]))(bn_data)
- conv0 = Conv2D(filters = 64, kernel_size = (7, 7), name = 'conv0', strides = [2, 2], padding = 'VALID', use_bias = False)(conv0_pad)
+ conv0 = Conv2D(
+ filters=64,
+ kernel_size=(7, 7),
+ name="conv0",
+ strides=[2, 2],
+ padding="VALID",
+ use_bias=False,
+ )(conv0_pad)
- bn0 = BatchNormalization(epsilon=1.9999999494757503e-05, name='bn0', trainable=False)(conv0)
+ bn0 = BatchNormalization(epsilon=1.9999999494757503e-05, name="bn0", trainable=False)(conv0)
- relu0 = ReLU(name='relu0')(bn0)
+ relu0 = ReLU(name="relu0")(bn0)
pooling0_pad = ZeroPadding2D(padding=tuple([1, 1]))(relu0)
- pooling0 = MaxPool2D((3, 3), (2, 2), padding='VALID', name='pooling0')(pooling0_pad)
+ pooling0 = MaxPool2D((3, 3), (2, 2), padding="VALID", name="pooling0")(pooling0_pad)
- stage1_unit1_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit1_bn1', trainable=False)(pooling0)
+ stage1_unit1_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit1_bn1", trainable=False
+ )(pooling0)
- stage1_unit1_relu1 = ReLU(name='stage1_unit1_relu1')(stage1_unit1_bn1)
+ stage1_unit1_relu1 = ReLU(name="stage1_unit1_relu1")(stage1_unit1_bn1)
- stage1_unit1_conv1 = Conv2D(filters = 64, kernel_size = (1, 1), name = 'stage1_unit1_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit1_relu1)
+ stage1_unit1_conv1 = Conv2D(
+ filters=64,
+ kernel_size=(1, 1),
+ name="stage1_unit1_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit1_relu1)
- stage1_unit1_sc = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage1_unit1_sc', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit1_relu1)
+ stage1_unit1_sc = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage1_unit1_sc",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit1_relu1)
- stage1_unit1_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit1_bn2', trainable=False)(stage1_unit1_conv1)
+ stage1_unit1_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit1_bn2", trainable=False
+ )(stage1_unit1_conv1)
- stage1_unit1_relu2 = ReLU(name='stage1_unit1_relu2')(stage1_unit1_bn2)
+ stage1_unit1_relu2 = ReLU(name="stage1_unit1_relu2")(stage1_unit1_bn2)
stage1_unit1_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage1_unit1_relu2)
- stage1_unit1_conv2 = Conv2D(filters = 64, kernel_size = (3, 3), name = 'stage1_unit1_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit1_conv2_pad)
-
- stage1_unit1_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit1_bn3', trainable=False)(stage1_unit1_conv2)
-
- stage1_unit1_relu3 = ReLU(name='stage1_unit1_relu3')(stage1_unit1_bn3)
-
- stage1_unit1_conv3 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage1_unit1_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit1_relu3)
-
- plus0_v1 = Add()([stage1_unit1_conv3 , stage1_unit1_sc])
-
- stage1_unit2_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit2_bn1', trainable=False)(plus0_v1)
-
- stage1_unit2_relu1 = ReLU(name='stage1_unit2_relu1')(stage1_unit2_bn1)
-
- stage1_unit2_conv1 = Conv2D(filters = 64, kernel_size = (1, 1), name = 'stage1_unit2_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit2_relu1)
-
- stage1_unit2_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit2_bn2', trainable=False)(stage1_unit2_conv1)
-
- stage1_unit2_relu2 = ReLU(name='stage1_unit2_relu2')(stage1_unit2_bn2)
+ stage1_unit1_conv2 = Conv2D(
+ filters=64,
+ kernel_size=(3, 3),
+ name="stage1_unit1_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit1_conv2_pad)
+
+ stage1_unit1_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit1_bn3", trainable=False
+ )(stage1_unit1_conv2)
+
+ stage1_unit1_relu3 = ReLU(name="stage1_unit1_relu3")(stage1_unit1_bn3)
+
+ stage1_unit1_conv3 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage1_unit1_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit1_relu3)
+
+ plus0_v1 = Add()([stage1_unit1_conv3, stage1_unit1_sc])
+
+ stage1_unit2_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit2_bn1", trainable=False
+ )(plus0_v1)
+
+ stage1_unit2_relu1 = ReLU(name="stage1_unit2_relu1")(stage1_unit2_bn1)
+
+ stage1_unit2_conv1 = Conv2D(
+ filters=64,
+ kernel_size=(1, 1),
+ name="stage1_unit2_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit2_relu1)
+
+ stage1_unit2_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit2_bn2", trainable=False
+ )(stage1_unit2_conv1)
+
+ stage1_unit2_relu2 = ReLU(name="stage1_unit2_relu2")(stage1_unit2_bn2)
stage1_unit2_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage1_unit2_relu2)
- stage1_unit2_conv2 = Conv2D(filters = 64, kernel_size = (3, 3), name = 'stage1_unit2_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit2_conv2_pad)
-
- stage1_unit2_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit2_bn3', trainable=False)(stage1_unit2_conv2)
-
- stage1_unit2_relu3 = ReLU(name='stage1_unit2_relu3')(stage1_unit2_bn3)
-
- stage1_unit2_conv3 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage1_unit2_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit2_relu3)
-
- plus1_v2 = Add()([stage1_unit2_conv3 , plus0_v1])
-
- stage1_unit3_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit3_bn1', trainable=False)(plus1_v2)
-
- stage1_unit3_relu1 = ReLU(name='stage1_unit3_relu1')(stage1_unit3_bn1)
-
- stage1_unit3_conv1 = Conv2D(filters = 64, kernel_size = (1, 1), name = 'stage1_unit3_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit3_relu1)
-
- stage1_unit3_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit3_bn2', trainable=False)(stage1_unit3_conv1)
-
- stage1_unit3_relu2 = ReLU(name='stage1_unit3_relu2')(stage1_unit3_bn2)
+ stage1_unit2_conv2 = Conv2D(
+ filters=64,
+ kernel_size=(3, 3),
+ name="stage1_unit2_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit2_conv2_pad)
+
+ stage1_unit2_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit2_bn3", trainable=False
+ )(stage1_unit2_conv2)
+
+ stage1_unit2_relu3 = ReLU(name="stage1_unit2_relu3")(stage1_unit2_bn3)
+
+ stage1_unit2_conv3 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage1_unit2_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit2_relu3)
+
+ plus1_v2 = Add()([stage1_unit2_conv3, plus0_v1])
+
+ stage1_unit3_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit3_bn1", trainable=False
+ )(plus1_v2)
+
+ stage1_unit3_relu1 = ReLU(name="stage1_unit3_relu1")(stage1_unit3_bn1)
+
+ stage1_unit3_conv1 = Conv2D(
+ filters=64,
+ kernel_size=(1, 1),
+ name="stage1_unit3_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit3_relu1)
+
+ stage1_unit3_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit3_bn2", trainable=False
+ )(stage1_unit3_conv1)
+
+ stage1_unit3_relu2 = ReLU(name="stage1_unit3_relu2")(stage1_unit3_bn2)
stage1_unit3_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage1_unit3_relu2)
- stage1_unit3_conv2 = Conv2D(filters = 64, kernel_size = (3, 3), name = 'stage1_unit3_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit3_conv2_pad)
-
- stage1_unit3_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage1_unit3_bn3', trainable=False)(stage1_unit3_conv2)
-
- stage1_unit3_relu3 = ReLU(name='stage1_unit3_relu3')(stage1_unit3_bn3)
-
- stage1_unit3_conv3 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage1_unit3_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage1_unit3_relu3)
-
- plus2 = Add()([stage1_unit3_conv3 , plus1_v2])
-
- stage2_unit1_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit1_bn1', trainable=False)(plus2)
-
- stage2_unit1_relu1 = ReLU(name='stage2_unit1_relu1')(stage2_unit1_bn1)
-
- stage2_unit1_conv1 = Conv2D(filters = 128, kernel_size = (1, 1), name = 'stage2_unit1_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit1_relu1)
-
- stage2_unit1_sc = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage2_unit1_sc', strides = [2, 2], padding = 'VALID', use_bias = False)(stage2_unit1_relu1)
-
- stage2_unit1_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit1_bn2', trainable=False)(stage2_unit1_conv1)
-
- stage2_unit1_relu2 = ReLU(name='stage2_unit1_relu2')(stage2_unit1_bn2)
+ stage1_unit3_conv2 = Conv2D(
+ filters=64,
+ kernel_size=(3, 3),
+ name="stage1_unit3_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit3_conv2_pad)
+
+ stage1_unit3_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage1_unit3_bn3", trainable=False
+ )(stage1_unit3_conv2)
+
+ stage1_unit3_relu3 = ReLU(name="stage1_unit3_relu3")(stage1_unit3_bn3)
+
+ stage1_unit3_conv3 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage1_unit3_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage1_unit3_relu3)
+
+ plus2 = Add()([stage1_unit3_conv3, plus1_v2])
+
+ stage2_unit1_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit1_bn1", trainable=False
+ )(plus2)
+
+ stage2_unit1_relu1 = ReLU(name="stage2_unit1_relu1")(stage2_unit1_bn1)
+
+ stage2_unit1_conv1 = Conv2D(
+ filters=128,
+ kernel_size=(1, 1),
+ name="stage2_unit1_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit1_relu1)
+
+ stage2_unit1_sc = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage2_unit1_sc",
+ strides=[2, 2],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit1_relu1)
+
+ stage2_unit1_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit1_bn2", trainable=False
+ )(stage2_unit1_conv1)
+
+ stage2_unit1_relu2 = ReLU(name="stage2_unit1_relu2")(stage2_unit1_bn2)
stage2_unit1_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage2_unit1_relu2)
- stage2_unit1_conv2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'stage2_unit1_conv2', strides = [2, 2], padding = 'VALID', use_bias = False)(stage2_unit1_conv2_pad)
-
- stage2_unit1_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit1_bn3', trainable=False)(stage2_unit1_conv2)
-
- stage2_unit1_relu3 = ReLU(name='stage2_unit1_relu3')(stage2_unit1_bn3)
-
- stage2_unit1_conv3 = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage2_unit1_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit1_relu3)
-
- plus3 = Add()([stage2_unit1_conv3 , stage2_unit1_sc])
-
- stage2_unit2_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit2_bn1', trainable=False)(plus3)
-
- stage2_unit2_relu1 = ReLU(name='stage2_unit2_relu1')(stage2_unit2_bn1)
-
- stage2_unit2_conv1 = Conv2D(filters = 128, kernel_size = (1, 1), name = 'stage2_unit2_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit2_relu1)
-
- stage2_unit2_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit2_bn2', trainable=False)(stage2_unit2_conv1)
-
- stage2_unit2_relu2 = ReLU(name='stage2_unit2_relu2')(stage2_unit2_bn2)
+ stage2_unit1_conv2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="stage2_unit1_conv2",
+ strides=[2, 2],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit1_conv2_pad)
+
+ stage2_unit1_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit1_bn3", trainable=False
+ )(stage2_unit1_conv2)
+
+ stage2_unit1_relu3 = ReLU(name="stage2_unit1_relu3")(stage2_unit1_bn3)
+
+ stage2_unit1_conv3 = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage2_unit1_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit1_relu3)
+
+ plus3 = Add()([stage2_unit1_conv3, stage2_unit1_sc])
+
+ stage2_unit2_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit2_bn1", trainable=False
+ )(plus3)
+
+ stage2_unit2_relu1 = ReLU(name="stage2_unit2_relu1")(stage2_unit2_bn1)
+
+ stage2_unit2_conv1 = Conv2D(
+ filters=128,
+ kernel_size=(1, 1),
+ name="stage2_unit2_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit2_relu1)
+
+ stage2_unit2_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit2_bn2", trainable=False
+ )(stage2_unit2_conv1)
+
+ stage2_unit2_relu2 = ReLU(name="stage2_unit2_relu2")(stage2_unit2_bn2)
stage2_unit2_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage2_unit2_relu2)
- stage2_unit2_conv2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'stage2_unit2_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit2_conv2_pad)
-
- stage2_unit2_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit2_bn3', trainable=False)(stage2_unit2_conv2)
-
- stage2_unit2_relu3 = ReLU(name='stage2_unit2_relu3')(stage2_unit2_bn3)
-
- stage2_unit2_conv3 = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage2_unit2_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit2_relu3)
-
- plus4 = Add()([stage2_unit2_conv3 , plus3])
-
- stage2_unit3_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit3_bn1', trainable=False)(plus4)
-
- stage2_unit3_relu1 = ReLU(name='stage2_unit3_relu1')(stage2_unit3_bn1)
-
- stage2_unit3_conv1 = Conv2D(filters = 128, kernel_size = (1, 1), name = 'stage2_unit3_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit3_relu1)
-
- stage2_unit3_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit3_bn2', trainable=False)(stage2_unit3_conv1)
-
- stage2_unit3_relu2 = ReLU(name='stage2_unit3_relu2')(stage2_unit3_bn2)
+ stage2_unit2_conv2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="stage2_unit2_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit2_conv2_pad)
+
+ stage2_unit2_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit2_bn3", trainable=False
+ )(stage2_unit2_conv2)
+
+ stage2_unit2_relu3 = ReLU(name="stage2_unit2_relu3")(stage2_unit2_bn3)
+
+ stage2_unit2_conv3 = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage2_unit2_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit2_relu3)
+
+ plus4 = Add()([stage2_unit2_conv3, plus3])
+
+ stage2_unit3_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit3_bn1", trainable=False
+ )(plus4)
+
+ stage2_unit3_relu1 = ReLU(name="stage2_unit3_relu1")(stage2_unit3_bn1)
+
+ stage2_unit3_conv1 = Conv2D(
+ filters=128,
+ kernel_size=(1, 1),
+ name="stage2_unit3_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit3_relu1)
+
+ stage2_unit3_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit3_bn2", trainable=False
+ )(stage2_unit3_conv1)
+
+ stage2_unit3_relu2 = ReLU(name="stage2_unit3_relu2")(stage2_unit3_bn2)
stage2_unit3_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage2_unit3_relu2)
- stage2_unit3_conv2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'stage2_unit3_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit3_conv2_pad)
-
- stage2_unit3_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit3_bn3', trainable=False)(stage2_unit3_conv2)
-
- stage2_unit3_relu3 = ReLU(name='stage2_unit3_relu3')(stage2_unit3_bn3)
-
- stage2_unit3_conv3 = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage2_unit3_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit3_relu3)
-
- plus5 = Add()([stage2_unit3_conv3 , plus4])
-
- stage2_unit4_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit4_bn1', trainable=False)(plus5)
-
- stage2_unit4_relu1 = ReLU(name='stage2_unit4_relu1')(stage2_unit4_bn1)
-
- stage2_unit4_conv1 = Conv2D(filters = 128, kernel_size = (1, 1), name = 'stage2_unit4_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit4_relu1)
-
- stage2_unit4_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit4_bn2', trainable=False)(stage2_unit4_conv1)
-
- stage2_unit4_relu2 = ReLU(name='stage2_unit4_relu2')(stage2_unit4_bn2)
+ stage2_unit3_conv2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="stage2_unit3_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit3_conv2_pad)
+
+ stage2_unit3_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit3_bn3", trainable=False
+ )(stage2_unit3_conv2)
+
+ stage2_unit3_relu3 = ReLU(name="stage2_unit3_relu3")(stage2_unit3_bn3)
+
+ stage2_unit3_conv3 = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage2_unit3_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit3_relu3)
+
+ plus5 = Add()([stage2_unit3_conv3, plus4])
+
+ stage2_unit4_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit4_bn1", trainable=False
+ )(plus5)
+
+ stage2_unit4_relu1 = ReLU(name="stage2_unit4_relu1")(stage2_unit4_bn1)
+
+ stage2_unit4_conv1 = Conv2D(
+ filters=128,
+ kernel_size=(1, 1),
+ name="stage2_unit4_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit4_relu1)
+
+ stage2_unit4_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit4_bn2", trainable=False
+ )(stage2_unit4_conv1)
+
+ stage2_unit4_relu2 = ReLU(name="stage2_unit4_relu2")(stage2_unit4_bn2)
stage2_unit4_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage2_unit4_relu2)
- stage2_unit4_conv2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'stage2_unit4_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit4_conv2_pad)
-
- stage2_unit4_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage2_unit4_bn3', trainable=False)(stage2_unit4_conv2)
-
- stage2_unit4_relu3 = ReLU(name='stage2_unit4_relu3')(stage2_unit4_bn3)
-
- stage2_unit4_conv3 = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage2_unit4_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage2_unit4_relu3)
-
- plus6 = Add()([stage2_unit4_conv3 , plus5])
-
- stage3_unit1_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit1_bn1', trainable=False)(plus6)
-
- stage3_unit1_relu1 = ReLU(name='stage3_unit1_relu1')(stage3_unit1_bn1)
-
- stage3_unit1_conv1 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage3_unit1_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit1_relu1)
-
- stage3_unit1_sc = Conv2D(filters = 1024, kernel_size = (1, 1), name = 'stage3_unit1_sc', strides = [2, 2], padding = 'VALID', use_bias = False)(stage3_unit1_relu1)
-
- stage3_unit1_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit1_bn2', trainable=False)(stage3_unit1_conv1)
-
- stage3_unit1_relu2 = ReLU(name='stage3_unit1_relu2')(stage3_unit1_bn2)
+ stage2_unit4_conv2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="stage2_unit4_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit4_conv2_pad)
+
+ stage2_unit4_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage2_unit4_bn3", trainable=False
+ )(stage2_unit4_conv2)
+
+ stage2_unit4_relu3 = ReLU(name="stage2_unit4_relu3")(stage2_unit4_bn3)
+
+ stage2_unit4_conv3 = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage2_unit4_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage2_unit4_relu3)
+
+ plus6 = Add()([stage2_unit4_conv3, plus5])
+
+ stage3_unit1_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit1_bn1", trainable=False
+ )(plus6)
+
+ stage3_unit1_relu1 = ReLU(name="stage3_unit1_relu1")(stage3_unit1_bn1)
+
+ stage3_unit1_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage3_unit1_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit1_relu1)
+
+ stage3_unit1_sc = Conv2D(
+ filters=1024,
+ kernel_size=(1, 1),
+ name="stage3_unit1_sc",
+ strides=[2, 2],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit1_relu1)
+
+ stage3_unit1_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit1_bn2", trainable=False
+ )(stage3_unit1_conv1)
+
+ stage3_unit1_relu2 = ReLU(name="stage3_unit1_relu2")(stage3_unit1_bn2)
stage3_unit1_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage3_unit1_relu2)
- stage3_unit1_conv2 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'stage3_unit1_conv2', strides = [2, 2], padding = 'VALID', use_bias = False)(stage3_unit1_conv2_pad)
-
- ssh_m1_red_conv = Conv2D(filters = 256, kernel_size = (1, 1), name = 'ssh_m1_red_conv', strides = [1, 1], padding = 'VALID', use_bias = True)(stage3_unit1_relu2)
-
- stage3_unit1_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit1_bn3', trainable=False)(stage3_unit1_conv2)
-
- ssh_m1_red_conv_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m1_red_conv_bn', trainable=False)(ssh_m1_red_conv)
-
- stage3_unit1_relu3 = ReLU(name='stage3_unit1_relu3')(stage3_unit1_bn3)
-
- ssh_m1_red_conv_relu = ReLU(name='ssh_m1_red_conv_relu')(ssh_m1_red_conv_bn)
-
- stage3_unit1_conv3 = Conv2D(filters = 1024, kernel_size = (1, 1), name = 'stage3_unit1_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit1_relu3)
-
- plus7 = Add()([stage3_unit1_conv3 , stage3_unit1_sc])
-
- stage3_unit2_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit2_bn1', trainable=False)(plus7)
-
- stage3_unit2_relu1 = ReLU(name='stage3_unit2_relu1')(stage3_unit2_bn1)
-
- stage3_unit2_conv1 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage3_unit2_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit2_relu1)
-
- stage3_unit2_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit2_bn2', trainable=False)(stage3_unit2_conv1)
-
- stage3_unit2_relu2 = ReLU(name='stage3_unit2_relu2')(stage3_unit2_bn2)
+ stage3_unit1_conv2 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="stage3_unit1_conv2",
+ strides=[2, 2],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit1_conv2_pad)
+
+ ssh_m1_red_conv = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="ssh_m1_red_conv",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(stage3_unit1_relu2)
+
+ stage3_unit1_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit1_bn3", trainable=False
+ )(stage3_unit1_conv2)
+
+ ssh_m1_red_conv_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m1_red_conv_bn", trainable=False
+ )(ssh_m1_red_conv)
+
+ stage3_unit1_relu3 = ReLU(name="stage3_unit1_relu3")(stage3_unit1_bn3)
+
+ ssh_m1_red_conv_relu = ReLU(name="ssh_m1_red_conv_relu")(ssh_m1_red_conv_bn)
+
+ stage3_unit1_conv3 = Conv2D(
+ filters=1024,
+ kernel_size=(1, 1),
+ name="stage3_unit1_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit1_relu3)
+
+ plus7 = Add()([stage3_unit1_conv3, stage3_unit1_sc])
+
+ stage3_unit2_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit2_bn1", trainable=False
+ )(plus7)
+
+ stage3_unit2_relu1 = ReLU(name="stage3_unit2_relu1")(stage3_unit2_bn1)
+
+ stage3_unit2_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage3_unit2_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit2_relu1)
+
+ stage3_unit2_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit2_bn2", trainable=False
+ )(stage3_unit2_conv1)
+
+ stage3_unit2_relu2 = ReLU(name="stage3_unit2_relu2")(stage3_unit2_bn2)
stage3_unit2_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage3_unit2_relu2)
- stage3_unit2_conv2 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'stage3_unit2_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit2_conv2_pad)
-
- stage3_unit2_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit2_bn3', trainable=False)(stage3_unit2_conv2)
-
- stage3_unit2_relu3 = ReLU(name='stage3_unit2_relu3')(stage3_unit2_bn3)
-
- stage3_unit2_conv3 = Conv2D(filters = 1024, kernel_size = (1, 1), name = 'stage3_unit2_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit2_relu3)
-
- plus8 = Add()([stage3_unit2_conv3 , plus7])
-
- stage3_unit3_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit3_bn1', trainable=False)(plus8)
-
- stage3_unit3_relu1 = ReLU(name='stage3_unit3_relu1')(stage3_unit3_bn1)
-
- stage3_unit3_conv1 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage3_unit3_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit3_relu1)
-
- stage3_unit3_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit3_bn2', trainable=False)(stage3_unit3_conv1)
-
- stage3_unit3_relu2 = ReLU(name='stage3_unit3_relu2')(stage3_unit3_bn2)
+ stage3_unit2_conv2 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="stage3_unit2_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit2_conv2_pad)
+
+ stage3_unit2_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit2_bn3", trainable=False
+ )(stage3_unit2_conv2)
+
+ stage3_unit2_relu3 = ReLU(name="stage3_unit2_relu3")(stage3_unit2_bn3)
+
+ stage3_unit2_conv3 = Conv2D(
+ filters=1024,
+ kernel_size=(1, 1),
+ name="stage3_unit2_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit2_relu3)
+
+ plus8 = Add()([stage3_unit2_conv3, plus7])
+
+ stage3_unit3_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit3_bn1", trainable=False
+ )(plus8)
+
+ stage3_unit3_relu1 = ReLU(name="stage3_unit3_relu1")(stage3_unit3_bn1)
+
+ stage3_unit3_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage3_unit3_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit3_relu1)
+
+ stage3_unit3_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit3_bn2", trainable=False
+ )(stage3_unit3_conv1)
+
+ stage3_unit3_relu2 = ReLU(name="stage3_unit3_relu2")(stage3_unit3_bn2)
stage3_unit3_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage3_unit3_relu2)
- stage3_unit3_conv2 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'stage3_unit3_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit3_conv2_pad)
-
- stage3_unit3_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit3_bn3', trainable=False)(stage3_unit3_conv2)
-
- stage3_unit3_relu3 = ReLU(name='stage3_unit3_relu3')(stage3_unit3_bn3)
-
- stage3_unit3_conv3 = Conv2D(filters = 1024, kernel_size = (1, 1), name = 'stage3_unit3_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit3_relu3)
-
- plus9 = Add()([stage3_unit3_conv3 , plus8])
-
- stage3_unit4_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit4_bn1', trainable=False)(plus9)
-
- stage3_unit4_relu1 = ReLU(name='stage3_unit4_relu1')(stage3_unit4_bn1)
-
- stage3_unit4_conv1 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage3_unit4_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit4_relu1)
-
- stage3_unit4_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit4_bn2', trainable=False)(stage3_unit4_conv1)
-
- stage3_unit4_relu2 = ReLU(name='stage3_unit4_relu2')(stage3_unit4_bn2)
+ stage3_unit3_conv2 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="stage3_unit3_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit3_conv2_pad)
+
+ stage3_unit3_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit3_bn3", trainable=False
+ )(stage3_unit3_conv2)
+
+ stage3_unit3_relu3 = ReLU(name="stage3_unit3_relu3")(stage3_unit3_bn3)
+
+ stage3_unit3_conv3 = Conv2D(
+ filters=1024,
+ kernel_size=(1, 1),
+ name="stage3_unit3_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit3_relu3)
+
+ plus9 = Add()([stage3_unit3_conv3, plus8])
+
+ stage3_unit4_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit4_bn1", trainable=False
+ )(plus9)
+
+ stage3_unit4_relu1 = ReLU(name="stage3_unit4_relu1")(stage3_unit4_bn1)
+
+ stage3_unit4_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage3_unit4_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit4_relu1)
+
+ stage3_unit4_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit4_bn2", trainable=False
+ )(stage3_unit4_conv1)
+
+ stage3_unit4_relu2 = ReLU(name="stage3_unit4_relu2")(stage3_unit4_bn2)
stage3_unit4_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage3_unit4_relu2)
- stage3_unit4_conv2 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'stage3_unit4_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit4_conv2_pad)
-
- stage3_unit4_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit4_bn3', trainable=False)(stage3_unit4_conv2)
-
- stage3_unit4_relu3 = ReLU(name='stage3_unit4_relu3')(stage3_unit4_bn3)
-
- stage3_unit4_conv3 = Conv2D(filters = 1024, kernel_size = (1, 1), name = 'stage3_unit4_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit4_relu3)
-
- plus10 = Add()([stage3_unit4_conv3 , plus9])
-
- stage3_unit5_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit5_bn1', trainable=False)(plus10)
-
- stage3_unit5_relu1 = ReLU(name='stage3_unit5_relu1')(stage3_unit5_bn1)
-
- stage3_unit5_conv1 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage3_unit5_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit5_relu1)
-
- stage3_unit5_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit5_bn2', trainable=False)(stage3_unit5_conv1)
-
- stage3_unit5_relu2 = ReLU(name='stage3_unit5_relu2')(stage3_unit5_bn2)
+ stage3_unit4_conv2 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="stage3_unit4_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit4_conv2_pad)
+
+ stage3_unit4_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit4_bn3", trainable=False
+ )(stage3_unit4_conv2)
+
+ stage3_unit4_relu3 = ReLU(name="stage3_unit4_relu3")(stage3_unit4_bn3)
+
+ stage3_unit4_conv3 = Conv2D(
+ filters=1024,
+ kernel_size=(1, 1),
+ name="stage3_unit4_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit4_relu3)
+
+ plus10 = Add()([stage3_unit4_conv3, plus9])
+
+ stage3_unit5_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit5_bn1", trainable=False
+ )(plus10)
+
+ stage3_unit5_relu1 = ReLU(name="stage3_unit5_relu1")(stage3_unit5_bn1)
+
+ stage3_unit5_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage3_unit5_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit5_relu1)
+
+ stage3_unit5_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit5_bn2", trainable=False
+ )(stage3_unit5_conv1)
+
+ stage3_unit5_relu2 = ReLU(name="stage3_unit5_relu2")(stage3_unit5_bn2)
stage3_unit5_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage3_unit5_relu2)
- stage3_unit5_conv2 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'stage3_unit5_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit5_conv2_pad)
-
- stage3_unit5_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit5_bn3', trainable=False)(stage3_unit5_conv2)
-
- stage3_unit5_relu3 = ReLU(name='stage3_unit5_relu3')(stage3_unit5_bn3)
-
- stage3_unit5_conv3 = Conv2D(filters = 1024, kernel_size = (1, 1), name = 'stage3_unit5_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit5_relu3)
-
- plus11 = Add()([stage3_unit5_conv3 , plus10])
-
- stage3_unit6_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit6_bn1', trainable=False)(plus11)
-
- stage3_unit6_relu1 = ReLU(name='stage3_unit6_relu1')(stage3_unit6_bn1)
-
- stage3_unit6_conv1 = Conv2D(filters = 256, kernel_size = (1, 1), name = 'stage3_unit6_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit6_relu1)
-
- stage3_unit6_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit6_bn2', trainable=False)(stage3_unit6_conv1)
-
- stage3_unit6_relu2 = ReLU(name='stage3_unit6_relu2')(stage3_unit6_bn2)
+ stage3_unit5_conv2 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="stage3_unit5_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit5_conv2_pad)
+
+ stage3_unit5_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit5_bn3", trainable=False
+ )(stage3_unit5_conv2)
+
+ stage3_unit5_relu3 = ReLU(name="stage3_unit5_relu3")(stage3_unit5_bn3)
+
+ stage3_unit5_conv3 = Conv2D(
+ filters=1024,
+ kernel_size=(1, 1),
+ name="stage3_unit5_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit5_relu3)
+
+ plus11 = Add()([stage3_unit5_conv3, plus10])
+
+ stage3_unit6_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit6_bn1", trainable=False
+ )(plus11)
+
+ stage3_unit6_relu1 = ReLU(name="stage3_unit6_relu1")(stage3_unit6_bn1)
+
+ stage3_unit6_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="stage3_unit6_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit6_relu1)
+
+ stage3_unit6_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit6_bn2", trainable=False
+ )(stage3_unit6_conv1)
+
+ stage3_unit6_relu2 = ReLU(name="stage3_unit6_relu2")(stage3_unit6_bn2)
stage3_unit6_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage3_unit6_relu2)
- stage3_unit6_conv2 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'stage3_unit6_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit6_conv2_pad)
-
- stage3_unit6_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage3_unit6_bn3', trainable=False)(stage3_unit6_conv2)
-
- stage3_unit6_relu3 = ReLU(name='stage3_unit6_relu3')(stage3_unit6_bn3)
-
- stage3_unit6_conv3 = Conv2D(filters = 1024, kernel_size = (1, 1), name = 'stage3_unit6_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage3_unit6_relu3)
-
- plus12 = Add()([stage3_unit6_conv3 , plus11])
-
- stage4_unit1_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit1_bn1', trainable=False)(plus12)
-
- stage4_unit1_relu1 = ReLU(name='stage4_unit1_relu1')(stage4_unit1_bn1)
-
- stage4_unit1_conv1 = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage4_unit1_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit1_relu1)
-
- stage4_unit1_sc = Conv2D(filters = 2048, kernel_size = (1, 1), name = 'stage4_unit1_sc', strides = [2, 2], padding = 'VALID', use_bias = False)(stage4_unit1_relu1)
-
- stage4_unit1_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit1_bn2', trainable=False)(stage4_unit1_conv1)
-
- stage4_unit1_relu2 = ReLU(name='stage4_unit1_relu2')(stage4_unit1_bn2)
+ stage3_unit6_conv2 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="stage3_unit6_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit6_conv2_pad)
+
+ stage3_unit6_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage3_unit6_bn3", trainable=False
+ )(stage3_unit6_conv2)
+
+ stage3_unit6_relu3 = ReLU(name="stage3_unit6_relu3")(stage3_unit6_bn3)
+
+ stage3_unit6_conv3 = Conv2D(
+ filters=1024,
+ kernel_size=(1, 1),
+ name="stage3_unit6_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage3_unit6_relu3)
+
+ plus12 = Add()([stage3_unit6_conv3, plus11])
+
+ stage4_unit1_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit1_bn1", trainable=False
+ )(plus12)
+
+ stage4_unit1_relu1 = ReLU(name="stage4_unit1_relu1")(stage4_unit1_bn1)
+
+ stage4_unit1_conv1 = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage4_unit1_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit1_relu1)
+
+ stage4_unit1_sc = Conv2D(
+ filters=2048,
+ kernel_size=(1, 1),
+ name="stage4_unit1_sc",
+ strides=[2, 2],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit1_relu1)
+
+ stage4_unit1_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit1_bn2", trainable=False
+ )(stage4_unit1_conv1)
+
+ stage4_unit1_relu2 = ReLU(name="stage4_unit1_relu2")(stage4_unit1_bn2)
stage4_unit1_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage4_unit1_relu2)
- stage4_unit1_conv2 = Conv2D(filters = 512, kernel_size = (3, 3), name = 'stage4_unit1_conv2', strides = [2, 2], padding = 'VALID', use_bias = False)(stage4_unit1_conv2_pad)
-
- ssh_c2_lateral = Conv2D(filters = 256, kernel_size = (1, 1), name = 'ssh_c2_lateral', strides = [1, 1], padding = 'VALID', use_bias = True)(stage4_unit1_relu2)
-
- stage4_unit1_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit1_bn3', trainable=False)(stage4_unit1_conv2)
-
- ssh_c2_lateral_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_c2_lateral_bn', trainable=False)(ssh_c2_lateral)
-
- stage4_unit1_relu3 = ReLU(name='stage4_unit1_relu3')(stage4_unit1_bn3)
-
- ssh_c2_lateral_relu = ReLU(name='ssh_c2_lateral_relu')(ssh_c2_lateral_bn)
-
- stage4_unit1_conv3 = Conv2D(filters = 2048, kernel_size = (1, 1), name = 'stage4_unit1_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit1_relu3)
-
- plus13 = Add()([stage4_unit1_conv3 , stage4_unit1_sc])
-
- stage4_unit2_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit2_bn1', trainable=False)(plus13)
-
- stage4_unit2_relu1 = ReLU(name='stage4_unit2_relu1')(stage4_unit2_bn1)
-
- stage4_unit2_conv1 = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage4_unit2_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit2_relu1)
-
- stage4_unit2_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit2_bn2', trainable=False)(stage4_unit2_conv1)
-
- stage4_unit2_relu2 = ReLU(name='stage4_unit2_relu2')(stage4_unit2_bn2)
+ stage4_unit1_conv2 = Conv2D(
+ filters=512,
+ kernel_size=(3, 3),
+ name="stage4_unit1_conv2",
+ strides=[2, 2],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit1_conv2_pad)
+
+ ssh_c2_lateral = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="ssh_c2_lateral",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(stage4_unit1_relu2)
+
+ stage4_unit1_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit1_bn3", trainable=False
+ )(stage4_unit1_conv2)
+
+ ssh_c2_lateral_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_c2_lateral_bn", trainable=False
+ )(ssh_c2_lateral)
+
+ stage4_unit1_relu3 = ReLU(name="stage4_unit1_relu3")(stage4_unit1_bn3)
+
+ ssh_c2_lateral_relu = ReLU(name="ssh_c2_lateral_relu")(ssh_c2_lateral_bn)
+
+ stage4_unit1_conv3 = Conv2D(
+ filters=2048,
+ kernel_size=(1, 1),
+ name="stage4_unit1_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit1_relu3)
+
+ plus13 = Add()([stage4_unit1_conv3, stage4_unit1_sc])
+
+ stage4_unit2_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit2_bn1", trainable=False
+ )(plus13)
+
+ stage4_unit2_relu1 = ReLU(name="stage4_unit2_relu1")(stage4_unit2_bn1)
+
+ stage4_unit2_conv1 = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage4_unit2_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit2_relu1)
+
+ stage4_unit2_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit2_bn2", trainable=False
+ )(stage4_unit2_conv1)
+
+ stage4_unit2_relu2 = ReLU(name="stage4_unit2_relu2")(stage4_unit2_bn2)
stage4_unit2_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage4_unit2_relu2)
- stage4_unit2_conv2 = Conv2D(filters = 512, kernel_size = (3, 3), name = 'stage4_unit2_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit2_conv2_pad)
-
- stage4_unit2_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit2_bn3', trainable=False)(stage4_unit2_conv2)
-
- stage4_unit2_relu3 = ReLU(name='stage4_unit2_relu3')(stage4_unit2_bn3)
-
- stage4_unit2_conv3 = Conv2D(filters = 2048, kernel_size = (1, 1), name = 'stage4_unit2_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit2_relu3)
-
- plus14 = Add()([stage4_unit2_conv3 , plus13])
-
- stage4_unit3_bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit3_bn1', trainable=False)(plus14)
-
- stage4_unit3_relu1 = ReLU(name='stage4_unit3_relu1')(stage4_unit3_bn1)
-
- stage4_unit3_conv1 = Conv2D(filters = 512, kernel_size = (1, 1), name = 'stage4_unit3_conv1', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit3_relu1)
-
- stage4_unit3_bn2 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit3_bn2', trainable=False)(stage4_unit3_conv1)
-
- stage4_unit3_relu2 = ReLU(name='stage4_unit3_relu2')(stage4_unit3_bn2)
+ stage4_unit2_conv2 = Conv2D(
+ filters=512,
+ kernel_size=(3, 3),
+ name="stage4_unit2_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit2_conv2_pad)
+
+ stage4_unit2_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit2_bn3", trainable=False
+ )(stage4_unit2_conv2)
+
+ stage4_unit2_relu3 = ReLU(name="stage4_unit2_relu3")(stage4_unit2_bn3)
+
+ stage4_unit2_conv3 = Conv2D(
+ filters=2048,
+ kernel_size=(1, 1),
+ name="stage4_unit2_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit2_relu3)
+
+ plus14 = Add()([stage4_unit2_conv3, plus13])
+
+ stage4_unit3_bn1 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit3_bn1", trainable=False
+ )(plus14)
+
+ stage4_unit3_relu1 = ReLU(name="stage4_unit3_relu1")(stage4_unit3_bn1)
+
+ stage4_unit3_conv1 = Conv2D(
+ filters=512,
+ kernel_size=(1, 1),
+ name="stage4_unit3_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit3_relu1)
+
+ stage4_unit3_bn2 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit3_bn2", trainable=False
+ )(stage4_unit3_conv1)
+
+ stage4_unit3_relu2 = ReLU(name="stage4_unit3_relu2")(stage4_unit3_bn2)
stage4_unit3_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(stage4_unit3_relu2)
- stage4_unit3_conv2 = Conv2D(filters = 512, kernel_size = (3, 3), name = 'stage4_unit3_conv2', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit3_conv2_pad)
+ stage4_unit3_conv2 = Conv2D(
+ filters=512,
+ kernel_size=(3, 3),
+ name="stage4_unit3_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit3_conv2_pad)
- stage4_unit3_bn3 = BatchNormalization(epsilon=1.9999999494757503e-05, name='stage4_unit3_bn3', trainable=False)(stage4_unit3_conv2)
+ stage4_unit3_bn3 = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="stage4_unit3_bn3", trainable=False
+ )(stage4_unit3_conv2)
- stage4_unit3_relu3 = ReLU(name='stage4_unit3_relu3')(stage4_unit3_bn3)
+ stage4_unit3_relu3 = ReLU(name="stage4_unit3_relu3")(stage4_unit3_bn3)
- stage4_unit3_conv3 = Conv2D(filters = 2048, kernel_size = (1, 1), name = 'stage4_unit3_conv3', strides = [1, 1], padding = 'VALID', use_bias = False)(stage4_unit3_relu3)
+ stage4_unit3_conv3 = Conv2D(
+ filters=2048,
+ kernel_size=(1, 1),
+ name="stage4_unit3_conv3",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=False,
+ )(stage4_unit3_relu3)
- plus15 = Add()([stage4_unit3_conv3 , plus14])
+ plus15 = Add()([stage4_unit3_conv3, plus14])
- bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name='bn1', trainable=False)(plus15)
+ bn1 = BatchNormalization(epsilon=1.9999999494757503e-05, name="bn1", trainable=False)(plus15)
- relu1 = ReLU(name='relu1')(bn1)
+ relu1 = ReLU(name="relu1")(bn1)
- ssh_c3_lateral = Conv2D(filters = 256, kernel_size = (1, 1), name = 'ssh_c3_lateral', strides = [1, 1], padding = 'VALID', use_bias = True)(relu1)
+ ssh_c3_lateral = Conv2D(
+ filters=256,
+ kernel_size=(1, 1),
+ name="ssh_c3_lateral",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(relu1)
- ssh_c3_lateral_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_c3_lateral_bn', trainable=False)(ssh_c3_lateral)
+ ssh_c3_lateral_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_c3_lateral_bn", trainable=False
+ )(ssh_c3_lateral)
- ssh_c3_lateral_relu = ReLU(name='ssh_c3_lateral_relu')(ssh_c3_lateral_bn)
+ ssh_c3_lateral_relu = ReLU(name="ssh_c3_lateral_relu")(ssh_c3_lateral_bn)
ssh_m3_det_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c3_lateral_relu)
- ssh_m3_det_conv1 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'ssh_m3_det_conv1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_conv1_pad)
+ ssh_m3_det_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="ssh_m3_det_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_conv1_pad)
ssh_m3_det_context_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c3_lateral_relu)
- ssh_m3_det_context_conv1 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m3_det_context_conv1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_context_conv1_pad)
+ ssh_m3_det_context_conv1 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m3_det_context_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_context_conv1_pad)
- ssh_c3_up = UpSampling2D(size=(2, 2), interpolation="nearest", name="ssh_c3_up")(ssh_c3_lateral_relu)
+ ssh_c3_up = UpSampling2D(size=(2, 2), interpolation="nearest", name="ssh_c3_up")(
+ ssh_c3_lateral_relu
+ )
- ssh_m3_det_conv1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m3_det_conv1_bn', trainable=False)(ssh_m3_det_conv1)
+ ssh_m3_det_conv1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m3_det_conv1_bn", trainable=False
+ )(ssh_m3_det_conv1)
- ssh_m3_det_context_conv1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m3_det_context_conv1_bn', trainable=False)(ssh_m3_det_context_conv1)
+ ssh_m3_det_context_conv1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m3_det_context_conv1_bn", trainable=False
+ )(ssh_m3_det_context_conv1)
x1_shape = tf.shape(ssh_c3_up)
x2_shape = tf.shape(ssh_c2_lateral_relu)
@@ -470,51 +1030,117 @@ def build_model():
size = [-1, x2_shape[1], x2_shape[2], -1]
crop0 = tf.slice(ssh_c3_up, offsets, size, "crop0")
- ssh_m3_det_context_conv1_relu = ReLU(name='ssh_m3_det_context_conv1_relu')(ssh_m3_det_context_conv1_bn)
-
- plus0_v2 = Add()([ssh_c2_lateral_relu , crop0])
-
- ssh_m3_det_context_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m3_det_context_conv1_relu)
-
- ssh_m3_det_context_conv2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m3_det_context_conv2', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_context_conv2_pad)
-
- ssh_m3_det_context_conv3_1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m3_det_context_conv1_relu)
-
- ssh_m3_det_context_conv3_1 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m3_det_context_conv3_1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_context_conv3_1_pad)
+ ssh_m3_det_context_conv1_relu = ReLU(name="ssh_m3_det_context_conv1_relu")(
+ ssh_m3_det_context_conv1_bn
+ )
+
+ plus0_v2 = Add()([ssh_c2_lateral_relu, crop0])
+
+ ssh_m3_det_context_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m3_det_context_conv1_relu
+ )
+
+ ssh_m3_det_context_conv2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m3_det_context_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_context_conv2_pad)
+
+ ssh_m3_det_context_conv3_1_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m3_det_context_conv1_relu
+ )
+
+ ssh_m3_det_context_conv3_1 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m3_det_context_conv3_1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_context_conv3_1_pad)
ssh_c2_aggr_pad = ZeroPadding2D(padding=tuple([1, 1]))(plus0_v2)
- ssh_c2_aggr = Conv2D(filters = 256, kernel_size = (3, 3), name = 'ssh_c2_aggr', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_c2_aggr_pad)
-
- ssh_m3_det_context_conv2_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m3_det_context_conv2_bn', trainable=False)(ssh_m3_det_context_conv2)
-
- ssh_m3_det_context_conv3_1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m3_det_context_conv3_1_bn', trainable=False)(ssh_m3_det_context_conv3_1)
-
- ssh_c2_aggr_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_c2_aggr_bn', trainable=False)(ssh_c2_aggr)
-
- ssh_m3_det_context_conv3_1_relu = ReLU(name='ssh_m3_det_context_conv3_1_relu')(ssh_m3_det_context_conv3_1_bn)
-
- ssh_c2_aggr_relu = ReLU(name='ssh_c2_aggr_relu')(ssh_c2_aggr_bn)
-
- ssh_m3_det_context_conv3_2_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m3_det_context_conv3_1_relu)
-
- ssh_m3_det_context_conv3_2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m3_det_context_conv3_2', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_context_conv3_2_pad)
+ ssh_c2_aggr = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="ssh_c2_aggr",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_c2_aggr_pad)
+
+ ssh_m3_det_context_conv2_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m3_det_context_conv2_bn", trainable=False
+ )(ssh_m3_det_context_conv2)
+
+ ssh_m3_det_context_conv3_1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m3_det_context_conv3_1_bn", trainable=False
+ )(ssh_m3_det_context_conv3_1)
+
+ ssh_c2_aggr_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_c2_aggr_bn", trainable=False
+ )(ssh_c2_aggr)
+
+ ssh_m3_det_context_conv3_1_relu = ReLU(name="ssh_m3_det_context_conv3_1_relu")(
+ ssh_m3_det_context_conv3_1_bn
+ )
+
+ ssh_c2_aggr_relu = ReLU(name="ssh_c2_aggr_relu")(ssh_c2_aggr_bn)
+
+ ssh_m3_det_context_conv3_2_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m3_det_context_conv3_1_relu
+ )
+
+ ssh_m3_det_context_conv3_2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m3_det_context_conv3_2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_context_conv3_2_pad)
ssh_m2_det_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c2_aggr_relu)
- ssh_m2_det_conv1 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'ssh_m2_det_conv1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_conv1_pad)
+ ssh_m2_det_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="ssh_m2_det_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_conv1_pad)
ssh_m2_det_context_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c2_aggr_relu)
- ssh_m2_det_context_conv1 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m2_det_context_conv1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_context_conv1_pad)
+ ssh_m2_det_context_conv1 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m2_det_context_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_context_conv1_pad)
- ssh_m2_red_up = UpSampling2D(size=(2, 2), interpolation="nearest", name="ssh_m2_red_up")(ssh_c2_aggr_relu)
+ ssh_m2_red_up = UpSampling2D(size=(2, 2), interpolation="nearest", name="ssh_m2_red_up")(
+ ssh_c2_aggr_relu
+ )
- ssh_m3_det_context_conv3_2_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m3_det_context_conv3_2_bn', trainable=False)(ssh_m3_det_context_conv3_2)
+ ssh_m3_det_context_conv3_2_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m3_det_context_conv3_2_bn", trainable=False
+ )(ssh_m3_det_context_conv3_2)
- ssh_m2_det_conv1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m2_det_conv1_bn', trainable=False)(ssh_m2_det_conv1)
+ ssh_m2_det_conv1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m2_det_conv1_bn", trainable=False
+ )(ssh_m2_det_conv1)
- ssh_m2_det_context_conv1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m2_det_context_conv1_bn', trainable=False)(ssh_m2_det_context_conv1)
+ ssh_m2_det_context_conv1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m2_det_context_conv1_bn", trainable=False
+ )(ssh_m2_det_context_conv1)
x1_shape = tf.shape(ssh_m2_red_up)
x2_shape = tf.shape(ssh_m1_red_conv_relu)
@@ -522,48 +1148,116 @@ def build_model():
size = [-1, x2_shape[1], x2_shape[2], -1]
crop1 = tf.slice(ssh_m2_red_up, offsets, size, "crop1")
- ssh_m3_det_concat = concatenate([ssh_m3_det_conv1_bn, ssh_m3_det_context_conv2_bn, ssh_m3_det_context_conv3_2_bn], 3, name='ssh_m3_det_concat')
-
- ssh_m2_det_context_conv1_relu = ReLU(name='ssh_m2_det_context_conv1_relu')(ssh_m2_det_context_conv1_bn)
-
- plus1_v1 = Add()([ssh_m1_red_conv_relu , crop1])
-
- ssh_m3_det_concat_relu = ReLU(name='ssh_m3_det_concat_relu')(ssh_m3_det_concat)
-
- ssh_m2_det_context_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m2_det_context_conv1_relu)
-
- ssh_m2_det_context_conv2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m2_det_context_conv2', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_context_conv2_pad)
-
- ssh_m2_det_context_conv3_1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m2_det_context_conv1_relu)
-
- ssh_m2_det_context_conv3_1 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m2_det_context_conv3_1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_context_conv3_1_pad)
+ ssh_m3_det_concat = concatenate(
+ [ssh_m3_det_conv1_bn, ssh_m3_det_context_conv2_bn, ssh_m3_det_context_conv3_2_bn],
+ 3,
+ name="ssh_m3_det_concat",
+ )
+
+ ssh_m2_det_context_conv1_relu = ReLU(name="ssh_m2_det_context_conv1_relu")(
+ ssh_m2_det_context_conv1_bn
+ )
+
+ plus1_v1 = Add()([ssh_m1_red_conv_relu, crop1])
+
+ ssh_m3_det_concat_relu = ReLU(name="ssh_m3_det_concat_relu")(ssh_m3_det_concat)
+
+ ssh_m2_det_context_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m2_det_context_conv1_relu
+ )
+
+ ssh_m2_det_context_conv2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m2_det_context_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_context_conv2_pad)
+
+ ssh_m2_det_context_conv3_1_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m2_det_context_conv1_relu
+ )
+
+ ssh_m2_det_context_conv3_1 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m2_det_context_conv3_1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_context_conv3_1_pad)
ssh_c1_aggr_pad = ZeroPadding2D(padding=tuple([1, 1]))(plus1_v1)
- ssh_c1_aggr = Conv2D(filters = 256, kernel_size = (3, 3), name = 'ssh_c1_aggr', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_c1_aggr_pad)
-
- face_rpn_cls_score_stride32 = Conv2D(filters = 4, kernel_size = (1, 1), name = 'face_rpn_cls_score_stride32', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_concat_relu)
-
- inter_1 = concatenate([face_rpn_cls_score_stride32[:, :, :, 0], face_rpn_cls_score_stride32[:, :, :, 1]], axis=1)
- inter_2 = concatenate([face_rpn_cls_score_stride32[:, :, :, 2], face_rpn_cls_score_stride32[:, :, :, 3]], axis=1)
+ ssh_c1_aggr = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="ssh_c1_aggr",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_c1_aggr_pad)
+
+ face_rpn_cls_score_stride32 = Conv2D(
+ filters=4,
+ kernel_size=(1, 1),
+ name="face_rpn_cls_score_stride32",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_concat_relu)
+
+ inter_1 = concatenate(
+ [face_rpn_cls_score_stride32[:, :, :, 0], face_rpn_cls_score_stride32[:, :, :, 1]], axis=1
+ )
+ inter_2 = concatenate(
+ [face_rpn_cls_score_stride32[:, :, :, 2], face_rpn_cls_score_stride32[:, :, :, 3]], axis=1
+ )
final = tf.stack([inter_1, inter_2])
- face_rpn_cls_score_reshape_stride32 = tf.transpose(final, (1, 2, 3, 0), name="face_rpn_cls_score_reshape_stride32")
-
- face_rpn_bbox_pred_stride32 = Conv2D(filters = 8, kernel_size = (1, 1), name = 'face_rpn_bbox_pred_stride32', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_concat_relu)
-
- face_rpn_landmark_pred_stride32 = Conv2D(filters = 20, kernel_size = (1, 1), name = 'face_rpn_landmark_pred_stride32', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m3_det_concat_relu)
-
- ssh_m2_det_context_conv2_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m2_det_context_conv2_bn', trainable=False)(ssh_m2_det_context_conv2)
-
- ssh_m2_det_context_conv3_1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m2_det_context_conv3_1_bn', trainable=False)(ssh_m2_det_context_conv3_1)
-
- ssh_c1_aggr_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_c1_aggr_bn', trainable=False)(ssh_c1_aggr)
-
- ssh_m2_det_context_conv3_1_relu = ReLU(name='ssh_m2_det_context_conv3_1_relu')(ssh_m2_det_context_conv3_1_bn)
-
- ssh_c1_aggr_relu = ReLU(name='ssh_c1_aggr_relu')(ssh_c1_aggr_bn)
-
- face_rpn_cls_prob_stride32 = Softmax(name = 'face_rpn_cls_prob_stride32')(face_rpn_cls_score_reshape_stride32)
+ face_rpn_cls_score_reshape_stride32 = tf.transpose(
+ final, (1, 2, 3, 0), name="face_rpn_cls_score_reshape_stride32"
+ )
+
+ face_rpn_bbox_pred_stride32 = Conv2D(
+ filters=8,
+ kernel_size=(1, 1),
+ name="face_rpn_bbox_pred_stride32",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_concat_relu)
+
+ face_rpn_landmark_pred_stride32 = Conv2D(
+ filters=20,
+ kernel_size=(1, 1),
+ name="face_rpn_landmark_pred_stride32",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m3_det_concat_relu)
+
+ ssh_m2_det_context_conv2_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m2_det_context_conv2_bn", trainable=False
+ )(ssh_m2_det_context_conv2)
+
+ ssh_m2_det_context_conv3_1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m2_det_context_conv3_1_bn", trainable=False
+ )(ssh_m2_det_context_conv3_1)
+
+ ssh_c1_aggr_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_c1_aggr_bn", trainable=False
+ )(ssh_c1_aggr)
+
+ ssh_m2_det_context_conv3_1_relu = ReLU(name="ssh_m2_det_context_conv3_1_relu")(
+ ssh_m2_det_context_conv3_1_bn
+ )
+
+ ssh_c1_aggr_relu = ReLU(name="ssh_c1_aggr_relu")(ssh_c1_aggr_bn)
+
+ face_rpn_cls_prob_stride32 = Softmax(name="face_rpn_cls_prob_stride32")(
+ face_rpn_cls_score_reshape_stride32
+ )
input_shape = [tf.shape(face_rpn_cls_prob_stride32)[k] for k in range(4)]
sz = tf.dtypes.cast(input_shape[1] / 2, dtype=tf.int32)
@@ -572,58 +1266,148 @@ def build_model():
inter_3 = face_rpn_cls_prob_stride32[:, sz:, :, 0]
inter_4 = face_rpn_cls_prob_stride32[:, sz:, :, 1]
final = tf.stack([inter_1, inter_3, inter_2, inter_4])
- face_rpn_cls_prob_reshape_stride32 = tf.transpose(final, (1, 2, 3, 0), name="face_rpn_cls_prob_reshape_stride32")
-
- ssh_m2_det_context_conv3_2_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m2_det_context_conv3_1_relu)
-
- ssh_m2_det_context_conv3_2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m2_det_context_conv3_2', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_context_conv3_2_pad)
-
- ssh_m1_det_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c1_aggr_relu)
-
- ssh_m1_det_conv1 = Conv2D(filters = 256, kernel_size = (3, 3), name = 'ssh_m1_det_conv1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_conv1_pad)
-
- ssh_m1_det_context_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c1_aggr_relu)
-
- ssh_m1_det_context_conv1 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m1_det_context_conv1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_context_conv1_pad)
-
- ssh_m2_det_context_conv3_2_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m2_det_context_conv3_2_bn', trainable=False)(ssh_m2_det_context_conv3_2)
-
- ssh_m1_det_conv1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m1_det_conv1_bn', trainable=False)(ssh_m1_det_conv1)
-
- ssh_m1_det_context_conv1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m1_det_context_conv1_bn', trainable=False)(ssh_m1_det_context_conv1)
-
- ssh_m2_det_concat = concatenate([ssh_m2_det_conv1_bn, ssh_m2_det_context_conv2_bn, ssh_m2_det_context_conv3_2_bn], 3, name='ssh_m2_det_concat')
-
- ssh_m1_det_context_conv1_relu = ReLU(name='ssh_m1_det_context_conv1_relu')(ssh_m1_det_context_conv1_bn)
-
- ssh_m2_det_concat_relu = ReLU(name='ssh_m2_det_concat_relu')(ssh_m2_det_concat)
-
- ssh_m1_det_context_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m1_det_context_conv1_relu)
-
- ssh_m1_det_context_conv2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m1_det_context_conv2', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_context_conv2_pad)
-
- ssh_m1_det_context_conv3_1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m1_det_context_conv1_relu)
-
- ssh_m1_det_context_conv3_1 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m1_det_context_conv3_1', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_context_conv3_1_pad)
-
- face_rpn_cls_score_stride16 = Conv2D(filters = 4, kernel_size = (1, 1), name = 'face_rpn_cls_score_stride16', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_concat_relu)
-
- inter_1 = concatenate([face_rpn_cls_score_stride16[:, :, :, 0], face_rpn_cls_score_stride16[:, :, :, 1]], axis=1)
- inter_2 = concatenate([face_rpn_cls_score_stride16[:, :, :, 2], face_rpn_cls_score_stride16[:, :, :, 3]], axis=1)
+ face_rpn_cls_prob_reshape_stride32 = tf.transpose(
+ final, (1, 2, 3, 0), name="face_rpn_cls_prob_reshape_stride32"
+ )
+
+ ssh_m2_det_context_conv3_2_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m2_det_context_conv3_1_relu
+ )
+
+ ssh_m2_det_context_conv3_2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m2_det_context_conv3_2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_context_conv3_2_pad)
+
+ ssh_m1_det_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c1_aggr_relu)
+
+ ssh_m1_det_conv1 = Conv2D(
+ filters=256,
+ kernel_size=(3, 3),
+ name="ssh_m1_det_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_conv1_pad)
+
+ ssh_m1_det_context_conv1_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_c1_aggr_relu)
+
+ ssh_m1_det_context_conv1 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m1_det_context_conv1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_context_conv1_pad)
+
+ ssh_m2_det_context_conv3_2_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m2_det_context_conv3_2_bn", trainable=False
+ )(ssh_m2_det_context_conv3_2)
+
+ ssh_m1_det_conv1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m1_det_conv1_bn", trainable=False
+ )(ssh_m1_det_conv1)
+
+ ssh_m1_det_context_conv1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m1_det_context_conv1_bn", trainable=False
+ )(ssh_m1_det_context_conv1)
+
+ ssh_m2_det_concat = concatenate(
+ [ssh_m2_det_conv1_bn, ssh_m2_det_context_conv2_bn, ssh_m2_det_context_conv3_2_bn],
+ 3,
+ name="ssh_m2_det_concat",
+ )
+
+ ssh_m1_det_context_conv1_relu = ReLU(name="ssh_m1_det_context_conv1_relu")(
+ ssh_m1_det_context_conv1_bn
+ )
+
+ ssh_m2_det_concat_relu = ReLU(name="ssh_m2_det_concat_relu")(ssh_m2_det_concat)
+
+ ssh_m1_det_context_conv2_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m1_det_context_conv1_relu
+ )
+
+ ssh_m1_det_context_conv2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m1_det_context_conv2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_context_conv2_pad)
+
+ ssh_m1_det_context_conv3_1_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m1_det_context_conv1_relu
+ )
+
+ ssh_m1_det_context_conv3_1 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m1_det_context_conv3_1",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_context_conv3_1_pad)
+
+ face_rpn_cls_score_stride16 = Conv2D(
+ filters=4,
+ kernel_size=(1, 1),
+ name="face_rpn_cls_score_stride16",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_concat_relu)
+
+ inter_1 = concatenate(
+ [face_rpn_cls_score_stride16[:, :, :, 0], face_rpn_cls_score_stride16[:, :, :, 1]], axis=1
+ )
+ inter_2 = concatenate(
+ [face_rpn_cls_score_stride16[:, :, :, 2], face_rpn_cls_score_stride16[:, :, :, 3]], axis=1
+ )
final = tf.stack([inter_1, inter_2])
- face_rpn_cls_score_reshape_stride16 = tf.transpose(final, (1, 2, 3, 0), name="face_rpn_cls_score_reshape_stride16")
-
- face_rpn_bbox_pred_stride16 = Conv2D(filters = 8, kernel_size = (1, 1), name = 'face_rpn_bbox_pred_stride16', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_concat_relu)
-
- face_rpn_landmark_pred_stride16 = Conv2D(filters = 20, kernel_size = (1, 1), name = 'face_rpn_landmark_pred_stride16', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m2_det_concat_relu)
-
- ssh_m1_det_context_conv2_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m1_det_context_conv2_bn', trainable=False)(ssh_m1_det_context_conv2)
-
- ssh_m1_det_context_conv3_1_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m1_det_context_conv3_1_bn', trainable=False)(ssh_m1_det_context_conv3_1)
-
- ssh_m1_det_context_conv3_1_relu = ReLU(name='ssh_m1_det_context_conv3_1_relu')(ssh_m1_det_context_conv3_1_bn)
-
- face_rpn_cls_prob_stride16 = Softmax(name = 'face_rpn_cls_prob_stride16')(face_rpn_cls_score_reshape_stride16)
+ face_rpn_cls_score_reshape_stride16 = tf.transpose(
+ final, (1, 2, 3, 0), name="face_rpn_cls_score_reshape_stride16"
+ )
+
+ face_rpn_bbox_pred_stride16 = Conv2D(
+ filters=8,
+ kernel_size=(1, 1),
+ name="face_rpn_bbox_pred_stride16",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_concat_relu)
+
+ face_rpn_landmark_pred_stride16 = Conv2D(
+ filters=20,
+ kernel_size=(1, 1),
+ name="face_rpn_landmark_pred_stride16",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m2_det_concat_relu)
+
+ ssh_m1_det_context_conv2_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m1_det_context_conv2_bn", trainable=False
+ )(ssh_m1_det_context_conv2)
+
+ ssh_m1_det_context_conv3_1_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m1_det_context_conv3_1_bn", trainable=False
+ )(ssh_m1_det_context_conv3_1)
+
+ ssh_m1_det_context_conv3_1_relu = ReLU(name="ssh_m1_det_context_conv3_1_relu")(
+ ssh_m1_det_context_conv3_1_bn
+ )
+
+ face_rpn_cls_prob_stride16 = Softmax(name="face_rpn_cls_prob_stride16")(
+ face_rpn_cls_score_reshape_stride16
+ )
input_shape = [tf.shape(face_rpn_cls_prob_stride16)[k] for k in range(4)]
sz = tf.dtypes.cast(input_shape[1] / 2, dtype=tf.int32)
@@ -632,29 +1416,75 @@ def build_model():
inter_3 = face_rpn_cls_prob_stride16[:, sz:, :, 0]
inter_4 = face_rpn_cls_prob_stride16[:, sz:, :, 1]
final = tf.stack([inter_1, inter_3, inter_2, inter_4])
- face_rpn_cls_prob_reshape_stride16 = tf.transpose(final, (1, 2, 3, 0), name="face_rpn_cls_prob_reshape_stride16")
-
- ssh_m1_det_context_conv3_2_pad = ZeroPadding2D(padding=tuple([1, 1]))(ssh_m1_det_context_conv3_1_relu)
-
- ssh_m1_det_context_conv3_2 = Conv2D(filters = 128, kernel_size = (3, 3), name = 'ssh_m1_det_context_conv3_2', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_context_conv3_2_pad)
-
- ssh_m1_det_context_conv3_2_bn = BatchNormalization(epsilon=1.9999999494757503e-05, name='ssh_m1_det_context_conv3_2_bn', trainable=False)(ssh_m1_det_context_conv3_2)
-
- ssh_m1_det_concat = concatenate([ssh_m1_det_conv1_bn, ssh_m1_det_context_conv2_bn, ssh_m1_det_context_conv3_2_bn], 3, name='ssh_m1_det_concat')
-
- ssh_m1_det_concat_relu = ReLU(name='ssh_m1_det_concat_relu')(ssh_m1_det_concat)
- face_rpn_cls_score_stride8 = Conv2D(filters = 4, kernel_size = (1, 1), name = 'face_rpn_cls_score_stride8', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_concat_relu)
-
- inter_1 = concatenate([face_rpn_cls_score_stride8[:, :, :, 0], face_rpn_cls_score_stride8[:, :, :, 1]], axis=1)
- inter_2 = concatenate([face_rpn_cls_score_stride8[:, :, :, 2], face_rpn_cls_score_stride8[:, :, :, 3]], axis=1)
+ face_rpn_cls_prob_reshape_stride16 = tf.transpose(
+ final, (1, 2, 3, 0), name="face_rpn_cls_prob_reshape_stride16"
+ )
+
+ ssh_m1_det_context_conv3_2_pad = ZeroPadding2D(padding=tuple([1, 1]))(
+ ssh_m1_det_context_conv3_1_relu
+ )
+
+ ssh_m1_det_context_conv3_2 = Conv2D(
+ filters=128,
+ kernel_size=(3, 3),
+ name="ssh_m1_det_context_conv3_2",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_context_conv3_2_pad)
+
+ ssh_m1_det_context_conv3_2_bn = BatchNormalization(
+ epsilon=1.9999999494757503e-05, name="ssh_m1_det_context_conv3_2_bn", trainable=False
+ )(ssh_m1_det_context_conv3_2)
+
+ ssh_m1_det_concat = concatenate(
+ [ssh_m1_det_conv1_bn, ssh_m1_det_context_conv2_bn, ssh_m1_det_context_conv3_2_bn],
+ 3,
+ name="ssh_m1_det_concat",
+ )
+
+ ssh_m1_det_concat_relu = ReLU(name="ssh_m1_det_concat_relu")(ssh_m1_det_concat)
+ face_rpn_cls_score_stride8 = Conv2D(
+ filters=4,
+ kernel_size=(1, 1),
+ name="face_rpn_cls_score_stride8",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_concat_relu)
+
+ inter_1 = concatenate(
+ [face_rpn_cls_score_stride8[:, :, :, 0], face_rpn_cls_score_stride8[:, :, :, 1]], axis=1
+ )
+ inter_2 = concatenate(
+ [face_rpn_cls_score_stride8[:, :, :, 2], face_rpn_cls_score_stride8[:, :, :, 3]], axis=1
+ )
final = tf.stack([inter_1, inter_2])
- face_rpn_cls_score_reshape_stride8 = tf.transpose(final, (1, 2, 3, 0), name="face_rpn_cls_score_reshape_stride8")
-
- face_rpn_bbox_pred_stride8 = Conv2D(filters = 8, kernel_size = (1, 1), name = 'face_rpn_bbox_pred_stride8', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_concat_relu)
-
- face_rpn_landmark_pred_stride8 = Conv2D(filters = 20, kernel_size = (1, 1), name = 'face_rpn_landmark_pred_stride8', strides = [1, 1], padding = 'VALID', use_bias = True)(ssh_m1_det_concat_relu)
-
- face_rpn_cls_prob_stride8 = Softmax(name = 'face_rpn_cls_prob_stride8')(face_rpn_cls_score_reshape_stride8)
+ face_rpn_cls_score_reshape_stride8 = tf.transpose(
+ final, (1, 2, 3, 0), name="face_rpn_cls_score_reshape_stride8"
+ )
+
+ face_rpn_bbox_pred_stride8 = Conv2D(
+ filters=8,
+ kernel_size=(1, 1),
+ name="face_rpn_bbox_pred_stride8",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_concat_relu)
+
+ face_rpn_landmark_pred_stride8 = Conv2D(
+ filters=20,
+ kernel_size=(1, 1),
+ name="face_rpn_landmark_pred_stride8",
+ strides=[1, 1],
+ padding="VALID",
+ use_bias=True,
+ )(ssh_m1_det_concat_relu)
+
+ face_rpn_cls_prob_stride8 = Softmax(name="face_rpn_cls_prob_stride8")(
+ face_rpn_cls_score_reshape_stride8
+ )
input_shape = [tf.shape(face_rpn_cls_prob_stride8)[k] for k in range(4)]
sz = tf.dtypes.cast(input_shape[1] / 2, dtype=tf.int32)
@@ -663,19 +1493,24 @@ def build_model():
inter_3 = face_rpn_cls_prob_stride8[:, sz:, :, 0]
inter_4 = face_rpn_cls_prob_stride8[:, sz:, :, 1]
final = tf.stack([inter_1, inter_3, inter_2, inter_4])
- face_rpn_cls_prob_reshape_stride8 = tf.transpose(final, (1, 2, 3, 0), name="face_rpn_cls_prob_reshape_stride8")
-
- model = Model(inputs=data,
- outputs=[face_rpn_cls_prob_reshape_stride32,
- face_rpn_bbox_pred_stride32,
- face_rpn_landmark_pred_stride32,
- face_rpn_cls_prob_reshape_stride16,
- face_rpn_bbox_pred_stride16,
- face_rpn_landmark_pred_stride16,
- face_rpn_cls_prob_reshape_stride8,
- face_rpn_bbox_pred_stride8,
- face_rpn_landmark_pred_stride8
- ])
+ face_rpn_cls_prob_reshape_stride8 = tf.transpose(
+ final, (1, 2, 3, 0), name="face_rpn_cls_prob_reshape_stride8"
+ )
+
+ model = Model(
+ inputs=data,
+ outputs=[
+ face_rpn_cls_prob_reshape_stride32,
+ face_rpn_bbox_pred_stride32,
+ face_rpn_landmark_pred_stride32,
+ face_rpn_cls_prob_reshape_stride16,
+ face_rpn_bbox_pred_stride16,
+ face_rpn_landmark_pred_stride16,
+ face_rpn_cls_prob_reshape_stride8,
+ face_rpn_bbox_pred_stride8,
+ face_rpn_landmark_pred_stride8,
+ ],
+ )
model = load_weights(model)
return model
diff --git a/scripts/push-release.sh b/scripts/push-release.sh
new file mode 100644
index 0000000..5b3e6fa
--- /dev/null
+++ b/scripts/push-release.sh
@@ -0,0 +1,11 @@
+cd ..
+
+echo "deleting existing release related files"
+rm -rf dist/*
+rm -rf build/*
+
+echo "creating a package for current release - pypi compatible"
+python setup.py sdist bdist_wheel
+
+echo "pushing the release to pypi"
+python -m twine upload dist/*
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 2dd8e63..8f5accb 100644
--- a/setup.py
+++ b/setup.py
@@ -3,8 +3,11 @@
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
+with open("requirements.txt", "r", encoding="utf-8") as f:
+ requirements = f.read().split("\n")
+
setuptools.setup(
- name="retina-face", #pip install retina-face
+ name="retina-face", # pip install retina-face
version="0.0.14",
author="Sefik Ilkin Serengil",
author_email="serengil@gmail.com",
@@ -16,8 +19,8 @@
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
- "Operating System :: OS Independent"
+ "Operating System :: OS Independent",
],
- python_requires='>=3.5.5',
- install_requires=["numpy>=1.14.0", "gdown>=3.10.1", "Pillow>=5.2.0", "opencv-python>=3.4.4", "tensorflow>=1.9.0"]
+ python_requires=">=3.5.5",
+ install_requires=requirements,
)
diff --git a/tests/dataset/img1.jpg b/tests/dataset/img1.jpg
deleted file mode 100644
index c10b680..0000000
Binary files a/tests/dataset/img1.jpg and /dev/null differ
diff --git a/tests/dataset/img2.jpg b/tests/dataset/img2.jpg
deleted file mode 100644
index 06c2b0f..0000000
Binary files a/tests/dataset/img2.jpg and /dev/null differ
diff --git a/tests/dataset/img4.jpg b/tests/dataset/img4.jpg
deleted file mode 100644
index 32bd655..0000000
Binary files a/tests/dataset/img4.jpg and /dev/null differ
diff --git a/tests/dataset/img5.jpg b/tests/dataset/img5.jpg
deleted file mode 100644
index 7df0558..0000000
Binary files a/tests/dataset/img5.jpg and /dev/null differ
diff --git a/tests/dataset/img6.jpg b/tests/dataset/img6.jpg
deleted file mode 100644
index eb7a310..0000000
Binary files a/tests/dataset/img6.jpg and /dev/null differ
diff --git a/tests/dataset/img7.jpg b/tests/dataset/img7.jpg
deleted file mode 100644
index 82bf87b..0000000
Binary files a/tests/dataset/img7.jpg and /dev/null differ
diff --git a/tests/dataset/img8.jpg b/tests/dataset/img8.jpg
deleted file mode 100644
index 1db4f69..0000000
Binary files a/tests/dataset/img8.jpg and /dev/null differ
diff --git a/tests/test_actions.py b/tests/test_actions.py
new file mode 100644
index 0000000..9921a7c
--- /dev/null
+++ b/tests/test_actions.py
@@ -0,0 +1,95 @@
+import cv2
+import numpy as np
+from retinaface import RetinaFace
+from retinaface.commons.logger import Logger
+
+logger = Logger("tests/test_actions.py")
+
+do_plotting = False
+
+if do_plotting is True:
+ import matplotlib.pyplot as plt
+
+
+def int_tuple(t):
+ return tuple(int(x) for x in t)
+
+
+def test_analyze_crowded_photo():
+ img_path = "tests/dataset/img3.jpg"
+ img = cv2.imread(img_path)
+ resp = RetinaFace.detect_faces(img_path, threshold=0.1)
+
+ # it has to find 239 faces with threshold 0.1
+ assert len(resp.keys()) > 200
+
+ for idx, identity in resp.items():
+ confidence = identity["score"]
+ logger.debug(f"Confidence score of {idx} is {confidence}")
+
+ rectangle_color = (255, 255, 255)
+
+ landmarks = identity["landmarks"]
+ diameter = 1
+
+ cv2.circle(img, int_tuple(landmarks["left_eye"]), diameter, (0, 0, 255), -1)
+ cv2.circle(img, int_tuple(landmarks["right_eye"]), diameter, (0, 0, 255), -1)
+ cv2.circle(img, int_tuple(landmarks["nose"]), diameter, (0, 0, 255), -1)
+ cv2.circle(img, int_tuple(landmarks["mouth_left"]), diameter, (0, 0, 255), -1)
+ cv2.circle(img, int_tuple(landmarks["mouth_right"]), diameter, (0, 0, 255), -1)
+
+ facial_area = identity["facial_area"]
+
+ cv2.rectangle(
+ img,
+ (facial_area[2], facial_area[3]),
+ (facial_area[0], facial_area[1]),
+ rectangle_color,
+ 1,
+ )
+
+ if do_plotting is True:
+ plt.imshow(img[:, :, ::-1])
+ plt.axis("off")
+ plt.show()
+ cv2.imwrite("outputs/" + img_path.split("/")[1], img)
+
+ logger.info("✅ Crowded photo analysis test done")
+
+
+def test_alignment_for_inverse_clock_way():
+ # img11.jpg is required to rotate inverse direction of clock
+ img_path = "tests/dataset/img11.jpg"
+ img = cv2.imread(img_path)
+ do_alignment_checks(img, expected_faces=1)
+ logger.info("✅ Alignment for inverse clock way test done")
+
+
+def test_alignment_for_clock_way():
+ # img11.jpg is required to rotate inverse direction of clock
+ img_path = "tests/dataset/img11.jpg"
+ img = cv2.imread(img_path)
+ mirror_img = cv2.flip(img, 1)
+ do_alignment_checks(mirror_img, expected_faces=1)
+ logger.info("✅ Alignment for clock way test done")
+
+
+def do_alignment_checks(img: np.ndarray, expected_faces: int) -> None:
+ faces = RetinaFace.extract_faces(img_path=img, align=True, expand_face_area=100)
+
+ # it has one clear face
+ assert len(faces) == expected_faces
+
+ for face in faces:
+ if do_plotting is True:
+ plt.imshow(face)
+ plt.axis("off")
+ plt.show()
+
+ obj = RetinaFace.detect_faces(face, threshold=0.1)
+ landmarks = obj["face_1"]["landmarks"]
+ right_eye = landmarks["right_eye"]
+ left_eye = landmarks["left_eye"]
+
+ # check eyes are on same horizantal
+ assert abs(right_eye[1] - left_eye[1]) < 10
diff --git a/tests/unit-tests.py b/tests/unit-tests.py
deleted file mode 100644
index fec1262..0000000
--- a/tests/unit-tests.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from retinaface import RetinaFace
-import matplotlib.pyplot as plt
-import cv2
-from PIL import Image
-import numpy as np
-
-img_path = "dataset/img3.jpg"
-img = cv2.imread(img_path)
-
-resp = RetinaFace.detect_faces(img_path, threshold = 0.1)
-#print(resp)
-
-def int_tuple(t):
- return tuple(int(x) for x in t)
-
-for key in resp:
- identity = resp[key]
-
- #---------------------
- confidence = identity["score"]
-
- rectangle_color = (255, 255, 255)
-
- landmarks = identity["landmarks"]
- diameter = 1
- cv2.circle(img, int_tuple(landmarks["left_eye"]), diameter, (0, 0, 255), -1)
- cv2.circle(img, int_tuple(landmarks["right_eye"]), diameter, (0, 0, 255), -1)
- cv2.circle(img, int_tuple(landmarks["nose"]), diameter, (0, 0, 255), -1)
- cv2.circle(img, int_tuple(landmarks["mouth_left"]), diameter, (0, 0, 255), -1)
- cv2.circle(img, int_tuple(landmarks["mouth_right"]), diameter, (0, 0, 255), -1)
-
- facial_area = identity["facial_area"]
-
- cv2.rectangle(img, (facial_area[2], facial_area[3]), (facial_area[0], facial_area[1]), rectangle_color, 1)
- #facial_img = img[facial_area[1]: facial_area[3], facial_area[0]: facial_area[2]]
- #plt.imshow(facial_img[:, :, ::-1])
-
-plt.imshow(img[:, :, ::-1])
-plt.axis('off')
-plt.show()
-cv2.imwrite('outputs/'+img_path.split("/")[1], img)
-
-#------------------------------
-#extract face with alignment
-
-img_paths = ["dataset/img11.jpg", "dataset/img6.jpg"]
-rotate_angles = [0, 30, 45, 60, 90, -30, -45, -60, -90]
-
-for img_path in img_paths:
-
- #resp = RetinaFace.extract_faces(img_path = img_path, align = True)
- img = cv2.imread(img_path)
- img_base = img.copy()
-
- for angle in rotate_angles:
- print(f"rotating {img_path} to {angle} degrees")
- img = img_base.copy()
- img = Image.fromarray(img)
- img = np.array(img.rotate(angle))
-
- faces = RetinaFace.extract_faces(img_path = img, align = True)
-
- for face in faces:
- plt.imshow(face)
- plt.axis('off')
- plt.show()
- #cv2.imwrite('outputs/'+img_path.split("/")[1], face[:, :, ::-1])