vladmandic / face-api

FaceAPI: AI-powered Face Detection & Rotation Tracking, Face Description & Recognition, Age & Gender & Emotion Prediction for Browser and NodeJS using TensorFlow/JS
https://vladmandic.github.io/face-api/demo/webcam.html
MIT License
850 stars 151 forks source link

@vladmandic/face-api usage #3

Closed hamza878 closed 4 years ago

hamza878 commented 4 years ago

I have been having some issues lately with face-api.js and not been able to deploy it on the server so tried your version of it and I'm not sure if I'm using it right or not. I'm getting a bunch of errors, can you please review the code and errors?

pasting the code here.

const express = require("express"); const faceapi = require("@vladmandic/face-api"); const fetch = require("node-fetch"); const path = require("path"); const canvas = require("canvas"); const tnsr = require("@tensorflow/tfjs-node");

const faceDetectionNet = faceapi.nets.ssdMobilenetv1;

const minConfidence = 0.5; const trainingDataLength = 1; const inputSize = 384;

const scoreThreshold = 0.5;

function getFaceDetectorOptions(net = faceapi.NeuralNetwork()) { return net === faceapi.nets.ssdMobilenetv1 ? new faceapi.SsdMobilenetv1Options({ minConfidence, }) : new faceapi.TinyFaceDetectorOptions({ inputSize, scoreThreshold, }); } const faceDetectionOptions = getFaceDetectorOptions(faceDetectionNet);

const { Canvas, Image, ImageData } = canvas; faceapi.env.monkeyPatch({ Canvas, Image, ImageData, }); faceapi.env.monkeyPatch({ fetch: fetch, });

loadModels = async () => { const WeightsDir1 = path.resolve(dirname, "src/weights"); const WeightsDir2 = path.resolve(dirname, "src/weights"); const WeightsDir3 = path.resolve(__dirname, "src/weights"); await faceDetectionNet.loadFromDisk(WeightsDir1); await faceapi.nets.faceLandmark68Net.loadFromDisk(WeightsDir2); await faceapi.nets.faceRecognitionNet.loadFromDisk(WeightsDir3); };

const app = express(); verifyFace = async () => { await loadModels(); const dir1 = path.resolve(dirname, "a.jpg"); const dir2 = path.resolve(dirname, "b.jpg"); const application_id = "123"; const QUERY_IMAGE = dir1; const queryImage = await canvas.loadImage(QUERY_IMAGE);

const resultsQuery = await faceapi
    .detectSingleFace(queryImage, faceDetectionOptions)
    .withFaceLandmarks()
    .withFaceDescriptor();
const labeledFaceDescriptors = await loadLabeledImages();
const faceMatcher = new faceapi.FaceMatcher(labeledFaceDescriptors);
if (resultsQuery) {
    const bestMatch = faceMatcher.findBestMatch(resultsQuery.descriptor);
    var match_percentage = 100 - Math.ceil(bestMatch._distance * 100);
    db.query(
        "update required_documents set _8applicant_image_verification_status = ? where application_id  = ?",
        [match_percentage, application_id],
        (err, result, field) => {
            if (err) throw err;
            if (result.affectedRows > 0) {
                console.log("match percentage added", match_percentage);
            } else {
                console.log("match percentage not added");
            }
        }
    );
}
const labels = faceMatcher.labeledDescriptors.map((ld) => ld.label);

function loadLabeledImages() {
    const labels = [application_id];
    return Promise.all(
        labels.map(async (label) => {
            const descriptions = [];
            //              let url = `../public/images/${application_id}/training_data`;

            //       const TrainingData = path.resolve(__dirname, dir2);
            for (let i = 1; i <= trainingDataLength; i++) {
                //   const REFERENCE_IMAGE = TrainingData + `/abc (${i}).jpg`;
                const referenceImage = await canvas.loadImage(dir2);
                const detections = await faceapi
                    .detectSingleFace(referenceImage, faceDetectionOptions)
                    .withFaceLandmarks()
                    .withFaceDescriptor();
                descriptions.push(detections.descriptor);
            }

            return new faceapi.LabeledFaceDescriptors(label, descriptions);
        })
    );
}

};

and the errors I'm getting are below:

user2@Hamza MINGW64 ~/Documents/letsTryAgain $ node app.js node-pre-gyp info This Node instance does not support builds for N-API version 6 node-pre-gyp info This Node instance does not support builds for N-API version 6 2020-09-08 14:39:17.082639: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 (node:13856) UnhandledPromiseRejectionWarning: TypeError: t.toFloat is not a function at C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:21279:59 at Array.map () at C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:21279:46 at C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:2604:16 at Engine.scopedRun (C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:2614:19) at Engine.tidy (C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:2603:17) at tidy (C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:4327:17) at NetInput.toBatchTensor (C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:21263:12) at C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:23288:33 at C:\Users\user2\Documents\letsTryAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:2604:16 (node:13856) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:13856) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

please review the code and errors and suggest me a solution of if possible, modify it for me please? i am trying to recognize faces on server-side. Thanks in advace

vladmandic commented 4 years ago

Just add
const tf = require('@tensorflow/tfjs-core'); or const tf = require('@tensorflow/tfjs);
at the top of your require list.

I've mentioned in README that this fork of FaceAPI does not package full TFJS, it inherits a loaded one (to make it lighter and to allow re-usability of TFJS itself for any other purpose).

I've tried your example and it works (just added console statement before DB query)

# node ./test.js
2020-09-08 08:29:18.421387: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-09-08 08:29:18.466476: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2299965000 Hz
2020-09-08 08:29:18.466931: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5eca480 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-09-08 08:29:18.466969: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
{
  detection: FaceDetection {
    _imageDims: Dimensions { _width: 1766, _height: 2000 },
    _score: 0.9878889918327332,
    _classScore: 0.9878889918327332,
    _className: '',
    _box: Box {
      _x: 904.3608204664382,
      _y: 148.6218273639679,
      _width: 174.38878226491192,
      _height: 232.84924030303955
    }
  },
...
hamza878 commented 4 years ago

My package.json file

"dependencies": { "@tensorflow/tfjs": "^2.3.0", "@tensorflow/tfjs-node": "^2.3.0", "@vladmandic/face-api": "^0.4.5", "canvas": "^2.6.1", "express": "^4.17.1", "face-api.js": "^0.22.2", "multer": "^1.4.2", "node-fetch": "^2.6.0", "vary": "^1.1.2" },

My Code is same as above and when i put const tf = require('@tensorflow/tfjs-node'); or const tf = require('@tensorflow/tfjs'); i get this error `var nonMaxSuppressionV3Impl = tf.kernel_impls.nonMaxSuppressionV3Impl; ^

TypeError: Cannot read property 'nonMaxSuppressionV3Impl' of undefined at Object. (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-backend-cpu\dist\tf-backend-cpu.node.js:268:47)`

When i put const tf = require('@tensorflow/tfjs-core');

(node:6640) UnhandledPromiseRejectionWarning: TypeError: backend2.batchNorm is not a function at C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:528:55 at C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:388:22 at Engine.scopedRun (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:398:23) at Engine.tidy (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:387:21) at kernelFunc (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:528:29) at C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:539:27 at Engine.scopedRun (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:398:23) at Engine.runKernelFunc (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-core\dist\engine.js:537:14) at batchNorm_ (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@vladmandic\face-api\dist\face-api.cjs:5107:22)

i tried downgrading tensorflow to 1.7.4 but it didnt help either

hamza878 commented 4 years ago

and with 1.7.4 i get the same error (node:13856) UnhandledPromiseRejectionWarning: TypeError: t.toFloat is not a function at C:\Users\user2\Documents\letsTryAgain\node_modules@vladmandic\face-api\dist\face-api.cjs:21279:59 at Array.map () at C:\Users\user2\Documents\letsTryAgain\node_modules@vladmandic\face-api\dist\face-api.cjs:21279:46 at C:\Users\user2\Documents\letsTryAgain\node_modules@vladmandic\face-api\dist\face-api.cjs:2604:16

vladmandic commented 4 years ago

I've created a simplified gist from your project (since I don't have access to your full project) - does this work? https://gist.github.com/vladmandic/b73e32cbe25077f4a0bfc867ab27810f

Btw, I've just published an updated version that checks for tfjs loaded state and will throw an appropriate error on call to new:

Error: module not loaded: load '@tensorflow/tfjs' or '@tensorflow/tfjs-core' with appropriate backend explicitly: Error: No backend found in registry.

And includes new object faceapi.version that returns a version and tf env detected flags.

hamza878 commented 4 years ago

still same error, simply using gist you made and im not sure whats the issue here `var nonMaxSuppressionV3Impl = tf.kernel_impls.nonMaxSuppressionV3Impl; ^

TypeError: Cannot read property 'nonMaxSuppressionV3Impl' of undefined at Object. (C:\Users\hamza\Documents\letstryfaceAgain\node_modules\@tensorflow\tfjs-backend-cpu\dist\tf-backend-cpu.node.js:268:47)`

Thanks a lot btw for being so patient with me.

vladmandic commented 4 years ago

this points to tfjs backend not present - and that is provided by tfjs-node package. silly question, did you use package.json from my gist in a clean folder and install dependencies with npm install? i've added another test in the gist under test2.js, can you run it and attach full output (not just error stack)?

hamza878 commented 4 years ago

i was uninstalling and reinstalling dependencies in the same project folder which seemed to be causing this error, if im not wrong you mentioned in some comment that node_modules is silly and could have different versions in same dependency and while debugging it actually was the case for me, deleted node_modules and made a fresh project for this and it works now. Thanks a lot!

vladmandic commented 4 years ago

glad the problem is solved! :)

As a complete sidenote, have you tried WSL instead of mingw? For Linux-first things like anything NodeJS, it's a much better experience (in my opinion). If nothing else, it avoids weird DLL loading (tensorflow.dll is provided by tfjs-node on Windows - that is where something went wrong with your test) and uses standard libraries.

hamza878 commented 4 years ago

No, I actually have not but would love to migrate as soon as possible. and yeah one more thing, we also have a verification related to on-screen handwritten signature matching where we would store signatures as images at the signup phase and match them with previously stored signature image and give them access if it matches. I'm currently using OpenCV's feature matching through python with my node.js app, if possible, can you suggest me something in node.js that could help me get the task done?

vladmandic commented 4 years ago

Interesting one, haven't played with ML for biometrics so far!

Seems there was an annual competition (see http://www.iapr-tc11.org/mediawiki/index.php?title=Datasets_List), so a good starting point is to search GitHub for projects using those training datasets: SigComp2009, 4NSigComp2010, SigComp2011, 4NSigComp2012. And there is Kaggle dataset as well, https://www.kaggle.com/divyanshrai/handwritten-signatures, so check out notebooks that use it.

The training set is relatively simple, so no need for pre-trained model, you should be able to implement model architecture in TFJS and train it relatively quickly.

hamza878 commented 4 years ago

I will look into it! you've so helpful to me so far! Thanks a lot!

vladmandic commented 4 years ago

you're welcome

i'm closing this issue now since it's resolved, but feel free to contact me with any questions.