Compare commits

..

15 Commits

Author SHA1 Message Date
Alexey Suhov
b4d9b68609 Fix license header in Movidius sources 2021-06-02 21:20:19 +03:00
Kate Generalova
a8984f3761 doc: add Red Hat docker registry (#5184) (#5254) 2021-04-15 19:34:14 +03:00
Andrey Zaytsev
a8a6e8f60a Feature/azaytsev/formula fixes (#4601)
* removed redundant tabs

* minor edit
2021-03-04 11:48:35 +03:00
Kate Generalova
71ebd41475 doc: add link to RHEL docker repo and GPU configuration guide (#4558)
* doc: add link to RHEL Docker repo (#4539)

(cherry picked from commit 03e68dd549)

* doc: configure docker container for GPU (#4519)

* doc: configure docker container for GPU

* Update docs/install_guides/installing-openvino-docker-linux.md

Co-authored-by: Alina Alborova <alina.alborova@intel.com>

* Update docs/install_guides/installing-openvino-docker-linux.md

Co-authored-by: Alina Alborova <alina.alborova@intel.com>

Co-authored-by: Alina Alborova <alina.alborova@intel.com>
(cherry picked from commit 2674dfeda4)
2021-03-02 14:37:37 +03:00
Andrey Zaytsev
3e8f2cc58b Inserting videos (#4254) 2021-02-11 22:56:48 +03:00
Andrey Zaytsev
e8c1a59329 Link fixes for 2021.2 benchmark page (#4086)
* Benchmark updates

* Fixed links
2021-02-01 23:05:40 +03:00
Andrey Zaytsev
b371b52680 Benchmark updates (#4041) 2021-01-28 15:35:43 +03:00
Ilya Churaev
7ea2d668ad Changed style of some headers (#3898) 2021-01-19 12:55:26 +03:00
Andrey Zaytsev
07f95e37b1 Doc updates 2021 2 (#3749)
* Change the name of parameter tensorflow_use_custom_operations_config to transformations_config

* Fixed formatting

* Corrected MYRIAD plugin name

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Installation Guides formatting fixes

* Fixed link to Model Optimizer Extensibility

* Fixed link to Model Optimizer Extensibility

* Fixed link to Model Optimizer Extensibility

* Fixed link to Model Optimizer Extensibility

* Fixed link to Model Optimizer Extensibility

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Updated IGS, added links to Get Started Guides

* Fixed links

* Fixed formatting issues

* Fixed formatting issues

* Fixed formatting issues

* Fixed formatting issues

* Move the Note to the proper place

* Removed optimization notice
2021-01-15 19:27:49 +03:00
Ilya Lavrenov
cd9aece3d7 Fixed headers for doxygen genration (#3746) (#3764)
* Fixed headers for doxygen genration (#3746)

* Fixed headers for doxygen genration (#3746)

Co-authored-by: Ilya Churaev <ilya.churaev@intel.com>
Co-authored-by: Alexander Zhogov <alexander.zhogov@intel.com>
2021-01-13 12:44:01 +03:00
Alexander Zhogov
2e6a746722 Azure CI: set testdata branch for Mac 2021-01-12 13:17:29 +03:00
Andrey Zaytsev
b37376100a Feature/azaytsev/g api docs (#3731)
* Initial commit

* Added content

* Added new content for g-api documentation. Removed obsolete links through all docs

* Fixed layout

* Fixed layout

* Added new topics

* Added new info

* added a note

* Removed redundant .svg
2020-12-25 18:17:07 +03:00
Evgeny Lazarev
0ed9857b97 Added missing information about the extension source code of the Custom Operation Guide (#3727)
* Added missing information about the extension source code of the Custom Operations Guide

* Code review comments
2020-12-25 11:08:01 +03:00
Nikolay Tyukaev
6f801e5b34 fix comments ngraph api 2021.2 (#3520)
* fix comments ngraph api

* remove whitespace

* fixes

Co-authored-by: Nikolay Tyukaev <ntyukaev_lo@jenkins.inn.intel.com>
2020-12-16 14:53:09 +03:00
Nikolay Tyukaev
5d5bbce492 fix latex formula (#3630)
Co-authored-by: Nikolay Tyukaev <ntyukaev_lo@jenkins.inn.intel.com>
2020-12-16 09:21:46 +03:00
82 changed files with 2603 additions and 1446 deletions

View File

@@ -111,7 +111,7 @@ jobs:
continueOnError: false
- script: |
git clone https://github.com/openvinotoolkit/testdata.git
git clone --single-branch --branch releases/2021/2 https://github.com/openvinotoolkit/testdata.git
workingDirectory: $(WORK_DIR)
displayName: 'Clone testdata'

View File

@@ -329,6 +329,17 @@ The "fft_kernel.cpp" with the implementation of the CPU has the following conten
Refer to the [How to Implement Custom CPU Operations](../IE_DG/Extensibility_DG/CPU_Kernel.md) for more details.
#### Extension Implementation
The source code of the extension itself contains the "extension.hpp" and "extension.cpp" files.
**extension.hpp**:
@snippet ie_cpu_extension/extension.hpp fft_extension:header
**extension.cpp**:
@snippet ie_cpu_extension/extension.cpp fft_extension:implementation
### Building and Running the Custom Extension
In order to build the extension run the following:<br>
```bash
@@ -360,7 +371,6 @@ python3 $INTEL_OPENVINO_DIR/deployment_tools/tools/benchmark_tool/benchmark_app.
- [Inference Engine Extensibility Mechanism](../IE_DG/Extensibility_DG/Intro.md)
- [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md)
- [Overview of OpenVINO™ Toolkit Pre-Trained Models](@ref omz_models_intel_index)
- [Inference Engine Tutorials](https://github.com/intel-iot-devkit/inference-tutorials-generic)
- For IoT Libraries and Code Samples see the [Intel® IoT Developer Kit](https://github.com/intel-iot-devkit).
## Converting Models:

View File

@@ -156,7 +156,7 @@ The sections below contain detailed list of changes made to the Inference Engine
### Deprecated API
**Myriad Plugin API:**
**MYRIAD Plugin API:**
* VPU_CONFIG_KEY(IGNORE_IR_STATISTIC)

View File

@@ -86,3 +86,7 @@ inference of a pre-trained and optimized deep learning model and a set of sample
* [Known Issues](Known_Issues_Limitations.md)
**Typical Next Step:** [Introduction to Inference Engine](inference_engine_intro.md)
## Video: Inference Engine Concept
[![](https://img.youtube.com/vi/e6R13V8nbak/0.jpg)](https://www.youtube.com/watch?v=e6R13V8nbak)
<iframe width="560" height="315" src="https://www.youtube.com/embed/e6R13V8nbak" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

View File

@@ -122,7 +122,4 @@ The open source version is available in the [OpenVINO™ toolkit GitHub reposito
- [Intel&reg; Deep Learning Deployment Toolkit Web Page](https://software.intel.com/en-us/computer-vision-sdk)
[scheme]: img/workflow_steps.png
#### Optimization Notice
<sup>For complete information about compiler optimizations, see our [Optimization Notice](https://software.intel.com/en-us/articles/optimization-notice#opt-en).</sup>
[scheme]: img/workflow_steps.png

View File

@@ -1,3 +0,0 @@
# Optimization Notice {#openvino_docs_IE_DG_Optimization_notice}
![Optimization_notice](img/opt-notice-en_080411.gif)

View File

@@ -59,5 +59,4 @@ should be called with `weights` passed as an empty `Blob`.
- Inference Engine Developer Guide: [Inference Engine Developer Guide](Deep_Learning_Inference_Engine_DevGuide.md)
- For more information on Sample Applications, see the [Inference Engine Samples Overview](Samples_Overview.md)
- For information on a set of pre-trained models, see the [Overview of OpenVINO™ Toolkit Pre-Trained Models](@ref omz_models_intel_index)
- For information on Inference Engine Tutorials, see the [Inference Tutorials](https://github.com/intel-iot-devkit/inference-tutorials-generic)
- For IoT Libraries and Code Samples see the [Intel® IoT Developer Kit](https://github.com/intel-iot-devkit).

View File

@@ -21,7 +21,7 @@ For the "Supported Networks", please reference to [MYRIAD Plugin](MYRIAD.md)
See VPU common configuration parameters for the [VPU Plugins](VPU.md).
When specifying key values as raw strings (that is, when using Python API), omit the `KEY_` prefix.
In addition to common parameters for Myriad plugin and HDDL plugin, HDDL plugin accepts the following options:
In addition to common parameters for MYRIAD plugin and HDDL plugin, HDDL plugin accepts the following options:
| Parameter Name | Parameter Values | Default | Description |
| :--- | :--- | :--- | :--- |

View File

@@ -92,11 +92,18 @@ Notice that until R2 you had to calculate number of requests in your application
Notice that every OpenVINO sample that supports "-d" (which stays for "device") command-line option transparently accepts the multi-device.
The [Benchmark Application](../../../inference-engine/samples/benchmark_app/README.md) is the best reference to the optimal usage of the multi-device. As discussed multiple times earlier, you don't need to setup number of requests, CPU streams or threads as the application provides optimal out of the box performance.
Below is example command-line to evaluate HDDL+GPU performance with that:
```bash
$ ./benchmark_app d MULTI:HDDL,GPU m <model> -i <input> -niter 1000
```sh
./benchmark_app d MULTI:HDDL,GPU m <model> -i <input> -niter 1000
```
Notice that you can use the FP16 IR to work with multi-device (as CPU automatically upconverts it to the fp32) and rest of devices support it naturally.
Also notice that no demos are (yet) fully optimized for the multi-device, by means of supporting the OPTIMAL_NUMBER_OF_INFER_REQUESTS metric, using the GPU streams/throttling, and so on.
## Video: MULTI Plugin
[![](https://img.youtube.com/vi/xbORYFEmrqU/0.jpg)](https://www.youtube.com/watch?v=xbORYFEmrqU)
<iframe width="560" height="315" src="https://www.youtube.com/embed/xbORYFEmrqU" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## See Also
* [Supported Devices](Supported_Devices.md)

View File

@@ -9,12 +9,12 @@ This chapter provides information on the Inference Engine plugins that enable in
## Known Layers Limitations
* `'ScaleShift'` layer is supported for zero value of `'broadcast'` attribute only.
* `'CTCGreedyDecoder'` layer works with `'ctc_merge_repeated'` attribute equal 1.
* `'DetectionOutput'` layer works with zero values of `'interpolate_orientation'` and `'num_orient_classes'` parameters only.
* `'MVN'` layer uses fixed value for `'eps'` parameters (1e-9).
* `'Normalize'` layer uses fixed value for `'eps'` parameters (1e-9) and is supported for zero value of `'across_spatial'` only.
* `'Pad'` layer works only with 4D tensors.
* `ScaleShift` layer is supported for zero value of `broadcast` attribute only.
* `CTCGreedyDecoder` layer works with `ctc_merge_repeated` attribute equal 1.
* `DetectionOutput` layer works with zero values of `interpolate_orientation` and `num_orient_classes` parameters only.
* `MVN` layer uses fixed value for `eps` parameters (1e-9).
* `Normalize` layer uses fixed value for `eps` parameters (1e-9) and is supported for zero value of `across_spatial` only.
* `Pad` layer works only with 4D tensors.
## Optimizations

View File

@@ -91,3 +91,16 @@ Model Optimizer produces an Intermediate Representation (IR) of the network, whi
* [Known Issues](Known_Issues_Limitations.md)
**Typical Next Step:** [Preparing and Optimizing your Trained Model with Model Optimizer](prepare_model/Prepare_Trained_Model.md)
## Video: Model Optimizer Concept
[![](https://img.youtube.com/vi/Kl1ptVb7aI8/0.jpg)](https://www.youtube.com/watch?v=Kl1ptVb7aI8)
<iframe width="560" height="315" src="https://www.youtube.com/embed/Kl1ptVb7aI8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## Video: Model Optimizer Basic Operation
[![](https://img.youtube.com/vi/BBt1rseDcy0/0.jpg)](https://www.youtube.com/watch?v=BBt1rseDcy0)
<iframe width="560" height="315" src="https://www.youtube.com/embed/BBt1rseDcy0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## Video: Choosing the Right Precision
[![](https://img.youtube.com/vi/RF8ypHyiKrY/0.jpg)](https://www.youtube.com/watch?v=RF8ypHyiKrY)
<iframe width="560" height="315" src="https://www.youtube.com/embed/RF8ypHyiKrY" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

View File

@@ -23,7 +23,7 @@ A summary of the steps for optimizing and deploying a model that was trained wit
* **Object detection models:**
* SSD300-VGG16, SSD500-VGG16
* Faster-RCNN
* RefineDet (Myriad plugin only)
* RefineDet (MYRIAD plugin only)
* **Face detection models:**
* VGG Face

View File

@@ -280,7 +280,7 @@ python3 mo_tf.py --input_model inception_v1.pb -b 1 --tensorflow_custom_operatio
* Launching the Model Optimizer for Inception V1 frozen model and use custom sub-graph replacement file `transform.json` for model conversion. For more information about this feature, refer to [Sub-Graph Replacement in the Model Optimizer](../customize_model_optimizer/Subgraph_Replacement_Model_Optimizer.md).
```sh
python3 mo_tf.py --input_model inception_v1.pb -b 1 --tensorflow_use_custom_operations_config transform.json
python3 mo_tf.py --input_model inception_v1.pb -b 1 --transformations_config transform.json
```
* Launching the Model Optimizer for Inception V1 frozen model and dump information about the graph to TensorBoard log dir `/tmp/log_dir`
@@ -368,6 +368,10 @@ Refer to [Supported Framework Layers ](../Supported_Frameworks_Layers.md) for th
The Model Optimizer provides explanatory messages if it is unable to run to completion due to issues like typographical errors, incorrectly used options, or other issues. The message describes the potential cause of the problem and gives a link to the [Model Optimizer FAQ](../Model_Optimizer_FAQ.md). The FAQ has instructions on how to resolve most issues. The FAQ also includes links to relevant sections in the Model Optimizer Developer Guide to help you understand what went wrong.
## Video: Converting a TensorFlow Model
[![](https://img.youtube.com/vi/QW6532LtiTc/0.jpg)](https://www.youtube.com/watch?v=QW6532LtiTc)
<iframe width="560" height="315" src="https://www.youtube.com/embed/QW6532LtiTc" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## Summary
In this document, you learned:

View File

@@ -46,7 +46,7 @@ To generate the IR of the EfficientDet TensorFlow model, run:<br>
```sh
python3 $MO_ROOT/mo.py \
--input_model savedmodeldir/efficientdet-d4_frozen.pb \
--tensorflow_use_custom_operations_config $MO_ROOT/extensions/front/tf/automl_efficientdet.json \
--transformations_config $MO_ROOT/extensions/front/tf/automl_efficientdet.json \
--input_shape [1,$IMAGE_SIZE,$IMAGE_SIZE,3] \
--reverse_input_channels
```
@@ -56,7 +56,7 @@ EfficientDet models were trained with different input image sizes. To determine
dictionary in the [hparams_config.py](https://github.com/google/automl/blob/96e1fee/efficientdet/hparams_config.py#L304) file.
The attribute `image_size` specifies the shape to be specified for the model conversion.
The `tensorflow_use_custom_operations_config` command line parameter specifies the configuration json file containing hints
The `transformations_config` command line parameter specifies the configuration json file containing hints
to the Model Optimizer on how to convert the model and trigger transformations implemented in the
`$MO_ROOT/extensions/front/tf/AutomlEfficientDet.py`. The json file contains some parameters which must be changed if you
train the model yourself and modified the `hparams_config` file or the parameters are different from the ones used for EfficientDet-D4.

View File

@@ -91,7 +91,7 @@ To generate the IR of the YOLOv3 TensorFlow model, run:<br>
```sh
python3 mo_tf.py
--input_model /path/to/yolo_v3.pb
--tensorflow_use_custom_operations_config $MO_ROOT/extensions/front/tf/yolo_v3.json
--transformations_config $MO_ROOT/extensions/front/tf/yolo_v3.json
--batch 1
```
@@ -99,14 +99,14 @@ To generate the IR of the YOLOv3-tiny TensorFlow model, run:<br>
```sh
python3 mo_tf.py
--input_model /path/to/yolo_v3_tiny.pb
--tensorflow_use_custom_operations_config $MO_ROOT/extensions/front/tf/yolo_v3_tiny.json
--transformations_config $MO_ROOT/extensions/front/tf/yolo_v3_tiny.json
--batch 1
```
where:
* `--batch` defines shape of model input. In the example, `--batch` is equal to 1, but you can also specify other integers larger than 1.
* `--tensorflow_use_custom_operations_config` adds missing `Region` layers to the model. In the IR, the `Region` layer has name `RegionYolo`.
* `--transformations_config` adds missing `Region` layers to the model. In the IR, the `Region` layer has name `RegionYolo`.
> **NOTE:** The color channel order (RGB or BGR) of an input data should match the channel order of the model training dataset. If they are different, perform the `RGB<->BGR` conversion specifying the command-line parameter: `--reverse_input_channels`. Otherwise, inference results may be incorrect. For more information about the parameter, refer to **When to Reverse Input Channels** section of [Converting a Model Using General Conversion Parameters](../Converting_Model_General.md).
@@ -167,14 +167,14 @@ python3 ./mo_tf.py
--input_model <path_to_model>/<model_name>.pb \
--batch 1 \
--scale 255 \
--tensorflow_use_custom_operations_config <OPENVINO_INSTALL_DIR>/deployment_tools/model_optimizer/extensions/front/tf/<yolo_config>.json
--transformations_config <OPENVINO_INSTALL_DIR>/deployment_tools/model_optimizer/extensions/front/tf/<yolo_config>.json
```
where:
* `--batch` defines shape of model input. In the example, `--batch` is equal to 1, but you can also specify other integers larger than 1.
* `--scale` specifies scale factor that input values will be divided by.
The model was trained with input values in the range `[0,1]`. OpenVINO&trade; toolkit samples read input images as values in `[0,255]` range, so the scale 255 must be applied.
* `--tensorflow_use_custom_operations_config` adds missing `Region` layers to the model. In the IR, the `Region` layer has name `RegionYolo`.
* `--transformations_config` adds missing `Region` layers to the model. In the IR, the `Region` layer has name `RegionYolo`.
For other applicable parameters, refer to [Convert Model from TensorFlow](../Convert_Model_From_TensorFlow.md).
> **NOTE:** The color channel order (RGB or BGR) of an input data should match the channel order of the model training dataset. If they are different, perform the `RGB<->BGR` conversion specifying the command-line parameter: `--reverse_input_channels`. Otherwise, inference results may be incorrect. For more information about the parameter, refer to **When to Reverse Input Channels** section of [Converting a Model Using General Conversion Parameters](../Converting_Model_General.md).

View File

@@ -1,4 +1,4 @@
# Sub-Graph Replacement in the Model Optimizer {#openvino_docs_MO_DG_prepare_model_customize_model_optimizer_Subgraph_Replacement_Model_Optimizer}
The document has been deprecated. Refer to the [Model Optimizer Extensibility](Subgraph_Replacement_Model_Optimizer.md)
The document has been deprecated. Refer to the [Model Optimizer Extensibility](Customize_Model_Optimizer.md)
for the up-to-date documentation.

View File

@@ -1,3 +0,0 @@
# Optimization Notice {#openvino_docs_Optimization_notice}
![Optimization_notice](img/opt-notice-en_080411.gif)

View File

@@ -26,65 +26,65 @@ Measuring inference performance involves many variables and is extremely use-cas
\htmlonly
<script src="bert-large-uncased-whole-word-masking-squad-int8-0001-ov-2021-2-170.js" id="bert-large-uncased-whole-word-masking-squad-int8-0001-ov-2021-2-170"></script>
<script src="bert-large-uncased-whole-word-masking-squad-int8-0001-ov-2021-2-185.js" id="bert-large-uncased-whole-word-masking-squad-int8-0001-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="deeplabv3-tf-ov-2021-2-170.js" id="deeplabv3-tf-ov-2021-2-170"></script>
<script src="deeplabv3-tf-ov-2021-2-185.js" id="deeplabv3-tf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="densenet-121-tf-ov-2021-2-170.js" id="densenet-121-tf-ov-2021-2-170"></script>
<script src="densenet-121-tf-ov-2021-2-185.js" id="densenet-121-tf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="faster-rcnn-resnet50-coco-tf-ov-2021-2-170.js" id="faster-rcnn-resnet50-coco-tf-ov-2021-2-170"></script>
<script src="faster-rcnn-resnet50-coco-tf-ov-2021-2-185.js" id="faster-rcnn-resnet50-coco-tf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="googlenet-v1-tf-ov-2021-2-170.js" id="googlenet-v1-tf-ov-2021-2-170"></script>
<script src="googlenet-v1-tf-ov-2021-2-185.js" id="googlenet-v1-tf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="inception-v3-tf-ov-2021-2-170.js" id="inception-v3-tf-ov-2021-2-170"></script>
<script src="inception-v3-tf-ov-2021-2-185.js" id="inception-v3-tf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="mobilenet-ssd-cf-ov-2021-2-170.js" id="mobilenet-ssd-cf-ov-2021-2-170"></script>
<script src="mobilenet-ssd-cf-ov-2021-2-185.js" id="mobilenet-ssd-cf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="mobilenet-v1-1-0-224-tf-ov-2021-2-170.js" id="mobilenet-v1-1-0-224-tf-ov-2021-2-170"></script>
<script src="mobilenet-v1-1-0-224-tf-ov-2021-2-185.js" id="mobilenet-v1-1-0-224-tf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="mobilenet-v2-pytorch-ov-2021-2-170.js" id="mobilenet-v2-pytorch-ov-2021-2-170"></script>
<script src="mobilenet-v2-pytorch-ov-2021-2-185.js" id="mobilenet-v2-pytorch-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="resnet-18-pytorch-ov-2021-2-170.js" id="resnet-18-pytorch-ov-2021-2-170"></script>
<script src="resnet-18-pytorch-ov-2021-2-185.js" id="resnet-18-pytorch-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="resnet-50-tf-ov-2021-2-170.js" id="resnet-50-tf-ov-2021-2-170"></script>
<script src="resnet-50-tf-ov-2021-2-185.js" id="resnet-50-tf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="se-resnext-50-cf-ov-2021-2-170.js" id="se-resnext-50-cf-ov-2021-2-170"></script>
<script src="se-resnext-50-cf-ov-2021-2-185.js" id="se-resnext-50-cf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="squeezenet1-1-cf-ov-2021-2-170.js" id="squeezenet1-1-cf-ov-2021-2-170"></script>
<script src="squeezenet1-1-cf-ov-2021-2-185.js" id="squeezenet1-1-cf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="ssd300-cf-ov-2021-2-170.js" id="ssd300-cf-ov-2021-2-170"></script>
<script src="ssd300-cf-ov-2021-2-185.js" id="ssd300-cf-ov-2021-2-185"></script>
\endhtmlonly
\htmlonly
<script src="yolo-v3-tf-ov-2021-2-170.js" id="yolo-v3-tf-ov-2021-2-170"></script>
<script src="yolo-v3-tf-ov-2021-2-185.js" id="yolo-v3-tf-ov-2021-2-185"></script>
\endhtmlonly
@@ -168,8 +168,8 @@ Testing by Intel done on: see test date for each HW platform below.
| Precision | INT8 | INT8 | INT8 | INT8 |
| Number of concurrent inference requests |4 | 24 | 5 | 4 |
| Test Date | December 9, 2020 | December 9, 2020 | December 9, 2020 | December 9, 2020 |
| Power dissipation, TDP in Watt | [35](https://ark.intel.com/content/www/us/en/ark/products/129948/intel-core-i7-8700t-processor-12m-cache-up-to-4-00-ghz.html#tab-blade-1-0-1) | [165](https://ark.intel.com/content/www/us/en/ark/products/198012/intel-core-i9-10920x-x-series-processor-19-25m-cache-3-50-ghz.html) | [35](https://ark.intel.com/content/www/us/en/ark/products/203901/intel-core-i9-10900te-processor-20m-cache-up-to-4-60-ghz.html) | [28](https://ark.intel.com/content/www/us/en/ark/products/208081/intel-core-i5-1145g7e-processor-8m-cache-up-to-4-10-ghz.html) |
| CPU Price on September 29, 2020, USD<br>Prices may vary | [303](https://ark.intel.com/content/www/us/en/ark/products/129948/intel-core-i7-8700t-processor-12m-cache-up-to-4-00-ghz.html) | [700](https://ark.intel.com/content/www/us/en/ark/products/198012/intel-core-i9-10920x-x-series-processor-19-25m-cache-3-50-ghz.html) | [444](https://ark.intel.com/content/www/us/en/ark/products/203901/intel-core-i9-10900te-processor-20m-cache-up-to-4-60-ghz.html) | [426](https://mysamples.intel.com/SAM_U_Product/ProductDetail.aspx?InputMMID=99A3D1&RequestID=0&ProductID=1213750) |
| Power dissipation, TDP in Watt | [35](https://ark.intel.com/content/www/us/en/ark/products/129948/intel-core-i7-8700t-processor-12m-cache-up-to-4-00-ghz.html#tab-blade-1-0-1) | [165](https://ark.intel.com/content/www/us/en/ark/products/198012/intel-core-i9-10920x-x-series-processor-19-25m-cache-3-50-ghz.html) | [35](https://ark.intel.com/content/www/us/en/ark/products/203901/intel-core-i9-10900te-processor-20m-cache-up-to-4-60-ghz.html) | [28](https://ark.intel.com/content/www/us/en/ark/products/208664/intel-core-i7-1185g7-processor-12m-cache-up-to-4-80-ghz-with-ipu.html#tab-blade-1-0-1) |
| CPU Price on September 29, 2020, USD<br>Prices may vary | [303](https://ark.intel.com/content/www/us/en/ark/products/129948/intel-core-i7-8700t-processor-12m-cache-up-to-4-00-ghz.html) | [700](https://ark.intel.com/content/www/us/en/ark/products/198012/intel-core-i9-10920x-x-series-processor-19-25m-cache-3-50-ghz.html) | [444](https://ark.intel.com/content/www/us/en/ark/products/203901/intel-core-i9-10900te-processor-20m-cache-up-to-4-60-ghz.html) | [426](https://ark.intel.com/content/www/us/en/ark/products/208664/intel-core-i7-1185g7-processor-12m-cache-up-to-4-80-ghz-with-ipu.html#tab-blade-1-0-0) |
**CPU Inference Engines (continue)**

View File

@@ -276,7 +276,6 @@
<tab type="user" title="GNA Plugin" url="@ref openvino_docs_IE_DG_supported_plugins_GNA"/>
</tab>
<tab type="user" title="Known Issues" url="@ref openvino_docs_IE_DG_Known_Issues_Limitations"/>
<tab type="user" title="Optimization Notice" url="@ref openvino_docs_Optimization_notice"/>
<tab type="user" title="Glossary" url="@ref openvino_docs_IE_DG_Glossary"/>
</tab>

View File

@@ -19,10 +19,7 @@
<tab type="user" title="DL Streamer API Reference" url="https://openvinotoolkit.github.io/dlstreamer_gst/"/>
<tab type="user" title="nGraph С++ API Reference" url="../ngraph_cpp_api/annotated.html"/>
<!-- nGraph Python API Reference -->
<tab type="files" visible="yes" title="nGraph Python API Reference">
<tab type="filelist" visible="yes" title="nGraph Python API Reference" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="filelist" visible="yes" title="nGraph Python API Reference" intro=""/>
</tab>
<!-- Chinese docs -->
<tab type="user" title="中文文件" url="https://docs.openvinotoolkit.org/cn/index.html"/>

View File

@@ -96,6 +96,19 @@
<tab type="user" title="DL Streamer API Reference" url="https://openvinotoolkit.github.io/dlstreamer_gst/"/>
<!-- DL Streamer Examples -->
<tab type="usergroup" title="DL Streamer Examples" url="@ref gst_samples_README">
</tab>
<!-- G-API -->
<tab type="usergroup" title="Graph API (G-API) Developer Guide" url="@ref openvino_docs_gapi_gapi_intro">
<tab type="user" title="Introduction to G-API" url="@ref openvino_docs_gapi_gapi_intro"/>
<tab type="user" title="G-API Kernel API" url="@ref openvino_docs_gapi_kernel_api"/>
<tab type="user" title="Use Cases: Implementing a Face Beautification Algorithm" url="@ref openvino_docs_gapi_face_beautification"/>
<tab type="user" title="Use Cases: Building a Face Analytics Pipeline" url="@ref openvino_docs_gapi_gapi_face_analytics_pipeline"/>
<tab type="usergroup" title="API Reference" url="">
<tab type="user" title="G-API Core functionality" url="https://docs.opencv.org/4.2.0/df/d1f/group__gapi__core.html"/>
<tab type="user" title="G-API Image processing functionality" url="https://docs.opencv.org/4.2.0/d2/d00/group__gapi__imgproc.html"/>
<tab type="user" title="G-API Drawing and composition functionality" url="https://docs.opencv.org/4.2.0/df/de4/group__gapi__draw.html"/>
<tab type="user" title="G-API Framework" url="https://docs.opencv.org/4.2.0/d7/d0d/group__gapi.html"/>
</tab>
</tab>
<!-- OpenVX -->
<tab type="user" title="OpenVX Developer Guide" url="https://software.intel.com/en-us/openvino-ovx-guide"/>

View File

@@ -0,0 +1,435 @@
# Implementing a Face Beautification Algorithm {#openvino_docs_gapi_face_beautification}
## Introduction
In this tutorial you will learn:
* Basics of a sample face beautification algorithm;
* How to infer different networks inside a pipeline with G-API;
* How to run a G-API pipeline on a video stream.
## Prerequisites
This sample requires:
* PC with GNU/Linux* or Microsoft Windows* (Apple macOS* is supported but was not tested)
* OpenCV 4.2 or higher built with [Intel® Distribution of OpenVINO™ Toolkit](https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit.html) (building with [Intel® TBB](https://www.threadingbuildingblocks.org/intel-tbb-tutorial) is a plus)
* The following pre-trained models from the [Open Model Zoo](@ref omz_models_intel_index)
* [face-detection-adas-0001](@ref omz_models_intel_face_detection_adas_0001_description_face_detection_adas_0001)
* [facial-landmarks-35-adas-0002](@ref omz_models_intel_facial_landmarks_35_adas_0002_description_facial_landmarks_35_adas_0002)
To download the models from the Open Model Zoo, use the [Model Downloader](@ref omz_tools_downloader_README) tool.
## Face Beautification Algorithm
We will implement a simple face beautification algorithm using a combination of modern Deep Learning techniques and traditional Computer Vision. The general idea behind the algorithm is to make face skin smoother while preserving face features like eyes or a mouth contrast. The algorithm identifies parts of the face using a DNN inference, applies different filters to the parts found, and then combines it into the final result using basic image arithmetics:
![Face Beautification Algorithm](../img/gapi_face_beautification_algorithm.png)
Briefly the algorithm is described as follows:
Briefly the algorithm is described as follows:
- Input image \f$I\f$ is passed to unsharp mask and bilateral filters
(\f$U\f$ and \f$L\f$ respectively);
- Input image \f$I\f$ is passed to an SSD-based face detector;
- SSD result (a \f$[1 \times 1 \times 200 \times 7]\f$ blob) is parsed and converted to an array of faces;
- Every face is passed to a landmarks detector;
- Based on landmarks found for every face, three image masks are generated:
- A background mask \f$b\f$ -- indicating which areas from the original image to keep as-is;
- A face part mask \f$p\f$ -- identifying regions to preserve (sharpen).
- A face skin mask \f$s\f$ -- identifying regions to blur;
- The final result \f$O\f$ is a composition of features above calculated as \f$O = b*I + p*U + s*L\f$.
Generating face element masks based on a limited set of features (just 35 per face, including all its parts) is not very trivial and is described in the sections below.
## Constructing a G-API Pipeline
### Declare Deep Learning Topologies
This sample is using two DNN detectors. Every network takes one input and produces one output. In G-API, networks are defined with macro G_API_NET():
```cpp
G_API_NET(FaceDetector, <cv::GMat(cv::GMat)>, "face_detector");
G_API_NET(LandmDetector, <cv::GMat(cv::GMat)>, "landm_detector");
```
To get more information, see Declaring Deep Learning topologies described in the "Face Analytics pipeline" tutorial.
### Describe the Processing Graph
The code below generates a graph for the algorithm above:
```cpp
cv::GComputation pipeline([=]()
{
cv::GMat gimgIn; // input
cv::GMat faceOut = cv::gapi::infer<custom::FaceDetector>(gimgIn);
GArrayROI garRects = custom::GFacePostProc::on(faceOut, gimgIn, config::kConfThresh); // post-proc
cv::GArray<cv::GMat> landmOut = cv::gapi::infer<custom::LandmDetector>(garRects, gimgIn);
cv::GArray<Landmarks> garElems; // |
cv::GArray<Contour> garJaws; // |output arrays
std::tie(garElems, garJaws) = custom::GLandmPostProc::on(landmOut, garRects); // post-proc
cv::GArray<Contour> garElsConts; // face elements
cv::GArray<Contour> garFaceConts; // whole faces
std::tie(garElsConts, garFaceConts) = custom::GGetContours::on(garElems, garJaws); // interpolation
cv::GMat mskSharp = custom::GFillPolyGContours::on(gimgIn, garElsConts); // |
cv::GMat mskSharpG = cv::gapi::gaussianBlur(mskSharp, config::kGKernelSize, // |
config::kGSigma); // |
cv::GMat mskBlur = custom::GFillPolyGContours::on(gimgIn, garFaceConts); // |
cv::GMat mskBlurG = cv::gapi::gaussianBlur(mskBlur, config::kGKernelSize, // |
config::kGSigma); // |draw masks
// The first argument in mask() is Blur as we want to subtract from // |
// BlurG the next step: // |
cv::GMat mskBlurFinal = mskBlurG - cv::gapi::mask(mskBlurG, mskSharpG); // |
cv::GMat mskFacesGaussed = mskBlurFinal + mskSharpG; // |
cv::GMat mskFacesWhite = cv::gapi::threshold(mskFacesGaussed, 0, 255, cv::THRESH_BINARY); // |
cv::GMat mskNoFaces = cv::gapi::bitwise_not(mskFacesWhite); // |
cv::GMat gimgBilat = custom::GBilatFilter::on(gimgIn, config::kBSize,
config::kBSigmaCol, config::kBSigmaSp);
cv::GMat gimgSharp = custom::unsharpMask(gimgIn, config::kUnshSigma,
config::kUnshStrength);
// Applying the masks
// Custom function mask3C() should be used instead of just gapi::mask()
// as mask() provides CV_8UC1 source only (and we have CV_8U3C)
cv::GMat gimgBilatMasked = custom::mask3C(gimgBilat, mskBlurFinal);
cv::GMat gimgSharpMasked = custom::mask3C(gimgSharp, mskSharpG);
cv::GMat gimgInMasked = custom::mask3C(gimgIn, mskNoFaces);
cv::GMat gimgBeautif = gimgBilatMasked + gimgSharpMasked + gimgInMasked;
return cv::GComputation(cv::GIn(gimgIn), cv::GOut(gimgBeautif,
cv::gapi::copy(gimgIn),
garFaceConts,
garElsConts,
garRects));
});
```
The resulting graph is a mixture of G-API's standard operations, user-defined operations (namespace custom::), and DNN inference. The generic function `cv::gapi::infer<>()` allows you to trigger inference within the pipeline; networks to infer are specified as template parameters. The sample code is using two versions of `cv::gapi::infer<>()`:
* A frame-oriented one is used to detect faces on the input frame.
* An ROI-list oriented one is used to run landmarks inference on a list of faces this version produces an array of landmarks per every face.
More on this in "Face Analytics pipeline" ([Building a GComputation](@ref gapi_ifd_gcomputation) section).
### Unsharp mask in G-API
The unsharp mask \f$U\f$ for image \f$I\f$ is defined as:
\f[U = I - s * L(M(I)),\f]
where \f$M()\f$ is a median filter, \f$L()\f$ is the Laplace operator, and \f$s\f$ is a strength coefficient. While G-API doesn't provide this function out-of-the-box, it is expressed naturally with the existing G-API operations:
```cpp
inline cv::GMat custom::unsharpMask(const cv::GMat &src,
const int sigma,
const float strength)
{
cv::GMat blurred = cv::gapi::medianBlur(src, sigma);
cv::GMat laplacian = custom::GLaplacian::on(blurred, CV_8U);
return (src - (laplacian * strength));
}
```
Note that the code snipped above is a regular C++ function defined with G-API types. Users can write functions like this to simplify graph construction; when called, this function just puts the relevant nodes to the pipeline it is used in.
## Custom Operations
The face beautification graph is using custom operations extensively. This chapter focuses on the most interesting kernels, refer to G-API Kernel API for general information on defining operations and implementing kernels in G-API.
### Face detector post-processing
A face detector output is converted to an array of faces with the following kernel:
```cpp
using VectorROI = std::vector<cv::Rect>;
GAPI_OCV_KERNEL(GCPUFacePostProc, GFacePostProc)
{
static void run(const cv::Mat &inDetectResult,
const cv::Mat &inFrame,
const float faceConfThreshold,
VectorROI &outFaces)
{
const int kObjectSize = 7;
const int imgCols = inFrame.size().width;
const int imgRows = inFrame.size().height;
const cv::Rect borders({0, 0}, inFrame.size());
outFaces.clear();
const int numOfDetections = inDetectResult.size[2];
const float *data = inDetectResult.ptr<float>();
for (int i = 0; i < numOfDetections; i++)
{
const float faceId = data[i * kObjectSize + 0];
if (faceId < 0.f) // indicates the end of detections
{
break;
}
const float faceConfidence = data[i * kObjectSize + 2];
// We can cut detections by the `conf` field
// to avoid mistakes of the detector.
if (faceConfidence > faceConfThreshold)
{
const float left = data[i * kObjectSize + 3];
const float top = data[i * kObjectSize + 4];
const float right = data[i * kObjectSize + 5];
const float bottom = data[i * kObjectSize + 6];
// These are normalized coordinates and are between 0 and 1;
// to get the real pixel coordinates we should multiply it by
// the image sizes respectively to the directions:
cv::Point tl(toIntRounded(left * imgCols),
toIntRounded(top * imgRows));
cv::Point br(toIntRounded(right * imgCols),
toIntRounded(bottom * imgRows));
outFaces.push_back(cv::Rect(tl, br) & borders);
}
}
}
};
```
### Facial Landmarks Post-Processing
The algorithm infers locations of face elements (like the eyes, the mouth and the head contour itself) using a generic facial landmarks detector (details) from OpenVINO™ Open Model Zoo. However, the detected landmarks as-is are not enough to generate masks — this operation requires regions of interest on the face represented by closed contours, so some interpolation is applied to get them. This landmarks processing and interpolation is performed by the following kernel:
```cpp
GAPI_OCV_KERNEL(GCPUGetContours, GGetContours)
{
static void run(const std::vector<Landmarks> &vctPtsFaceElems, // 18 landmarks of the facial elements
const std::vector<Contour> &vctCntJaw, // 17 landmarks of a jaw
std::vector<Contour> &vctElemsContours,
std::vector<Contour> &vctFaceContours)
{
size_t numFaces = vctCntJaw.size();
CV_Assert(numFaces == vctPtsFaceElems.size());
CV_Assert(vctElemsContours.size() == 0ul);
CV_Assert(vctFaceContours.size() == 0ul);
// vctFaceElemsContours will store all the face elements' contours found
// in an input image, namely 4 elements (two eyes, nose, mouth) for every detected face:
vctElemsContours.reserve(numFaces * 4);
// vctFaceElemsContours will store all the faces' contours found in an input image:
vctFaceContours.reserve(numFaces);
Contour cntFace, cntLeftEye, cntRightEye, cntNose, cntMouth;
cntNose.reserve(4);
for (size_t i = 0ul; i < numFaces; i++)
{
// The face elements contours
// A left eye:
// Approximating the lower eye contour by half-ellipse (using eye points) and storing in cntLeftEye:
cntLeftEye = getEyeEllipse(vctPtsFaceElems[i][1], vctPtsFaceElems[i][0]);
// Pushing the left eyebrow clock-wise:
cntLeftEye.insert(cntLeftEye.end(), {vctPtsFaceElems[i][12], vctPtsFaceElems[i][13],
vctPtsFaceElems[i][14]});
// A right eye:
// Approximating the lower eye contour by half-ellipse (using eye points) and storing in vctRightEye:
cntRightEye = getEyeEllipse(vctPtsFaceElems[i][2], vctPtsFaceElems[i][3]);
// Pushing the right eyebrow clock-wise:
cntRightEye.insert(cntRightEye.end(), {vctPtsFaceElems[i][15], vctPtsFaceElems[i][16],
vctPtsFaceElems[i][17]});
// A nose:
// Storing the nose points clock-wise
cntNose.clear();
cntNose.insert(cntNose.end(), {vctPtsFaceElems[i][4], vctPtsFaceElems[i][7],
vctPtsFaceElems[i][5], vctPtsFaceElems[i][6]});
// A mouth:
// Approximating the mouth contour by two half-ellipses (using mouth points) and storing in vctMouth:
cntMouth = getPatchedEllipse(vctPtsFaceElems[i][8], vctPtsFaceElems[i][9],
vctPtsFaceElems[i][10], vctPtsFaceElems[i][11]);
// Storing all the elements in a vector:
vctElemsContours.insert(vctElemsContours.end(), {cntLeftEye, cntRightEye, cntNose, cntMouth});
// The face contour:
// Approximating the forehead contour by half-ellipse (using jaw points) and storing in vctFace:
cntFace = getForeheadEllipse(vctCntJaw[i][0], vctCntJaw[i][16], vctCntJaw[i][8]);
// The ellipse is drawn clock-wise, but jaw contour points goes vice versa, so it's necessary to push
// cntJaw from the end to the begin using a reverse iterator:
std::copy(vctCntJaw[i].crbegin(), vctCntJaw[i].crend(), std::back_inserter(cntFace));
// Storing the face contour in another vector:
vctFaceContours.push_back(cntFace);
}
}
};
```
The kernel takes two arrays of denormalized landmarks coordinates and returns an array of elements' closed contours and an array of faces' closed contours; in other words, outputs are, the first, an array of contours of image areas to be sharpened and, the second, another one to be smoothed.
Here and below `Contour` is a vector of points.
#### Get an Eye Contour
Eye contours are estimated with the following function:
```cpp
inline int custom::getLineInclinationAngleDegrees(const cv::Point &ptLeft, const cv::Point &ptRight)
{
const cv::Point residual = ptRight - ptLeft;
if (residual.y == 0 && residual.x == 0)
return 0;
else
return toIntRounded(atan2(toDouble(residual.y), toDouble(residual.x)) * 180.0 / CV_PI);
}
inline Contour custom::getEyeEllipse(const cv::Point &ptLeft, const cv::Point &ptRight)
{
Contour cntEyeBottom;
const cv::Point ptEyeCenter((ptRight + ptLeft) / 2);
const int angle = getLineInclinationAngleDegrees(ptLeft, ptRight);
const int axisX = toIntRounded(cv::norm(ptRight - ptLeft) / 2.0);
// According to research, in average a Y axis of an eye is approximately
// 1/3 of an X one.
const int axisY = axisX / 3;
// We need the lower part of an ellipse:
static constexpr int kAngEyeStart = 0;
static constexpr int kAngEyeEnd = 180;
cv::ellipse2Poly(ptEyeCenter, cv::Size(axisX, axisY), angle, kAngEyeStart, kAngEyeEnd, config::kAngDelta,
cntEyeBottom);
return cntEyeBottom;
}
```
Briefly, this function restores the bottom side of an eye by a half-ellipse based on two points in left and right eye corners. In fact, `cv::ellipse2Poly()` is used to approximate the eye region, and the function only defines ellipse parameters based on just two points:
- The ellipse center and the \f$X\f$ half-axis calculated by two eye Points.
- The \f$Y\f$ half-axis calculated according to the assumption that an average eye width is \f$1/3\f$ of its length.
- The start and the end angles which are 0 and 180 (refer to `cv::ellipse()` documentation).
- The angle delta: how much points to produce in the contour.
- The inclination angle of the axes.
The use of the `atan2()` instead of just `atan()` in function `custom::getLineInclinationAngleDegrees()` is essential as it allows to return a negative value depending on the `x` and the `y` signs so we can get the right angle even in case of upside-down face arrangement (if we put the points in the right order, of course).
#### Get a Forehead Contour
The function approximates the forehead contour:
```cpp
inline Contour custom::getForeheadEllipse(const cv::Point &ptJawLeft,
const cv::Point &ptJawRight,
const cv::Point &ptJawLower)
{
Contour cntForehead;
// The point amid the top two points of a jaw:
const cv::Point ptFaceCenter((ptJawLeft + ptJawRight) / 2);
// This will be the center of the ellipse.
// The angle between the jaw and the vertical:
const int angFace = getLineInclinationAngleDegrees(ptJawLeft, ptJawRight);
// This will be the inclination of the ellipse
// Counting the half-axis of the ellipse:
const double jawWidth = cv::norm(ptJawLeft - ptJawRight);
// A forehead width equals the jaw width, and we need a half-axis:
const int axisX = toIntRounded(jawWidth / 2.0);
const double jawHeight = cv::norm(ptFaceCenter - ptJawLower);
// According to research, in average a forehead is approximately 2/3 of
// a jaw:
const int axisY = toIntRounded(jawHeight * 2 / 3.0);
// We need the upper part of an ellipse:
static constexpr int kAngForeheadStart = 180;
static constexpr int kAngForeheadEnd = 360;
cv::ellipse2Poly(ptFaceCenter, cv::Size(axisX, axisY), angFace, kAngForeheadStart, kAngForeheadEnd,
config::kAngDelta, cntForehead);
return cntForehead;
}
```
As we have only jaw points in our detected landmarks, we have to get a half-ellipse based on three points of a jaw: the leftmost, the rightmost and the lowest one. The jaw width is assumed to be equal to the forehead width and the latter is calculated using the left and the right points. Speaking of the \f$Y\f$ axis, we have no points to get it directly, and instead assume that the forehead height is about \f$2/3\f$ of the jaw height, which can be figured out from the face center (the middle between the left and right points) and the lowest jaw point.
### Draw Masks
When we have all the contours needed, you are able to draw masks:
```cpp
cv::GMat mskSharp = custom::GFillPolyGContours::on(gimgIn, garElsConts); // |
cv::GMat mskSharpG = cv::gapi::gaussianBlur(mskSharp, config::kGKernelSize, // |
config::kGSigma); // |
cv::GMat mskBlur = custom::GFillPolyGContours::on(gimgIn, garFaceConts); // |
cv::GMat mskBlurG = cv::gapi::gaussianBlur(mskBlur, config::kGKernelSize, // |
config::kGSigma); // |draw masks
// The first argument in mask() is Blur as we want to subtract from // |
// BlurG the next step: // |
cv::GMat mskBlurFinal = mskBlurG - cv::gapi::mask(mskBlurG, mskSharpG); // |
cv::GMat mskFacesGaussed = mskBlurFinal + mskSharpG; // |
cv::GMat mskFacesWhite = cv::gapi::threshold(mskFacesGaussed, 0, 255, cv::THRESH_BINARY); // |
cv::GMat mskNoFaces = cv::gapi::bitwise_not(mskFacesWhite); // |
```
The steps to get the masks are:
* the "sharp" mask calculation:
* fill the contours that should be sharpened;
* blur that to get the "sharp" mask (`mskSharpG`);
* the "bilateral" mask calculation:
* fill all the face contours fully;
* blur that;
* subtract areas which intersect with the "sharp" mask --- and get the "bilateral" mask (`mskBlurFinal`);
* the background mask calculation:
* add two previous masks
* set all non-zero pixels of the result as 255 (by `cv::gapi::threshold()`)
* revert the output (by `cv::gapi::bitwise_not`) to get the background mask (`mskNoFaces`).
## Configuring and Running the Pipeline
Once the graph is fully expressed, we can finally compile it and run on real data. G-API graph compilation is the stage where the G-API framework actually understands which kernels and networks to use. This configuration happens via G-API compilation arguments.
### DNN Parameters
This sample is using OpenVINO™ Toolkit Inference Engine backend for DL inference, which is configured the following way:
```cpp
auto faceParams = cv::gapi::ie::Params<custom::FaceDetector>
{
/*std::string*/ faceXmlPath,
/*std::string*/ faceBinPath,
/*std::string*/ faceDevice
};
auto landmParams = cv::gapi::ie::Params<custom::LandmDetector>
{
/*std::string*/ landmXmlPath,
/*std::string*/ landmBinPath,
/*std::string*/ landmDevice
};
```
Every `cv::gapi::ie::Params<>` object is related to the network specified in its template argument. We should pass there the network type we have defined in `G_API_NET()` in the early beginning of the tutorial.
Network parameters are then wrapped in `cv::gapi::NetworkPackage`:
```cpp
auto networks = cv::gapi::networks(faceParams, landmParams);
```
More details in "Face Analytics Pipeline" ([Configuring the Pipeline](@ref gapi_ifd_configuration) section).
### Kernel Packages
In this example we use a lot of custom kernels, in addition to that we use Fluid backend to optimize out memory for G-API's standard kernels where applicable. The resulting kernel package is formed like this:
```cpp
auto customKernels = cv::gapi::kernels<custom::GCPUBilateralFilter,
custom::GCPULaplacian,
custom::GCPUFillPolyGContours,
custom::GCPUPolyLines,
custom::GCPURectangle,
custom::GCPUFacePostProc,
custom::GCPULandmPostProc,
custom::GCPUGetContours>();
auto kernels = cv::gapi::combine(cv::gapi::core::fluid::kernels(),
customKernels);
```
### Compiling the Streaming Pipeline
G-API optimizes execution for video streams when compiled in the "Streaming" mode.
```cpp
cv::GStreamingCompiled stream = pipeline.compileStreaming(cv::compile_args(kernels, networks));
```
More on this in "Face Analytics Pipeline" ([Configuring the pipeline](@ref gapi_ifd_configuration) section).
### Running the streaming pipeline
In order to run the G-API streaming pipeline, all we need is to specify the input video source, call `cv::GStreamingCompiled::start()`, and then fetch the pipeline processing results:
```cpp
if (parser.has("input"))
{
stream.setSource(cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(parser.get<cv::String>("input")));
}
auto out_vector = cv::gout(imgBeautif, imgShow, vctFaceConts,
vctElsConts, vctRects);
stream.start();
avg.start();
while (stream.running())
{
if (!stream.try_pull(std::move(out_vector)))
{
// Use a try_pull() to obtain data.
// If there's no data, let UI refresh (and handle keypress)
if (cv::waitKey(1) >= 0) break;
else continue;
}
frames++;
// Drawing face boxes and landmarks if necessary:
if (flgLandmarks == true)
{
cv::polylines(imgShow, vctFaceConts, config::kClosedLine,
config::kClrYellow);
cv::polylines(imgShow, vctElsConts, config::kClosedLine,
config::kClrYellow);
}
if (flgBoxes == true)
for (auto rect : vctRects)
cv::rectangle(imgShow, rect, config::kClrGreen);
cv::imshow(config::kWinInput, imgShow);
cv::imshow(config::kWinFaceBeautification, imgBeautif);
}
```
Once results are ready and can be pulled from the pipeline we display it on the screen and handle GUI events.
See [Running the pipeline](@ref gapi_ifd_running) section in the "Face Analytics Pipeline" tutorial for more details.
## Conclusion
The tutorial has two goals: to show the use of brand new features of G-API introduced in OpenCV 4.2, and give a basic understanding on a sample face beautification algorithm.
The result of the algorithm application:
![Face Beautification example](../img/gapi_face_beautification_example.jpg)
On the test machine (Intel® Core™ i7-8700) the G-API-optimized video pipeline outperforms its serial (non-pipelined) version by a factor of 2.7 meaning that for such a non-trivial graph, the proper pipelining can bring almost 3x increase in performance.

View File

@@ -0,0 +1,325 @@
# Building a Face Analytics Pipeline {#openvino_docs_gapi_gapi_face_analytics_pipeline}
## Overview
In this tutorial you will learn:
* How to integrate Deep Learning inference in a G-API graph.
* How to run a G-API graph on a video stream and obtain data from it.
## Prerequisites
This sample requires:
* PC with GNU/Linux* or Microsoft Windows* (Apple macOS* is supported but was not tested)
* OpenCV 4.2 or higher built with [Intel® Distribution of OpenVINO™ Toolkit](https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit.html) (building with [Intel® TBB](https://www.threadingbuildingblocks.org/intel-tbb-tutorial)
* The following pre-trained models from the [Open Model Zoo](@ref omz_models_intel_index):
* [face-detection-adas-0001](@ref omz_models_intel_face_detection_adas_0001_description_face_detection_adas_0001)
* [age-gender-recognition-retail-0013](@ref omz_models_intel_age_gender_recognition_retail_0013_description_age_gender_recognition_retail_0013)
* [emotions-recognition-retail-0003](@ref omz_models_intel_emotions_recognition_retail_0003_description_emotions_recognition_retail_0003)
To download the models from the Open Model Zoo, use the [Model Downloader](@ref omz_tools_downloader_README) tool.
## Introduction: Why G-API
Many computer vision algorithms run on a video stream rather than on individual images. Stream processing usually consists of multiple steps like decode, preprocessing, detection, tracking, classification (on detected objects), and visualization forming a *video processing pipeline*. Moreover, many these steps of such pipeline can run in parallel modern platforms have different hardware blocks on the same chip like decoders and GPUs, and extra accelerators can be plugged in as extensions, like Intel® Movidius™ Neural Compute Stick for deep learning offload.
Given all this manifold of options and a variety in video analytics algorithms, managing such pipelines effectively quickly becomes a problem. For sure it can be done manually, but this approach doesn't scale: if a change is required in the algorithm (e.g. a new pipeline step is added), or if it is ported on a new platform with different capabilities, the whole pipeline needs to be re-optimized.
Starting with version 4.2, OpenCV offers a solution to this problem. OpenCV G-API now can manage Deep Learning inference (a cornerstone of any modern analytics pipeline) with a traditional Computer Vision as well as video capturing/decoding, all in a single pipeline. G-API takes care of pipelining itself so if the algorithm or platform changes, the execution model adapts to it automatically.
## Pipeline Overview
Our sample application is based on [Interactive Face Detection](omz_demos_interactive_face_detection_demo_README) demo from Open Model Zoo. A simplified pipeline consists of the following steps:
1. Image acquisition and decode
2. Detection with preprocessing
3. Classification with preprocessing for every detected object with two networks
4. Visualization
![Face Analytics Pipeline Overview](../img/gapi_face_analytics_pipeline.png)
## Construct a pipeline {#gapi_ifd_constructing}
Constructing a G-API graph for a video streaming case does not differ much from a [regular usage](https://docs.opencv.org/4.5.0/d0/d1e/gapi.html#gapi_example) of G-API -- it is still about defining graph *data* (with cv::GMat, `cv::GScalar`, and `cv::GArray`) and *operations* over it. Inference also becomes an operation in the graph, but is defined in a little bit different way.
### Declare Deep Learning topologies {#gapi_ifd_declaring_nets}
In contrast with traditional CV functions (see [core](https://docs.opencv.org/4.5.0/df/d1f/group__gapi__core.html) and [imgproc](https://docs.opencv.org/4.5.0/d2/d00/group__gapi__imgproc.html)) where G-API declares distinct operations for every function, inference in G-API is a single generic operation `cv::gapi::infer<>`. As usual, it is just an interface and it can be implemented in a number of ways under the hood. In OpenCV 4.2, only OpenVINO™ Inference Engine-based backend is available, and OpenCV's own DNN module-based backend is to come.
`cv::gapi::infer<>` is _parametrized_ by the details of a topology we are going to execute. Like operations, topologies in G-API are strongly typed and are defined with a special macro `G_API_NET()`:
```cpp
// Face detector: takes one Mat, returns another Mat
G_API_NET(Faces, <cv::GMat(cv::GMat)>, "face-detector");
// Age/Gender recognition - takes one Mat, returns two:
// one for Age and one for Gender. In G-API, multiple-return-value operations
// are defined using std::tuple<>.
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "age-gender-recoginition");
// Emotion recognition - takes one Mat, returns another.
G_API_NET(Emotions, <cv::GMat(cv::GMat)>, "emotions-recognition");
```
Similar to how operations are defined with `G_API_OP()`, network description requires three parameters:
1. A type name. Every defined topology is declared as a distinct C++ type which is used further in the program -- see below.
2. A `std::function<>`-like API signature. G-API traits networks as regular "functions" which take and return data. Here network `Faces` (a detector) takes a `cv::GMat` and returns a `cv::GMat`, while network `AgeGender` is known to provide two outputs (age and gender blobs, respectively) -- so its has a `std::tuple<>` as a return type.
3. A topology name -- can be any non-empty string, G-API is using these names to distinguish networks inside. Names should be unique in the scope of a single graph.
## Building a GComputation {#gapi_ifd_gcomputation}
Now the above pipeline is expressed in G-API like this:
```cpp
cv::GComputation pp([]() {
// Declare an empty GMat - the beginning of the pipeline.
cv::GMat in;
// Run face detection on the input frame. Result is a single GMat,
// internally representing an 1x1x200x7 SSD output.
// This is a single-patch version of infer:
// - Inference is running on the whole input image;
// - Image is converted and resized to the network's expected format
// automatically.
cv::GMat detections = cv::gapi::infer<custom::Faces>(in);
// Parse SSD output to a list of ROI (rectangles) using
// a custom kernel. Note: parsing SSD may become a "standard" kernel.
cv::GArray<cv::Rect> faces = custom::PostProc::on(detections, in);
// Now run Age/Gender model on every detected face. This model has two
// outputs (for age and gender respectively).
// A special ROI-list-oriented form of infer<>() is used here:
// - First input argument is the list of rectangles to process,
// - Second one is the image where to take ROI from;
// - Crop/Resize/Layout conversion happens automatically for every image patch
// from the list
// - Inference results are also returned in form of list (GArray<>)
// - Since there're two outputs, infer<> return two arrays (via std::tuple).
cv::GArray<cv::GMat> ages;
cv::GArray<cv::GMat> genders;
std::tie(ages, genders) = cv::gapi::infer<custom::AgeGender>(faces, in);
// Recognize emotions on every face.
// ROI-list-oriented infer<>() is used here as well.
// Since custom::Emotions network produce a single output, only one
// GArray<> is returned here.
cv::GArray<cv::GMat> emotions = cv::gapi::infer<custom::Emotions>(faces, in);
// Return the decoded frame as a result as well.
// Input matrix can't be specified as output one, so use copy() here
// (this copy will be optimized out in the future).
cv::GMat frame = cv::gapi::copy(in);
// Now specify the computation's boundaries - our pipeline consumes
// one images and produces five outputs.
return cv::GComputation(cv::GIn(in),
cv::GOut(frame, faces, ages, genders, emotions));
});
```
Every pipeline starts with declaring empty data objects which act as inputs to the pipeline. Then we call a generic `cv::gapi::infer<>` specialized to Faces detection network. `cv::gapi::infer<>` inherits its signature from its template parameter and in this case it expects one input cv::GMat and produces one output cv::GMat.
In this sample we use a pre-trained SSD-based network and its output needs to be parsed to an array of detections (object regions of interest, ROIs). It is done by a custom operation custom::PostProc, which returns an array of rectangles (of type `cv::GArray<cv::Rect>`) back to the pipeline. This operation also filters out results by a confidence threshold and these details are hidden in the kernel itself. Still, at the moment of graph construction we operate with interfaces only and don't need actual kernels to express the pipeline so the implementation of this post-processing will be listed later.
After detection result output is parsed to an array of objects, we can run classification on any of those. G-API doesn't support syntax for in-graph loops like `for_each()` yet, but instead `cv::gapi::infer<>` comes with a special list-oriented overload.
User can call `cv::gapi::infer<>` with a `cv::GArray` as the first argument, so then G-API assumes it needs to run the associated network on every rectangle from the given list of the given frame (second argument). Result of such operation is also a list a cv::GArray of `cv::GMat`.
Since AgeGender network itself produces two outputs, it's output type for a list-based version of `cv::gapi::infer` is a tuple of arrays. We use `std::tie()` to decompose this input into two distinct objects.
Emotions network produces a single output so its list-based inference's return type is `cv::GArray<cv::GMat>`.
## Configure the Pipeline {#gapi_ifd_configuration}
G-API strictly separates construction from configuration -- with the idea to keep algorithm code itself platform-neutral. In the above listings we only declared our operations and expressed the overall data flow, but didn't even mention that we use OpenVINO™. We only described *what* we do, but not *how* we do it. Keeping these two aspects clearly separated is the design goal for G-API.
Platform-specific details arise when the pipeline is *compiled* -- i.e. is turned from a declarative to an executable form. The way *how* to run stuff is specified via compilation arguments, and new inference/streaming features are no exception from this rule.
G-API is built on backends which implement interfaces (see [Architecture](https://docs.opencv.org/4.5.0/de/d4d/gapi_hld.html) and [Kernels](kernel_api.md) for details) -- thus `cv::gapi::infer<>` is a function which can be implemented by different backends. In OpenCV 4.2, only OpenVINO™ Inference Engine backend for inference is available. Every inference backend in G-API has to provide a special parameterizable structure to express *backend-specific* neural network parameters -- and in this case, it is `cv::gapi::ie::Params`:
```cpp
auto det_net = cv::gapi::ie::Params<custom::Faces> {
cmd.get<std::string>("fdm"), // read cmd args: path to topology IR
cmd.get<std::string>("fdw"), // read cmd args: path to weights
cmd.get<std::string>("fdd"), // read cmd args: device specifier
};
auto age_net = cv::gapi::ie::Params<custom::AgeGender> {
cmd.get<std::string>("agem"), // read cmd args: path to topology IR
cmd.get<std::string>("agew"), // read cmd args: path to weights
cmd.get<std::string>("aged"), // read cmd args: device specifier
}.cfgOutputLayers({ "age_conv3", "prob" });
auto emo_net = cv::gapi::ie::Params<custom::Emotions> {
cmd.get<std::string>("emom"), // read cmd args: path to topology IR
cmd.get<std::string>("emow"), // read cmd args: path to weights
cmd.get<std::string>("emod"), // read cmd args: device specifier
};
```
Here we define three parameter objects: `det_net`, `age_net`, and `emo_net`. Every object is a `cv::gapi::ie::Params` structure parametrization for each particular network we use. On a compilation stage, G-API automatically matches network parameters with their `cv::gapi::infer<>` calls in graph using this information.
Regardless of the topology, every parameter structure is constructed with three string arguments specific to the OpenVINO™ Inference Engine:
* Path to the topology's intermediate representation (.xml file);
* Path to the topology's model weights (.bin file);
* Device where to run "CPU", "GPU", and others based on your OpenVINO™ Toolkit installation. These arguments are taken from the command-line parser.
Once networks are defined and custom kernels are implemented, the pipeline is compiled for streaming:
```cpp
// Form a kernel package (with a single OpenCV-based implementation of our
// post-processing) and a network package (holding our three networks).
auto kernels = cv::gapi::kernels<custom::OCVPostProc>();
auto networks = cv::gapi::networks(det_net, age_net, emo_net);
// Compile our pipeline and pass our kernels & networks as
// parameters. This is the place where G-API learns which
// networks & kernels we're actually operating with (the graph
// description itself known nothing about that).
auto cc = pp.compileStreaming(cv::compile_args(kernels, networks));
```
`cv::GComputation::compileStreaming()` triggers a special video-oriented form of graph compilation where G-API is trying to optimize throughput. Result of this compilation is an object of special type `cv::GStreamingCompiled` in contrast to a traditional callable `cv::GCompiled`, these objects are closer to media players in their semantics.
> **NOTE**: There is no need to pass metadata arguments describing the format of the input video stream in `cv::GComputation::compileStreaming()` G-API figures automatically what are the formats of the input vector and adjusts the pipeline to these formats on-the-fly. User still can pass metadata there as with regular `cv::GComputation::compile()` in order to fix the pipeline to the specific input format.
## Running the Pipeline {#gapi_ifd_running}
Pipelining optimization is based on processing multiple input video frames simultaneously, running different steps of the pipeline in parallel. This is why it works best when the framework takes full control over the video stream.
The idea behind streaming API is that user specifies an *input source* to the pipeline and then G-API manages its execution automatically until the source ends or user interrupts the execution. G-API pulls new image data from the source and passes it to the pipeline for processing.
Streaming sources are represented by the interface `cv::gapi::wip::IStreamSource`. Objects implementing this interface may be passed to `GStreamingCompiled` as regular inputs via `cv::gin()` helper function. In OpenCV 4.2, only one streaming source is allowed per pipeline -- this requirement will be relaxed in the future.
OpenCV comes with a great class cv::VideoCapture and by default G-API ships with a stream source class based on it -- `cv::gapi::wip::GCaptureSource`. Users can implement their own
streaming sources e.g. using [VAAPI](https://01.org/vaapi) or other Media or Networking APIs.
Sample application specifies the input source as follows:
```cpp
auto in_src = cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(input);
cc.setSource(cv::gin(in_src));
```
Please note that a GComputation may still have multiple inputs like `cv::GMat`, `cv::GScalar`, or `cv::GArray` objects. User can pass their respective host-side types (`cv::Mat`, `cv::Scalar`, `std::vector<>`) in the input vector as well, but in Streaming mode these objects will create "endless" constant streams. Mixing a real video source stream and a const data stream is allowed.
Running a pipeline is easy just call `cv::GStreamingCompiled::start()` and fetch your data with blocking `cv::GStreamingCompiled::pull()` or non-blocking `cv::GStreamingCompiled::try_pull()`; repeat until the stream ends:
```cpp
// After data source is specified, start the execution
cc.start();
// Declare data objects we will be receiving from the pipeline.
cv::Mat frame; // The captured frame itself
std::vector<cv::Rect> faces; // Array of detected faces
std::vector<cv::Mat> out_ages; // Array of inferred ages (one blob per face)
std::vector<cv::Mat> out_genders; // Array of inferred genders (one blob per face)
std::vector<cv::Mat> out_emotions; // Array of classified emotions (one blob per face)
// Implement different execution policies depending on the display option
// for the best performance.
while (cc.running()) {
auto out_vector = cv::gout(frame, faces, out_ages, out_genders, out_emotions);
if (no_show) {
// This is purely a video processing. No need to balance
// with UI rendering. Use a blocking pull() to obtain
// data. Break the loop if the stream is over.
if (!cc.pull(std::move(out_vector)))
break;
} else if (!cc.try_pull(std::move(out_vector))) {
// Use a non-blocking try_pull() to obtain data.
// If there's no data, let UI refresh (and handle keypress)
if (cv::waitKey(1) >= 0) break;
else continue;
}
// At this point we have data for sure (obtained in either
// blocking or non-blocking way).
frames++;
labels::DrawResults(frame, faces, out_ages, out_genders, out_emotions);
labels::DrawFPS(frame, frames, avg.fps(frames));
if (!no_show) cv::imshow("Out", frame);
}
```
The above code may look complex but in fact it handles two modes with and without graphical user interface (GUI):
* When a sample is running in a "headless" mode (`--pure` option is set), this code simply pulls data from the pipeline with the blocking `pull()` until it ends. This is the most performant mode of execution.
* When results are also displayed on the screen, the Window System needs to take some time to refresh the window contents and handle GUI events. In this case, the demo pulls data with a non-blocking `try_pull()` until there is no more data available (but it does not mark end of the stream just means new data is not ready yet), and only then displays the latest obtained result and refreshes the screen. Reducing the time spent in GUI with this trick increases the overall performance a little bit.
## Comparison with Serial Mode
The sample can also run in a serial mode for a reference and benchmarking purposes. In this case, a regular `cv::GComputation::compile()` is used and a regular single-frame `cv::GCompiled` object is produced; the pipelining optimization is not applied within G-API; it is the user responsibility to acquire image frames from `cv::VideoCapture` object and pass those to G-API.
```cpp
cv::VideoCapture cap(input);
cv::Mat in_frame, frame; // The captured frame itself
std::vector<cv::Rect> faces; // Array of detected faces
std::vector<cv::Mat> out_ages; // Array of inferred ages (one blob per face)
std::vector<cv::Mat> out_genders; // Array of inferred genders (one blob per face)
std::vector<cv::Mat> out_emotions; // Array of classified emotions (one blob per face)
while (cap.read(in_frame)) {
pp.apply(cv::gin(in_frame),
cv::gout(frame, faces, out_ages, out_genders, out_emotions),
cv::compile_args(kernels, networks));
labels::DrawResults(frame, faces, out_ages, out_genders, out_emotions);
frames++;
if (frames == 1u) {
// Start timer only after 1st frame processed -- compilation
// happens on-the-fly here
avg.start();
} else {
// Measurfe & draw FPS for all other frames
labels::DrawFPS(frame, frames, avg.fps(frames-1));
}
if (!no_show) {
cv::imshow("Out", frame);
if (cv::waitKey(1) >= 0) break;
}
}
```
On a test machine (Intel® Core™ i5-6600), with OpenCV built with [Intel® TBB](https://www.threadingbuildingblocks.org/intel-tbb-tutorial) support, detector network assigned to CPU, and classifiers to iGPU, the pipelined sample outperformes the serial one by the factor of 1.36x (thus adding +36% in overall throughput).
## Conclusion
G-API introduces a technological way to build and optimize hybrid pipelines. Switching to a new execution model does not require changes in the algorithm code expressed with G-API only the way how graph is triggered differs.
## Listing: Post-Processing Kernel
G-API gives an easy way to plug custom code into the pipeline even if it is running in a streaming mode and processing tensor data. Inference results are represented by multi-dimensional `cv::Mat` objects so accessing those is as easy as with a regular DNN module.
The OpenCV-based SSD post-processing kernel is defined and implemented in this sample as follows:
```cpp
// SSD Post-processing function - this is not a network but a kernel.
// The kernel body is declared separately, this is just an interface.
// This operation takes two Mats (detections and the source image),
// and returns a vector of ROI (filtered by a default threshold).
// Threshold (or a class to select) may become a parameter, but since
// this kernel is custom, it doesn't make a lot of sense.
G_API_OP(PostProc, <cv::GArray<cv::Rect>(cv::GMat, cv::GMat)>, "custom.fd_postproc") {
static cv::GArrayDesc outMeta(const cv::GMatDesc &, const cv::GMatDesc &) {
// This function is required for G-API engine to figure out
// what the output format is, given the input parameters.
// Since the output is an array (with a specific type),
// there's nothing to describe.
return cv::empty_array_desc();
}
};
// OpenCV-based implementation of the above kernel.
GAPI_OCV_KERNEL(OCVPostProc, PostProc) {
static void run(const cv::Mat &in_ssd_result,
const cv::Mat &in_frame,
std::vector<cv::Rect> &out_faces) {
const int MAX_PROPOSALS = 200;
const int OBJECT_SIZE = 7;
const cv::Size upscale = in_frame.size();
const cv::Rect surface({0,0}, upscale);
out_faces.clear();
const float *data = in_ssd_result.ptr<float>();
for (int i = 0; i < MAX_PROPOSALS; i++) {
const float image_id = data[i * OBJECT_SIZE + 0]; // batch id
const float confidence = data[i * OBJECT_SIZE + 2];
const float rc_left = data[i * OBJECT_SIZE + 3];
const float rc_top = data[i * OBJECT_SIZE + 4];
const float rc_right = data[i * OBJECT_SIZE + 5];
const float rc_bottom = data[i * OBJECT_SIZE + 6];
if (image_id < 0.f) { // indicates end of detections
break;
}
if (confidence < 0.5f) { // a hard-coded snapshot
continue;
}
// Convert floating-point coordinates to the absolute image
// frame coordinates; clip by the source image boundaries.
cv::Rect rc;
rc.x = static_cast<int>(rc_left * upscale.width);
rc.y = static_cast<int>(rc_top * upscale.height);
rc.width = static_cast<int>(rc_right * upscale.width) - rc.x;
rc.height = static_cast<int>(rc_bottom * upscale.height) - rc.y;
out_faces.push_back(rc & surface);
}
}
};
```

52
docs/gapi/gapi_intro.md Normal file
View File

@@ -0,0 +1,52 @@
# Introduction to OpenCV Graph API (G-API) {#openvino_docs_gapi_gapi_intro}
OpenCV Graph API (G-API) is an OpenCV module targeted to make regular image and video processing fast and portable. G-API is a special module in OpenCV in contrast with the majority of other main modules, this one acts as a framework rather than some specific CV algorithm.
G-API is positioned as a next level optimization enabler for computer vision, focusing not on particular CV functions but on the whole algorithm optimization.
G-API provides means to define CV operations, construct graphs (in form of expressions) using it, and finally implement and run the operations for a particular backend.
The idea behind G-API is that if an algorithm can be expressed in a special embedded language (currently in C++), the framework can catch its sense and apply a number of optimizations to the whole thing automatically. Particular optimizations are selected based on which [kernels](kernel_api.md) and [backends](https://docs.opencv.org/4.5.0/dc/d1c/group__gapi__std__backends.html) are involved in the graph compilation process, for example, the graph can be offloaded to GPU via the OpenCL backend, or optimized for memory consumption with the Fluid backend. Kernels, backends, and their settings are parameters to the graph compilation, so the graph itself does not depend on any platform-specific details and can be ported easily.
> **NOTE**: Graph API (G-API) was introduced in the most recent major OpenCV 4.0 release and now is being actively developed. The API is volatile at the moment and there may be minor but compatibility-breaking changes in the future.
## G-API Concepts
* *Graphs* are built by applying operations to data objects.
* API itself has no "graphs", it is expression-based instead.
* *Data objects* do not hold actual data, only capture dependencies.
* *Operations* consume and produce data objects.
* A graph is defined by specifying its boundaries with data objects:
* What data objects are inputs to the graph?
* What are its outputs?
The paragraphs below explain the G-API programming model and development workflow.
## Programming Model
Building graphs is easy with G-API. In fact, there is no notion of graphs exposed in the API, so the user doesnt need to operate in terms of “nodes” and “edges” — instead, graphs are constructed implicitly via expressions in a "functional" way. Expression-based graphs are built using two major concepts: *[operations](kernel_api.md)* and *[data objects](https://docs.opencv.org/4.2.0/db/df1/group__gapi__data__objects.html)*.
In G-API, every graph begins and ends with data objects; data objects are passed to operations which produce (“return”) their results — new data objects, which are then passed to other operations, and so on. You can declare their own operations, G-API does not distinguish user-defined operations from its own predefined ones in any way.
After the graph is defined, it needs to be compiled for execution. During the compilation, G-API figures out what the graph looks like, which kernels are available to run the operations in the graph, how to manage heterogeneity and to optimize the execution path. The result of graph compilation is a so-called “compiled” object. This object encapsulates the execution sequence for the graph inside and operates on real image data. You can set up the compilation process using various [compilation arguments](https://docs.opencv.org/4.5.0/dc/d1c/group__gapi__std__backends.html). Backends expose some of their options as these arguments; also, actual kernels and DL network settings are passed into the framework this way.
G-API supports graph compilation for two execution modes, *regular* and *streaming*, producing different types of compiled objects as the result.
* <strong>Regular</strong> compiled objects are represented with class GCompiled, which follows functor-like semantics and has an overloaded operator(). When called for execution on the given input data, the GCompiled functor blocks the current thread and processes the data immediately — like a regular C++ function. By default, G-API tries to optimize the execution time for latency in this compilation mode.
* Starting with OpenCV 4.2, G-API can also produce GStreamingCompiled objects that better fit the asynchronous pipelined execution model. This compilation mode is called **streaming mode**, and G-API tries to optimize the overall throughput by implementing the pipelining technique as described above. We will use both in our example.
The overall process for the regular case is summarized in the diagram below:
![G-API Programming Model](../img/gapi_programming_model.png)
The graph is built with operations so having operations defined (**0**) is a basic prerequisite; a constructed expression graph (**1**) forms a `cv::GComputation` object; kernels (**2**) which implement operations are the basic requirement to the graph compilation (**3**); the actual execution (**4**) is handled by a `cv::GCompiled` object with takes input and produces output data.
## Development Workflow
One of the ways to organize a G-API development workflow is presented in the diagram below:
![G-API development workflow](../img/gapi_development_workflow.png)
Basically, it is a derivative from the programming model illustrated in the previous chapter. You start with an algorithm or a data flow in mind (**0**), mapping it to a graph model (**1**), then identifying what operations you need (**2**) to construct this graph. These operations may already exist in G-API or be missing, in the latter case we implement the missing ones as kernels (**3**). Then decide which execution model fits our case better, pass kernels and DL networks as arguments to the compilation process (**4**), and finally switch to the execution (**5**). The process is iterative, so if you want to change anything based on the execution results, get back to steps (**0**) or (**1**) (a dashed line).

188
docs/gapi/kernel_api.md Normal file
View File

@@ -0,0 +1,188 @@
# Graph API Kernel API {#openvino_docs_gapi_kernel_api}
The core idea behind Graph API (G-API) is portability a pipeline built with G-API must be portable (or at least able to be portable). It means that either it works out-of-the box when compiled for new platform, or G-API provides necessary tools to make it running there, with little-to-no changes in the algorithm itself.
This idea can be achieved by separating kernel interface from its implementation. Once a pipeline is built using kernel interfaces, it becomes implementation-neutral the implementation details (i.e. which kernels to use) are passed on a separate stage (graph compilation).
Kernel-implementation hierarchy may look like:
![Kernel API/implementation hierarchy example](../img/gapi_kernel_implementation_hierarchy.png)
A pipeline itself then can be expressed only in terms of `A`, `B`, and so on, and choosing which implementation to use in execution becomes an external parameter.
## Define a Kernel
G-API provides a macro to define a new kernel interface `G_TYPED_KERNEL()`:
```cpp
#include <opencv2/gapi.hpp>
G_TYPED_KERNEL(GFilter2D,
<cv::GMat(cv::GMat,int,cv::Mat,cv::Point,double,int,cv::Scalar)>,
"org.opencv.imgproc.filters.filter2D")
{
static cv::GMatDesc // outMeta's return value type
outMeta(cv::GMatDesc in , // descriptor of input GMat
int ddepth , // depth parameter
cv::Mat /* coeffs */, // (unused)
cv::Point /* anchor */, // (unused)
double /* scale */, // (unused)
int /* border */, // (unused)
cv::Scalar /* bvalue */ ) // (unused)
{
return in.withDepth(ddepth);
}
};
```
This macro is a shortcut to a new type definition. It takes three arguments to register a new type, and requires type body to be present (see below). The macro arguments are:
* Kernel interface name -- Also serves as a name of new type defined with this macro;
* Kernel signature -- An `std::function<>`-like signature which defines API of the kernel;
* Kernel's unique name -- Used to identify kernel when its type information is stripped within the system.
* Kernel declaration may be seen as function declaration -- In both cases a new entity must be used then according to the way it was defined.
Kernel signature defines kernel's usage syntax -- which parameters it takes during graph construction. Implementations can also use this signature to derive it into backend-specific callback signatures (see next chapter).
Kernel may accept values of any type, and G-API dynamic types are handled in a special way. All other types are opaque to G-API and passed to kernel in `outMeta()` or in execution callbacks as-is.
Kernel's return value can only be of G-API dynamic type `cv::GMat`, `cv::GScalar`, or `cv::GArray<T>`. If an operation has more than one output, it should be wrapped into an `std::tuple<>` (which can contain only mentioned G-API types). Arbitrary-output-number operations are not supported.
Once a kernel is defined, it can be used in pipelines with special, G-API-supplied method `on()`. This method has the same signature as defined in kernel, so the following code is a perfectly legal construction:
```cpp
cv::GMat in;
cv::GMat out = GFilter2D::on(/* GMat */ in,
/* int */ -1,
/* Mat */ conv_kernel_mat,
/* Point */ cv::Point(-1,-1),
/* double */ 0.,
/* int */ cv::BORDER_DEFAULT,
/* Scalar */ cv::Scalar(0));
```
This example has some verbosity, though, so usually a kernel declaration comes with a C++ function wrapper ("factory method") which enables optional parameters, more compact syntax, Doxygen comments, etc.:
```cpp
cv::GMat filter2D(cv::GMat in,
int ddepth,
cv::Mat k,
cv::Point anchor = cv::Point(-1,-1),
double scale = 0.,
int border = cv::BORDER_DEFAULT,
cv::Scalar bval = cv::Scalar(0))
{
return GFilter2D::on(in, ddepth, k, anchor, scale, border, bval);
}
```
So now it can be used like:
```cpp
cv::GMat in;
cv::GMat out = filter2D(in, -1, conv_kernel_mat);
```
### Extra information
In the current version, kernel declaration body (everything within the curly braces) must contain a static function `outMeta()`. This function establishes a functional dependency between operation's input and output metadata.
Metadata is an information about data kernel operates on. Since non-G-API types are opaque to G-API, G-API cares only about G* data descriptors (i.e. dimensions and format of `cv::GMat`, etc).
`outMeta()` is also an example of how kernel's signature can be transformed into a derived callback note that in this example, outMeta() signature exactly follows the kernel signature (defined within the macro) but is different where kernel expects `cv::GMat`, `outMeta()` takes and returns `cv::GMatDesc` (a G-API structure metadata for `cv::GMat`).
The point of `outMeta()` is to propagate metadata information within computation from inputs to outputs and infer metadata of internal (intermediate, temporary) data objects. This information is required for further pipeline optimizations, memory allocation, and other operations done by G-API framework during graph compilation.
## Implement a Kernel
Once a kernel is declared, its interface can be used to implement versions of this kernel in different backends. This concept is naturally projected from object-oriented programming "Interface/Implementation" idiom: an interface can be implemented multiple times, and different implementations of a kernel should be substitutable with each other without breaking the algorithm (pipeline) logic (Liskov Substitution Principle).
Every backend defines its own way to implement a kernel interface. This way is regular, though whatever plugin is, its kernel implementation must be "derived" from a kernel interface type.
Kernel implementation are then organized into kernel packages. Kernel packages are passed to `cv::GComputation::compile()` as compile arguments, with some hints to G-API on how to select proper kernels (see more on this in "Heterogeneity"[TBD]).
For example, the aforementioned Filter2D is implemented in "reference" CPU (OpenCV) plugin this way (NOTE this is a simplified form with improper border handling):
```cpp
#include <opencv2/gapi/cpu/gcpukernel.hpp> // GAPI_OCV_KERNEL()
#include <opencv2/imgproc.hpp> // cv::filter2D()
GAPI_OCV_KERNEL(GCPUFilter2D, GFilter2D)
{
static void
run(const cv::Mat &in, // in - derived from GMat
const int ddepth, // opaque (passed as-is)
const cv::Mat &k, // opaque (passed as-is)
const cv::Point &anchor, // opaque (passed as-is)
const double delta, // opaque (passed as-is)
const int border, // opaque (passed as-is)
const cv::Scalar &, // opaque (passed as-is)
cv::Mat &out) // out - derived from GMat (retval)
{
cv::filter2D(in, out, ddepth, k, anchor, delta, border);
}
};
```
Note how CPU (OpenCV) plugin has transformed the original kernel signature:
* Input `cv::GMat` has been substituted with `cv::Mat`, holding actual input data for the underlying OpenCV function call;
* Output `cv::GMat `has been transformed into extra output parameter, thus `GCPUFilter2D::run()` takes one argument more than the original kernel signature.
The basic intuition for kernel developer here is not to care where that cv::Mat objects come from instead of the original `cv::GMat` and just follow the signature conventions defined by the plugin. G-API will call this method during execution and supply all the necessary information (and forward the original opaque data as-is).
## Compound Kernels
Sometimes kernel is a single thing only on API level. It is convenient for users, but on a particular implementation side it would be better to have multiple kernels (a subgraph) doing the thing instead. An example is `goodFeaturesToTrack()` while in OpenCV backend it may remain a single kernel, with Fluid it becomes compound Fluid can handle Harris response calculation but can't do sparse non-maxima suppression and point extraction to an STL vector:
A compound kernel implementation can be defined using a generic macro `GAPI_COMPOUND_KERNEL()`:
```cpp
#include <opencv2/gapi/gcompoundkernel.hpp> // GAPI_COMPOUND_KERNEL()
using PointArray2f = cv::GArray<cv::Point2f>;
G_TYPED_KERNEL(HarrisCorners,
<PointArray2f(cv::GMat,int,double,double,int,double)>,
"org.opencv.imgproc.harris_corner")
{
static cv::GArrayDesc outMeta(const cv::GMatDesc &,
int,
double,
double,
int,
double)
{
// No special metadata for arrays in G-API (yet)
return cv::empty_array_desc();
}
};
// Define Fluid-backend-local kernels which form GoodFeatures
G_TYPED_KERNEL(HarrisResponse,
<cv::GMat(cv::GMat,double,int,double)>,
"org.opencv.fluid.harris_response")
{
static cv::GMatDesc outMeta(const cv::GMatDesc &in,
double,
int,
double)
{
return in.withType(CV_32F, 1);
}
};
G_TYPED_KERNEL(ArrayNMS,
<PointArray2f(cv::GMat,int,double)>,
"org.opencv.cpu.nms_array")
{
static cv::GArrayDesc outMeta(const cv::GMatDesc &,
int,
double)
{
return cv::empty_array_desc();
}
};
GAPI_COMPOUND_KERNEL(GFluidHarrisCorners, HarrisCorners)
{
static PointArray2f
expand(cv::GMat in,
int maxCorners,
double quality,
double minDist,
int blockSize,
double k)
{
cv::GMat response = HarrisResponse::on(in, quality, blockSize, k);
return ArrayNMS::on(response, maxCorners, minDist);
}
};
// Then implement HarrisResponse as Fluid kernel and NMSresponse
// as a generic (OpenCV) kernel
```
It is important to distinguish a compound kernel from G-API high-order function, i.e. a C++ function which looks like a kernel but in fact generates a subgraph. The core difference is that a compound kernel is an *implementation detail* and a kernel implementation may be either compound or not (depending on backend capabilities), while a high-order function is a "macro" in terms of G-API and so cannot act as an interface which then needs to be implemented by a backend.

View File

@@ -33,7 +33,7 @@ Prerequisite | Linux* | Windows* | macOS*
Operating system|Ubuntu\* 18.04. Other Linux distributions, such as Ubuntu\* 16.04 and CentOS\* 7, are not validated.|Windows\* 10 | macOS\* 10.15 Catalina
CPU | Intel® Core™ i5| Intel® Core™ i5 | Intel® Core™ i5
GPU| Intel® Pentium® processor N4200/5 with Intel® HD Graphics | Not supported| Not supported
HDDL, Myriad| Intel® Neural Compute Stick 2 <br> Intel® Vision Accelerator Design with Intel® Movidius™ VPUs| Not supported | Not supported
HDDL, MYRIAD| Intel® Neural Compute Stick 2 <br> Intel® Vision Accelerator Design with Intel® Movidius™ VPUs| Not supported | Not supported
Available RAM space| 4 GB| 4 GB| 4 GB
Available storage space | 8 GB + space for imported artifacts| 8 GB + space for imported artifacts| 8 GB + space for imported artifacts
Docker\*| Docker CE 18.06.1 | Docker Desktop 2.1.0.1|Docker CE 18.06.1
@@ -136,5 +136,4 @@ For detailed instructions to create a new project, visit the links below:
* [Inference Engine Developer Guide](../IE_DG/Deep_Learning_Inference_Engine_DevGuide.md)
* [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
* [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md)
* [Overview of OpenVINO™ Toolkit Pre-Trained Models](https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models)
* [OpenVINO™ Hello World Face Detection Exercise](https://github.com/intel-iot-devkit/inference-tutorials-generic)
* [Overview of OpenVINO™ Toolkit Pre-Trained Models](https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models)

View File

@@ -570,4 +570,3 @@ Use these resources to learn more about the OpenVINO™ toolkit:
* [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
* [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md)
* [Overview of OpenVINO™ Toolkit Pre-Trained Models](https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models)
* [OpenVINO™ Hello World Face Detection Exercise](https://github.com/intel-iot-devkit/inference-tutorials-generic)

View File

@@ -529,4 +529,3 @@ Use these resources to learn more about the OpenVINO™ toolkit:
* [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
* [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md)
* [Overview of OpenVINO™ Toolkit Pre-Trained Models](https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models)
* [OpenVINO™ Hello World Face Detection Exercise](https://github.com/intel-iot-devkit/inference-tutorials-generic)

View File

@@ -57,25 +57,21 @@ The OpenVINO™ workflow on Raspbian* OS is as follows:
Follow the steps below to run pre-trained Face Detection network using Inference Engine samples from the OpenVINO toolkit.
1. Create a samples build directory. This example uses a directory named `build`:
```sh
mkdir build && cd build
```
2. Build the Object Detection Sample with the following command:
```sh
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=armv7-a" /opt/intel/openvino/deployment_tools/inference_engine/samples/cpp
```
```sh
make -j2 object_detection_sample_ssd
```
3. Download the pre-trained Face Detection model with the Model Downloader:
```sh
git clone --depth 1 https://github.com/openvinotoolkit/open_model_zoo
cd open_model_zoo/tools/downloader
python3 -m pip install -r requirements.in
python3 downloader.py --name face-detection-adas-0001
mkdir build && cd build
```
2. Build the Object Detection Sample with the following command:
```sh
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=armv7-a" /opt/intel/openvino/deployment_tools/inference_engine/samples/cpp
make -j2 object_detection_sample_ssd
```
3. Download the pre-trained Face Detection model with the [Model Downloader tool](@ref omz_tools_downloader_README):
```sh
git clone --depth 1 https://github.com/openvinotoolkit/open_model_zoo
cd open_model_zoo/tools/downloader
python3 -m pip install -r requirements.in
python3 downloader.py --name face-detection-adas-0001
```
4. Run the sample, specifying the model and path to the input image:
```sh
./armv7l/Release/object_detection_sample_ssd -m face-detection-adas-0001.xml -d MYRIAD -i <path_to_image>
@@ -91,11 +87,9 @@ Following are some basic guidelines for executing the OpenVINO™ workflow using
source <INSTALL_DIR>/bin/setupvars.sh
```
2. Have the directory path for the following:
- Code Sample binaries
- Media: Video or image. Many sources are available from which you can download video media to use the code samples and demo applications, like https://videos.pexels.com and https://images.google.com.
- Model in the IR format (.bin and .xml files).
- Code Sample binaries
- Media: Video or image. Many sources are available from which you can download video media to use the code samples and demo applications, like https://videos.pexels.com and https://images.google.com.
- Model in the IR format (.bin and .xml files).
## Additional Resources
Use these resources to learn more about the OpenVINO™ toolkit:
@@ -106,4 +100,3 @@ Use these resources to learn more about the OpenVINO™ toolkit:
* [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
* [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md)
* [Overview of OpenVINO™ Toolkit Pre-Trained Models](https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models)
* [OpenVINO™ Hello World Face Detection Exercise](https://github.com/intel-iot-devkit/inference-tutorials-generic)

View File

@@ -537,5 +537,4 @@ Use these resources to learn more about the OpenVINO™ toolkit:
* [Inference Engine Developer Guide](../IE_DG/Deep_Learning_Inference_Engine_DevGuide.md)
* [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
* [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md)
* [Overview of OpenVINO™ Toolkit Pre-Trained Models](https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models)
* [OpenVINO™ Hello World Face Detection Exercise](https://github.com/intel-iot-devkit/inference-tutorials-generic)
* [Overview of OpenVINO™ Toolkit Pre-Trained Models](https://software.intel.com/en-us/openvino-toolkit/documentation/pretrained-models)

View File

@@ -44,7 +44,6 @@ To learn about what is *custom operation* and how to work with them in the Deep
[![](https://img.youtube.com/vi/Kl1ptVb7aI8/0.jpg)](https://www.youtube.com/watch?v=Kl1ptVb7aI8)
<iframe width="560" height="315" src="https://www.youtube.com/embed/Kl1ptVb7aI8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## Computer Vision with Intel
[![](https://img.youtube.com/vi/FZZD4FCvO9c/0.jpg)](https://www.youtube.com/watch?v=FZZD4FCvO9c)

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a0a11bedbfe2df3352b064e80498aa39fbc3817eaf99439865a090f34501e44a
size 25936

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:662a823fbef3be0cca1755de9118e73b4137fe7ec4b7cb6a389e64b9ec5a9c13
size 13511

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12fe8e0b841aa6759f3b1975d3a877e65b8d72b752d11ffd212b67d11e62e048
size 19539

View File

@@ -0,0 +1,415 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by Microsoft Visio, SVG Export gapi_face_beautification_algorithm.svg Page-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="10.1331in" height="3.58042in"
viewBox="0 0 729.585 257.79" xml:space="preserve" color-interpolation-filters="sRGB" class="st13">
<v:documentProperties v:langID="1033" v:metric="true" v:viewMarkup="false"/>
<style type="text/css">
<![CDATA[
.st1 {fill:#007dc4;stroke:#c7c8c8;stroke-width:0.25}
.st2 {fill:#feffff;font-family:Intel Clear;font-size:1.00001em}
.st3 {font-size:1em}
.st4 {fill:#174a7c;stroke:#41719c;stroke-width:1}
.st5 {fill:#ffffff;font-family:Intel Clear;font-size:1.00001em}
.st6 {fill:none;stroke:none;stroke-width:0.25}
.st7 {fill:#ffffff;font-family:Intel Clear;font-size:1.99999em}
.st8 {fill:#feffff;font-family:Intel Clear;font-size:1.99999em}
.st9 {marker-end:url(#mrkr4-58);stroke:#174a7c;stroke-linecap:round;stroke-linejoin:round;stroke-width:1}
.st10 {fill:#174a7c;fill-opacity:1;stroke:#174a7c;stroke-opacity:1;stroke-width:0.28409090909091}
.st11 {fill:none;stroke:#174a7c;stroke-dasharray:0.01,3;stroke-width:1}
.st12 {fill:#174a7c;font-family:Intel Clear;font-size:1.00001em}
.st13 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<defs id="Markers">
<g id="lend4">
<path d="M 2 1 L 0 0 L 2 -1 L 2 1 " style="stroke:none"/>
</g>
<marker id="mrkr4-58" class="st10" v:arrowType="4" v:arrowSize="2" v:setback="7.04" refX="-7.04" orient="auto"
markerUnits="strokeWidth" overflow="visible">
<use xlink:href="#lend4" transform="scale(-3.52,-3.52) "/>
</marker>
</defs>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<title>Page-1</title>
<v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
v:shadowOffsetY="-8.50394"/>
<v:layer v:name="Connector" v:index="0"/>
<g id="shape1-1" v:mID="1" v:groupContext="shape" transform="translate(239.315,-170.329)">
<title>Rounded Rectangle</title>
<desc>Landmarks detector</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st1"/>
<text x="10.51" y="232.22" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Landmarks<v:lf/><tspan
x="17.59" dy="1.2em" class="st3">detector</tspan></text> </g>
<g id="shape4-5" v:mID="4" v:groupContext="shape" transform="translate(371.074,-170.329)">
<title>Rounded Rectangle.4</title>
<desc>Generate BG mask</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st1"/>
<text x="15.79" y="232.22" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Generate<v:lf/><tspan
x="16.93" dy="1.2em" class="st3">BG mask</tspan></text> </g>
<g id="shape5-9" v:mID="5" v:groupContext="shape" transform="translate(0.999867,-85.2894)">
<title>Rounded Rectangle.5</title>
<desc>Input</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st4"/>
<text x="26.22" y="239.42" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Input</text> </g>
<g id="shape7-12" v:mID="7" v:groupContext="shape" transform="translate(120.157,-85.2894)">
<title>Rounded Rectangle.7</title>
<desc>Unsharp mask</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st1"/>
<text x="17.49" y="232.22" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Unsharp<v:newlineChar/><tspan
x="26.2" dy="1.2em" class="st3">mask</tspan></text> </g>
<g id="shape8-16" v:mID="8" v:groupContext="shape" transform="translate(120.157,-0.25)">
<title>Rounded Rectangle.8</title>
<desc>Bilateral filter</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st1"/>
<text x="18.25" y="232.22" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Bilateral<v:newlineChar/><tspan
x="27.86" dy="1.2em" class="st3">filter</tspan></text> </g>
<g id="shape9-20" v:mID="9" v:groupContext="shape" transform="translate(120.157,-170.329)">
<title>Rounded Rectangle.9</title>
<desc>Face detector</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st1"/>
<text x="28.03" y="232.22" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Face<v:newlineChar/><tspan
x="17.59" dy="1.2em" class="st3">detector</tspan></text> </g>
<g id="shape10-24" v:mID="10" v:groupContext="shape" transform="translate(371.074,-85.2894)">
<title>Rounded Rectangle.10</title>
<desc>Generate sharp mask</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st1"/>
<text x="15.79" y="232.22" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Generate<v:lf/><tspan
x="9.44" dy="1.2em" class="st3">sharp mask</tspan></text> </g>
<g id="shape11-28" v:mID="11" v:groupContext="shape" transform="translate(647.472,-170.329)">
<title>Rounded Rectangle.11</title>
<desc>Output</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st4"/>
<text x="21.25" y="239.42" class="st5" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Output</text> </g>
<g id="shape13-31" v:mID="13" v:groupContext="shape" transform="translate(371.074,-0.25)">
<title>Rounded Rectangle.13</title>
<desc>Generate blur mask</desc>
<v:userDefs>
<v:ud v:nameU="CTypeTopLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeTopRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotLeftSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CTypeBotRightSnip" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="CornerLockHoriz" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockVert" v:prompt="" v:val="VT0(1):5"/>
<v:ud v:nameU="CornerLockDiag" v:prompt="" v:val="VT0(0):5"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.15748031496063):24"/>
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
<v:ud v:nameU="TopLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="TopRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotLeftOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
<v:ud v:nameU="BotRightOffset" v:prompt="" v:val="VT0(0.11265748238444):1"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="40.5567" cy="235.822" width="81.12" height="43.937"/>
<path d="M8.11 257.79 L73 257.79 A8.11121 8.11121 -180 0 0 81.11 249.68 L81.11 221.96 A8.11121 8.11121 -180 0 0 73 213.85
L8.11 213.85 A8.11121 8.11121 -180 0 0 0 221.96 L0 249.68 A8.11121 8.11121 -180 0 0 8.11 257.79 Z"
class="st1"/>
<text x="15.79" y="232.22" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Generate<v:lf/><tspan
x="13.76" dy="1.2em" class="st3">blur mask</tspan></text> </g>
<g id="shape14-35" v:mID="14" v:groupContext="shape" transform="translate(490.149,-170.329)">
<title>Circle</title>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
</v:userDefs>
<path d="M0 235.82 A21.9685 21.9685 0 0 1 43.94 235.82 A21.9685 21.9685 0 1 1 0 235.82 Z" class="st1"/>
</g>
<g id="shape15-37" v:mID="15" v:groupContext="shape" transform="translate(501.133,-178.124)">
<title>Circle.15</title>
<desc>*</desc>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="10.9843" cy="246.806" width="21.97" height="21.9685"/>
<rect x="0" y="235.822" width="21.9685" height="21.9685" class="st6"/>
<text x="6.24" y="254.01" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>*</text> </g>
<g id="shape16-40" v:mID="16" v:groupContext="shape" transform="translate(490.149,-0.25)">
<title>Circle.16</title>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
</v:userDefs>
<path d="M0 235.82 A21.9685 21.9685 0 0 1 43.94 235.82 A21.9685 21.9685 0 1 1 0 235.82 Z" class="st1"/>
</g>
<g id="shape17-42" v:mID="17" v:groupContext="shape" transform="translate(501.133,-8.04528)">
<title>Circle.17</title>
<desc>*</desc>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="10.9843" cy="246.806" width="21.97" height="21.9685"/>
<rect x="0" y="235.822" width="21.9685" height="21.9685" class="st6"/>
<text x="6.24" y="254.01" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>*</text> </g>
<g id="shape18-45" v:mID="18" v:groupContext="shape" transform="translate(568.81,-170.329)">
<title>Circle.18</title>
<desc>+</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="21.9685" cy="235.822" width="38.45" height="32.9528"/>
<path d="M0 235.82 A21.9685 21.9685 0 0 1 43.94 235.82 A21.9685 21.9685 0 1 1 0 235.82 Z" class="st1"/>
<text x="14.84" y="243.02" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>+</text> </g>
<g id="shape20-48" v:mID="20" v:groupContext="shape" transform="translate(491.566,-85.2894)">
<title>Circle.20</title>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
</v:userDefs>
<path d="M0 235.82 A21.9685 21.9685 0 0 1 43.94 235.82 A21.9685 21.9685 0 1 1 0 235.82 Z" class="st1"/>
</g>
<g id="shape21-50" v:mID="21" v:groupContext="shape" transform="translate(502.551,-93.0847)">
<title>Circle.21</title>
<desc>*</desc>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="10.9843" cy="246.806" width="21.97" height="21.9685"/>
<rect x="0" y="235.822" width="21.9685" height="21.9685" class="st6"/>
<text x="6.24" y="254.01" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>*</text> </g>
<g id="shape26-53" v:mID="26" v:groupContext="shape" v:layerMember="0" transform="translate(82.1133,-100.171)">
<title>Dynamic connector</title>
<path d="M0 250.7 L31 250.7" class="st9"/>
</g>
<g id="shape27-59" v:mID="27" v:groupContext="shape" v:layerMember="0" transform="translate(82.1133,-107.258)">
<title>Dynamic connector.27</title>
<path d="M0 257.79 L12.67 257.79 L12.67 172.75 L31 172.75" class="st9"/>
</g>
<g id="shape28-64" v:mID="28" v:groupContext="shape" v:layerMember="0" transform="translate(82.1133,-107.258)">
<title>Dynamic connector.28</title>
<path d="M0 257.79 L12.67 257.79 L12.67 342.83 L31 342.83" class="st9"/>
</g>
<g id="shape29-69" v:mID="29" v:groupContext="shape" v:layerMember="0" transform="translate(82.1133,-107.258)">
<title>Dynamic connector.29</title>
<path d="M0 257.79 L12.67 257.79 L12.67 116.06 L430 116.06 L430 143.74" class="st9"/>
</g>
<g id="shape30-74" v:mID="30" v:groupContext="shape" v:layerMember="0" transform="translate(201.271,-185.211)">
<title>Dynamic connector.30</title>
<path d="M0 250.7 L31 250.7" class="st9"/>
</g>
<g id="shape31-79" v:mID="31" v:groupContext="shape" v:layerMember="0" transform="translate(320.428,-185.211)">
<title>Dynamic connector.31</title>
<path d="M0 250.7 L43.61 250.7" class="st9"/>
</g>
<g id="shape32-84" v:mID="32" v:groupContext="shape" v:layerMember="0" transform="translate(452.188,-185.211)">
<title>Dynamic connector.32</title>
<path d="M0 250.7 L30.92 250.7" class="st9"/>
</g>
<g id="shape33-89" v:mID="33" v:groupContext="shape" v:layerMember="0" transform="translate(534.086,-199.384)">
<title>Dynamic connector.33</title>
<path d="M0 264.88 L27.68 264.88" class="st9"/>
</g>
<g id="shape34-94" v:mID="34" v:groupContext="shape" v:layerMember="0" transform="translate(612.747,-185.211)">
<title>Dynamic connector.34</title>
<path d="M0 250.7 L27.68 250.7" class="st9"/>
</g>
<g id="shape35-99" v:mID="35" v:groupContext="shape" v:layerMember="0" transform="translate(534.086,-22.2185)">
<title>Dynamic connector.35</title>
<path d="M0 257.79 L56.69 257.79 L56.69 116.72" class="st9"/>
</g>
<g id="shape36-104" v:mID="36" v:groupContext="shape" v:layerMember="0" transform="translate(535.503,-107.258)">
<title>Dynamic connector.36</title>
<path d="M0 257.79 L55.28 257.79 L55.28 201.76" class="st9"/>
</g>
<g id="shape37-109" v:mID="37" v:groupContext="shape" v:layerMember="0" transform="translate(160.714,-122.14)">
<title>Dynamic connector.37</title>
<path d="M0 250.7 L0 238.03 L176.99 238.03 A2.3622 2.3622 0 0 1 181.71 238.03 L352.82 238.03 L352.82 243.66"
class="st9"/>
</g>
<g id="shape38-114" v:mID="38" v:groupContext="shape" v:layerMember="0" transform="translate(320.428,-192.297)">
<title>Dynamic connector.38</title>
<path d="M0 257.79 L19.64 257.79 L19.64 342.83 L43.61 342.83" class="st9"/>
</g>
<g id="shape39-119" v:mID="39" v:groupContext="shape" v:layerMember="0" transform="translate(320.428,-192.297)">
<title>Dynamic connector.39</title>
<path d="M0 257.79 L19.64 257.79 L19.64 427.87 L43.61 427.87" class="st9"/>
</g>
<g id="shape40-124" v:mID="40" v:groupContext="shape" v:layerMember="0" transform="translate(160.714,-37.1004)">
<title>Dynamic connector.40</title>
<path d="M0 250.7 L0 238.03 L176.99 238.03 A2.3622 2.3622 0 0 1 181.71 238.03 L351.4 238.03 L351.4 243.66" class="st9"/>
</g>
<g id="shape41-129" v:mID="41" v:groupContext="shape" transform="translate(232.493,-156.864)">
<title>Rectangle</title>
<desc>For each face</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(15):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197" v:verticalAlign="0"/>
<v:textRect cx="47.3781" cy="217.396" width="94.76" height="80.7874"/>
<path d="M0 257.79 L94.76 257.79 L94.76 177 L0 177 L0 257.79 Z" class="st11"/>
<text x="11.36" y="191.8" class="st12" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>For each face</text> </g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fb32d3db8768ff157daeff999cc7f4361d2bca866ed6dc95b8f78d8cc62ae208
size 176525

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f291422f562825d4c5eee718b7c22e472b02a5a0a9c0be01d59b6b7cd8d756b1
size 14603

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:925f70ede92d71e16733d78e003f62cd8bfdee0790bddbf2b7ce4fc8ef3f44bf
size 171518

View File

@@ -236,11 +236,7 @@ classification_sample_async -m squeezenet1.1.xml -i $IE_INSTALL/demo/car.png -d
classification_sample_async -m squeezenet1.1.xml -i $IE_INSTALL/demo/car.png -d HETERO:FPGA,CPU -ni 100
```
Congratulations, You are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA. To learn more about how the Intel® Distribution of OpenVINO™ toolkit works, the Hello World tutorial and are other resources are provided below.
## Hello World Face Detection Tutorial
Use the [Intel® Distribution of OpenVINO™ toolkit with FPGA Hello World Face Detection Exercise](https://github.com/fritzboyle/openvino-with-fpga-hello-world-face-detection) to learn more about how the software and hardware work together.
Congratulations, You are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA.
## Additional Resources

View File

@@ -237,12 +237,7 @@ classification_sample_async -m squeezenet1.1.xml -i $IE_INSTALL/demo/car.png
classification_sample_async -m squeezenet1.1.xml -i $IE_INSTALL/demo/car.png -d HETERO:FPGA,CPU
```
Congratulations, You are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA. To learn more about how the Intel® Distribution of OpenVINO™ toolkit works, the Hello World tutorial and are other resources are provided below.
## Hello World Face Detection Tutorial
Use the [Intel® Distribution of OpenVINO™ toolkit with FPGA Hello World Face Detection Exercise](https://github.com/fritzboyle/openvino-with-fpga-hello-world-face-detection) to learn more about how the software and hardware work together.
Congratulations, You are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA.
## Additional Resources
Intel® Distribution of OpenVINO™ toolkit home page: [https://software.intel.com/en-us/openvino-toolkit](https://software.intel.com/en-us/openvino-toolkit)

View File

@@ -319,11 +319,7 @@ The throughput on FPGA is listed and may show a lower FPS. This is due to the in
./classification_sample_async -i car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d HETERO:FPGA,CPU -ni 100
```
Congratulations, you are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA. To learn more about how the Intel® Distribution of OpenVINO™ toolkit works, the Hello World tutorial and are other resources are provided below.
## Hello World Face Detection Tutorial
Use the [Intel® Distribution of OpenVINO™ toolkit with FPGA Hello World Face Detection Exercise](https://github.com/fritzboyle/openvino-with-fpga-hello-world-face-detection) to learn more about how the software and hardware work together.
Congratulations, you are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA.
## Additional Resources

View File

@@ -270,11 +270,7 @@ The throughput on FPGA is listed and may show a lower FPS. This is due to the in
./classification_sample_async -i car.png -m ~/squeezenet1.1_FP16/squeezenet1.1.xml -d HETERO:FPGA,CPU -ni 100
```
Congratulations, you are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA. To learn more about how the Intel® Distribution of OpenVINO™ toolkit works, the Hello World tutorial and are other resources are provided below.
## Hello World Face Detection Tutorial
Use the [Intel® Distribution of OpenVINO™ toolkit with FPGA Hello World Face Detection Exercise](https://github.com/fritzboyle/openvino-with-fpga-hello-world-face-detection) to learn more about how the software and hardware work together.
Congratulations, you are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA.
## Additional Resources

View File

@@ -270,11 +270,7 @@ Note the CPU throughput in Frames Per Second (FPS). This tells you how quickly t
```
The throughput on FPGA is listed and may show a lower FPS. This may be due to the initialization time. To account for that, increase the number of iterations or batch size when deploying to get a better sense of the speed the FPGA can run inference at.
Congratulations, you are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA. To learn more about how the Intel® Distribution of OpenVINO™ toolkit works, the Hello World tutorial and are other resources are provided below.
## Hello World Face Detection Tutorial
Use the [Intel® Distribution of OpenVINO™ toolkit with FPGA Hello World Face Detection Exercise](https://github.com/fritzboyle/openvino-with-fpga-hello-world-face-detection) to learn more about how the software and hardware work together.
Congratulations, you are done with the Intel® Distribution of OpenVINO™ toolkit installation for FPGA.
## Additional Resources

View File

@@ -129,6 +129,5 @@ sudo apt autoremove intel-openvino-<PACKAGE_TYPE>-ubuntu<OS_VERSION>-<VERSION>.<
- [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md).
- [Inference Engine Developer Guide](../IE_DG/Deep_Learning_Inference_Engine_DevGuide.md).
- For more information on Sample Applications, see the [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md).
- For information on Inference Engine Tutorials, see the [Inference Tutorials](https://github.com/intel-iot-devkit/inference-tutorials-generic).
- For IoT Libraries & Code Samples see the [Intel® IoT Developer Kit](https://github.com/intel-iot-devkit).

View File

@@ -49,7 +49,7 @@ Now you can start to develop and run your application.
## Known Issues and Limitations
- You cannot use Python bindings included in Intel® Distribution of OpenVINO™ toolkit with [Anaconda* distribution](https://www.anaconda.com/products/individual/)
- You cannot use Python OpenVINO™ bindings included in Anaconda* package with official [Python distribution](https://https://www.python.org/).
- You cannot use Python OpenVINO™ bindings included in Anaconda* package with official [Python distribution](https://www.python.org/).
## Additional Resources
@@ -59,6 +59,5 @@ Now you can start to develop and run your application.
- [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md).
- [Inference Engine Developer Guide](../IE_DG/Deep_Learning_Inference_Engine_DevGuide.md).
- For more information on Sample Applications, see the [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md).
- For information on Inference Engine Tutorials, see the [Inference Tutorials](https://github.com/intel-iot-devkit/inference-tutorials-generic).
- Intel® Distribution of OpenVINO™ toolkit Anaconda* home page: [https://anaconda.org/intel/openvino-ie4py](https://anaconda.org/intel/openvino-ie4py)

View File

@@ -18,7 +18,10 @@ This guide provides the steps for creating a Docker* image with Intel® Distribu
## Prebuilt images
Prebuilt images are available on [Docker Hub](https://hub.docker.com/u/openvino).
Prebuilt images are available on:
- [Docker Hub](https://hub.docker.com/u/openvino)
- [Red Hat* Quay.io](https://quay.io/organization/openvino)
- [Red Hat* Ecosystem Catalog](https://catalog.redhat.com/software/containers/intel/openvino-runtime/606ff4d7ecb5241699188fb3)
## Use Docker* Image for CPU
@@ -44,7 +47,8 @@ docker run -it --rm <image_name>
- GPU is not available in container by default, you must attach it to the container.
- Kernel driver must be installed on the host.
- Intel® OpenCL™ runtime package must be included into the container.
- In the container, user must be in the `video` group.
- In the container, non-root user must be in the `video` and `render` groups. To add a user to the render group, follow the [Configuration Guide for the Intel® Graphics Compute Runtime for OpenCL™ on Ubuntu* 20.04](https://github.com/openvinotoolkit/docker_ci/blob/master/configure_gpu_ubuntu20.md).
Before building a Docker* image on GPU, add the following commands to a Dockerfile:
@@ -59,7 +63,7 @@ RUN apt-get update && \
curl -L "https://github.com/intel/compute-runtime/releases/download/19.41.14441/intel-igc-core_1.0.2597_amd64.deb" --output "intel-igc-core_1.0.2597_amd64.deb" && \
curl -L "https://github.com/intel/compute-runtime/releases/download/19.41.14441/intel-igc-opencl_1.0.2597_amd64.deb" --output "intel-igc-opencl_1.0.2597_amd64.deb" && \
curl -L "https://github.com/intel/compute-runtime/releases/download/19.41.14441/intel-opencl_19.41.14441_amd64.deb" --output "intel-opencl_19.41.14441_amd64.deb" && \
curl -L "https://github.com/intel/compute-runtime/releases/download/19.41.14441/intel-ocloc_19.04.12237_amd64.deb" --output "intel-ocloc_19.04.12237_amd64.deb" && \
curl -L "https://github.com/intel/compute-runtime/releases/download/19.41.14441/intel-ocloc_19.41.14441_amd64.deb" --output "intel-ocloc_19.04.12237_amd64.deb" && \
dpkg -i /tmp/opencl/*.deb && \
ldconfig && \
rm /tmp/opencl
@@ -90,6 +94,7 @@ To make GPU available in the container, attach the GPU to the container using `-
```sh
docker run -it --rm --device /dev/dri <image_name>
```
> **NOTE**: If your host system is Ubuntu 20, follow the [Configuration Guide for the Intel® Graphics Compute Runtime for OpenCL™ on Ubuntu* 20.04](https://github.com/openvinotoolkit/docker_ci/blob/master/configure_gpu_ubuntu20.md).
## Use a Docker* Image for Intel® Neural Compute Stick 2

View File

@@ -78,14 +78,12 @@ This guide provides step-by-step instructions on how to install the Intel® Dist
2. <a href="#install-external-dependencies">Install External software dependencies</a>
3. <a href="#set-the-environment-variables">Set the OpenVINO™ Environment Variables: Optional Update to .bashrc</a>.
4. <a href="#configure-model-optimizer">Configure the Model Optimizer </a>
5. <a href="#run-the-demos">Run the Verification Scripts to Verify Installation and Compile Samples</a>
6. <a href="#additional-GPU-steps">Steps for Intel® Processor Graphics (GPU)</a>
7. <a href="#additional-NCS-steps">Steps for Intel® Neural Compute Stick 2</a>
8. <a href="#install-VPU">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPU</a><br>
5. <a href="#additional-GPU-steps">Steps for Intel® Processor Graphics (GPU)</a>
6. <a href="#additional-NCS-steps">Steps for Intel® Neural Compute Stick 2</a>
7. <a href="#install-VPU">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPU</a><br>
After installing your Intel® Movidius™ VPU, you will return to this guide to complete OpenVINO™ installation.
9. <a href="#run-a-sample">Run a Sample Application</a>
10. <a href="#uninstall">Uninstall the Intel® Distribution of OpenVINO™ Toolkit.</a>
11. <a href="#Hello-World-Face-Detection-Tutorial">Use the Face Detection Tutorial</a>
8. <a href="#get-started">Get Started with Code Samples and Demo Applications</a>
9. <a href="#uninstall">Steps to uninstall the Intel® Distribution of OpenVINO™ Toolkit.</a>
## <a name="install-openvino"></a>Install the Intel® Distribution of OpenVINO™ Toolkit Core Components
@@ -111,15 +109,10 @@ cd l_openvino_toolkit_p_<version>
```
If you have a previous version of the Intel Distribution of OpenVINO
toolkit installed, rename or delete these two directories:
- `~/inference_engine_samples_build`
- `~/openvino_models`
**Installation Notes:**
- Choose an installation option and run the related script as root.
- You can use either a GUI installation wizard or command line instructions (CLI).
- Screenshots are provided for the GUI, but not for CLI. The following information also applies to CLI and will be helpful to your installation where you will be presented with the same choices and tasks.
5. Choose your installation option:
- `~/inference_engine_samples_build`
- `~/openvino_models`
5. Choose your installation option and run the related script as root to use either a GUI installation wizard or command line instructions (CLI).<br>
Screenshots are provided for the GUI, but not for CLI. The following information also applies to CLI and will be helpful to your installation where you will be presented with the same choices and tasks.
- **Option 1:** GUI Installation Wizard:
```sh
sudo ./install_GUI.sh
@@ -133,27 +126,22 @@ sudo ./install.sh
sudo sed -i 's/decline/accept/g' silent.cfg
sudo ./install.sh -s silent.cfg
```
You can select which OpenVINO components will be installed by modifying the `COMPONENTS` parameter in the `silent.cfg` file. For example, to install only CPU runtime for the Inference Engine, set
`COMPONENTS=intel-openvino-ie-rt-cpu__x86_64` in `silent.cfg`.
To get a full list of available components for installation, run the `./install.sh --list_components` command from the unpacked OpenVINO™ toolkit package.
6. Follow the instructions on your screen. Watch for informational
messages such as the following in case you must complete additional
steps:
![](../img/openvino-install-linux-01.png)
You can select which OpenVINO components will be installed by modifying the `COMPONENTS` parameter in the `silent.cfg` file. For example, to install only CPU runtime for the Inference Engine, set `COMPONENTS=intel-openvino-ie-rt-cpu__x86_64` in `silent.cfg`. To get a full list of available components for installation, run the `./install.sh --list_components` command from the unpacked OpenVINO™ toolkit package.
6. Follow the instructions on your screen. Watch for informational messages such as the following in case you must complete additional steps:
![](../img/openvino-install-linux-01.png)
7. If you select the default options, the **Installation summary** GUI screen looks like this:
![](../img/openvino-install-linux-02.png)
**Optional:** You can choose **Customize** to change the installation directory or the components you want to install:
![](../img/openvino-install-linux-03.png)
By default, the Intel® Distribution of OpenVINO™ is installed to the following directory, referred to as `<INSTALL_DIR>`:
- For root or administrator: `/opt/intel/openvino_<version>/`
- For regular users: `/home/<USER>/intel/openvino_<version>/`
For simplicity, a symbolic link to the latest installation is also created: `/opt/intel/openvino_2021/`.
> **NOTE**: The Intel® Media SDK component is always installed in the `/opt/intel/mediasdk` directory regardless of the OpenVINO installation path chosen.
8. A Complete screen indicates that the core components have been installed:
![](../img/openvino-install-linux-02.png)
By default, the Intel® Distribution of OpenVINO™ is installed to the following directory, referred to as `<INSTALL_DIR>`:
* For root or administrator: `/opt/intel/openvino_<version>/`
* For regular users: `/home/<USER>/intel/openvino_<version>/`
For simplicity, a symbolic link to the latest installation is also created: `/opt/intel/openvino_2021/`.
![](../img/openvino-install-linux-04.png)
8. **Optional**: You can choose **Customize** to change the installation directory or the components you want to install:
> **NOTE**: If there is an OpenVINO™ toolkit version previously installed on your system, the installer will use the same destination directory for next installations. If you want to install a newer version to a different directory, you need to uninstall the previously installed versions.
![](../img/openvino-install-linux-03.png)
> **NOTE**: The Intel® Media SDK component is always installed in the `/opt/intel/mediasdk` directory regardless of the OpenVINO installation path chosen.
9. A Complete screen indicates that the core components have been installed:
![](../img/openvino-install-linux-04.png)
The first core components are installed. Continue to the next section to install additional dependencies.
@@ -279,51 +267,15 @@ cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisit
```
The Model Optimizer is configured for one or more frameworks.
You are ready to compile the samples by <a href="#run-the-demos">running the verification scripts</a>.
You have completed all required installation, configuration and build steps in this guide to use your CPU to work with your trained models.
## <a name="run-the-demos"></a>Run the Verification Scripts to Verify Installation
> **IMPORTANT**: This section is required. In addition to confirming your installation was successful, demo scripts perform other steps, such as setting up your computer to use the Inference Engine samples.
To verify the installation and compile two samples, use the steps below to run the verification applications provided with the product on the CPU.
> **NOTE:** To run the demo applications on Intel® Processor Graphics or Intel® Neural Compute Stick 2 devices, make sure you first completed the additional <a href="#additional-GPU-steps">Steps for Intel® Processor Graphics (GPU)</a> or <a href="#additional-NCS-steps">Steps for Intel® Neural Compute Stick 2</a>.
1. Go to the **Inference Engine demo** directory:
```sh
cd /opt/intel/openvino_2021/deployment_tools/demo
```
2. Run the **Image Classification verification script**:
```sh
./demo_squeezenet_download_convert_run.sh
```
This verification script downloads a SqueezeNet model, uses the Model Optimizer to convert the model to the .bin and .xml Intermediate Representation (IR) files. The Inference Engine requires this model conversion so it can use the IR as input and achieve optimum performance on Intel hardware.<br>
This verification script builds the [Image Classification Sample Async](../../inference-engine/samples/classification_sample_async/README.md) application and run it with the `car.png` image located in the demo directory. When the verification script completes, you will have the label and confidence for the top-10 categories:
![](../img/image_classification_script_output_lnx.png)
3. Run the **Inference Pipeline verification script**:
```sh
./demo_security_barrier_camera.sh
```
This script downloads three pre-trained model IRs, builds the [Security Barrier Camera Demo](@ref omz_demos_security_barrier_camera_demo_README) application, and runs it with the downloaded models and the `car_1.bmp` image from the `demo` directory to show an inference pipeline. The verification script uses vehicle recognition in which vehicle attributes build on each other to narrow in on a specific attribute.<br>
First, an object is identified as a vehicle. This identification is used as input to the next model, which identifies specific vehicle attributes, including the license plate. Finally, the attributes identified as the license plate are used as input to the third model, which recognizes specific characters in the license plate.<br>
When the verification script completes, you will see an image that displays the resulting frame with detections rendered as bounding boxes, and text:
![](../img/inference_pipeline_script_lnx.png)
4. Close the image viewer window to complete the verification script.
To learn about the verification scripts, see the `README.txt` file in `/opt/intel/openvino_2021/deployment_tools/demo`.
For a description of the Intel Distribution of OpenVINO™ pre-trained object detection and object recognition models, see [Overview of OpenVINO™ Toolkit Pre-Trained Models](@ref omz_models_intel_index).
You have completed all required installation, configuration and build steps in this guide to use your CPU to work with your trained models.
To use other hardware, see;
To enable inference on other hardware, see:
- <a href="#additional-GPU-steps">Steps for Intel® Processor Graphics (GPU)</a>
- <a href="#additional-NCS-steps">Steps for Intel® Neural Compute Stick 2</a>
- <a href="#install-VPU">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</a><br>
Or proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
## <a name="additional-GPU-steps"></a>Steps for Intel® Processor Graphics (GPU)
The steps in this section are required only if you want to enable the toolkit components to use processor graphics (GPU) on your system.
@@ -351,6 +303,9 @@ Add OpenCL user to video group
4. **Optional** Install header files to allow compiling a new code. You can find the header files at [Khronos OpenCL™ API Headers](https://github.com/KhronosGroup/OpenCL-Headers.git).
You've completed all required configuration steps to perform inference on processor graphics.
Proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
## <a name="additional-NCS-steps"></a>Steps for Intel® Neural Compute Stick 2
These steps are only required if you want to perform inference on Intel® Movidius™ NCS powered by the Intel® Movidius™ Myriad™ 2 VPU or Intel® Neural Compute Stick 2 powered by the Intel® Movidius™ Myriad™ X VPU. See also the [Get Started page for Intel® Neural Compute Stick 2:](https://software.intel.com/en-us/neural-compute-stick/get-started)
@@ -361,20 +316,23 @@ sudo usermod -a -G users "$(whoami)"
```
Log out and log in for it to take effect.
2. To perform inference on Intel® Neural Compute Stick 2, install the USB rules as follows:
```sh
sudo cp /opt/intel/openvino_2021/inference_engine/external/97-myriad-usbboot.rules /etc/udev/rules.d/
```
```sh
sudo udevadm control --reload-rules
```
```sh
sudo udevadm trigger
```
```sh
sudo ldconfig
```
```sh
sudo cp /opt/intel/openvino_2021/inference_engine/external/97-myriad-usbboot.rules /etc/udev/rules.d/
```
```sh
sudo udevadm control --reload-rules
```
```sh
sudo udevadm trigger
```
```sh
sudo ldconfig
```
> **NOTE**: You may need to reboot your machine for this to take effect.
You've completed all required configuration steps to perform inference on Intel® Neural Compute Stick 2.
Proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
## <a name="install-VPU"></a>Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs
To install and configure your Intel® Vision Accelerator Design with Intel® Movidius™ VPUs, see the [Intel® Vision Accelerator Design with Intel® Movidius™ VPUs Configuration Guide](installing-openvino-linux-ivad-vpu.md).
@@ -398,61 +356,14 @@ cd /opt/intel/openvino_2021/deployment_tools/demo
./demo_security_barrier_camera.sh -d HDDL
```
## <a name="run-a-sample"></a>Run a Sample Application
You've completed all required configuration steps to perform inference on Intel® Vision Accelerator Design with Intel® Movidius™ VPUs.
Proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
> **IMPORTANT**: This section requires that you have [Run the Verification Scripts to Verify Installation](#run-the-demos). This script builds the Image Classification sample application and downloads and converts the required Caffe* Squeezenet model to an IR.
## <a name="get-started"></a>Get Started
In this section you will run the Image Classification sample application, with the Caffe* Squeezenet1.1 model on three types of Intel® hardware: CPU, GPU and VPUs.
Image Classification sample application binary file was automatically built and the FP16 model IR files are created when you [Ran the Image Classification Verification Script](#run-the-image-classification-verification-script).
The Image Classification sample application binary file located in the `/home/<user>/inference_engine_samples_build/intel64/Release` directory.
The Caffe* Squeezenet model IR files (`.bin` and `.xml`) are located in the `/home/<user>/openvino_models/ir/public/squeezenet1.1/FP16/` directory.
> **NOTE**: If you installed the Intel® Distribution of OpenVINO™ to the non-default install directory, replace `/opt/intel` with the directory in which you installed the software.
To run the sample application:
1. Set up environment variables:
```sh
source /opt/intel/openvino_2021/bin/setupvars.sh
```
2. Go to the samples build directory:
```sh
cd ~/inference_engine_samples_build/intel64/Release
```
3. Run the sample executable with specifying the `car.png` file from the `demo` directory as an input image, the IR of your FP16 model and a plugin for a hardware device to perform inference on.
> **NOTE**: Running the sample application on hardware other than CPU requires performing [additional hardware configuration steps](#optional-steps).
- **For CPU**:
```sh
./classification_sample_async -i /opt/intel/openvino_2021/deployment_tools/demo/car.png -m ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml -d CPU
```
- **For GPU**:
```sh
./classification_sample_async -i /opt/intel/openvino_2021/deployment_tools/demo/car.png -m ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml -d GPU
```
- **For MYRIAD**:
> **NOTE**: Running inference on Intel® Neural Compute Stick 2 with the MYRIAD plugin requires performing [additional hardware configuration steps](#additional-NCS-steps).
```sh
./classification_sample_async -i /opt/intel/openvino_2021/deployment_tools/demo/car.png -m ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml -d MYRIAD
```
- **For HDDL**:
> **NOTE**: Running inference on Intel® Vision Accelerator Design with Intel® Movidius™ VPUs with the HDDL plugin requires performing [additional hardware configuration steps](installing-openvino-linux-ivad-vpu.md)
```sh
./classification_sample_async -i /opt/intel/openvino_2021/deployment_tools/demo/car.png -m ~/openvino_models/ir/public/squeezenet1.1/FP16/squeezenet1.1.xml -d HDDL
```
For information on Sample Applications, see the [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md).
Congratulations, you have finished the installation of the Intel® Distribution of OpenVINO™ toolkit for Linux*. To learn more about how the Intel® Distribution of OpenVINO™ toolkit works, the Hello World tutorial and other resources are provided below.
## <a name="Hello-World-Face-Detection-Tutorial"></a>Hello World Face Detection Tutorial
See the [OpenVINO™ Hello World Face Detection Exercise](https://github.com/intel-iot-devkit/inference-tutorials-generic).
Now you are ready to get started. To continue, see the following pages:
* [OpenVINO™ Toolkit Overview](../index.md)
* [Get Started Guide for Linux](../get_started/get_started_linux.md) to learn the basic OpenVINO™ toolkit workflow and run code samples and demo applications with pre-trained models on different inference devices.
## <a name="uninstall"></a>Uninstall the Intel® Distribution of OpenVINO™ Toolkit
Choose one of the options provided below to uninstall the Intel® Distribution of OpenVINO™ Toolkit from your system.
@@ -505,7 +416,6 @@ trusted-host = mirrors.aliyun.com
- [Inference Engine Developer Guide](../IE_DG/Deep_Learning_Inference_Engine_DevGuide.md).
- For more information on Sample Applications, see the [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md).
- For information on a set of pre-trained models, see the [Overview of OpenVINO™ Toolkit Pre-Trained Models](@ref omz_models_intel_index)
- For information on Inference Engine Tutorials, see the [Inference Tutorials](https://github.com/intel-iot-devkit/inference-tutorials-generic)
- For IoT Libraries and Code Samples see the [Intel® IoT Developer Kit](https://github.com/intel-iot-devkit).
To learn more about converting models, go to:

View File

@@ -77,9 +77,9 @@ The following steps will be covered:
1. <a href="#Install-Core">Install the Intel® Distribution of OpenVINO™ Toolkit </a>.
2. <a href="#set-the-environment-variables">Set the OpenVINO environment variables and (optional) Update to <code>.bash_profile</code></a>.
4. <a href="#configure-the-model-optimizer">Configure the Model Optimizer</a>.
5. <a href="#Run-Demos">Run verification scripts to verify installation and compile samples</a>.
6. <a href="#uninstall">Uninstall the Intel® Distribution of OpenVINO™ Toolkit</a>.
3. <a href="#configure-the-model-optimizer">Configure the Model Optimizer</a>.
4. <a href="#get-started">Get Started with Code Samples and Demo Applications</a>.
5. <a href="#uninstall">Uninstall the Intel® Distribution of OpenVINO™ Toolkit</a>.
## <a name="Install-Core"></a>Install the Intel® Distribution of OpenVINO™ toolkit Core Components
@@ -106,7 +106,7 @@ The disk image is mounted to `/Volumes/m_openvino_toolkit_p_<version>` and autom
![](../img/openvino-install-macos-01.png)
The default installation directory path depends on the privileges you choose for the installation.
The default installation directory path depends on the privileges you choose for the installation.
5. Click **Next** and follow the instructions on your screen.
@@ -117,18 +117,16 @@ The disk image is mounted to `/Volumes/m_openvino_toolkit_p_<version>` and autom
8. The **Installation summary** screen shows you the default component set to install:
![](../img/openvino-install-macos-03.png)
By default, the Intel® Distribution of OpenVINO™ is installed to the following directory, referred to as `<INSTALL_DIR>`:
By default, the Intel® Distribution of OpenVINO™ is installed to the following directory, referred to as `<INSTALL_DIR>`:
* For root or administrator: `/opt/intel/openvino_<version>/`
* For regular users: `/home/<USER>/intel/openvino_<version>/`
For simplicity, a symbolic link to the latest installation is also created: `/home/<user>/intel/openvino_2021/`.
* For root or administrator: `/opt/intel/openvino_<version>/`
* For regular users: `/home/<USER>/intel/openvino_<version>/`
For simplicity, a symbolic link to the latest installation is also created: `/home/<user>/intel/openvino_2021/`.
9. If needed, click **Customize** to change the installation directory or the components you want to install:
![](../img/openvino-install-macos-04.png)
Click **Next** to save the installation options and show the Installation summary screen.
![](../img/openvino-install-macos-04.png)
> **NOTE**: If there is an OpenVINO™ toolkit version previously installed on your system, the installer will use the same destination directory for next installations. If you want to install a newer version to a different directory, you need to uninstall the previously installed versions.
Click **Next** to save the installation options and show the Installation summary screen.
10. On the **Installation summary** screen, press **Install** to begin the installation.
@@ -241,55 +239,11 @@ Configure individual frameworks separately **ONLY** if you did not select **Opti
The Model Optimizer is configured for one or more frameworks.
You are ready to verify the installation by <a href="#Run-Demos">running the verification scripts</a>.
You have completed all required installation, configuration and build steps in this guide to use your CPU to work with your trained models.
## <a name="Run-Demos"></a>Run the Verification Scripts to Verify Installation and Compile Samples
To enable inference on Intel® Neural Compute Stick 2, see the <a href="#additional-NCS2-steps">Steps for Intel® Neural Compute Stick 2</a>.
> **NOTES**:
> - The steps shown here assume you used the default installation directory to install the OpenVINO toolkit. If you installed the software to a directory other than `/opt/intel/`, update the directory path with the location where you installed the toolkit.
> - If you installed the product as a root user, you must switch to the root mode before you continue: `sudo -i`.
To verify the installation and compile two Inference Engine samples, run the verification applications provided with the product on the CPU:
### Run the Image Classification Verification Script
1. Go to the **Inference Engine demo** directory:
```sh
cd /opt/intel/openvino_2021/deployment_tools/demo
```
2. Run the **Image Classification verification script**:
```sh
./demo_squeezenet_download_convert_run.sh
```
The Image Classification verification script downloads a public SqueezeNet Caffe* model and runs the Model Optimizer to convert the model to `.bin` and `.xml` Intermediate Representation (IR) files. The Inference Engine requires this model conversion so it can use the IR as input and achieve optimum performance on Intel hardware.
This verification script creates the directory `/home/<user>/inference_engine_samples/`, builds the [Image Classification Sample](../../inference-engine/samples/classification_sample_async/README.md) application and runs with the model IR and `car.png` image located in the `demo` directory. When the verification script completes, you will have the label and confidence for the top-10 categories:
![](../img/image_classification_script_output_lnx.png)
For a brief description of the Intermediate Representation `.bin` and `.xml` files, see [Configuring the Model Optimizer](#configure-the-model-optimizer).
This script is complete. Continue to the next section to run the Inference Pipeline verification script.
### Run the Inference Pipeline Verification Script
While still in `/opt/intel/openvino_2021/deployment_tools/demo/`, run the Inference Pipeline verification script:
```sh
./demo_security_barrier_camera.sh
```
This verification script downloads three pre-trained model IRs, builds the [Security Barrier Camera Demo](@ref omz_demos_security_barrier_camera_demo_README) application and runs it with the downloaded models and the `car_1.bmp` image from the `demo` directory to show an inference pipeline. The verification script uses vehicle recognition in which vehicle attributes build on each other to narrow in on a specific attribute.
First, an object is identified as a vehicle. This identification is used as input to the next model, which identifies specific vehicle attributes, including the license plate. Finally, the attributes identified as the license plate are used as input to the third model, which recognizes specific characters in the license plate.
When the verification script completes, you will see an image that displays the resulting frame with detections rendered as bounding boxes, and text:
![](../img/inference_pipeline_script_mac.png)
Close the image viewer screen to end the demo.
**Congratulations**, you have completed the Intel® Distribution of OpenVINO™ 2020.1 installation for macOS. To learn more about what you can do with the Intel® Distribution of OpenVINO™ toolkit, see the additional resources provided below.
Or proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
## <a name="additional-NCS2-steps"></a>Steps for Intel® Neural Compute Stick 2
@@ -304,9 +258,14 @@ For example, to install the `libusb` library using Homebrew\*, use the following
brew install libusb
```
## <a name="Hello-World-Tutorial"></a>Hello World Tutorials
You've completed all required configuration steps to perform inference on your Intel® Neural Compute Stick 2.
Proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
Visit the Intel Distribution of OpenVINO Toolkit [Inference Tutorials for Face Detection and Car Detection Exercises](https://github.com/intel-iot-devkit/inference-tutorials-generic/tree/openvino_toolkit_r3_0)
## <a name="get-started"></a>Get Started
Now you are ready to get started. To continue, see the following pages:
* [OpenVINO™ Toolkit Overview](../index.md)
* [Get Started Guide for Windows](../get_started/get_started_macos.md) to learn the basic OpenVINO™ toolkit workflow and run code samples and demo applications with pre-trained models on different inference devices.
## <a name="uninstall"></a>Uninstall the Intel® Distribution of OpenVINO™ Toolkit

View File

@@ -26,9 +26,7 @@ Your installation is complete when these are all completed:
4. <a href="#Configure_MO">Configure the Model Optimizer</a>
5. Run two <a href="#Using-Demo-Scripts">Verification Scripts to Verify Installation</a>
6. Optional: 
5. Optional: 
- <a href="#Install-GPU">Install the Intel® Graphics Driver for Windows*</a>
@@ -36,7 +34,9 @@ Your installation is complete when these are all completed:
- <a href="#Update-Path">Update Windows* environment variables</a>
7. <a href="#uninstall">Uninstall the Intel® Distribution of OpenVINO™ Toolkit</a>
Also, the following steps will be covered in the guide:
- <a href="#get-started">Get Started with Code Samples and Demo Applications</a>
- <a href="#uninstall">Uninstall the Intel® Distribution of OpenVINO™ Toolkit</a>
### About the Intel® Distribution of OpenVINO™ toolkit
@@ -112,29 +112,20 @@ Proceed to an [easy installation from Docker](@ref workbench_docs_Workbench_DG_I
### <a name="Install-Core-Components"></a>Install the Intel® Distribution of OpenVINO™ toolkit Core Components
1. If you have not downloaded the Intel® Distribution of OpenVINO™ toolkit, [download the latest version](http://software.intel.com/en-us/openvino-toolkit/choose-download/free-download-windows). By default, the file is saved to the `Downloads` directory as `w_openvino_toolkit_p_<version>.exe`.
2. Go to the `Downloads` folder and double-click `w_openvino_toolkit_p_<version>.exe`. A window opens to let you choose your installation directory and components. The default installation directory is `C:\Program Files (x86)\Intel\openvino_<version>`, for simplicity, a shortcut to the latest installation is also created: `C:\Program Files (x86)\Intel\openvino_2021`. If you choose a different installation directory, the installer will create the directory for you:
1. If you have not downloaded the Intel® Distribution of OpenVINO™ toolkit, [download the latest version](https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/download.html). By default, the file is saved to the `Downloads` directory as `w_openvino_toolkit_p_<version>.exe`.
2. Go to the `Downloads` folder and double-click `w_openvino_toolkit_p_<version>.exe`. A window opens to let you choose your installation directory and components.
![](../img/openvino-install-windows-01.png)
The default installation directory is `C:\Program Files (x86)\Intel\openvino_<version>`, for simplicity, a shortcut to the latest installation is also created: `C:\Program Files (x86)\Intel\openvino_2021`. If you choose a different installation directory, the installer will create the directory for you.
> **NOTE**: If there is an OpenVINO™ toolkit version previously installed on your system, the installer will use the same destination directory for next installations. If you want to install a newer version to a different directory, you need to uninstall the previously installed versions.
3. Click **Next**.
4. You are asked if you want to provide consent to gather information. Choose the option of your choice. Click **Next**.
5. If you are missing external dependencies, you will see a warning screen. Write down the dependencies you are missing. **You need to take no other action at this time**. After installing the Intel® Distribution of OpenVINO™ toolkit core components, install the missing dependencies.
The screen example below indicates you are missing two dependencies:
![](../img/openvino-install-windows-02.png)
6. Click **Next**.
7. When the first part of installation is complete, the final screen informs you that the core components have been installed and additional steps still required:
![](../img/openvino-install-windows-03.png)
![](../img/openvino-install-windows-03.png)
8. Click **Finish** to close the installation wizard. A new browser window opens to the next section of the installation guide to set the environment variables. You are in the same document. The new window opens in case you ran the installation without first opening this installation guide.
9. If the installation indicated you must install dependencies, install them first. If there are no missing dependencies, you can go ahead and <a href="#set-the-environment-variables">set the environment variables</a>.
### Set the Environment Variables <a name="set-the-environment-variables"></a>
@@ -152,14 +143,14 @@ setupvars.bat
<strong>(Optional)</strong>: OpenVINO toolkit environment variables are removed when you close the Command Prompt window. As an option, you can permanently set the environment variables manually.
> **NOTE**: If you see an error indicating Python is not installed when you know you installed it, your computer might not be able to find the program. For the instructions to add Python to your system environment variables, see <a href="#Update-Path">Update Your Windows Environment Variables</a>.
The environment variables are set. Continue to the next section to configure the Model Optimizer.
## Configure the Model Optimizer <a name="Configure_MO"></a>
> **IMPORTANT**: These steps are required. You must configure the Model Optimizer for at least one framework. The Model Optimizer will fail if you do not complete the steps in this section.
> **NOTE**: If you see an error indicating Python is not installed when you know you installed it, your computer might not be able to find the program. For the instructions to add Python to your system environment variables, see <a href="#Update-Path">Update Your Windows Environment Variables</a>.
The Model Optimizer is a key component of the Intel® Distribution of OpenVINO™ toolkit. You cannot do inference on your trained model without running the model through the Model Optimizer. When you run a pre-trained model through the Model Optimizer, your output is an Intermediate Representation (IR) of the network. The IR is a pair of files that describe the whole model:
- `.xml`: Describes the network topology
@@ -247,89 +238,25 @@ The Model Optimizer is configured for one or more frameworks. Success is indicat
![](../img/Configure-MO.PNG)
You are ready to use two short demos to see the results of running the Intel Distribution of OpenVINO toolkit and to verify your installation was successful. The demo scripts are required since they perform additional configuration steps. Continue to the next section.
You have completed all required installation, configuration and build steps in this guide to use your CPU to work with your trained models.
If you want to use a GPU or VPU, or update your Windows* environment variables, read through the <a href="#optional-steps">Optional Steps</a> section.
If you want to use a GPU or VPU, or update your Windows* environment variables, read through the <a href="#optional-steps">Optional Steps</a> section:
- <a href="#Install-GPU">Steps for Intel® Processor Graphics (GPU)</a>
- <a href="#hddl-myriad">Steps for Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</a>
- <a href="#Update-Path">Add CMake* or Python* to your Windows* environment variables</a><br>
## <a name="Using-Demo-Scripts"></a>Use Verification Scripts to Verify Your Installation
> **IMPORTANT**: This section is required. In addition to confirming your installation was successful, demo scripts perform other steps, such as setting up your computer to use the Inference Engine samples.
> **NOTE**:
> The paths in this section assume you used the default installation directory. If you used a directory other than `C:\Program Files (x86)\Intel`, update the directory with the location where you installed the software.
To verify the installation and compile two samples, run the verification applications provided with the product on the CPU:
1. Open a command prompt window.
2. Go to the Inference Engine demo directory:<br>
```sh
cd C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo\
```
3. Run the verification scripts by following the instructions in the next section.
### <a name="run-the-image-classification-verification-script"></a>Run the Image Classification Verification Script
To run the script, start the `demo_squeezenet_download_convert_run.bat` file:
```sh
demo_squeezenet_download_convert_run.bat
```
This script downloads a SqueezeNet model, uses the Model Optimizer to convert the model to the `.&zwj;bin` and `.&zwj;xml` Intermediate Representation (IR) files. The Inference Engine requires this model conversion so it can use the IR as input and achieve optimum performance on Intel hardware.<br>
This verification script builds the [Image Classification Sample Async](../../inference-engine/samples/classification_sample_async/README.md) application and run it with the `car.png` image in the demo directory. For a brief description of the Intermediate Representation, see <a href="#Configure_MO">Configuring the Model Optimizer</a>.
When the verification script completes, you will have the label and confidence for the top-10 categories:
![](../img/image_classification_script_output_win.png)
This demo is complete. Leave the console open and continue to the next section to run the Inference Pipeline demo.
### Run the Inference Pipeline Verification Script
To run the script, start the `demo_security_barrier_camera.bat` file while still in the console:
```sh
demo_security_barrier_camera.bat
```
This script downloads three pre-trained model IRs, builds the [Security Barrier Camera Demo](@ref omz_demos_security_barrier_camera_demo_README) application, and runs it with the downloaded models and the `car_1.bmp` image from the `demo` directory to show an inference pipeline. The verification script uses vehicle recognition in which vehicle attributes build on each other to narrow in on a specific attribute.
First, an object is identified as a vehicle. This identification is used as input to the next model, which identifies specific vehicle attributes, including the license plate. Finally, the attributes identified as the license plate are used as input to the third model, which recognizes specific characters in the license plate.
When the demo completes, you have two windows open:
* A console window that displays information about the tasks performed by the demo
* An image viewer window that displays a resulting frame with detections rendered as bounding boxes, similar to the following:
![](../img/inference_pipeline_script_win.png)
Close the image viewer window to end the demo.
To learn more about the verification scripts, see `README.txt` in `C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo`.
For detailed description of the OpenVINO™ pre-trained object detection and object recognition models, see the [Overview of OpenVINO™ toolkit Pre-Trained Models](@ref omz_models_intel_index) page.
In this section, you saw a preview of the Intel® Distribution of OpenVINO™ toolkit capabilities.
Congratulations. You have completed all the required installation, configuration, and build steps to work with your trained models using CPU.
If you want to use Intel® Processor graphics (GPU), Intel® Neural Compute Stick 2 or Intel® Vision Accelerator Design with Intel® Movidius™ VPUs, or add CMake* and Python* to your Windows* environment variables, read through the next section for additional steps.
If you want to continue and run the Image Classification Sample Application on one of the supported hardware device, see the [Run the Image Classification Sample Application](#run-the-image-classification-sample-application) section.
Or proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
## <a name="optional-steps"></a>Optional Steps
Use the optional steps below if you want to:
* Infer models on <a href="#Install-GPU">Intel® Processor Graphics</a>
* Infer models on <a href="#usb-myriad">Intel® Vision Accelerator Design with Intel® Movidius™ VPUs</a>
* <a href="#Update-Path">Add CMake* or Python* to your Windows* environment variables</a>.
### <a name="Install-GPU"></a>Optional: Additional Installation Steps for Intel® Processor Graphics (GPU)
> **NOTE**: These steps are required only if you want to use a GPU.
If your applications offload computation to **Intel® Integrated Graphics**, you must have the Intel Graphics Driver for Windows version 15.65 or higher. To see if you have this driver installed:
If your applications offload computation to **Intel® Integrated Graphics**, you must have the latest version of Intel Graphics Driver for Windows installed for your hardware.
[Download and install a higher version](http://downloadcenter.intel.com/product/80939/Graphics-Drivers).
To check if you have this driver installed:
1. Type **device manager** in your **Search Windows** box. The **Device Manager** opens.
@@ -339,16 +266,13 @@ If your applications offload computation to **Intel® Integrated Graphics**, you
3. Right-click the adapter name and select **Properties**.
4. Click the **Driver** tab to see the driver version. Make sure the version number is 15.65 or higher.
4. Click the **Driver** tab to see the driver version.
![](../img/DeviceDriverVersion.PNG)
5. If your device driver version is lower than 15.65, [download and install a higher version](http://downloadcenter.intel.com/product/80939/Graphics-Drivers).
To use the **Intel® Iris® Xe MAX Graphics**, install the driver manually. See the [Drivers & Software](https://downloadcenter.intel.com/download/29993/Intel-Iris-Xe-MAX-Dedicated-Graphics-Drivers?product=80939) page for driver downloads and installation instructions.
You are done updating your device driver and are ready to use your GPU.
> **NOTE**: To use the **Intel® Iris® Xe MAX Graphics**, see the [Drivers & Software](https://downloadcenter.intel.com/download/29993/Intel-Iris-Xe-MAX-Dedicated-Graphics-Drivers?product=80939) page for driver downloads and installation instructions.
You are done updating your device driver and are ready to use your GPU. Proceed to the <a href="#get-started">Get Started</a> to get started with running code samples and demo applications.
### <a name="hddl-myriad"></a> Optional: Additional Installation Steps for the Intel® Vision Accelerator Design with Intel® Movidius™ VPUs
@@ -369,22 +293,7 @@ See also:
* After you've configurated your Intel® Vision Accelerator Design with Intel® Movidius™ VPUs, see [Intel® Movidius™ VPUs Programming Guide for Use with Intel® Distribution of OpenVINO™ toolkit](movidius-programming-guide.md) to learn how to distribute a model across all 8 VPUs to maximize performance.
After configuration is done, you are ready to run the verification scripts with the HDDL Plugin for your Intel® Vision Accelerator Design with Intel® Movidius™ VPUs.
1. Open a command prompt window.
2. Go to the Inference Engine demo directory:
```sh
cd C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo\
```
3. Run the Image Classification verification script. If you have access to the Internet through the proxy server only, please make sure that it is configured in your environment.
```sh
demo_squeezenet_download_convert_run.bat -d HDDL
```
4. Run the Inference Pipeline verification script:
```sh
demo_security_barrier_camera.bat -d HDDL
```
After configuration is done, you are ready to <a href="#get-started">Get Started</a> with running code samples and demo applications.
### <a name="Update-Path"></a>Optional: Update Your Windows Environment Variables
@@ -411,55 +320,11 @@ Use these steps to update your Windows `PATH` if a command you execute returns a
Your `PATH` environment variable is updated.
## <a name="run-the-image-classification-sample-application"></a>Run the Image Classification Sample Application
## <a name="get-started"></a>Get Started
> **IMPORTANT**: This section requires that you have [Run the Verification Scripts to Verify Installation](#run-the-demos). This script builds the Image Classification sample application and downloads and converts the required Caffe* Squeezenet model to an IR.
In this section you will run the Image Classification sample application, with the Caffe* Squeezenet1.1 model on three types of Intel® hardware: CPU, GPU and VPUs.
Image Classification sample application binary file was automatically built and the FP16 model IR files are created when you [Ran the Image Classification Verification Script](#run-the-image-classification-verification-script).
The Image Classification sample application binary file located in the `C:\Users\<username>\Documents\Intel\OpenVINO\inference_engine_samples_build\intel64\Release\` directory.
The Caffe* Squeezenet model IR files (`.bin` and `.xml`) are located in the in the `C:\Users\<username>\Documents\Intel\OpenVINO\openvino_models\ir\public\squeezenet1.1\FP16\` directory.
> **NOTE**: If you installed the Intel® Distribution of OpenVINO™ toolkit to the non-default installation directory, replace `C:\Program Files (x86)\Intel` with the directory where you installed the software.
To run the sample application:
1. Set up environment variables:
```sh
cd C:\Program Files (x86)\Intel\openvino_2021\bin\setupvars.bat
```
2. Go to the samples build directory:
```sh
cd C:\Users\<username>\Documents\Intel\OpenVINO\inference_engine_samples_build\intel64\Release
```
3. Run the sample executable with specifying the `car.png` file from the `demo` directory as an input image, the IR of your FP16 model and a plugin for a hardware device to perform inference on.
> **NOTE**: Running the sample application on hardware other than CPU requires performing [additional hardware configuration steps](#optional-steps).
- For CPU:
```sh
classification_sample_async.exe -i "C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo\car.png" -m "C:\Users\<username>\Documents\Intel\OpenVINO\openvino_models\ir\public\squeezenet1.1\FP16\squeezenet1.1.xml" -d CPU
```
- For GPU:
```sh
classification_sample_async.exe -i "C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo\car.png" -m "C:\Users\<username>\Documents\Intel\OpenVINO\openvino_models\ir\public\squeezenet1.1\FP16\squeezenet1.1.xml" -d GPU
```
- For VPU (Intel® Neural Compute Stick 2):
```sh
classification_sample_async.exe -i "C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo\car.png" -m "C:\Users\<username>\Documents\Intel\OpenVINO\openvino_models\ir\public\squeezenet1.1\FP16\squeezenet1.1.xml" -d MYRIAD
```
- For VPU (Intel® Vision Accelerator Design with Intel® Movidius™ VPUs):
```sh
classification_sample_async.exe -i "C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\demo\car.png" -m "C:\Users\<username>\Documents\Intel\OpenVINO\openvino_models\ir\public\squeezenet1.1\FP16\squeezenet1.1.xml" -d HDDL
```
For information on Sample Applications, see the [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md).
Congratulations, you have finished the installation of the Intel® Distribution of OpenVINO™ toolkit for Windows*. To learn more about how the Intel® Distribution of OpenVINO™ toolkit works, the Hello World tutorial and other resources are provided below.
Now you are ready to get started. To continue, see the following pages:
* [OpenVINO™ Toolkit Overview](../index.md)
* [Get Started Guide for Windows](../get_started/get_started_windows.md) to learn the basic OpenVINO™ toolkit workflow and run code samples and demo applications with pre-trained models on different inference devices.
## <a name="uninstall"></a>Uninstall the Intel® Distribution of OpenVINO™ Toolkit
Follow the steps below to uninstall the Intel® Distribution of OpenVINO™ Toolkit from your system:
@@ -484,14 +349,12 @@ To learn more about converting deep learning models, go to:
## Additional Resources
- [Intel Distribution of OpenVINO Toolkit home page](https://software.intel.com/en-us/openvino-toolkit)
- [Intel Distribution of OpenVINO Toolkit documentation](https://software.intel.com/en-us/openvino-toolkit/documentation/featured)
- [OpenVINO™ Release Notes](https://software.intel.com/en-us/articles/OpenVINO-RelNotes)
- [Introduction to Inference Engine](../IE_DG/inference_engine_intro.md)
- [Inference Engine Developer Guide](../IE_DG/Deep_Learning_Inference_Engine_DevGuide.md)
- [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md)
- [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md)
- [Overview of OpenVINO™ Toolkit Pre-Trained Models](@ref omz_models_intel_index)
- Intel Distribution of OpenVINO Toolkit Hello World Activities, see the [Inference Tutorials for Face Detection and Car Detection Exercises](https://github.com/intel-iot-devkit/inference-tutorials-generic/tree/openvino_toolkit_r3_0)
- [Intel® Neural Compute Stick 2 Get Started](https://software.intel.com/en-us/neural-compute-stick/get-started)

View File

@@ -106,6 +106,5 @@ sudo yum autoremove intel-openvino-runtime-centos<OS_VERSION>-<VERSION>.<UPDATE>
- [Model Optimizer Developer Guide](../MO_DG/Deep_Learning_Model_Optimizer_DevGuide.md).
- [Inference Engine Developer Guide](../IE_DG/Deep_Learning_Inference_Engine_DevGuide.md).
- For more information on Sample Applications, see the [Inference Engine Samples Overview](../IE_DG/Samples_Overview.md).
- For information on Inference Engine Tutorials, see the [Inference Tutorials](https://github.com/intel-iot-devkit/inference-tutorials-generic).
- For IoT Libraries & Code Samples see the [Intel® IoT Developer Kit](https://github.com/intel-iot-devkit).

View File

@@ -9,9 +9,9 @@
**Detailed description**: For each element from the input tensor calculates corresponding
element in the output tensor with the following formula:
\f[
HSigmoid(x) = \frac{min(max(x + 3, 0), 6)}{6}
\f]
\f[
HSigmoid(x) = \frac{min(max(x + 3, 0), 6)}{6}
\f]
The HSigmoid operation is introduced in the following [article](https://arxiv.org/pdf/1905.02244.pdf).

View File

@@ -6,9 +6,7 @@
**Short description**: *HardSigmoid* calculates the hard sigmoid function `y(x) = max(0, min(1, alpha * x + beta))` element-wise with given tensor.
**Attributes**:
No attributes available.
**Attributes**: No attributes available.
**Inputs**

View File

@@ -6,7 +6,7 @@
**Short description**: *DetectionOutput* performs non-maximum suppression to generate the detection output using information on location and confidence predictions.
**Detailed description**: [Reference](https://arxiv.org/pdf/1512.02325.pdf). The layer has 3 mandatory inputs: tensor with box logits, tensor with confidence predictions and tensor with box coordinates (proposals). It can have 2 additional inputs with additional confidence predictions and box coordinates described in the [article](https://arxiv.org/pdf/1711.06897.pdf). The 5-input version of the layer is supported with Myriad plugin only. The output tensor contains information about filtered detections described with 7 element tuples: *[batch_id, class_id, confidence, x_1, y_1, x_2, y_2]*. The first tuple with *batch_id* equal to *-1* means end of output.
**Detailed description**: [Reference](https://arxiv.org/pdf/1512.02325.pdf). The layer has 3 mandatory inputs: tensor with box logits, tensor with confidence predictions and tensor with box coordinates (proposals). It can have 2 additional inputs with additional confidence predictions and box coordinates described in the [article](https://arxiv.org/pdf/1711.06897.pdf). The 5-input version of the layer is supported with MYRIAD plugin only. The output tensor contains information about filtered detections described with 7 element tuples: *[batch_id, class_id, confidence, x_1, y_1, x_2, y_2]*. The first tuple with *batch_id* equal to *-1* means end of output.
At each feature map cell, *DetectionOutput* predicts the offsets relative to the default box shapes in the cell, as well as the per-class scores that indicate the presence of a class instance in each of those boxes. Specifically, for each box out of k at a given location, *DetectionOutput* computes class scores and the four offsets relative to the original default box shape. This results in a total of \f$(c + 4)k\f$ filters that are applied around each location in the feature map, yielding \f$(c + 4)kmn\f$ outputs for a *m \* n* feature map.

View File

@@ -41,7 +41,7 @@ p(S) = \prod_{t=1}^{L_i} p_{i,t,ct}
3. Finally, compute negative log of summed up probabilities of all found alignments:
\f[
CTCLoss = \minus \ln \sum_{S} p(S)
CTCLoss = - \ln \sum_{S} p(S)
\f]
**Note 1**: This calculation scheme does not provide steps for optimal implementation and primarily serves for better explanation.

View File

@@ -1,20 +1,6 @@
/*
* Copyright 2017-2019 Intel Corporation.
* The source code, information and material ("Material") contained herein is
* owned by Intel Corporation or its suppliers or licensors, and title to such
* Material remains with Intel Corporation or its suppliers or licensors.
* The Material contains proprietary information of Intel or its suppliers and
* licensors. The Material is protected by worldwide copyright laws and treaty
* provisions.
* No part of the Material may be used, copied, reproduced, modified, published,
* uploaded, posted, transmitted, distributed or disclosed in any way without
* Intel's prior express written permission. No license under any patent,
* copyright or other intellectual property rights in the Material is granted to
* or conferred upon you, either expressly, by implication, inducement, estoppel
* or otherwise.
* Any license under such intellectual property rights must be express and
* approved by Intel in writing.
*/
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "XLinkStringUtils.h"

View File

@@ -1,20 +1,6 @@
/*
* Copyright 2017-2019 Intel Corporation.
* The source code, information and material ("Material") contained herein is
* owned by Intel Corporation or its suppliers or licensors, and title to such
* Material remains with Intel Corporation or its suppliers or licensors.
* The Material contains proprietary information of Intel or its suppliers and
* licensors. The Material is protected by worldwide copyright laws and treaty
* provisions.
* No part of the Material may be used, copied, reproduced, modified, published,
* uploaded, posted, transmitted, distributed or disclosed in any way without
* Intel's prior express written permission. No license under any patent,
* copyright or other intellectual property rights in the Material is granted to
* or conferred upon you, either expressly, by implication, inducement, estoppel
* or otherwise.
* Any license under such intellectual property rights must be express and
* approved by Intel in writing.
*/
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "mvnc_data.h"
#include "mvnc_tool.h"

View File

@@ -37,107 +37,103 @@ namespace ngraph
{
namespace event
{
class Duration;
class Object;
class Manager;
//
// This class records timestamps for a given user defined event and
// produces output in the chrome tracing format that can be used to view
// the events of a running program
//
// Following is the format of a trace event
//
// {
// "name": "myName",
// "cat": "category,list",
// "ph": "B",
// "ts": 12345,
// "pid": 123,
// "tid": 456,
// "args": {
// "someArg": 1,
// "anotherArg": {
// "value": "my value"
// }
// }
// }
//
// The trace file format is defined here:
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
//
// The trace file can be viewed by Chrome browser using the
// URL: chrome://tracing/
//
// More information about this is at:
// http://dev.chromium.org/developers/how-tos/trace-event-profiling-tool
class Manager
{
friend class Duration;
friend class Object;
public:
static void open(const std::string& path = "runtime_event_trace.json");
static void close();
static bool is_tracing_enabled() { return s_tracing_enabled; }
static void enable_event_tracing();
static void disable_event_tracing();
static bool is_event_tracing_enabled();
private:
static std::ofstream& get_output_stream();
static const std::string& get_process_id();
static size_t get_current_microseconds()
{
return std::chrono::high_resolution_clock::now().time_since_epoch().count() / 1000;
}
static std::string get_thread_id();
static std::mutex& get_mutex() { return s_file_mutex; }
static std::ostream s_ostream;
static std::mutex s_file_mutex;
static bool s_tracing_enabled;
};
class NGRAPH_API Duration
{
public:
explicit Duration(const std::string& name,
const std::string& category,
const std::string& args = "");
~Duration() { write(); }
/// \brief stop the timer without writing the data to the log file. To write the data
/// call the `write` method
/// Calls to stop() are optional
void stop();
/// \brief write the log data to the log file for this event
/// This funtion has an implicit stop() if stop() has not been previously called
void write();
Duration(const Duration&) = delete;
Duration& operator=(Duration const&) = delete;
private:
std::string to_json() const;
size_t m_start{0};
size_t m_stop{0};
std::string m_name;
std::string m_category;
std::string m_args;
};
class Object
{
public:
Object(const std::string& name, const std::string& args);
void snapshot(const std::string& args);
void destroy();
private:
void write_snapshot(std::ostream& out, const std::string& args);
const std::string m_name;
size_t m_id{0};
};
}
}
//
// This class records timestamps for a given user defined event and
// produces output in the chrome tracing format that can be used to view
// the events of a running program
//
// Following is the format of a trace event
//
// {
// "name": "myName",
// "cat": "category,list",
// "ph": "B",
// "ts": 12345,
// "pid": 123,
// "tid": 456,
// "args": {
// "someArg": 1,
// "anotherArg": {
// "value": "my value"
// }
// }
// }
//
// The trace file format is defined here:
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
//
// The trace file can be viewed by Chrome browser using the
// URL: chrome://tracing/
//
// More information about this is at:
// http://dev.chromium.org/developers/how-tos/trace-event-profiling-tool
class ngraph::event::Manager
{
friend class Duration;
friend class Object;
public:
static void open(const std::string& path = "runtime_event_trace.json");
static void close();
static bool is_tracing_enabled() { return s_tracing_enabled; }
static void enable_event_tracing();
static void disable_event_tracing();
static bool is_event_tracing_enabled();
private:
static std::ofstream& get_output_stream();
static const std::string& get_process_id();
static size_t get_current_microseconds()
{
return std::chrono::high_resolution_clock::now().time_since_epoch().count() / 1000;
}
static std::string get_thread_id();
static std::mutex& get_mutex() { return s_file_mutex; }
static std::ostream s_ostream;
static std::mutex s_file_mutex;
static bool s_tracing_enabled;
};
class NGRAPH_API ngraph::event::Duration
{
public:
explicit Duration(const std::string& name,
const std::string& category,
const std::string& args = "");
~Duration() { write(); }
/// \brief stop the timer without writing the data to the log file. To write the data
/// call the `write` method
/// Calls to stop() are optional
void stop();
/// \brief write the log data to the log file for this event
/// This funtion has an implicit stop() if stop() has not been previously called
void write();
Duration(const Duration&) = delete;
Duration& operator=(Duration const&) = delete;
private:
std::string to_json() const;
size_t m_start{0};
size_t m_stop{0};
std::string m_name;
std::string m_category;
std::string m_args;
};
class ngraph::event::Object
{
public:
Object(const std::string& name, const std::string& args);
void snapshot(const std::string& args);
void destroy();
private:
void write_snapshot(std::ostream& out, const std::string& args);
const std::string m_name;
size_t m_id{0};
};

View File

@@ -24,20 +24,19 @@ namespace ngraph
{
namespace pass
{
class ConstantFolding;
bool revalidate_and_ensure_static(std::shared_ptr<ngraph::Node> n);
}
}
bool revalidate_and_ensure_static(std::shared_ptr<Node> n);
class NGRAPH_API ngraph::pass::ConstantFolding : public ngraph::pass::GraphRewrite
{
public:
NGRAPH_RTTI_DECLARATION;
ConstantFolding(const ngraph::BuildNodeExecutorMap& cfmap = ngraph::BuildNodeExecutorMap());
class NGRAPH_API ConstantFolding : public GraphRewrite
{
public:
NGRAPH_RTTI_DECLARATION;
ConstantFolding(const BuildNodeExecutorMap& cfmap = BuildNodeExecutorMap());
private:
void copy_runtime_info_to_target_inputs(const std::shared_ptr<Node>& node,
const Output<Node>& replacement);
private:
void copy_runtime_info_to_target_inputs(const std::shared_ptr<Node>& node,
const Output<Node>& replacement);
ngraph::BuildNodeExecutorMap m_cfmap;
};
BuildNodeExecutorMap m_cfmap;
};
} // namespace pass
} // namespace ngraph

View File

@@ -22,24 +22,21 @@ namespace ngraph
{
namespace pass
{
class ConvertFP32ToFP16;
class NGRAPH_API ConvertFP32ToFP16 : public ngraph::pass::GraphRewrite
{
public:
NGRAPH_RTTI_DECLARATION;
ConvertFP32ToFP16()
: GraphRewrite()
{
convert_constants_precision();
convert_parameters_precision();
}
private:
void convert_constants_precision();
void convert_parameters_precision();
};
} // namespace pass
} // namespace ngraph
class NGRAPH_API ngraph::pass::ConvertFP32ToFP16 : public ngraph::pass::GraphRewrite
{
public:
NGRAPH_RTTI_DECLARATION;
ConvertFP32ToFP16()
: GraphRewrite()
{
convert_constants_precision();
convert_parameters_precision();
}
private:
void convert_constants_precision();
void convert_parameters_precision();
};

View File

@@ -25,178 +25,194 @@
namespace ngraph
{
namespace pass
{
class GraphRewrite;
class RecurrentGraphRewrite;
class MatcherPass;
}
using matcher_pass_callback = std::function<bool(ngraph::pattern::Matcher& m)>;
using graph_rewrite_callback = std::function<bool(ngraph::pattern::Matcher& m)>;
using recurrent_graph_rewrite_callback =
std::function<bool(ngraph::pattern::RecurrentMatcher& m)>;
using handler_callback = std::function<bool(const std::shared_ptr<Node>& node)>;
}
/// \brief MatcherPass is a basic block for pattern based transformations. It describes pattern and
/// action that is applied if pattern is matched.
///
/// MatcherPass consists of Matcher and matcher_pass_callback that needs to be implemented and
/// finally registered by using \sa register_matcher. MatcherPass can be executed on node within
/// \sa apply method. To run matcher pass on Function use GraphRewrite.
/// In addition MatcherPass provides a way for adding new operations into GraphRewrite execution
/// queue. That means that operations that were created inside transformation callback can be added
/// for matching. To register node use \sa register_new_node method. GraphRewrite automatically
/// takes registered nodes and put them to execution queue. If multiple nodes were register make
/// sure that they were registered in topological order.
/// Note: when implementing pattern for Matcher make sure that root node is an operation from opset
/// or has ngraph::pattern::op::WrapType. That will help GraphRewrite to execute matcher passes more
/// efficient.
class NGRAPH_API ngraph::pass::MatcherPass : public ngraph::pass::PassBase
{
public:
NGRAPH_RTTI_DECLARATION;
MatcherPass() = default;
MatcherPass(const MatcherPass&) = delete;
MatcherPass& operator=(const MatcherPass&) = delete;
explicit MatcherPass(const std::string& name,
const std::shared_ptr<pattern::Matcher>& m,
const handler_callback& handler,
const PassPropertyMask& property = PassProperty::CHANGE_DYNAMIC_STATE)
: PassBase()
, m_handler(handler)
, m_matcher(m)
namespace pass
{
set_name(name);
set_property(property, true);
}
/// \brief MatcherPass is a basic block for pattern based transformations. It describes
/// pattern and
/// action that is applied if pattern is matched.
///
/// MatcherPass consists of Matcher and matcher_pass_callback that needs to be implemented
/// and
/// finally registered by using \sa register_matcher. MatcherPass can be executed on node
/// within
/// \sa apply method. To run matcher pass on Function use GraphRewrite.
/// In addition MatcherPass provides a way for adding new operations into GraphRewrite
/// execution
/// queue. That means that operations that were created inside transformation callback can
/// be added
/// for matching. To register node use \sa register_new_node method. GraphRewrite
/// automatically
/// takes registered nodes and put them to execution queue. If multiple nodes were register
/// make
/// sure that they were registered in topological order.
/// Note: when implementing pattern for Matcher make sure that root node is an operation
/// from opset
/// or has ngraph::pattern::op::WrapType. That will help GraphRewrite to execute matcher
/// passes more
/// efficient.
bool apply(std::shared_ptr<ngraph::Node> node);
template <typename T, class... Args>
std::shared_ptr<T> register_new_node(Args&&... args)
{
auto node = std::make_shared<T>(std::forward<Args>(args)...);
m_new_nodes.push_back(node);
return node;
}
const std::vector<std::shared_ptr<ngraph::Node>>& get_new_nodes() { return m_new_nodes; }
void clear_new_nodes() { m_new_nodes.clear(); }
std::shared_ptr<pattern::Matcher> get_matcher() { return m_matcher; }
protected:
void register_matcher(const std::shared_ptr<pattern::Matcher>& m,
const ngraph::graph_rewrite_callback& callback,
const PassPropertyMask& property = PassProperty::CHANGE_DYNAMIC_STATE);
private:
handler_callback m_handler;
std::shared_ptr<pattern::Matcher> m_matcher;
std::vector<std::shared_ptr<ngraph::Node>> m_new_nodes;
};
/// \brief GraphRewrite is a container for MatcherPasses that allows to run them on Function in
/// efficient way
///
/// Graph rewrite pass is used for matcher passes execution on Function.
/// To register MatcherPass use \sa add_matcher<T>(args) method where T is a MatcherPass class.
/// As a default algorithm graph rewrite pass traverse Function in topological order and applies
/// registered matcher passes for each node. But if all registered matcher passes have type based
/// root node in Matcher pattern then efficient mechanism is used to execute them.
/// Matcher pattern root is type based if it's operation from opset or pattern::op::WrapType.
/// Note: when implementing pattern for Matcher make sure that root node is an operation from opset
/// or has ngraph::pattern::op::WrapType. That will help GraphRewrite to execute matcher passes more
/// efficient.
class NGRAPH_API ngraph::pass::GraphRewrite : public ngraph::pass::FunctionPass
{
public:
NGRAPH_RTTI_DECLARATION;
GraphRewrite() = default;
explicit GraphRewrite(const std::shared_ptr<MatcherPass>& pass)
: FunctionPass()
{
m_matchers.push_back(pass);
}
/// \brief Register given transformation class type to GraphRewrite execution list
/// All registered transformations will be executed in a single graph traversal.
/// Example below show the basic usage of pass::GraphRewrite
///
/// pass::Manager manager;
/// auto anchor = manager.register_pass<GraphRewrite>();
/// anchor->add_matcher<MatcherPassA>();
/// anchor->add_matcher<MatcherPassB>();
/// anchor->set_name("CommonMathcers");
/// manager.run_passes(f);
///
/// For some purposes transformation can be registered and disabled by default.
///
/// anchor->add_matcher<MatcherPassB, false>();
///
/// \return shared_ptr to the transformation instance
template <typename T, bool Enabled = true, class... Args>
std::shared_ptr<T> add_matcher(Args&&... args)
{
static_assert(std::is_base_of<pass::MatcherPass, T>::value,
"pass not derived from MatcherPass");
auto pass = std::make_shared<T>(std::forward<Args>(args)...);
auto pass_config = get_pass_config();
pass->set_pass_config(pass_config);
if (!Enabled && !pass_config->is_enabled<T>())
class NGRAPH_API MatcherPass : public ngraph::pass::PassBase
{
pass_config->disable<T>();
}
m_matchers.push_back(pass);
return pass;
}
NGRAPH_DEPRECATED("Use MatcherPass instead")
void add_matcher(const std::shared_ptr<pattern::Matcher>& m,
const ngraph::graph_rewrite_callback& callback,
const PassPropertyMask& property);
public:
NGRAPH_RTTI_DECLARATION;
NGRAPH_DEPRECATED("Use MatcherPass instead")
void add_matcher(const std::shared_ptr<pattern::Matcher>& m,
const ngraph::graph_rewrite_callback& callback);
MatcherPass() = default;
bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
MatcherPass(const MatcherPass&) = delete;
MatcherPass& operator=(const MatcherPass&) = delete;
void set_pass_config(const std::shared_ptr<PassConfig>& pass_config) override;
explicit MatcherPass(
const std::string& name,
const std::shared_ptr<pattern::Matcher>& m,
const handler_callback& handler,
const PassPropertyMask& property = PassProperty::CHANGE_DYNAMIC_STATE)
: PassBase()
, m_handler(handler)
, m_matcher(m)
{
set_name(name);
set_property(property, true);
}
protected:
bool m_enable_shape_inference = false;
bool apply(std::shared_ptr<ngraph::Node> node);
std::vector<std::shared_ptr<ngraph::pass::MatcherPass>> m_matchers;
};
template <typename T, class... Args>
std::shared_ptr<T> register_new_node(Args&&... args)
{
auto node = std::make_shared<T>(std::forward<Args>(args)...);
m_new_nodes.push_back(node);
return node;
}
class NGRAPH_API ngraph::pass::RecurrentGraphRewrite : public ngraph::pass::FunctionPass
{
public:
RecurrentGraphRewrite(size_t num_iters = 10)
: FunctionPass()
, m_num_iters(num_iters)
{
}
const std::vector<std::shared_ptr<ngraph::Node>>& get_new_nodes()
{
return m_new_nodes;
}
void clear_new_nodes() { m_new_nodes.clear(); }
std::shared_ptr<pattern::Matcher> get_matcher() { return m_matcher; }
protected:
void register_matcher(
const std::shared_ptr<pattern::Matcher>& m,
const ngraph::graph_rewrite_callback& callback,
const PassPropertyMask& property = PassProperty::CHANGE_DYNAMIC_STATE);
void add_matcher(const std::shared_ptr<pattern::RecurrentMatcher>& m,
const ngraph::recurrent_graph_rewrite_callback& callback,
const PassPropertyMask& property);
private:
handler_callback m_handler;
std::shared_ptr<pattern::Matcher> m_matcher;
std::vector<std::shared_ptr<ngraph::Node>> m_new_nodes;
};
// TODO: This interface may deprecate after all passes are refactored.
void add_matcher(const std::shared_ptr<pattern::RecurrentMatcher>& m,
const ngraph::recurrent_graph_rewrite_callback& callback);
/// \brief GraphRewrite is a container for MatcherPasses that allows to run them on Function
/// in
/// efficient way
///
/// Graph rewrite pass is used for matcher passes execution on Function.
/// To register MatcherPass use \sa add_matcher<T>(args) method where T is a MatcherPass
/// class.
/// As a default algorithm graph rewrite pass traverse Function in topological order and
/// applies
/// registered matcher passes for each node. But if all registered matcher passes have type
/// based
/// root node in Matcher pattern then efficient mechanism is used to execute them.
/// Matcher pattern root is type based if it's operation from opset or
/// pattern::op::WrapType.
/// Note: when implementing pattern for Matcher make sure that root node is an operation
/// from opset
/// or has ngraph::pattern::op::WrapType. That will help GraphRewrite to execute matcher
/// passes more
/// efficient.
virtual bool run_on_function(std::shared_ptr<ngraph::Function> f);
class NGRAPH_API GraphRewrite : public ngraph::pass::FunctionPass
{
public:
NGRAPH_RTTI_DECLARATION;
private:
size_t m_num_iters;
GraphRewrite() = default;
std::vector<std::shared_ptr<ngraph::pass::MatcherPass>> m_matchers;
};
explicit GraphRewrite(const std::shared_ptr<MatcherPass>& pass)
: FunctionPass()
{
m_matchers.push_back(pass);
}
/// \brief Register given transformation class type to GraphRewrite execution list
/// All registered transformations will be executed in a single graph traversal.
/// Example below show the basic usage of pass::GraphRewrite
///
/// pass::Manager manager;
/// auto anchor = manager.register_pass<GraphRewrite>();
/// anchor->add_matcher<MatcherPassA>();
/// anchor->add_matcher<MatcherPassB>();
/// anchor->set_name("CommonMathcers");
/// manager.run_passes(f);
///
/// For some purposes transformation can be registered and disabled by default.
///
/// anchor->add_matcher<MatcherPassB, false>();
///
/// \return shared_ptr to the transformation instance
template <typename T, bool Enabled = true, class... Args>
std::shared_ptr<T> add_matcher(Args&&... args)
{
static_assert(std::is_base_of<pass::MatcherPass, T>::value,
"pass not derived from MatcherPass");
auto pass = std::make_shared<T>(std::forward<Args>(args)...);
auto pass_config = get_pass_config();
pass->set_pass_config(pass_config);
if (!Enabled && !pass_config->is_enabled<T>())
{
pass_config->disable<T>();
}
m_matchers.push_back(pass);
return pass;
}
NGRAPH_DEPRECATED("Use MatcherPass instead")
void add_matcher(const std::shared_ptr<pattern::Matcher>& m,
const ngraph::graph_rewrite_callback& callback,
const PassPropertyMask& property);
NGRAPH_DEPRECATED("Use MatcherPass instead")
void add_matcher(const std::shared_ptr<pattern::Matcher>& m,
const ngraph::graph_rewrite_callback& callback);
bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
void set_pass_config(const std::shared_ptr<PassConfig>& pass_config) override;
protected:
bool m_enable_shape_inference = false;
std::vector<std::shared_ptr<ngraph::pass::MatcherPass>> m_matchers;
};
class NGRAPH_API RecurrentGraphRewrite : public ngraph::pass::FunctionPass
{
public:
RecurrentGraphRewrite(size_t num_iters = 10)
: FunctionPass()
, m_num_iters(num_iters)
{
}
void add_matcher(const std::shared_ptr<pattern::RecurrentMatcher>& m,
const ngraph::recurrent_graph_rewrite_callback& callback,
const PassPropertyMask& property);
// TODO: This interface may deprecate after all passes are refactored.
void add_matcher(const std::shared_ptr<pattern::RecurrentMatcher>& m,
const ngraph::recurrent_graph_rewrite_callback& callback);
virtual bool run_on_function(std::shared_ptr<ngraph::Function> f);
private:
size_t m_num_iters;
std::vector<std::shared_ptr<ngraph::pass::MatcherPass>> m_matchers;
};
} // namespace pass
} // namespace ngraph

View File

@@ -13,43 +13,47 @@ namespace ngraph
{
namespace pass
{
class NGRAPH_API LowLatency;
/**
* @brief The transformation finds all TensorIterator layers in the network, processes all
* back
* edges that describe a connection between Result and Parameter of the TensorIterator body,
* and inserts ReadValue layer between Parameter and the next layers after this Parameter,
* and Assign layer after the layers before the Result layer.
* Supported platforms: CPU, GNA.
*
* The example below describes the changes to the inner part (body, back edges) of the
* Tensor
* Iterator layer.
* [] - TensorIterator body
* () - new layer
*
* before applying the transformation:
* back_edge_1 -> [Parameter -> some layers ... -> Result ] -> back_edge_1
*
* after applying the transformation:
* back_edge_1 -> [Parameter -> (ReadValue layer) -> some layers ... -> (Assign layer) ]
* \
* -> Result ] -> back_edge_1
*
* It is recommended to use this transformation in conjunction with the Reshape feature to
* set
* sequence dimension to 1 and with the UnrollTensorIterator transformation.
* For convenience, we have already enabled the unconditional execution of the
* UnrollTensorIterator
* transformation when using the LowLatency transformation for CPU, GNA plugins, no action
* is
* required here.
* After applying both of these transformations, the resulting network can be inferred step
* by
* step, the states will store between inferences.
*
*/
class NGRAPH_API LowLatency : public ngraph::pass::MatcherPass
{
public:
NGRAPH_RTTI_DECLARATION;
LowLatency();
};
} // namespace pass
} // namespace ngraph
/**
* @brief The transformation finds all TensorIterator layers in the network, processes all back
* edges that describe a connection between Result and Parameter of the TensorIterator body,
* and inserts ReadValue layer between Parameter and the next layers after this Parameter,
* and Assign layer after the layers before the Result layer.
* Supported platforms: CPU, GNA.
*
* The example below describes the changes to the inner part (body, back edges) of the Tensor
* Iterator layer.
* [] - TensorIterator body
* () - new layer
*
* before applying the transformation:
* back_edge_1 -> [Parameter -> some layers ... -> Result ] -> back_edge_1
*
* after applying the transformation:
* back_edge_1 -> [Parameter -> (ReadValue layer) -> some layers ... -> (Assign layer) ]
* \
* -> Result ] -> back_edge_1
*
* It is recommended to use this transformation in conjunction with the Reshape feature to set
* sequence dimension to 1 and with the UnrollTensorIterator transformation.
* For convenience, we have already enabled the unconditional execution of the UnrollTensorIterator
* transformation when using the LowLatency transformation for CPU, GNA plugins, no action is
* required here.
* After applying both of these transformations, the resulting network can be inferred step by
* step, the states will store between inferences.
*
*/
class ngraph::pass::LowLatency : public ngraph::pass::MatcherPass
{
public:
NGRAPH_RTTI_DECLARATION;
LowLatency();
};

View File

@@ -28,93 +28,103 @@ namespace ngraph
{
namespace pass
{
class Manager;
class NGRAPH_API Manager
{
public:
Manager();
~Manager();
//// \brief Construct Manager with shared PassConfig instance
explicit Manager(std::shared_ptr<PassConfig> pass_config);
/// \brief Register given transformation class type to execution list
/// Example below show the basic usage of pass::Manager
///
/// pass::Manager manager;
/// manager.register_pass<MyTransformation>(/*transformation constructor ars*/);
/// manager.run_passes(f);
///
/// For some purposes transformation can be registered and disabled by default.
///
/// manager.register_pass<MyTransformation, false>();
///
/// \return shared_ptr to the transformation instance
template <typename T, bool Enable = true, class... Args>
std::shared_ptr<T> register_pass(Args&&... args)
{
auto rc = push_pass<T>(std::forward<Args>(args)...);
rc->set_pass_config(m_pass_config);
if (m_per_pass_validation)
{
push_pass<Validate>();
}
if (!Enable && !m_pass_config->is_enabled<T>())
{
m_pass_config->disable<T>();
}
return rc;
}
void run_passes(std::shared_ptr<Function>);
void set_pass_visualization(bool new_state) { m_visualize = new_state; }
/// \brief Set flag to enable/disable running Validate pass after executing
/// each registered pass
/// \param new_state Value "true" enables Validate pass run; "false", otherwise
void set_per_pass_validation(bool new_state) { m_per_pass_validation = new_state; }
/// \brief Callback is a lambda function that can be used by registered transformations.
/// The main purpose of this callback is to provide a way for plugins to disable/enable
/// transformations based on some conditions. In some cases plugins may want not to
/// execute some
/// transformations.
/// For example plugin can disable unpleasant decompositions because of performance
/// reasons for
/// some cases.
/// Callback example:
/// auto callback = [](const std::shared_ptr<const ngraph::Node> & node) -> bool {
/// return std::dynamic_pointer_cast<const ngraph::opset3::DepthToSpace>(node) !=
/// nullptr;
/// };
/// This callback returns true in case of DepthToSpace operation. So when execution
/// DepthToSpace
/// decomposition pass will check is this decomposition needed or plugin can execute
/// this
/// operation directly. And of course on transformation side we need to have a response
/// for this
/// callback.
/// if (transformation_callback(batch_to_space)) {
/// return false;
/// }
/// \param callback lamda function that returns true in case if node is supported by
/// plugin and
/// transformation is not needed
NGRAPH_DEPRECATED("Please use get_pass_config() to configure transformation pipeline")
void set_callback(const param_callback& callback)
{
m_pass_config->set_callback(callback);
}
/// \return PassConfig shared object. This object is used for transformations pipeline
/// configuration.
/// This object allows to disable/enable transformations execution, set callback to
/// particular
/// transformation. For mo details see PassConfig class.
std::shared_ptr<PassConfig> get_pass_config() { return m_pass_config; }
protected:
template <typename T, class... Args>
std::shared_ptr<T> push_pass(Args&&... args)
{
static_assert(std::is_base_of<pass::PassBase, T>::value,
"pass not derived from pass base");
auto pass = std::make_shared<T>(std::forward<Args>(args)...);
auto pass_base = std::static_pointer_cast<PassBase>(pass);
m_pass_list.push_back(pass_base);
return pass;
}
std::shared_ptr<PassConfig> m_pass_config;
std::vector<std::shared_ptr<PassBase>> m_pass_list;
bool m_visualize = false;
bool m_per_pass_validation = true;
};
}
}
class NGRAPH_API ngraph::pass::Manager
{
public:
Manager();
~Manager();
//// \brief Construct Manager with shared PassConfig instance
explicit Manager(std::shared_ptr<PassConfig> pass_config);
/// \brief Register given transformation class type to execution list
/// Example below show the basic usage of pass::Manager
///
/// pass::Manager manager;
/// manager.register_pass<MyTransformation>(/*transformation constructor ars*/);
/// manager.run_passes(f);
///
/// For some purposes transformation can be registered and disabled by default.
///
/// manager.register_pass<MyTransformation, false>();
///
/// \return shared_ptr to the transformation instance
template <typename T, bool Enable = true, class... Args>
std::shared_ptr<T> register_pass(Args&&... args)
{
auto rc = push_pass<T>(std::forward<Args>(args)...);
rc->set_pass_config(m_pass_config);
if (m_per_pass_validation)
{
push_pass<Validate>();
}
if (!Enable && !m_pass_config->is_enabled<T>())
{
m_pass_config->disable<T>();
}
return rc;
}
void run_passes(std::shared_ptr<Function>);
void set_pass_visualization(bool new_state) { m_visualize = new_state; }
/// \brief Set flag to enable/disable running Validate pass after executing
/// each registered pass
/// \param new_state Value "true" enables Validate pass run; "false", otherwise
void set_per_pass_validation(bool new_state) { m_per_pass_validation = new_state; }
/// \brief Callback is a lambda function that can be used by registered transformations.
/// The main purpose of this callback is to provide a way for plugins to disable/enable
/// transformations based on some conditions. In some cases plugins may want not to execute some
/// transformations.
/// For example plugin can disable unpleasant decompositions because of performance reasons for
/// some cases.
/// Callback example:
/// auto callback = [](const std::shared_ptr<const ngraph::Node> & node) -> bool {
/// return std::dynamic_pointer_cast<const ngraph::opset3::DepthToSpace>(node) != nullptr;
/// };
/// This callback returns true in case of DepthToSpace operation. So when execution DepthToSpace
/// decomposition pass will check is this decomposition needed or plugin can execute this
/// operation directly. And of course on transformation side we need to have a response for this
/// callback.
/// if (transformation_callback(batch_to_space)) {
/// return false;
/// }
/// \param callback lamda function that returns true in case if node is supported by plugin and
/// transformation is not needed
NGRAPH_DEPRECATED("Please use get_pass_config() to configure transformation pipeline")
void set_callback(const param_callback& callback) { m_pass_config->set_callback(callback); }
/// \return PassConfig shared object. This object is used for transformations pipeline
/// configuration.
/// This object allows to disable/enable transformations execution, set callback to particular
/// transformation. For mo details see PassConfig class.
std::shared_ptr<PassConfig> get_pass_config() { return m_pass_config; }
protected:
template <typename T, class... Args>
std::shared_ptr<T> push_pass(Args&&... args)
{
static_assert(std::is_base_of<pass::PassBase, T>::value, "pass not derived from pass base");
auto pass = std::make_shared<T>(std::forward<Args>(args)...);
auto pass_base = std::static_pointer_cast<PassBase>(pass);
m_pass_list.push_back(pass_base);
return pass;
}
std::shared_ptr<PassConfig> m_pass_config;
std::vector<std::shared_ptr<PassBase>> m_pass_list;
bool m_visualize = false;
bool m_per_pass_validation = true;
};

View File

@@ -27,49 +27,51 @@
#include "ngraph/pass/pass.hpp"
namespace ngraph
{
namespace pass
{
class VisualizeTree;
}
}
class HeightMap;
using visualize_tree_ops_map_t =
std::unordered_map<ngraph::Node::type_info_t,
std::function<void(const ngraph::Node&, std::ostream& ss)>>;
class NGRAPH_API ngraph::pass::VisualizeTree : public FunctionPass
namespace ngraph
{
public:
NGRAPH_RTTI_DECLARATION;
namespace pass
{
class NGRAPH_API VisualizeTree : public FunctionPass
{
public:
NGRAPH_RTTI_DECLARATION;
using node_modifiers_t =
std::function<void(const Node& node, std::vector<std::string>& attributes)>;
VisualizeTree(const std::string& file_name,
node_modifiers_t nm = nullptr,
bool dot_only = false);
bool run_on_function(std::shared_ptr<ngraph::Function>) override;
using node_modifiers_t =
std::function<void(const Node& node, std::vector<std::string>& attributes)>;
VisualizeTree(const std::string& file_name,
node_modifiers_t nm = nullptr,
bool dot_only = false);
bool run_on_function(std::shared_ptr<ngraph::Function>) override;
void set_ops_to_details(const visualize_tree_ops_map_t& ops_map) { m_ops_to_details = ops_map; }
protected:
void add_node_arguments(std::shared_ptr<Node> node,
std::unordered_map<Node*, HeightMap>& height_maps,
size_t& fake_node_ctr);
std::string add_attributes(std::shared_ptr<Node> node);
virtual std::string get_attributes(std::shared_ptr<Node> node);
virtual std::string get_node_name(std::shared_ptr<Node> node);
std::string get_constant_value(std::shared_ptr<Node> node, size_t max_elements = 7);
void set_ops_to_details(const visualize_tree_ops_map_t& ops_map)
{
m_ops_to_details = ops_map;
}
void render() const;
protected:
void add_node_arguments(std::shared_ptr<Node> node,
std::unordered_map<Node*, HeightMap>& height_maps,
size_t& fake_node_ctr);
std::string add_attributes(std::shared_ptr<Node> node);
virtual std::string get_attributes(std::shared_ptr<Node> node);
virtual std::string get_node_name(std::shared_ptr<Node> node);
std::string get_constant_value(std::shared_ptr<Node> node, size_t max_elements = 7);
std::stringstream m_ss;
std::string m_name;
std::set<std::shared_ptr<Node>> m_nodes_with_attributes;
visualize_tree_ops_map_t m_ops_to_details;
node_modifiers_t m_node_modifiers = nullptr;
bool m_dot_only;
static const int max_jump_distance;
};
void render() const;
std::stringstream m_ss;
std::string m_name;
std::set<std::shared_ptr<Node>> m_nodes_with_attributes;
visualize_tree_ops_map_t m_ops_to_details;
node_modifiers_t m_node_modifiers = nullptr;
bool m_dot_only;
static const int max_jump_distance;
};
}
}

View File

@@ -24,59 +24,55 @@ namespace ngraph
{
namespace runtime
{
class AlignedBuffer;
/// \brief Allocates a block of memory on the specified alignment. The actual size of the
/// allocated memory is larger than the requested size by the alignment, so allocating 1
/// byte
/// on 64 byte alignment will allocate 65 bytes.
class NGRAPH_API AlignedBuffer
{
public:
// Allocator objects and the allocation interfaces are owned by the
// creators of AlignedBuffers. They need to ensure that the lifetime of
// allocator exceeds the lifetime of this AlignedBuffer.
AlignedBuffer(size_t byte_size, size_t alignment = 64);
AlignedBuffer();
~AlignedBuffer();
AlignedBuffer(AlignedBuffer&& other);
AlignedBuffer& operator=(AlignedBuffer&& other);
size_t size() const { return m_byte_size; }
void* get_ptr(size_t offset) const { return m_aligned_buffer + offset; }
void* get_ptr() { return m_aligned_buffer; }
const void* get_ptr() const { return m_aligned_buffer; }
template <typename T>
T* get_ptr()
{
return reinterpret_cast<T*>(m_aligned_buffer);
}
template <typename T>
const T* get_ptr() const
{
return reinterpret_cast<const T*>(m_aligned_buffer);
}
template <typename T>
explicit operator T*()
{
return get_ptr<T>();
}
private:
AlignedBuffer(const AlignedBuffer&) = delete;
AlignedBuffer& operator=(const AlignedBuffer&) = delete;
protected:
char* m_allocated_buffer;
char* m_aligned_buffer;
size_t m_byte_size;
};
}
}
/// \brief Allocates a block of memory on the specified alignment. The actual size of the
/// allocated memory is larger than the requested size by the alignment, so allocating 1 byte
/// on 64 byte alignment will allocate 65 bytes.
class NGRAPH_API ngraph::runtime::AlignedBuffer
{
public:
// Allocator objects and the allocation interfaces are owned by the
// creators of AlignedBuffers. They need to ensure that the lifetime of
// allocator exceeds the lifetime of this AlignedBuffer.
AlignedBuffer(size_t byte_size, size_t alignment = 64);
AlignedBuffer();
~AlignedBuffer();
AlignedBuffer(AlignedBuffer&& other);
AlignedBuffer& operator=(AlignedBuffer&& other);
size_t size() const { return m_byte_size; }
void* get_ptr(size_t offset) const { return m_aligned_buffer + offset; }
void* get_ptr() { return m_aligned_buffer; }
const void* get_ptr() const { return m_aligned_buffer; }
template <typename T>
T* get_ptr()
{
return reinterpret_cast<T*>(m_aligned_buffer);
}
template <typename T>
const T* get_ptr() const
{
return reinterpret_cast<const T*>(m_aligned_buffer);
}
template <typename T>
explicit operator T*()
{
return get_ptr<T>();
}
private:
AlignedBuffer(const AlignedBuffer&) = delete;
AlignedBuffer& operator=(const AlignedBuffer&) = delete;
char* m_allocated_buffer;
char* m_aligned_buffer;
size_t m_byte_size;
};
namespace ngraph
{
template <>
class NGRAPH_API AttributeAdapter<std::shared_ptr<runtime::AlignedBuffer>>
: public ValueAccessor<void*>

View File

@@ -25,10 +25,6 @@
namespace ngraph
{
namespace runtime
{
class HostTensor;
}
namespace op
{
namespace v0
@@ -36,100 +32,106 @@ namespace ngraph
class Constant;
}
}
namespace runtime
{
class NGRAPH_API HostTensor : public ngraph::runtime::Tensor
{
public:
HostTensor(const element::Type& element_type,
const Shape& shape,
void* memory_pointer,
const std::string& name = "");
HostTensor(const element::Type& element_type,
const Shape& shape,
const std::string& name = "");
HostTensor(const element::Type& element_type,
const PartialShape& partial_shape,
const std::string& name = "");
HostTensor(const std::string& name = "");
explicit HostTensor(const Output<Node>&);
explicit HostTensor(const std::shared_ptr<op::v0::Constant>& constant);
virtual ~HostTensor() override;
void initialize(const std::shared_ptr<op::v0::Constant>& constant);
void* get_data_ptr();
const void* get_data_ptr() const;
template <typename T>
T* get_data_ptr()
{
return static_cast<T*>(get_data_ptr());
}
template <typename T>
const T* get_data_ptr() const
{
return static_cast<T*>(get_data_ptr());
}
template <element::Type_t ET>
typename element_type_traits<ET>::value_type* get_data_ptr()
{
NGRAPH_CHECK(ET == get_element_type(),
"get_data_ptr() called for incorrect element type.");
return static_cast<typename element_type_traits<ET>::value_type*>(get_data_ptr());
}
template <element::Type_t ET>
const typename element_type_traits<ET>::value_type* get_data_ptr() const
{
NGRAPH_CHECK(ET == get_element_type(),
"get_data_ptr() called for incorrect element type.");
return static_cast<typename element_type_traits<ET>::value_type>(get_data_ptr());
}
/// \brief Write bytes directly into the tensor
/// \param p Pointer to source of data
/// \param n Number of bytes to write, must be integral number of elements.
void write(const void* p, size_t n) override;
/// \brief Read bytes directly from the tensor
/// \param p Pointer to destination for data
/// \param n Number of bytes to read, must be integral number of elements.
void read(void* p, size_t n) const override;
bool get_is_allocated() const;
/// \brief Set the element type. Must be compatible with the current element type.
/// \param element_type The element type
void set_element_type(const element::Type& element_type);
/// \brief Set the actual shape of the tensor compatibly with the partial shape.
/// \param shape The shape being set
void set_shape(const Shape& shape);
/// \brief Set the shape of a node from an input
/// \param arg The input argument
void set_unary(const HostTensorPtr& arg);
/// \brief Set the shape of the tensor using broadcast rules
/// \param autob The broadcast mode
/// \param arg0 The first argument
/// \param arg1 The second argument
void set_broadcast(const op::AutoBroadcastSpec& autob,
const HostTensorPtr& arg0,
const HostTensorPtr& arg1);
/// \brief Set the shape of the tensor using broadcast rules
/// \param autob The broadcast mode
/// \param arg0 The first argument
/// \param arg1 The second argument
/// \param element_type The output element type
void set_broadcast(const op::AutoBroadcastSpec& autob,
const HostTensorPtr& arg0,
const HostTensorPtr& arg1,
const element::Type& element_type);
private:
void allocate_buffer();
HostTensor(const HostTensor&) = delete;
HostTensor(HostTensor&&) = delete;
HostTensor& operator=(const HostTensor&) = delete;
void* m_memory_pointer{nullptr};
void* m_allocated_buffer_pool{nullptr};
void* m_aligned_buffer_pool{nullptr};
size_t m_buffer_size;
};
}
}
class NGRAPH_API ngraph::runtime::HostTensor : public ngraph::runtime::Tensor
{
public:
HostTensor(const element::Type& element_type,
const Shape& shape,
void* memory_pointer,
const std::string& name = "");
HostTensor(const element::Type& element_type, const Shape& shape, const std::string& name = "");
HostTensor(const element::Type& element_type,
const PartialShape& partial_shape,
const std::string& name = "");
HostTensor(const std::string& name = "");
explicit HostTensor(const Output<Node>&);
explicit HostTensor(const std::shared_ptr<op::v0::Constant>& constant);
virtual ~HostTensor() override;
void initialize(const std::shared_ptr<op::v0::Constant>& constant);
void* get_data_ptr();
const void* get_data_ptr() const;
template <typename T>
T* get_data_ptr()
{
return static_cast<T*>(get_data_ptr());
}
template <typename T>
const T* get_data_ptr() const
{
return static_cast<T*>(get_data_ptr());
}
template <element::Type_t ET>
typename element_type_traits<ET>::value_type* get_data_ptr()
{
NGRAPH_CHECK(ET == get_element_type(), "get_data_ptr() called for incorrect element type.");
return static_cast<typename element_type_traits<ET>::value_type*>(get_data_ptr());
}
template <element::Type_t ET>
const typename element_type_traits<ET>::value_type* get_data_ptr() const
{
NGRAPH_CHECK(ET == get_element_type(), "get_data_ptr() called for incorrect element type.");
return static_cast<typename element_type_traits<ET>::value_type>(get_data_ptr());
}
/// \brief Write bytes directly into the tensor
/// \param p Pointer to source of data
/// \param n Number of bytes to write, must be integral number of elements.
void write(const void* p, size_t n) override;
/// \brief Read bytes directly from the tensor
/// \param p Pointer to destination for data
/// \param n Number of bytes to read, must be integral number of elements.
void read(void* p, size_t n) const override;
bool get_is_allocated() const;
/// \brief Set the element type. Must be compatible with the current element type.
/// \param element_type The element type
void set_element_type(const element::Type& element_type);
/// \brief Set the actual shape of the tensor compatibly with the partial shape.
/// \param shape The shape being set
void set_shape(const Shape& shape);
/// \brief Set the shape of a node from an input
/// \param arg The input argument
void set_unary(const HostTensorPtr& arg);
/// \brief Set the shape of the tensor using broadcast rules
/// \param autob The broadcast mode
/// \param arg0 The first argument
/// \param arg1 The second argument
void set_broadcast(const op::AutoBroadcastSpec& autob,
const HostTensorPtr& arg0,
const HostTensorPtr& arg1);
/// \brief Set the shape of the tensor using broadcast rules
/// \param autob The broadcast mode
/// \param arg0 The first argument
/// \param arg1 The second argument
/// \param element_type The output element type
void set_broadcast(const op::AutoBroadcastSpec& autob,
const HostTensorPtr& arg0,
const HostTensorPtr& arg1,
const element::Type& element_type);
private:
void allocate_buffer();
HostTensor(const HostTensor&) = delete;
HostTensor(HostTensor&&) = delete;
HostTensor& operator=(const HostTensor&) = delete;
void* m_memory_pointer{nullptr};
void* m_allocated_buffer_pool{nullptr};
void* m_aligned_buffer_pool{nullptr};
size_t m_buffer_size;
};

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
"""! ngraph module namespace, exposing factory functions for all ops and other classes."""
"""ngraph module namespace, exposing factory functions for all ops and other classes."""
# noqa: F401
from pkg_resources import get_distribution, DistributionNotFound

View File

@@ -13,16 +13,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
"""! ngraph exceptions hierarchy. All exceptions are descendants of NgraphError."""
"""ngraph exceptions hierarchy. All exceptions are descendants of NgraphError."""
class NgraphError(Exception):
"""! Base class for Ngraph exceptions."""
"""Base class for Ngraph exceptions."""
class UserInputError(NgraphError):
"""! User provided unexpected input."""
"""User provided unexpected input."""
class NgraphTypeError(NgraphError, TypeError):
"""! Type mismatch error."""
"""Type mismatch error."""

View File

@@ -13,14 +13,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
"""! nGraph helper functions."""
"""nGraph helper functions."""
from ngraph.impl import Function
from openvino.inference_engine import IENetwork
def function_from_cnn(cnn_network: IENetwork) -> Function:
"""! Get nGraph function from Inference Engine CNN network."""
"""Get nGraph function from Inference Engine CNN network."""
capsule = cnn_network._get_function_capsule()
ng_function = Function.from_capsule(capsule)
return ng_function

View File

@@ -24,7 +24,7 @@ import numpy as np
from _pyngraph.op import Constant
""" Retrieve Constant inner data.
"""Retrieve Constant inner data.
Internally uses PyBind11 Numpy's buffer protocol.

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@
# limitations under the License.
# ******************************************************************************
"""! Factory functions for all ngraph ops."""
"""Factory functions for all ngraph ops."""
from typing import Callable, Iterable, List, Optional, Set, Union
import numpy as np
@@ -66,7 +66,7 @@ def batch_to_space(
crops_end: NodeInput,
name: Optional[str] = None,
) -> Node:
"""! Perform BatchToSpace operation on the input tensor.
"""Perform BatchToSpace operation on the input tensor.
BatchToSpace permutes data from the batch dimension of the data tensor into spatial dimensions.
@@ -84,14 +84,13 @@ def batch_to_space(
@unary_op
def gelu(node: NodeInput, name: Optional[str] = None) -> Node:
r"""! Perform Gaussian Error Linear Unit operation element-wise on data from input node.
r"""Perform Gaussian Error Linear Unit operation element-wise on data from input node.
Computes GELU function:
\f[ f(x) = 0.5\cdot x\cdot(1 + erf( \dfrac{x}{\sqrt{2}}) \f]
For more information refer to:
`Gaussian Error Linear Unit (GELU) <https://arxiv.org/pdf/1606.08415.pdf>`_
For more information refer to [Gaussian Error Linear Unit (GELU)](https://arxiv.org/pdf/1606.08415.pdf>)
@param node: Input tensor. One of: input node, array or scalar.
@param name: Optional output node name.
@@ -108,7 +107,7 @@ def mvn(
eps: float = 1e-9,
name: str = None,
) -> Node:
r"""! Perform Mean Variance Normalization operation on data from input node.
r"""Perform Mean Variance Normalization operation on data from input node.
Computes MVN on the input tensor `data` (called `X`) using formula:
@@ -131,7 +130,7 @@ def mvn(
@nameable_op
def reorg_yolo(input: Node, stride: List[int], name: Optional[str] = None) -> Node:
"""! Return a node which produces the ReorgYolo operation.
"""Return a node which produces the ReorgYolo operation.
@param input: Input data
@param stride: Stride to reorganize input by
@@ -150,7 +149,7 @@ def roi_pooling(
method: str,
name: Optional[str] = None,
) -> Node:
"""! Return a node which produces an ROIPooling operation.
"""Return a node which produces an ROIPooling operation.
@param input: Input feature map {N, C, ...}
@param coords: Coordinates of bounding boxes
@@ -175,7 +174,7 @@ def space_to_batch(
pads_end: NodeInput,
name: Optional[str] = None,
) -> Node:
"""! Perform SpaceToBatch operation on the input tensor.
"""Perform SpaceToBatch operation on the input tensor.
SpaceToBatch permutes data tensor blocks of spatial data into batch dimension.
The operator returns a copy of the input tensor where values from spatial blocks dimensions

View File

@@ -14,7 +14,7 @@
# limitations under the License.
# ******************************************************************************
"""! Factory functions for all ngraph ops."""
"""Factory functions for all ngraph ops."""
from typing import Callable, Iterable, List, Optional, Set, Union
import numpy as np
@@ -60,7 +60,7 @@ _get_node_factory_opset3 = partial(_get_node_factory, "opset3")
@nameable_op
def assign(new_value: NodeInput, variable_id: str, name: Optional[str] = None) -> Node:
"""! Return a node which produces the Assign operation.
"""Return a node which produces the Assign operation.
@param new_value: Node producing a value to be assigned to a variable.
@param variable_id: Id of a variable to be updated.
@@ -82,7 +82,7 @@ def broadcast(
broadcast_spec: str = "NUMPY",
name: Optional[str] = None,
) -> Node:
"""! Create a node which broadcasts the input node's values along specified axes to a desired shape.
"""Create a node which broadcasts the input node's values along specified axes to a desired shape.
@param data: The node with input tensor data.
@param target_shape: The node with a new shape we want to broadcast tensor to.
@@ -109,7 +109,7 @@ def bucketize(
with_right_bound: bool = True,
name: Optional[str] = None,
) -> Node:
"""! Return a node which produces the Bucketize operation.
"""Return a node which produces the Bucketize operation.
@param data: Input data to bucketize
@param buckets: 1-D of sorted unique boundaries for buckets
@@ -134,7 +134,7 @@ def cum_sum(
reverse: bool = False,
name: Optional[str] = None,
) -> Node:
"""! Construct a cumulative summation operation.
"""Construct a cumulative summation operation.
@param arg: The tensor to be summed.
@param axis: zero dimension tensor specifying axis position along which sum will be performed.
@@ -156,7 +156,7 @@ def embedding_bag_offsets_sum(
per_sample_weights: Optional[NodeInput] = None,
name: Optional[str] = None,
) -> Node:
"""! Return a node which performs sums of bags of embeddings without the intermediate embeddings.
"""Return a node which performs sums of bags of embeddings without the intermediate embeddings.
@param emb_table: Tensor containing the embedding lookup table.
@param indices: Tensor with indices.
@@ -183,7 +183,7 @@ def embedding_bag_packed_sum(
per_sample_weights: Optional[NodeInput] = None,
name: Optional[str] = None,
) -> Node:
"""! Return an EmbeddingBagPackedSum node.
"""Return an EmbeddingBagPackedSum node.
EmbeddingSegmentsSum constructs an output tensor by replacing every index in a given
input tensor with a row (from the weights matrix) at that index
@@ -211,7 +211,7 @@ def embedding_segments_sum(
per_sample_weights: Optional[NodeInput] = None,
name: Optional[str] = None,
) -> Node:
"""! Return an EmbeddingSegmentsSum node.
"""Return an EmbeddingSegmentsSum node.
EmbeddingSegmentsSum constructs an output tensor by replacing every index in a given
input tensor with a row (from the weights matrix) at that index
@@ -248,7 +248,7 @@ def extract_image_patches(
auto_pad: str,
name: Optional[str] = None,
) -> Node:
"""! Return a node which produces the ExtractImagePatches operation.
"""Return a node which produces the ExtractImagePatches operation.
@param image: 4-D Input data to extract image patches.
@param sizes: Patch size in the format of [size_rows, size_cols].
@@ -280,7 +280,7 @@ def gru_cell(
linear_before_reset: bool = False,
name: Optional[str] = None,
) -> Node:
"""! Perform GRUCell operation on the tensor from input node.
"""Perform GRUCell operation on the tensor from input node.
GRUCell represents a single GRU Cell that computes the output
using the formula described in the paper: https://arxiv.org/abs/1406.1078
@@ -342,7 +342,7 @@ def non_max_suppression(
output_type: str = "i64",
name: Optional[str] = None,
) -> Node:
"""! Return a node which performs NonMaxSuppression.
"""Return a node which performs NonMaxSuppression.
@param boxes: Tensor with box coordinates.
@param scores: Tensor with box scores.
@@ -375,7 +375,7 @@ def non_max_suppression(
@nameable_op
def non_zero(data: NodeInput, output_type: str = "i64", name: Optional[str] = None,) -> Node:
"""! Return the indices of the elements that are non-zero.
"""Return the indices of the elements that are non-zero.
@param data: Input data.
@param output_type: Output tensor type.
@@ -391,7 +391,7 @@ def non_zero(data: NodeInput, output_type: str = "i64", name: Optional[str] = No
@nameable_op
def read_value(init_value: NodeInput, variable_id: str, name: Optional[str] = None) -> Node:
"""! Return a node which produces the Assign operation.
"""Return a node which produces the Assign operation.
@param init_value: Node producing a value to be returned instead of an unassigned variable.
@param variable_id: Id of a variable to be read.
@@ -419,7 +419,7 @@ def rnn_cell(
clip: float = 0.0,
name: Optional[str] = None,
) -> Node:
"""! Perform RNNCell operation on tensor from input node.
"""Perform RNNCell operation on tensor from input node.
It follows notation and equations defined as in ONNX standard:
https://github.com/onnx/onnx/blob/master/docs/Operators.md#RNN
@@ -475,7 +475,7 @@ def roi_align(
mode: str,
name: Optional[str] = None,
) -> Node:
"""! Return a node which performs ROIAlign.
"""Return a node which performs ROIAlign.
@param data: Input data.
@param rois: RoIs (Regions of Interest) to pool over.
@@ -509,23 +509,23 @@ def scatter_elements_update(
axis: NodeInput,
name: Optional[str] = None,
) -> Node:
"""! Return a node which produces a ScatterElementsUpdate operation.
"""Return a node which produces a ScatterElementsUpdate operation.
@param data: The input tensor to be updated.
@param indices: The tensor with indexes which will be updated.
@param updates: The tensor with update values.
@param axis: The axis for scatter.
@return ScatterElementsUpdate node
ScatterElementsUpdate creates a copy of the first input tensor with updated elements
specified with second and third input tensors.
For each entry in `updates`, the target index in `data` is obtained by combining
the corresponding entry in `indices` with the index of the entry itself: the
index-value for dimension equal to `axis` is obtained from the value of the
corresponding entry in `indices` and the index-value for dimension not equal
to `axis` is obtained from the index of the entry itself.
@param data: The input tensor to be updated.
@param indices: The tensor with indexes which will be updated.
@param updates: The tensor with update values.
@param axis: The axis for scatter.
@return ScatterElementsUpdate node
"""
return _get_node_factory_opset3().create(
"ScatterElementsUpdate", as_nodes(data, indices, updates, axis)
@@ -536,7 +536,7 @@ def scatter_elements_update(
def scatter_update(
data: Node, indices: NodeInput, updates: NodeInput, axis: NodeInput, name: Optional[str] = None
) -> Node:
"""! Return a node which produces a ScatterUpdate operation.
"""Return a node which produces a ScatterUpdate operation.
ScatterUpdate sets new values to slices from data addressed by indices.
@@ -554,7 +554,7 @@ def scatter_update(
@nameable_op
def shape_of(data: NodeInput, output_type: str = "i64", name: Optional[str] = None) -> Node:
"""! Return a node which produces a tensor containing the shape of its input data.
"""Return a node which produces a tensor containing the shape of its input data.
@param data: The tensor containing the input data.
@param output_type: Output element type.
@@ -569,7 +569,17 @@ def shape_of(data: NodeInput, output_type: str = "i64", name: Optional[str] = No
@nameable_op
def shuffle_channels(data: Node, axis: int, groups: int, name: Optional[str] = None) -> Node:
"""! Perform permutation on data in the channel dimension of the input tensor.
"""Perform permutation on data in the channel dimension of the input tensor.
@param data: The node with input tensor.
@param axis: Channel dimension index in the data tensor.
A negative value means that the index should be calculated
from the back of the input data shape.
@param group: The channel dimension specified by the axis parameter
should be split into this number of groups.
@param name: Optional output node name.
@return The new node performing a permutation on data in the channel dimension
of the input tensor.
The operation is the equivalent with the following transformation of the input tensor
`data` of shape [N, C, H, W]:
@@ -582,7 +592,7 @@ def shuffle_channels(data: Node, axis: int, groups: int, name: Optional[str] = N
For example:
~~~~~~~~~~~~~{.py}
@code{.py}
Inputs: tensor of shape [1, 6, 2, 2]
data = [[[[ 0., 1.], [ 2., 3.]],
@@ -603,17 +613,7 @@ def shuffle_channels(data: Node, axis: int, groups: int, name: Optional[str] = N
[[ 4., 5.], [ 6., 7.]],
[[12., 13.], [14., 15.]],
[[20., 21.], [22., 23.]]]]
~~~~~~~~~~~~~
@param data: The node with input tensor.
@param axis: Channel dimension index in the data tensor.
A negative value means that the index should be calculated
from the back of the input data shape.
@param group: The channel dimension specified by the axis parameter
should be split into this number of groups.
@param name: Optional output node name.
@return The new node performing a permutation on data in the channel dimension
of the input tensor.
@endcode
"""
return _get_node_factory_opset3().create(
"ShuffleChannels", [as_node(data)], {"axis": axis, "groups": groups}
@@ -630,7 +630,7 @@ def topk(
index_element_type: str = "i32",
name: Optional[str] = None,
) -> Node:
"""! Return a node which performs TopK.
"""Return a node which performs TopK.
@param data: Input data.
@param k: K.

View File

@@ -14,7 +14,7 @@
# limitations under the License.
# ******************************************************************************
"""! Factory functions for all ngraph ops."""
"""Factory functions for all ngraph ops."""
from typing import Callable, Iterable, List, Optional, Set, Union
import numpy as np
@@ -70,7 +70,7 @@ def ctc_loss(
unique: bool = False,
name: Optional[str] = None,
) -> Node:
"""! Return a node which performs CTCLoss.
"""Return a node which performs CTCLoss.
@param logits: 3-D tensor of logits.
@param logit_length: 1-D tensor of lengths for each object from a batch.
@@ -108,7 +108,7 @@ def non_max_suppression(
output_type: str = "i64",
name: Optional[str] = None,
) -> Node:
"""! Return a node which performs NonMaxSuppression.
"""Return a node which performs NonMaxSuppression.
@param boxes: Tensor with box coordinates.
@param scores: Tensor with box scores.
@@ -141,7 +141,7 @@ def non_max_suppression(
@nameable_op
def softplus(data: NodeInput, name: Optional[str] = None) -> Node:
"""! Apply SoftPlus operation on each element of input tensor.
"""Apply SoftPlus operation on each element of input tensor.
@param data: The tensor providing input data.
@return The new node with SoftPlus operation applied on each element.
@@ -151,7 +151,7 @@ def softplus(data: NodeInput, name: Optional[str] = None) -> Node:
@nameable_op
def mish(data: NodeInput, name: Optional[str] = None,) -> Node:
"""! Return a node which performs Mish.
"""Return a node which performs Mish.
@param data: Tensor with input data floating point type.
@return The new node which performs Mish
@@ -161,7 +161,7 @@ def mish(data: NodeInput, name: Optional[str] = None,) -> Node:
@nameable_op
def hswish(data: NodeInput, name: Optional[str] = None,) -> Node:
"""! Return a node which performs HSwish (hard version of Swish).
"""Return a node which performs HSwish (hard version of Swish).
@param data: Tensor with input data floating point type.
@return The new node which performs HSwish
@@ -175,7 +175,7 @@ def swish(
beta: Optional[NodeInput] = None,
name: Optional[str] = None,
) -> Node:
"""! Return a node which performing Swish activation function Swish(x, beta=1.0) = x * sigmoid(x * beta)).
"""Return a node which performing Swish activation function Swish(x, beta=1.0) = x * sigmoid(x * beta)).
@param data: Tensor with input data floating point type.
@return The new node which performs Swish
@@ -187,7 +187,7 @@ def swish(
@nameable_op
def acosh(node: NodeInput, name: Optional[str] = None) -> Node:
"""! Apply hyperbolic inverse cosine function on the input node element-wise.
"""Apply hyperbolic inverse cosine function on the input node element-wise.
@param node: One of: input node, array or scalar.
@param name: Optional new name for output node.
@@ -198,7 +198,7 @@ def acosh(node: NodeInput, name: Optional[str] = None) -> Node:
@nameable_op
def asinh(node: NodeInput, name: Optional[str] = None) -> Node:
"""! Apply hyperbolic inverse sinus function on the input node element-wise.
"""Apply hyperbolic inverse sinus function on the input node element-wise.
@param node: One of: input node, array or scalar.
@param name: Optional new name for output node.
@@ -209,7 +209,7 @@ def asinh(node: NodeInput, name: Optional[str] = None) -> Node:
@nameable_op
def atanh(node: NodeInput, name: Optional[str] = None) -> Node:
"""! Apply hyperbolic inverse tangent function on the input node element-wise.
"""Apply hyperbolic inverse tangent function on the input node element-wise.
@param node: One of: input node, array or scalar.
@param name: Optional new name for output node.
@@ -226,7 +226,7 @@ def proposal(
attrs: dict,
name: Optional[str] = None,
) -> Node:
"""! Filter bounding boxes and outputs only those with the highest prediction confidence.
"""Filter bounding boxes and outputs only those with the highest prediction confidence.
@param class_probs: 4D input floating point tensor with class prediction scores.
@param bbox_deltas: 4D input floating point tensor with corrected predictions of bounding boxes
@@ -295,8 +295,9 @@ def proposal(
Object Detection API models
Default value: "" (empty string)
Required: no
Example of attribute dictionary:
~~~~~~~~~~~~~~~~~~~~~~~~{.py}
@code{.py}
# just required ones
attrs = {
'base_size': 85,
@@ -308,7 +309,7 @@ def proposal(
'ratio': [0.1, 1.5, 2.0, 2.5],
'scale': [2, 3, 3, 4],
}
~~~~~~~~~~~~~~~~~~~~~~~~
@endcode
Optional attributes which are absent from dictionary will be set with corresponding default.
@return Node representing Proposal operation.
"""
@@ -340,7 +341,7 @@ def proposal(
def reduce_l1(
node: NodeInput, reduction_axes: NodeInput, keep_dims: bool = False, name: Optional[str] = None
) -> Node:
"""! L1-reduction operation on input tensor, eliminating the specified reduction axes.
"""L1-reduction operation on input tensor, eliminating the specified reduction axes.
@param node: The tensor we want to mean-reduce.
@param reduction_axes: The axes to eliminate through mean operation.
@@ -357,7 +358,7 @@ def reduce_l1(
def reduce_l2(
node: NodeInput, reduction_axes: NodeInput, keep_dims: bool = False, name: Optional[str] = None
) -> Node:
"""! L2-reduction operation on input tensor, eliminating the specified reduction axes.
"""L2-reduction operation on input tensor, eliminating the specified reduction axes.
@param node: The tensor we want to mean-reduce.
@param reduction_axes: The axes to eliminate through mean operation.
@@ -385,7 +386,7 @@ def lstm_cell(
clip: float = 0.0,
name: Optional[str] = None,
) -> Node:
"""! Return a node which performs LSTMCell operation.
"""Return a node which performs LSTMCell operation.
@param X: The input tensor with shape: [batch_size, input_size].
@param initial_hidden_state: The hidden state tensor with shape: [batch_size, hidden_size].

View File

@@ -27,7 +27,7 @@ from ngraph.utils.types import (
def _get_node_factory(opset_version: Optional[str] = None) -> NodeFactory:
"""! Return NodeFactory configured to create operators from specified opset version."""
"""Return NodeFactory configured to create operators from specified opset version."""
if opset_version:
return NodeFactory(opset_version)
else:

View File

@@ -13,4 +13,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
"""! Generic utilities. Factor related functions out to separate files."""
"""Generic utilities. Factor related functions out to separate files."""

View File

@@ -26,7 +26,7 @@ log = logging.getLogger(__name__)
def get_broadcast_axes(
output_shape: TensorShape, input_shape: TensorShape, axis: int = None
) -> AxisSet:
"""! Generate a list of broadcast axes for ngraph++ broadcast.
"""Generate a list of broadcast axes for ngraph++ broadcast.
Informally, a broadcast "adds" axes to the input tensor,
replicating elements from the input tensor as needed to fill the new dimensions.

View File

@@ -27,7 +27,7 @@ def _set_node_friendly_name(node: Node, **kwargs: Any) -> Node:
def nameable_op(node_factory_function: Callable) -> Callable:
"""! Set the name to the ngraph operator returned by the wrapped function."""
"""Set the name to the ngraph operator returned by the wrapped function."""
@wraps(node_factory_function)
def wrapper(*args: Any, **kwargs: Any) -> Node:
@@ -39,7 +39,7 @@ def nameable_op(node_factory_function: Callable) -> Callable:
def unary_op(node_factory_function: Callable) -> Callable:
"""! Convert the first input value to a Constant Node if a numeric value is detected."""
"""Convert the first input value to a Constant Node if a numeric value is detected."""
@wraps(node_factory_function)
def wrapper(input_value: NodeInput, *args: Any, **kwargs: Any) -> Node:
@@ -52,7 +52,7 @@ def unary_op(node_factory_function: Callable) -> Callable:
def binary_op(node_factory_function: Callable) -> Callable:
"""! Convert the first two input values to Constant Nodes if numeric values are detected."""
"""Convert the first two input values to Constant Nodes if numeric values are detected."""
@wraps(node_factory_function)
def wrapper(left: NodeInput, right: NodeInput, *args: Any, **kwargs: Any) -> Node:

View File

@@ -14,7 +14,7 @@
# limitations under the License.
# ******************************************************************************
"""! Helper functions for validating user input."""
"""Helper functions for validating user input."""
import logging
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type
@@ -27,7 +27,7 @@ log = logging.getLogger(__name__)
def assert_list_of_ints(value_list: Iterable[int], message: str) -> None:
"""! Verify that the provided value is an iterable of integers."""
"""Verify that the provided value is an iterable of integers."""
try:
for value in value_list:
if not isinstance(value, int):
@@ -39,7 +39,7 @@ def assert_list_of_ints(value_list: Iterable[int], message: str) -> None:
def _check_value(op_name, attr_key, value, val_type, cond=None):
# type: (str, str, Any, Type, Optional[Callable[[Any], bool]]) -> bool
"""! Check whether provided value satisfies specified criteria.
"""Check whether provided value satisfies specified criteria.
@param op_name: The operator name which attributes are checked.
@param attr_key: The attribute name.
@@ -67,7 +67,7 @@ def _check_value(op_name, attr_key, value, val_type, cond=None):
def check_valid_attribute(op_name, attr_dict, attr_key, val_type, cond=None, required=False):
# type: (str, dict, str, Type, Optional[Callable[[Any], bool]], Optional[bool]) -> bool
"""! Check whether specified attribute satisfies given criteria.
"""Check whether specified attribute satisfies given criteria.
@param op_name: The operator name which attributes are checked.
@param attr_dict: Dictionary containing key-value attributes to check.
@@ -110,7 +110,7 @@ def check_valid_attributes(
requirements, # type: List[Tuple[str, bool, Type, Optional[Callable]]]
):
# type: (...) -> bool
"""! Perform attributes validation according to specified type, value criteria.
"""Perform attributes validation according to specified type, value criteria.
@param op_name: The operator name which attributes are checked.
@param attributes: The dictionary with user provided attributes to check.
@@ -130,7 +130,7 @@ def check_valid_attributes(
def is_positive_value(x): # type: (Any) -> bool
"""! Determine whether the specified x is positive value.
"""Determine whether the specified x is positive value.
@param x: The value to check.
@@ -140,7 +140,7 @@ def is_positive_value(x): # type: (Any) -> bool
def is_non_negative_value(x): # type: (Any) -> bool
"""! Determine whether the specified x is non-negative value.
"""Determine whether the specified x is non-negative value.
@param x: The value to check.

View File

@@ -9,10 +9,10 @@ DEFAULT_OPSET = "opset5"
class NodeFactory(object):
"""! Factory front-end to create node objects."""
"""Factory front-end to create node objects."""
def __init__(self, opset_version: str = DEFAULT_OPSET) -> None:
"""! Create the NodeFactory object.
"""Create the NodeFactory object.
@param opset_version: The opset version the factory will use to produce ops from.
"""
@@ -21,7 +21,7 @@ class NodeFactory(object):
def create(
self, op_type_name: str, arguments: List[Node], attributes: Optional[Dict[str, Any]] = None
) -> Node:
"""! Create node object from provided description.
"""Create node object from provided description.
The user does not have to provide all node's attributes, but only required ones.
@@ -65,7 +65,7 @@ class NodeFactory(object):
@staticmethod
def _normalize_attr_name(attr_name: str, prefix: str) -> str:
"""! Normalize attribute name.
"""Normalize attribute name.
@param attr_name: The attribute name.
@param prefix: The prefix to attach to attribute name.
@@ -79,7 +79,7 @@ class NodeFactory(object):
@classmethod
def _normalize_attr_name_getter(cls, attr_name: str) -> str:
"""! Normalize atr name to be suitable for getter function name.
"""Normalize atr name to be suitable for getter function name.
@param attr_name: The attribute name to normalize
@@ -89,7 +89,7 @@ class NodeFactory(object):
@classmethod
def _normalize_attr_name_setter(cls, attr_name: str) -> str:
"""! Normalize attribute name to be suitable for setter function name.
"""Normalize attribute name to be suitable for setter function name.
@param attr_name: The attribute name to normalize
@@ -99,7 +99,7 @@ class NodeFactory(object):
@staticmethod
def _get_node_attr_value(node: Node, attr_name: str) -> Any:
"""! Get provided node attribute value.
"""Get provided node attribute value.
@param node: The node we retrieve attribute value from.
@param attr_name: The attribute name.
@@ -113,7 +113,7 @@ class NodeFactory(object):
@staticmethod
def _set_node_attr_value(node: Node, attr_name: str, value: Any) -> None:
"""! Set the node attribute value.
"""Set the node attribute value.
@param node: The node we change attribute value for.
@param attr_name: The attribute name.

View File

@@ -20,7 +20,7 @@ from ngraph.impl import Node
def get_reduction_axes(node: Node, reduction_axes: Optional[Iterable[int]]) -> Iterable[int]:
"""! Get reduction axes if it is None and convert it to set if its type is different.
"""Get reduction axes if it is None and convert it to set if its type is different.
If reduction_axes is None we default to reduce all axes.

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
"""! Helper classes for aggregating TensorIterator input/output desciptor attributes."""
"""Helper classes for aggregating TensorIterator input/output desciptor attributes."""
from typing import List
@@ -22,14 +22,14 @@ from ngraph.impl.op import Parameter
class GraphBody(object):
"""! Class containing graph parameters and results."""
"""Class containing graph parameters and results."""
def __init__(self, parameters: List[Parameter], results: List[Node],) -> None:
self.parameters = parameters
self.results = results
def serialize(self) -> dict:
"""! Serialize GraphBody as a dictionary."""
"""Serialize GraphBody as a dictionary."""
return {
"parameters": self.parameters,
"results": self.results,
@@ -37,14 +37,14 @@ class GraphBody(object):
class TensorIteratorInputDesc(object):
"""! Represents a generic input descriptor for TensorIterator operator."""
"""Represents a generic input descriptor for TensorIterator operator."""
def __init__(self, input_idx: int, body_parameter_idx: int,) -> None:
self.input_idx = input_idx
self.body_parameter_idx = body_parameter_idx
def serialize(self) -> dict:
"""! Serialize TensorIteratorInputDesc as a dictionary."""
"""Serialize TensorIteratorInputDesc as a dictionary."""
return {
"input_idx": self.input_idx,
"body_parameter_idx": self.body_parameter_idx,
@@ -52,7 +52,7 @@ class TensorIteratorInputDesc(object):
class TensorIteratorSliceInputDesc(TensorIteratorInputDesc):
"""! Represents a TensorIterator graph body input formed from slices of TensorIterator input."""
"""Represents a TensorIterator graph body input formed from slices of TensorIterator input."""
def __init__(
self,
@@ -72,7 +72,7 @@ class TensorIteratorSliceInputDesc(TensorIteratorInputDesc):
self.axis = axis
def serialize(self) -> dict:
"""! Serialize TensorIteratorSliceInputDesc as a dictionary."""
"""Serialize TensorIteratorSliceInputDesc as a dictionary."""
output = super().serialize()
output["start"] = self.start
output["stride"] = self.stride
@@ -83,7 +83,7 @@ class TensorIteratorSliceInputDesc(TensorIteratorInputDesc):
class TensorIteratorMergedInputDesc(TensorIteratorInputDesc):
"""! Represents a TensorIterator graph body input with initial value in the first iteration.
"""Represents a TensorIterator graph body input with initial value in the first iteration.
Later on, this input value is computed inside graph body.
"""
@@ -93,28 +93,28 @@ class TensorIteratorMergedInputDesc(TensorIteratorInputDesc):
self.body_value_idx = body_value_idx
def serialize(self) -> dict:
"""! Serialize TensorIteratorMergedInputDesc as a dictionary."""
"""Serialize TensorIteratorMergedInputDesc as a dictionary."""
output = super().serialize()
output["body_value_idx"] = self.body_value_idx
return output
class TensorIteratorInvariantInputDesc(TensorIteratorInputDesc):
"""! Represents a TensorIterator graph body input that has invariant value during iteration."""
"""Represents a TensorIterator graph body input that has invariant value during iteration."""
def __init__(self, input_idx: int, body_parameter_idx: int,) -> None:
super().__init__(input_idx, body_parameter_idx)
class TensorIteratorOutputDesc(object):
"""! Represents a generic output descriptor for TensorIterator operator."""
"""Represents a generic output descriptor for TensorIterator operator."""
def __init__(self, body_value_idx: int, output_idx: int,) -> None:
self.body_value_idx = body_value_idx
self.output_idx = output_idx
def serialize(self) -> dict:
"""! Serialize TensorIteratorOutputDesc as a dictionary."""
"""Serialize TensorIteratorOutputDesc as a dictionary."""
return {
"body_value_idx": self.body_value_idx,
"output_idx": self.output_idx,
@@ -122,21 +122,21 @@ class TensorIteratorOutputDesc(object):
class TensorIteratorBodyOutputDesc(TensorIteratorOutputDesc):
"""! Represents an output from a specific iteration."""
"""Represents an output from a specific iteration."""
def __init__(self, body_value_idx: int, output_idx: int, iteration: int,) -> None:
super().__init__(body_value_idx, output_idx)
self.iteration = iteration
def serialize(self) -> dict:
"""! Serialize TensorIteratorBodyOutputDesc as a dictionary."""
"""Serialize TensorIteratorBodyOutputDesc as a dictionary."""
output = super().serialize()
output["iteration"] = self.iteration
return output
class TensorIteratorConcatOutputDesc(TensorIteratorOutputDesc):
"""! Represents an output produced by concatenation of output from each iteration."""
"""Represents an output produced by concatenation of output from each iteration."""
def __init__(
self,
@@ -156,7 +156,7 @@ class TensorIteratorConcatOutputDesc(TensorIteratorOutputDesc):
self.axis = axis
def serialize(self) -> dict:
"""! Serialize TensorIteratorConcatOutputDesc as a dictionary."""
"""Serialize TensorIteratorConcatOutputDesc as a dictionary."""
output = super().serialize()
output["start"] = self.start
output["stride"] = self.stride

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
"""! Functions related to converting between Python and numpy types and ngraph types."""
"""Functions related to converting between Python and numpy types and ngraph types."""
import logging
from typing import List, Union
@@ -66,7 +66,7 @@ ngraph_to_numpy_types_str_map = [
def get_element_type(data_type: NumericType) -> NgraphType:
"""! Return an ngraph element type for a Python type or numpy.dtype."""
"""Return an ngraph element type for a Python type or numpy.dtype."""
if data_type is int:
log.warning("Converting int type of undefined bitwidth to 32-bit ngraph integer.")
return NgraphType.i32
@@ -85,7 +85,7 @@ def get_element_type(data_type: NumericType) -> NgraphType:
def get_element_type_str(data_type: NumericType) -> str:
"""! Return an ngraph element type string representation for a Python type or numpy dtype."""
"""Return an ngraph element type string representation for a Python type or numpy dtype."""
if data_type is int:
log.warning("Converting int type of undefined bitwidth to 32-bit ngraph integer.")
return "i32"
@@ -105,7 +105,7 @@ def get_element_type_str(data_type: NumericType) -> str:
def get_dtype(ngraph_type: NgraphType) -> np.dtype:
"""! Return a numpy.dtype for an ngraph element type."""
"""Return a numpy.dtype for an ngraph element type."""
np_type = next(
(np_type for (ng_type, np_type) in ngraph_to_numpy_types_map if ng_type == ngraph_type),
None,
@@ -118,14 +118,14 @@ def get_dtype(ngraph_type: NgraphType) -> np.dtype:
def get_ndarray(data: NumericData) -> np.ndarray:
"""! Wrap data into a numpy ndarray."""
"""Wrap data into a numpy ndarray."""
if type(data) == np.ndarray:
return data
return np.array(data)
def get_shape(data: NumericData) -> TensorShape:
"""! Return a shape of NumericData."""
"""Return a shape of NumericData."""
if type(data) == np.ndarray:
return data.shape # type: ignore
elif type(data) == list:
@@ -134,7 +134,7 @@ def get_shape(data: NumericData) -> TensorShape:
def make_constant_node(value: NumericData, dtype: NumericType = None) -> Constant:
"""! Return an ngraph Constant node with the specified value."""
"""Return an ngraph Constant node with the specified value."""
ndarray = get_ndarray(value)
if dtype:
element_type = get_element_type(dtype)
@@ -145,12 +145,12 @@ def make_constant_node(value: NumericData, dtype: NumericType = None) -> Constan
def as_node(input_value: NodeInput) -> Node:
"""! Return input values as nodes. Scalars will be converted to Constant nodes."""
"""Return input values as nodes. Scalars will be converted to Constant nodes."""
if issubclass(type(input_value), Node):
return input_value
return make_constant_node(input_value)
def as_nodes(*input_values: NodeInput) -> List[Node]:
"""! Return input values as nodes. Scalars will be converted to Constant nodes."""
"""Return input values as nodes. Scalars will be converted to Constant nodes."""
return [as_node(input_value) for input_value in input_values]