Node.js + face-recognition.js:深層学習によるシンプルで信頼性の高い顔認識





Node.js + face-recognition.jsの翻訳:ディープラーニングを使用したシンプルで堅牢な顔認識



この記事では、 face-recognition.jsを使用して信頼できる顔認識システムを実装する方法を説明します。 顔を正確に認識できるが、何も見つからない適切なNode.jsライブラリを探していました。 私は自分で書かなければなりませんでした!



このnpmパッケージdlibライブラリを使用します。dlibライブラリは、このライブラリ内で非常によく認識されている認識ツールにNode.jsバインダーを提供します。 Dlibはディープラーニングメソッドを使用し、LFWベンチマークの実行 99.38%の 認識精度を示す事前トレーニングモデルが付属しています



なんで?



最近、私たちはNode.jsに基づいて、The Big Bang Theoryシリーズのキャラクターの顔を区別して認識する顔認識アプリケーションを作成しようとしています。 Node.js + OpenCV for Face Recognitionで説明されているように、最初はOpenCV認識ツールを使用してアプリケーションを作成することが計画されていました。



しかし、高速にもかかわらず、これらのツールの品質は不十分であることが判明しました。 より正確には、彼らはフルフェイスの顔にうまく対処しましたが、人がカメラに少し背を向けるとすぐに、認識の質が低下しました。



解決策を探して、C ++が手に入りました-dlibライブラリ。 Python APIをいじり、その結果に感銘を受け、最終的に決定しました。 このライブラリをNode.jsとともに使用します 。 そのため、このnpmパッケージが登場し、顔認識用の単純化されたNode.js APIが提供されました。



そして、face-recognition.jsとは何ですか?



face-recogntion.jsに基づいてパッケージを作成したかった。





パッケージはまだ完成していませんが、既にいくつかのツールをダウンロードできます。



顔検出



画像内の顔の迅速で信頼性の低い決定には、ディープラーニングニューラルネットワークまたは単純なフロントエンドレコグナイザーを使用できます。







顔認識



認識エンジンは、上記のモデルを使用して一意の顔記述子を計算する深層学習ニューラルネットワークです。 認識エンジンは、タグ付けされた顔画像の配列でトレーニングできます。その後、入力画像に顔をマークできます。







顔のランドマーク



このパッケージを使用すると、面上の5〜68個の参照ポイントを決定することもできます。







素晴らしいストーリー、今それがどのように機能するかを示します!



そのため、OpenCVを使用して問題を解決することはできませんでした。 シェルドン、ラジェッシュ、レナード、ハワード、スチュアートの顔のパックがまだあり、それぞれのサイズは150 x 150ピクセルです。 このデータを使用すると、新しい顔を認識するようにFace Recognizerに簡単に教えることができます。 この例のコードはリポジトリにあります。



データ準備



さまざまな角度から各キャラクターの約20の顔を収集しました。







トレーニング用に10個の顔を取り、残りを使用して認識精度を評価します。



 const path = require('path') const fs = require('fs') const fr = require('face-recognition') const dataPath = path.resolve('./data/faces') const classNames = ['sheldon', 'lennard', 'raj', 'howard', 'stuart'] const allFiles = fs.readdirSync(dataPath) const imagesByClass = classNames.map(c => allFiles .filter(f => f.includes(c)) .map(f => path.join(dataPath, f)) .map(fp => fr.loadImage(fp)) ) const numTrainingFaces = 10 const trainDataByClass = imagesByClass.map(imgs => imgs.slice(0, numTrainingFaces)) const testDataByClass = imagesByClass.map(imgs => imgs.slice(numTrainingFaces))
      
      





各ファイル名には文字名が含まれているため、クラス名を簡単に一致させることができます。



['sheldon', 'lennard', 'raj', 'howard', 'stuart']







各クラスの画像の配列。 fr.loadImage(fp)



すると、ファイルパスで指定されたイメージを読み取ることができます。



人の識別



サイズが150 x 150ピクセルの顔画像は、opencv4nodejsを使用して事前にカットされています。 ただし、次の方法で顔を識別し、切り取り、保存し、ラベルを付けることができます。



 const image = fr.loadImage('image.png') const detector = fr.FaceDetector() const targetSize = 150 const faceImages = detector.detectFaces(image, targetSize) faceImages.forEach((img, i) => fr.saveImage(img, `face_${i}.png`))
      
      





レコグナイザートレーニング



これで学習を開始できます。



 const recognizer = fr.FaceRecognizer() trainDataByClass.forEach((faces, label) => { const name = classNames[label] recognizer.addFaces(faces, name) })
      
      





このコードはニューラルネットワークのフェイスにフィードし、各フェイスの記述子を生成して適切なクラスに保存します。 3番目の引数としてnumJitters



numJitters



ことにより、 rotationscaling、 mirroringを適用して、各入力面の異なるバージョンを作成できます。 変更の数を増やすと認識精度が向上しますが、ニューラルネットワークはより長く学習します。



また、レコグナイザーの状態を保存して、毎回再認識しないようにするだけでなく、ファイルから単にロードすることもできます。



保存中:



 const modelState = recognizer.serialize() fs.writeFileSync('model.json', JSON.stringify(modelState))
      
      





ダウンロード:



 const modelState = require('model.json') recognizer.load(modelState)
      
      





顔認識



次に、制御データを使用して、認識精度を確認し、結果をログに保存します。



 const errors = classNames.map(_ => []) testDataByClass.forEach((faces, label) => { const name = classNames[label] console.log() console.log('testing %s', name) faces.forEach((face, i) => { const prediction = recognizer.predictBest(face) console.log('%s (%s)', prediction.className, prediction.distance) // count number of wrong classifications if (prediction.className !== name) { errors[label] = errors[label] + 1 } }) }) // print the result const result = classNames.map((className, label) => { const numTestFaces = testDataByClass[label].length const numCorrect = numTestFaces - errors[label].length const accuracy = parseInt((numCorrect / numTestFaces) * 10000) / 100 return `${className} ( ${accuracy}% ) : ${numCorrect} of ${numTestFaces} faces have been recognized correctly` }) console.log('result:') console.log(result)
      
      





現在、認識は次のように実行されます。最初に、各クラス記述子への記述子ベクトルのユークリッド距離が入力面で計算され、次にすべての距離の平均値が計算されます。 k-meansクラスタリングまたはSVM分類器がこのタスクに最適であると主張するかもしれません。 おそらく将来的にはそれらも実現されるでしょうが、ユークリッド距離の速度と効率はまだ十分です。



predictBest



を呼び出すと、ユークリッド距離が最小、つまり類似度が最大の結果が得られます。 このようなもの:



{ className: 'sheldon', distance: 0.5 }







特定の人のすべてのクラスの記述子の距離を取得する必要がある場合は、クラスごとに距離の配列を生成するacknowledger.predict recognizer.predict(image)



使用できます。



 [ { className: 'sheldon', distance: 0.5 }, { className: 'raj', distance: 0.8 }, { className: 'howard', distance: 0.7 }, { className: 'lennard', distance: 0.69 }, { className: 'stuart', distance: 0.75 } ]
      
      





結果



上記のコードを実行すると、そのような結果が得られます。



各キャラクターの10面でトレーニングする:



 sheldon ( 90.9% ) : 10 of 11 faces have been recognized correctly lennard ( 100% ) : 12 of 12 faces have been recognized correctly raj ( 100% ) : 12 of 12 faces have been recognized correctly howard ( 100% ) : 12 of 12 faces have been recognized correctly stuart ( 100% ) : 3 of 3 faces have been recognized correctly
      
      





各キャラクターの5つの顔でのみトレーニングします。



 sheldon ( 100% ) : 16 of 16 faces have been recognized correctly lennard ( 88.23% ) : 15 of 17 faces have been recognized correctly raj ( 100% ) : 17 of 17 faces have been recognized correctly howard ( 100% ) : 17 of 17 faces have been recognized correctly stuart ( 87.5% ) : 7 of 8 faces have been recognized correctly
      
      





そして、これがビデオでどのように見えるかです:







おわりに



結果から判断すると、トレーニングデータの小さなサンプルでもかなり正確な認識が可能です。 これは、サイズが小さいために入力画像の一部が非常にぼやけているという事実にもかかわらずです。



All Articles