Commit 065c8858 authored by HMKS Herath's avatar HMKS Herath

add flask API to model

parent 469f315c
Pipeline #1933 failed with stages
.idea/
.vscode/
test/
\ No newline at end of file
upload/*
# Created by https://www.gitignore.io/api/macos,linux,django,python,pycharm
### Django ###
*.log
*.pot
*.pyc
__pycache__/
local_settings.py
db.sqlite3
media
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### PyCharm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### PyCharm Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/sonarlint
### Python ###
# Byte-compiled / optimized / DLL files
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
# Django stuff:
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
\ No newline at end of file
# Dog breed classifier
## Intorudction
This model is developed on top of the inception v3 pre-trained model. Using transfer learning, the model has further enhanced. To train the model, the Stanford data set has been used which consists of 20000+ images from 120 different dog breeds. Model is connected with the Flask (python micro-framework for web) server which allows API consumers to request "dog breed" predictions via JSON based API. Server accepts both image and video media types.
### Request
```
curl --location --request POST '{base_url}/predict' \
--form 'file=@/path/to/file'
```
### Response
```
{
"code_name": "N02086240-Shih-Tzu",
"image": "90d00cda8e414e299f8aec70a77d6cb8.jpg",
"name": "Shih-Tzu",
"probability": "0.94594604"
}
```
## Installation
This guide is using conda to setup the enviroment.
1. Create an enviroment
```conda create -n dog-breed python=3.6```
2. Activate created enviroment
```conda activate dog-breed```
3. Install dependencies
```pip install -r requirment.txt```
4. Run server
```python app.py```
import numpy as np
from keras.applications.inception_v3 import preprocess_input
from pathlib import Path
import math
import uuid
from werkzeug.utils import secure_filename
from flask import Flask, request, jsonify
import mimetypes
import model.imagegenerator as im
import cv2
import tensorflow_hub as hub
import os
import model.load_model as lm
import predictor as pd
global hub
global model, graph
# global variables
feature_extractor_url = 'https://tfhub.dev/google/imagenet/inception_v3/feature_vector/3'
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
script_location = Path(__file__).absolute().parent
app = Flask(__name__, static_folder='upload')
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'dog-breed.sqlite'),
)
app.config['UPLOAD_FOLDER'] = script_location / 'upload'
# load model
model, graph = lm.ModelInitializer()
def get_file_type(filename):
mimetypes.init()
mimestart = mimetypes.guess_type(filename)[0]
return mimestart
def save_image(frame):
filename = secure_filename('{}.{}'.format(uuid.uuid4().hex, 'jpg'))
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
cv2.imwrite(filepath, frame)
return filename
def predict_from_video(pred_target):
cap = cv2.VideoCapture(pred_target)
# 5 == parameter select frame rate of video source
frameRate = cap.get(5)
# predict dog in each frame
results = []
i = 1
while(cap.isOpened()):
frameId = cap.get(1) # current frame number
ret, frame = cap.read()
if (ret != True):
break
if (frameId % math.floor(frameRate) == 0):
i += i
img_tensor = im.InputImageGeneratorVideo(frame)
prediction = pd.Predict(img_tensor, model, graph)
prediction['frame'] = frame
results.append(prediction)
cap.release()
# get breed which has maximum probability of the list of results
predicted_breed = max(results, key=lambda x: x['probability'])
# add saved image name
predicted_breed['image'] = save_image(predicted_breed['frame'])
# remove frame from the dict
del predicted_breed['frame']
return predicted_breed
def predict_from_image(pred_target):
img_tensor = im.InputImageGeneratorImage(pred_target)
prediction = pd.Predict(img_tensor, model, graph)
return prediction
# index endpoint, can use to check server status
@app.route('/', methods=['GET', 'POST'])
def hello():
return ("Server is running!")
@app.route('/predict', methods=['POST'])
def get_breed_from_image():
# check if the post request has the file part
if 'file' not in request.files:
return jsonify(dict({'message': 'No file attached to the request.'}))
# uploaded file
file = request.files['file']
# if user does not select file, browser also submit an empty part without filename
if file.filename == '':
return jsonify(dict({'message': 'No selected file.'}))
# check file type
mime = get_file_type(file.filename)
filetype, extension = mime.split('/')
if str(filetype) not in ('image', 'video'):
return jsonify(dict({'message': 'File type is not allowed'}))
# create new filename
filename = secure_filename('{}.{}'.format(uuid.uuid4().hex, extension))
# save video in tempory folder
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
# predict base on the type of file
result = {}
if filetype == 'video':
result = predict_from_video(filepath)
# delete video file since we don't need it anymore
os.remove(filepath)
else:
result = predict_from_image(filepath)
# add filename of image to result
result['image'] = filename
return jsonify(result)
if __name__ == "__main__":
app.run(debug=True)
File deleted
{"class_name": "Sequential", "config": {"name": "sequential", "layers": [{"class_name": "Lambda", "config": {"name": "lambda", "trainable": false, "batch_input_shape": [null, 299, 299, 3], "dtype": "float32", "function": ["4wEAAAAAAAAAAgAAAAIAAABDAAAAcxIAAAB0AGoBdAKDAX0BfAF8AIMBUwApAU4pA9oDaHVi2gZN\nb2R1bGXaFWZlYXR1cmVfZXh0cmFjdG9yX3VybCkC2gF42hhmZWF0dXJlX2V4dHJhY3Rvcl9tb2R1\nbGWpAHIGAAAA+h48aXB5dGhvbi1pbnB1dC05LTI3YzBmOGE2OWI0MD7aEWZlYXR1cmVfZXh0cmFj\ndG9yAQAAAHMEAAAAAAEKAQ==\n", null, null], "module": "__main__", "function_type": "lambda", "output_shape": null, "output_shape_type": "raw", "output_shape_module": null, "arguments": {}}}, {"class_name": "Dense", "config": {"name": "dense", "trainable": true, "dtype": "float32", "units": 120, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null, "dtype": "float32"}}, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}]}, "keras_version": "2.2.4-tf", "backend": "tensorflow"}
\ No newline at end of file
from tensorflow import keras
import tensorflow.keras.backend as K
def ModelInitializer():
import tensorflow as tf
import tensorflow_hub as hub
#Inception model's bottom layer as feature extractor.
# Inception model's bottom layer as feature extractor.
feature_extractor_url = 'https://tfhub.dev/google/imagenet/inception_v3/feature_vector/3'
#Loading the trained dog classification model
# Loading the trained dog classification model
model = tf.contrib.saved_model.load_keras_model('saved_model')
model.summary()
#Variables Intialization
# Variables Intialization
sess = K.get_session()
init = tf.global_variables_initializer()
sess.run(init)
#Loading trained weights
# Loading trained weights
model.load_weights('saved_model/model.h5')
#Compiling the model
# Compiling the model
model.compile(
optimizer=tf.train.AdamOptimizer(),
loss='categorical_crossentropy',
......@@ -23,4 +24,4 @@ def ModelInitializer():
)
graph = tf.get_default_graph()
return model , graph
return model, graph
import os
import argparse
import model.load_model as lm
import predictor as pd
global hub
import tensorflow_hub as hub
global model , graph
import cv2
import model.imagegenerator as im
import mimetypes
mimetypes.init()
feature_extractor_url = 'https://tfhub.dev/google/imagenet/inception_v3/feature_vector/3'
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
parser = argparse.ArgumentParser(description='Input local image path.')
parser.add_argument('-i', metavar='--image', type=str, help='Relative path or absolute path of image.')
# Load model
model , graph = lm.ModelInitializer()
def main():
args = parser.parse_args()
if args.i:
mimestart = mimetypes.guess_type(args.i)[0]
if 'video' in mimestart:
predict_from_video(args.i)
elif 'image' in mimestart:
predict_from_image(args.i)
else:
print("Please enter a valid image or video path")
else:
print("Please enter image path.")
# Opens the video file
#cap = cv2.VideoCapture(r"C:\Users\kumudu\Documents\sliit\research\backup\Dog-Breed-Classifier\test\Sad_Dog.mp4")
def predict_from_video(pred_target):
i = 0
cap = cv2.VideoCapture(pred_target)
while(cap.isOpened()):
ret, frame = cap.read()
if ret == False:
break
img_tensor = im.InputImageGeneratorVideo(frame)
prediction = pd.Predict(img_tensor , model , graph)
print("This is a " + str(prediction))
if prediction:
break
cap.release()
cv2.destroyAllWindows()
def predict_from_image(pred_target):
img_tensor = im.InputImageGeneratorImage(pred_target)
prediction = pd.Predict(img_tensor , model , graph)
print("This is a " + str(prediction))
main()
\ No newline at end of file
import logging, os
import model.imagegenerator as im
import model.formatter as ft
from model.labels import label_names
from tensorflow.keras.preprocessing import image
import tensorflow.keras.backend as K
from tensorflow import keras
import tensorflow as tf
import numpy as np
import logging
import os
from keras.applications.inception_v3 import preprocess_input
logging.disable(logging.WARNING)
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
import numpy as np
import tensorflow as tf
from tensorflow import keras
import tensorflow.keras.backend as K
from tensorflow.keras.preprocessing import image
from model.labels import label_names
import model.formatter as ft
import model.imagegenerator as im
def Predict(img_tensor , model , graph1):
def Predict(img_tensor, model, graph1):
with tf.Session(graph=graph1) as sess:
init = tf.global_variables_initializer()
sess.run(init)
......@@ -20,5 +22,5 @@ def Predict(img_tensor , model , graph1):
labels = label_names[np.argmax(result, axis=-1)]
unformatted_prediction = labels[0]
prediction = ft.formatString(unformatted_prediction)
return prediction
probability = max(result[0])
return {'name': prediction, 'probability': str(probability), 'code_name': unformatted_prediction}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment