My objective is to use the following class and script, derived from this excellent work: https://github.com/timesler/facenet-pytorch :
from facenet_pytorch import MTCNN, InceptionResnetV1
import torch
from torch.utils.data import DataLoader
from torchvision import datasets
import numpy as np
import pandas as pd
import os
workers = 0 if os.name == 'nt' else 4
def collate_fn(x):
return x[0]
def describe(x):
print("Type: {}".format(x.type()))
print("Shape/size: {}".format(x.shape))
print("Values: \n{}".format(x))
class GetFaceEmbedding(torch.nn.Module):
def __init__(self):
super(GetFaceEmbedding, self).__init__()
@classmethod
def getFaceEmbedding(self, imagePath):
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('Running on device: {}'.format(device))
mtcnn = MTCNN(
image_size=160, margin=0, min_face_size=20,
thresholds=[0.6, 0.7, 0.7], factor=0.709, post_process=True,
device=device
)
resnet = InceptionResnetV1(pretrained='vggface2').eval().to(device)
dataset = datasets.ImageFolder(imagePath)
dataset.idx_to_class = {i:c for c, i in dataset.class_to_idx.items()}
loader = DataLoader(dataset, collate_fn=collate_fn, num_workers=workers)
aligned = []
names = []
for x, y in loader:
x_aligned, prob = mtcnn(x, return_prob=True)
if x_aligned is not None:
print('Face detected with probability: {:8f}'.format(prob))
aligned.append(x_aligned)
names.append(dataset.idx_to_class[y])
aligned = torch.stack(aligned).to(device)
embeddings = resnet(aligned).detach().cpu()
return embeddings
With python it works fine:
(venv373) (base) marco@pc01:~/PyTorchMatters/facenet_pytorch/examples$ python3 .
/getFaceEmbedding-01.py
Running on device: cpu
Face detected with probability: 0.999430
Type: torch.FloatTensor
Shape/size: torch.Size([1, 512])
Values:
tensor([[ 3.6307e-02, -8.8092e-02, -3.5002e-02, -8.2932e-02, 1.9032e-02,
2.3228e-02, 2.4253e-02, -3.7844e-02, -6.8906e-02, 2.0351e-02,
-6.7093e-02, 3.6181e-02, -2.5933e-02, -6.0015e-02, 2.6653e-02,
9.4335e-02, -2.9241e-02, -2.8357e-02, 7.2207e-02, -3.7747e-02,
6.3515e-03, -3.0220e-02, -2.4530e-02, 1.0004e-01, 6.6520e-02,
....
3.2497e-02, 2.3421e-02, -5.3921e-02, 1.9589e-02, -2.8655e-03,
1.3474e-02, -2.2743e-02, 3.2976e-02, -5.6658e-02, 2.0837e-02,
-4.7152e-02, -6.5534e-02]])
Following the indications found here: https://pytorch.org/tutorials/advanced/cpp_export.html
I added to getFaceEmbedding.py these lines:
my_module = GetFaceEmbedding()
sm = torch.jit.script(my_module)
sm.save("annotated_get_face_embedding.pt")
I then saved the serialized file:
(venv373) (base) marco@pc01:~/PyTorchMatters/facenet_pytorch/examples$ python3
./getFaceEmbedding.py
-rw-r--r-- 1 marco marco 1,4K mar 19 18:52 annotated_get_face_embedding.pt
And created this cpp file:
(venv373) (base) marco@pc01:~/PyTorchMatters/facenet_pytorch/examples$ nano
faceEmbedding.cpp :
#include <torch/script.h>
#include <iostream>
#include <memory>
#include <filesystem>
int main(int argc, const char* argv[]) {
//if(argc != 3) {
// std::cerr << "usage:usage: faceEmbedding <path-to-exported-script-module> <path-to-image-f
ile> \n";
// return -1;
//}
torch::jit::script::Module module;
try {
// Deserialize the ScriptModule from a file using torch::jit::load().
module = torch::jit::load(argv[1]);
std::filesystem::path imgPath = argv[2];
// Execute the model and turn its output into a tensor
at::Tensor output = module.getFaceEmbedding(imgPath).ToTensor();
}
catch (const c10::Error& e) {
std::cerr << "error loading the model\n";
return -1;
}
std::cout << "ok\n";
} // end of main() function
But during the compilation phase I get this error :
"struct torch::jit::script::Module’ has no member named ‘getFaceEmbedding’ "
(venv373) (base) marco@pc01:~/PyTorchMatters/facenet_pytorch/examples$ mkdir build
(venv373) (base) marco@pc01:~/PyTorchMatters/facenet_pytorch/examples$ cd build
(venv373) (base) marco@pc01:~/PyTorchMatters/facenet_pytorch/examples/build$ cmake
-DCMAKE_PREFIX_PATH=/home/marco/PyTorchMatters/libtorch ..
-- The C compiler identification is GNU 9.2.1
-- The CXX compiler identification is GNU 9.2.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Found torch: /home/marco/PyTorchMatters/libtorch/lib/libtorch.so
-- Configuring done
-- Generating done
-- Build files have been written to: /home/marco/PyTorchMatters/facenet_pytorch/examples/build
(venv373) (base) marco@pc01:~/PyTorchMatters/facenet_pytorch/examples/build$ cmake --build .
--config Release
Scanning dependencies of target faceEmbedding
[ 50%] Building CXX object CMakeFiles/faceEmbedding.dir/faceEmbedding.cpp.o
/home/marco/PyTorchMatters/facenet_pytorch/examples/faceEmbedding.cpp: In function ‘int
main(int, const char**)’:
/home/marco/PyTorchMatters/facenet_pytorch/examples/faceEmbedding.cpp:20:34: error: ‘struct
torch::jit::script::Module’ has no member named ‘getFaceEmbedding’
20 | at::Tensor output = module.getFaceEmbedding(imgPath).ToTensor();
| ^~~~~~~~~~~~~~~~
CMakeFiles/faceEmbedding.dir/build.make:62: recipe for target 'CMakeFiles/faceEmbedding.dir
/faceEmbedding.cpp.o' failed
make[2]: *** [CMakeFiles/faceEmbedding.dir/faceEmbedding.cpp.o] Error 1
CMakeFiles/Makefile2:75: recipe for target 'CMakeFiles/faceEmbedding.dir/all' failed
make[1]: *** [CMakeFiles/faceEmbedding.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
How to solve the problem?
Looking forward to your kind help.
Marco