takuya-takeuchi / FaceRecognitionDotNet

The world's simplest facial recognition api for .NET on Windows, MacOS and Linux
MIT License
1.27k stars 309 forks source link

Running .FaceEncodings(image) possible in parallel? #34

Closed Seth-Julien-de-Lampon closed 5 years ago

Seth-Julien-de-Lampon commented 5 years ago

I'm trying to run the code in parallel on multiple CPU cores, just like the example (https://github.com/takuya-takeuchi/FaceRecognitionDotNet/tree/master/examples/FaceDetection). But the distances that I print out with the following code (see down below) are not between 0 and 2 and actually do not make any sense.

Do I miss a thing or is the Encoding calculation just not possible to run in Paralell?

I am using the cpu nuget package in a .Net Core console app.

class Program
{
    public static FaceRecognition faceRecognition { get; set; }
    public static List<FaceEncoding> Results { get; set; }

    static void Main(string[] args)
    {
        faceRecognition = FaceRecognition.Create("models");

        DirectoryInfo d = new DirectoryInfo(Path.GetFullPath("images/test"));
        List<FileInfo> files = d.GetFiles().ToList();
        var testEncoding = calcEncoding(files[0]);

        Results = new List<FaceEncoding>();
        Object Lock = new Object();

        var option = new ParallelOptions
        {
            MaxDegreeOfParallelism = Environment.ProcessorCount
        };

        DateTime time = DateTime.Now;
        Parallel.For(1, files.Count, option, i=>
        {
            calcEncodings(files[i], Lock);
        });
        double totalTime = (DateTime.Now - time).TotalSeconds;
        Console.WriteLine($"Time: {totalTime}, images/s: {files.Count/totalTime}");

        Results.ForEach(r =>
        {
            Console.WriteLine(FaceRecognition.FaceDistance(r, testEncoding));
        });

        Console.ReadLine();
    }

    private static void calcEncodings(FileInfo file, Object Lock)
    {
        using(var image = FaceRecognition.LoadImageFile(file.FullName))
        {
            var faceEncodings = faceRecognition.FaceEncodings(image);

            foreach(var faceEncoding in faceEncodings)
            {
                Console.WriteLine($"{file.Name}: {faceEncoding.Size}");
                lock (Lock)
                {
                    Results.Add(faceEncoding); 
                }
            }
        }
    }

    private static FaceEncoding calcEncoding(FileInfo file)
    {
        using (var image = FaceRecognition.LoadImageFile(file.FullName))
        {
            return faceRecognition.FaceEncodings(image).First() ;               
        }
    }
}

Result:

77330,4555392426 116594805,513795 3905512926785,24 99675592693821,5 9,99817851362896E+15 8,02151826515965E+17 8,16535264000558E+18 7,76799579452464E+18 NaN NaN NaN NaN NaN NaN NaN NaN 2442073,74932843 7821815,3598267 106,853336907902 106,854189097259

Seth-Julien-de-Lampon commented 5 years ago

Calculating the locations like the example does work fine btw.

takuya-takeuchi commented 5 years ago

Could you create new FaceRecognition per thread? FaceEncoding and FaceLocation use Dnn. It is not thread safe.

Seth-Julien-de-Lampon commented 5 years ago

That works perfectly! Thanks for the tip!