forked from idealo/image-quality-assessment
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request idealo#13 from bmachin/add-tfs-support
Adding TF Serving support.
- Loading branch information
Showing
36 changed files
with
629 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
FROM tensorflow/serving:latest | ||
|
||
WORKDIR /tf_serving | ||
|
||
# copy project files | ||
COPY tfs_models/mobilenet_aesthetic /models/mobilenet_aesthetic/1 | ||
COPY tfs_models/mobilenet_technical /models/mobilenet_technical/1 | ||
COPY tf_serving_models.cfg /tf_serving/tf_serving_models.cfg | ||
|
||
EXPOSE 8500 | ||
ENTRYPOINT [] | ||
|
||
CMD ["tensorflow_model_server" ,"--port=8500", "--model_config_file=tf_serving_models.cfg"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Keras==2.2.* | ||
Pillow==5.3.* | ||
tensorflow-serving-api==1.12.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import keras.backend as K | ||
import argparse | ||
from keras.applications.mobilenet import DepthwiseConv2D, relu6 | ||
from keras.utils.generic_utils import CustomObjectScope | ||
from tensorflow.python.saved_model import builder as saved_model_builder | ||
from tensorflow.python.saved_model import tag_constants | ||
from tensorflow.python.saved_model.signature_def_utils_impl import \ | ||
predict_signature_def | ||
|
||
from src.handlers.model_builder import Nima | ||
|
||
|
||
def main(base_model_name, weights_file, export_path): | ||
# Load model and weights | ||
nima = Nima(base_model_name, weights=None) | ||
nima.build() | ||
nima.nima_model.load_weights(weights_file) | ||
|
||
# Tell keras that this will be used for making predictions | ||
K.set_learning_phase(0) | ||
|
||
# CustomObject required by MobileNet | ||
with CustomObjectScope({'relu6': relu6, 'DepthwiseConv2D': DepthwiseConv2D}): | ||
builder = saved_model_builder.SavedModelBuilder(export_path) | ||
signature = predict_signature_def( | ||
inputs={'input_image': nima.nima_model.input}, | ||
outputs={'quality_prediction': nima.nima_model.output} | ||
) | ||
|
||
builder.add_meta_graph_and_variables( | ||
sess=K.get_session(), | ||
tags=[tag_constants.SERVING], | ||
signature_def_map={'image_quality': signature} | ||
) | ||
builder.save() | ||
|
||
print(f'TF model exported to: {export_path}') | ||
|
||
|
||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('-b', '--base-model-name', help='CNN base model name', required=True) | ||
parser.add_argument('-w', '--weights-file', help='path of weights file', required=True) | ||
parser.add_argument('-ep', '--export-path', help='path to save the tfs model', required=True) | ||
|
||
args = parser.parse_args() | ||
|
||
main(**args.__dict__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
model_config_list: { | ||
|
||
config: { | ||
name: "mobilenet_technical", | ||
base_path: "/models/mobilenet_technical", | ||
model_platform: "tensorflow" | ||
}, | ||
config: { | ||
name: "mobilenet_aesthetic", | ||
base_path: "/models/mobilenet_aesthetic", | ||
model_platform: "tensorflow" | ||
} | ||
} |
Binary file not shown.
Binary file added
BIN
+12.4 MB
contrib/tf_serving/tfs_models/mobilenet_aesthetic/variables/variables.data-00000-of-00001
Binary file not shown.
Binary file added
BIN
+8.39 KB
contrib/tf_serving/tfs_models/mobilenet_aesthetic/variables/variables.index
Binary file not shown.
Binary file not shown.
Binary file added
BIN
+12.4 MB
contrib/tf_serving/tfs_models/mobilenet_technical/variables/variables.data-00000-of-00001
Binary file not shown.
Binary file added
BIN
+8.39 KB
contrib/tf_serving/tfs_models/mobilenet_technical/variables/variables.index
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import json | ||
import argparse | ||
import keras | ||
import numpy as np | ||
import tensorflow as tf | ||
from src.utils import utils | ||
from grpc.beta import implementations | ||
from tensorflow_serving.apis import predict_pb2, prediction_service_pb2 | ||
|
||
TFS_HOST = 'localhost' | ||
TFS_PORT = 8500 | ||
|
||
|
||
def normalize_labels(labels): | ||
labels_np = np.array(labels) | ||
return labels_np / labels_np.sum() | ||
|
||
|
||
def calc_mean_score(score_dist): | ||
score_dist = normalize_labels(score_dist) | ||
return (score_dist * np.arange(1, 11)).sum() | ||
|
||
|
||
def get_image_quality_predictions(image_path, model_name): | ||
# Load and preprocess image | ||
image = utils.load_image(image_path, target_size=(224, 224)) | ||
image = keras.applications.mobilenet.preprocess_input(image) | ||
|
||
# Run through model | ||
channel = implementations.insecure_channel(TFS_HOST, TFS_PORT) | ||
stub = prediction_service_pb2.beta_create_PredictionService_stub(channel) | ||
request = predict_pb2.PredictRequest() | ||
request.model_spec.name = model_name | ||
request.model_spec.signature_name = 'image_quality' | ||
|
||
request.inputs['input_image'].CopyFrom( | ||
tf.contrib.util.make_tensor_proto(np.expand_dims(image, 0)) | ||
) | ||
|
||
response = stub.Predict(request, 10.0) | ||
result = round(calc_mean_score(response.outputs['quality_prediction'].float_val), 2) | ||
|
||
print(json.dumps({'mean_score_prediction': np.round(result, 3)}, indent=2)) | ||
|
||
|
||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('-ip', '--image-path', help='Path to image file.', required=True) | ||
parser.add_argument( | ||
'-mn', '--model-name', help='mobilenet_aesthetic or mobilenet_technical', required=True | ||
) | ||
args = parser.parse_args() | ||
get_image_quality_predictions(**args.__dict__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# This file must be used with "source bin/activate" *from bash* | ||
# you cannot run it directly | ||
|
||
deactivate () { | ||
unset -f pydoc >/dev/null 2>&1 | ||
|
||
# reset old environment variables | ||
# ! [ -z ${VAR+_} ] returns true if VAR is declared at all | ||
if ! [ -z "${_OLD_VIRTUAL_PATH+_}" ] ; then | ||
PATH="$_OLD_VIRTUAL_PATH" | ||
export PATH | ||
unset _OLD_VIRTUAL_PATH | ||
fi | ||
if ! [ -z "${_OLD_VIRTUAL_PYTHONHOME+_}" ] ; then | ||
PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" | ||
export PYTHONHOME | ||
unset _OLD_VIRTUAL_PYTHONHOME | ||
fi | ||
|
||
# This should detect bash and zsh, which have a hash command that must | ||
# be called to get it to forget past commands. Without forgetting | ||
# past commands the $PATH changes we made may not be respected | ||
if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then | ||
hash -r 2>/dev/null | ||
fi | ||
|
||
if ! [ -z "${_OLD_VIRTUAL_PS1+_}" ] ; then | ||
PS1="$_OLD_VIRTUAL_PS1" | ||
export PS1 | ||
unset _OLD_VIRTUAL_PS1 | ||
fi | ||
|
||
unset VIRTUAL_ENV | ||
if [ ! "${1-}" = "nondestructive" ] ; then | ||
# Self destruct! | ||
unset -f deactivate | ||
fi | ||
} | ||
|
||
# unset irrelevant variables | ||
deactivate nondestructive | ||
|
||
VIRTUAL_ENV="/Users/christopher.lennan/github_repos/image-quality-assessment/contrib/tf_serving/venv_tfs_nima" | ||
export VIRTUAL_ENV | ||
|
||
_OLD_VIRTUAL_PATH="$PATH" | ||
PATH="$VIRTUAL_ENV/bin:$PATH" | ||
export PATH | ||
|
||
# unset PYTHONHOME if set | ||
if ! [ -z "${PYTHONHOME+_}" ] ; then | ||
_OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" | ||
unset PYTHONHOME | ||
fi | ||
|
||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then | ||
_OLD_VIRTUAL_PS1="$PS1" | ||
if [ "x" != x ] ; then | ||
PS1="$PS1" | ||
else | ||
PS1="(`basename \"$VIRTUAL_ENV\"`) $PS1" | ||
fi | ||
export PS1 | ||
fi | ||
|
||
# Make sure to unalias pydoc if it's already there | ||
alias pydoc 2>/dev/null >/dev/null && unalias pydoc | ||
|
||
pydoc () { | ||
python -m pydoc "$@" | ||
} | ||
|
||
# This should detect bash and zsh, which have a hash command that must | ||
# be called to get it to forget past commands. Without forgetting | ||
# past commands the $PATH changes we made may not be respected | ||
if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then | ||
hash -r 2>/dev/null | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# This file must be used with "source bin/activate.csh" *from csh*. | ||
# You cannot run it directly. | ||
# Created by Davide Di Blasi <[email protected]>. | ||
|
||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' | ||
|
||
# Unset irrelevant variables. | ||
deactivate nondestructive | ||
|
||
setenv VIRTUAL_ENV "/Users/christopher.lennan/github_repos/image-quality-assessment/contrib/tf_serving/venv_tfs_nima" | ||
|
||
set _OLD_VIRTUAL_PATH="$PATH" | ||
setenv PATH "$VIRTUAL_ENV/bin:$PATH" | ||
|
||
|
||
|
||
if ("" != "") then | ||
set env_name = "" | ||
else | ||
set env_name = `basename "$VIRTUAL_ENV"` | ||
endif | ||
|
||
# Could be in a non-interactive environment, | ||
# in which case, $prompt is undefined and we wouldn't | ||
# care about the prompt anyway. | ||
if ( $?prompt ) then | ||
set _OLD_VIRTUAL_PROMPT="$prompt" | ||
set prompt = "[$env_name] $prompt" | ||
endif | ||
|
||
unset env_name | ||
|
||
alias pydoc python -m pydoc | ||
|
||
rehash | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# This file must be used using `. bin/activate.fish` *within a running fish ( http://fishshell.com ) session*. | ||
# Do not run it directly. | ||
|
||
function deactivate -d 'Exit virtualenv mode and return to the normal environment.' | ||
# reset old environment variables | ||
if test -n "$_OLD_VIRTUAL_PATH" | ||
set -gx PATH $_OLD_VIRTUAL_PATH | ||
set -e _OLD_VIRTUAL_PATH | ||
end | ||
|
||
if test -n "$_OLD_VIRTUAL_PYTHONHOME" | ||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME | ||
set -e _OLD_VIRTUAL_PYTHONHOME | ||
end | ||
|
||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE" | ||
# Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`. | ||
set -l fish_function_path | ||
|
||
# Erase virtualenv's `fish_prompt` and restore the original. | ||
functions -e fish_prompt | ||
functions -c _old_fish_prompt fish_prompt | ||
functions -e _old_fish_prompt | ||
set -e _OLD_FISH_PROMPT_OVERRIDE | ||
end | ||
|
||
set -e VIRTUAL_ENV | ||
|
||
if test "$argv[1]" != 'nondestructive' | ||
# Self-destruct! | ||
functions -e pydoc | ||
functions -e deactivate | ||
end | ||
end | ||
|
||
# Unset irrelevant variables. | ||
deactivate nondestructive | ||
|
||
set -gx VIRTUAL_ENV "/Users/christopher.lennan/github_repos/image-quality-assessment/contrib/tf_serving/venv_tfs_nima" | ||
|
||
set -gx _OLD_VIRTUAL_PATH $PATH | ||
set -gx PATH "$VIRTUAL_ENV/bin" $PATH | ||
|
||
# Unset `$PYTHONHOME` if set. | ||
if set -q PYTHONHOME | ||
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME | ||
set -e PYTHONHOME | ||
end | ||
|
||
function pydoc | ||
python -m pydoc $argv | ||
end | ||
|
||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" | ||
# Copy the current `fish_prompt` function as `_old_fish_prompt`. | ||
functions -c fish_prompt _old_fish_prompt | ||
|
||
function fish_prompt | ||
# Save the current $status, for fish_prompts that display it. | ||
set -l old_status $status | ||
|
||
# Prompt override provided? | ||
# If not, just prepend the environment name. | ||
if test -n "" | ||
printf '%s%s' "" (set_color normal) | ||
else | ||
printf '%s(%s) ' (set_color normal) (basename "$VIRTUAL_ENV") | ||
end | ||
|
||
# Restore the original $status | ||
echo "exit $old_status" | source | ||
_old_fish_prompt | ||
end | ||
|
||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
"""By using execfile(this_file, dict(__file__=this_file)) you will | ||
activate this virtualenv environment. | ||
This can be used when you must use an existing Python interpreter, not | ||
the virtualenv bin/python | ||
""" | ||
|
||
try: | ||
__file__ | ||
except NameError: | ||
raise AssertionError( | ||
"You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") | ||
import sys | ||
import os | ||
|
||
old_os_path = os.environ.get('PATH', '') | ||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path | ||
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
if sys.platform == 'win32': | ||
site_packages = os.path.join(base, 'Lib', 'site-packages') | ||
else: | ||
site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') | ||
prev_sys_path = list(sys.path) | ||
import site | ||
site.addsitedir(site_packages) | ||
sys.real_prefix = sys.prefix | ||
sys.prefix = base | ||
# Move the added items to the front of the path: | ||
new_sys_path = [] | ||
for item in list(sys.path): | ||
if item not in prev_sys_path: | ||
new_sys_path.append(item) | ||
sys.path.remove(item) | ||
sys.path[:0] = new_sys_path |
Oops, something went wrong.