-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add serverless function with attributes handling
- Loading branch information
1 parent
9fa32b4
commit 35dd7e6
Showing
7 changed files
with
191 additions
and
11 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
61 changes: 61 additions & 0 deletions
61
serverless/openvino/omz/intel/face-detection-0205/function.yaml
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,61 @@ | ||
metadata: | ||
name: openvino-omz-face-detection-0205 | ||
namespace: cvat | ||
annotations: | ||
name: Attributed face detection | ||
type: detector | ||
framework: openvino | ||
# attribute names have to be the same as in annotated task, otherwise values will be ignored | ||
spec: | | ||
[ | ||
{ "id": 0, "name": "face", "attributes": ["age", "gender", "emotion"]} | ||
] | ||
spec: | ||
description: Detection network finding faces and defining age, gender and emotion attributes | ||
runtime: 'python:3.6' | ||
handler: main:handler | ||
eventTimeout: 30000s | ||
env: | ||
- name: NUCLIO_PYTHON_EXE_PATH | ||
value: /opt/nuclio/common/openvino/python3 | ||
|
||
build: | ||
image: cvat/openvino.omz.intel.face-detection-0205 | ||
baseImage: openvino/ubuntu18_dev:2021.1 | ||
|
||
directives: | ||
preCopy: | ||
- kind: USER | ||
value: root | ||
- kind: WORKDIR | ||
value: /opt/nuclio | ||
- kind: RUN | ||
value: ln -s /usr/bin/pip3 /usr/bin/pip | ||
- kind: RUN | ||
value: /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/downloader.py --name face-detection-0205 -o /opt/nuclio/open_model_zoo | ||
- kind: RUN | ||
value: /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/downloader.py --name emotions-recognition-retail-0003 -o /opt/nuclio/open_model_zoo | ||
- kind: RUN | ||
value: /opt/intel/openvino/deployment_tools/open_model_zoo/tools/downloader/downloader.py --name age-gender-recognition-retail-0013 -o /opt/nuclio/open_model_zoo | ||
|
||
postCopy: | ||
- kind: RUN | ||
value: apt update && DEBIAN_FRONTEND=noninteractive apt install --no-install-recommends -y python3-skimage | ||
- kind: RUN | ||
value: pip3 install "numpy<1.16.0" # workaround for skimage | ||
|
||
triggers: | ||
myHttpTrigger: | ||
maxWorkers: 2 | ||
kind: 'http' | ||
workerAvailabilityTimeoutMilliseconds: 10000 | ||
attributes: | ||
maxRequestBodySize: 33554432 # 32MB | ||
|
||
platform: | ||
attributes: | ||
restartPolicy: | ||
name: always | ||
maximumRetryCount: 3 | ||
mountMode: volume |
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,35 @@ | ||
import json | ||
import base64 | ||
from PIL import Image | ||
import io | ||
from model_handler import FaceDetectorHandler, AttributesExtractorHandler | ||
import yaml | ||
import debugpy | ||
|
||
def init_context(context): | ||
context.logger.info("Init context... 0%") | ||
|
||
# Read labels | ||
with open("/opt/nuclio/function.yaml", 'rb') as function_file: | ||
functionconfig = yaml.safe_load(function_file) | ||
|
||
# Read the DL model | ||
context.user_data.detector_model = FaceDetectorHandler() | ||
context.user_data.attributes_model = AttributesExtractorHandler() | ||
|
||
context.logger.info("Init context...100%") | ||
|
||
def handler(context, event): | ||
context.logger.info("Run face-detection-0206 model") | ||
data = event.body | ||
buf = io.BytesIO(base64.b64decode(data["image"])) | ||
threshold = float(data.get("threshold", 0.5)) | ||
image = Image.open(buf) | ||
|
||
results, faces = context.user_data.detector_model.infer(image, threshold) | ||
for idx, face in enumerate(faces): | ||
attributes = context.user_data.attributes_model.infer(face) | ||
results[idx].update(attributes) | ||
|
||
return context.Response(body=json.dumps(results), headers={}, | ||
content_type='application/json', status_code=200) |
72 changes: 72 additions & 0 deletions
72
serverless/openvino/omz/intel/face-detection-0205/model_handler.py
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,72 @@ | ||
# Copyright (C) 2020 Intel Corporation | ||
# | ||
# SPDX-License-Identifier: MIT | ||
|
||
import os | ||
import cv2 | ||
import numpy as np | ||
from model_loader import ModelLoader | ||
|
||
class FaceDetectorHandler: | ||
def __init__(self): | ||
base_dir = os.path.abspath(os.environ.get("DETECTOR_MODEL_PATH", | ||
"/opt/nuclio/open_model_zoo/intel/face-detection-0205/FP32")) | ||
model_xml = os.path.join(base_dir, "face-detection-0205.xml") | ||
model_bin = os.path.join(base_dir, "face-detection-0205.bin") | ||
self.model = ModelLoader(model_xml, model_bin) | ||
|
||
def infer(self, image, threshold): | ||
infer_res = self.model.infer(image)["boxes"] | ||
infer_res = infer_res[infer_res[:,4] > threshold] | ||
|
||
results = [] | ||
faces = [] | ||
h_scale = image.height / 416 | ||
w_scale = image.width / 416 | ||
for face in infer_res: | ||
xmin = int(face[0] * w_scale) | ||
ymin = int(face[1] * h_scale) | ||
xmax = int(face[2] * w_scale) | ||
ymax = int(face[3] * h_scale) | ||
confidence = face[4] | ||
|
||
faces.append(np.array(image)[ymin:ymax, xmin:xmax]) | ||
results.append({ | ||
"confidence": str(confidence), | ||
"label": "face", | ||
"points": [xmin, ymin, xmax, ymax], | ||
"type": "rectangle", | ||
"attributes": [] | ||
}) | ||
|
||
return results, faces | ||
|
||
class AttributesExtractorHandler: | ||
def __init__(self): | ||
age_gender_base_dir = os.path.abspath(os.environ.get("AGE_GENDER_MODEL_PATH", | ||
"/opt/nuclio/open_model_zoo/intel/age-gender-recognition-retail-0013/FP32")) | ||
age_gender_model_xml = os.path.join(age_gender_base_dir, "age-gender-recognition-retail-0013.xml") | ||
age_gender_model_bin = os.path.join(age_gender_base_dir, "age-gender-recognition-retail-0013.bin") | ||
self.age_gender_model = ModelLoader(age_gender_model_xml, age_gender_model_bin) | ||
emotions_base_dir = os.path.abspath(os.environ.get("EMOTIONS_MODEL_PATH", | ||
"/opt/nuclio/open_model_zoo/intel/emotions-recognition-retail-0003/FP32")) | ||
emotions_model_xml = os.path.join(emotions_base_dir, "emotions-recognition-retail-0003.xml") | ||
emotions_model_bin = os.path.join(emotions_base_dir, "emotions-recognition-retail-0003.bin") | ||
self.emotions_model = ModelLoader(emotions_model_xml, emotions_model_bin) | ||
self.genders_map = ["female", "male"] | ||
self.emotions_map = ["neutral", "happy", "sad", "surprise", "anger"] | ||
|
||
def infer(self, image): | ||
age_gender_reqest = self.age_gender_model.async_infer(image) | ||
emotions_reqest = self.emotions_model.async_infer(image) | ||
# Wait until both age_gender and emotion recognition async inferences finish | ||
while not (age_gender_reqest.wait(0) == 0 and emotions_reqest.wait(0) == 0): | ||
continue | ||
age = int(np.squeeze(age_gender_reqest.output_blobs["age_conv3"].buffer) * 100) | ||
gender = self.genders_map[np.argmax(np.squeeze(age_gender_reqest.output_blobs["prob"].buffer))] | ||
emotion = self.emotions_map[np.argmax(np.squeeze(emotions_reqest.output_blobs['prob_emotion'].buffer))] | ||
return {"attributes": [ | ||
{"name": "age", "value": str(age)}, | ||
{"name": "gender", "value": gender}, | ||
{"name": "emotion", "value": emotion} | ||
]} |