Skip to content

Best practices#

This section provides a set of recommendations and performance tips that you should follow to get optimal performance when running the LUNA SDK algorithms on your target device.

Creation and deletion order#

All LUNA SDK objects should be destroyed in the order reversal to their creation order. This implies the following:

  1. The FaceEngine object should be created by using the createFaceEngine method.

  2. All child objects, such as detectors, estimators and so on, can be created.

  3. At the end of the work all these child objects should be deleted in the first place.

  4. The main FaceEngine object can be deleted.

We do not recommend that you use FaceEngine objects as globals or static objects, because in this case their deletion order could be undefined. In the case when such a usage is necessary, the correct deletion order should be guaranteed via an explicit deletion of all objects in the correct order before the end of the program. For example:

fsdk::IFaceEnginePtr faceEngine = fsdk::createFaceEngine("./data");
fsdk::IDetectorPtr detector = faceEngine->createDetector();
fsdk::IBestShotQualityEstimator bestShotQualityEstimator = faceEngine->createBestShotQualityEstimator();

int main() {
    // application code here

    detector.reset();
    bestShotQualityEstimator.reset();
    faceEngine.reset();
    return 0;
}

Multithread scenario#

Creating and destroying LUNA SDK algorithms from different threads is prohibited due to internal implementation restrictions. All objects of the FaceEngine class and all objects of algorithms (for example, detectors, estimators, extractors and others) must be created and destroyed by the same thread.

A typical scenario is as follows: Thread 1 (may be the main thread) creates the FaceEngine object and all needed algorithms (for example, IDetector). Threads 2..N (maybe several) uses that objects for any purpose. Thread 1 destroys the FaceEngine object and all algorithms after all work is complete.

Thread pools#

We recommend that you use thread pools for user-created threads when running LUNA SDK algorithms in a multithreaded environment. For each thread, LUNA SDK caches some amount of thread local objects under the hood in order to make its algorithms run faster next time the same thread is used at the cost of higher memory footprint. For this reason, we recommend that you reuse threads from a pool to avoid caching new internal objects and to reduce penalty of creating or destroying new user threads.

Estimator creation and inference#

Create face engine objects once and reuse them when you need to make a new estimate to reduce RAM usage and increase performance. The reason is that recreating of estimators leads to reopen the corresponding plan file every time. These plan files are cached separately for every load and will be removed only when they are flushed from the cache or after calling the destructor of FaceEngine root object.

Forking process#

UNIX-like operating systems implement a mechanism to duplicate a process. It creates a new child process and copies its parents' memory space into the child’s one. This is typically done programmatically by calling the fork() system function in the parent process.

Care should be taken when forking a process running the SDK.

Important: Always fork before the first instance of IFaceEngine is created!
This is because the SDK internally maintains a pool of worker threads, which is created lazily at the time the very first IFaceEngine object is born and destroyed right after the last IFaceEngine object is released. When using GPU or NPU devices, their runtime is initialized and shut down in the same manner.

The hazard comes from the fact that while fork() copies process memory, it only creates just one thread - the main thread. For details, see https://man7.org/linux/man-pages/man2/fork.2.html.

As a result, if at least one IFaceEngine object is alive at the time the process is being forked, the child processes will inherit the knowledge of the object, and therefore, the implicit thread pool (and device runtime, when appropriate). But there will be no worker threads actually running (in both, the inherited pool and the runtime, when appropriate) and attempting to call certain SDK functions will cause a deadlock.

Liveness estimator combination#

Depending on your device and its camera, you can simultaneously use a combination of two universal liveness estimators to increase the accuracy of a model. For example, you can use LivenessDepthRGBEstimator and NIRLivenessEstimator or LivenessDepthEstimator and LivenessOneShotRGBEstimator or their models together. To do this, you need to aggregate the rates of each liveness and change the thresholds in the faceengine.cong configuration file.

Changing the threshold#

All models are calibrated so that the base threshold is 0.5 for any model of any modality.

If you need greater protection against hacking, then the threshold can be raised, and if the convenience of real users is more important, then lowered. We recommend that you configure specific values for changing the threshold in deviation from the basic one on a client basis.

Aggregating the scores#

Any of two liveness modalities can be aggregated with each other. To do this, you need to multiply the speeds of the corresponding networks. The threshold in this case is also multiplied and becomes equal to 0.25.

The recommended threshold is an optimal balance between TPR and FPR.

Possible LivenessOneShotRGBEstimator model combinations#

You can use the LivenessOneShotRGBEstimator models in the following combinations:

  • Use these models in the backend as an analogue of server LivenessOneShotRGBEstimator.
    • oneshot_rgb_liveness_v7_model_1_cpu-avx2.plan
    • oneshot_rgb_liveness_v7_model_2_cpu-avx2.plan
    • oneshot_rgb_liveness_v7_model_3_cpu-avx2.plan
    • oneshot_rgb_liveness_v7_model_4_cpu-avx2.plan
  • Use these models on smartphones as an analogue of LivenessOneShotRGBEstimator.
    • oneshot_rgb_liveness_v7_model_3_cpu-avx2.plan
    • oneshot_rgb_liveness_v7_model_4_cpu-avx2.plan
  • Use the below model on devices with Orbbec cameras, such as payment terminals (POS) and self-service cash registers (KCO):
    • oneshot_rgb_liveness_v7_model_4_cpu-avx2.plan