人脸识别Adaface之libpytorch部署

news2025/1/17 4:03:35

目录

  • 1. libpytorch下载
  • 2. Adaface模型下载
  • 3. 模型转换
  • 4. c++推理
    • 4.1 前处理
    • 4.2 推理
    • 4.3 编译运行
      • 4.3.1 写CMakeLists.txt
      • 4.3.2 编译
      • 4.3.3 运行

1. libpytorch下载

参考:
https://blog.csdn.net/liang_baikai/article/details/127849577
下载完成后,将其解压到/usr/local下

2. Adaface模型下载

https://github.com/mk-minchul/AdaFace?tab=readme-ov-file
在这里插入图片描述
WebFace4M模型准确率最高,R50 WebFace4M和R100 WebFace12M的准确率十分接近,但耗时却低了不少,所以建议使用R50 WebFace4M

3. 模型转换

下载Adaface源码,并将下面代码放到其目录下执行即可

model_trans.py

import torch
import torch.nn as nn
from head import AdaFace 
import net
import onnxruntime as ort
import numpy as np
import onnx


# 加载模型
adaface_models = {
#    'ir_101':"./adaface_ir101_ms1mv2.ckpt",
    'ir_50':"./adaface_ir50_webface4m.ckpt",
}
architecture = 'ir_50'

model = net.build_model(architecture)
#model = AdaFace()
statedict = torch.load(adaface_models[architecture],map_location=torch.device('cpu'),weights_only=True)['state_dict']
model_statedict = {key[6:]:val for key, val in statedict.items() if key.startswith('model.')}

model.load_state_dict(model_statedict, strict=True)

for p in model.parameters():
    p.requires_grad = False

model.eval()
device = torch.device("cpu");
model_cpu = model.to(device)

# 创建一个示例输入
example_input = torch.rand(1, 3, 112, 112)  # 假设输入大小为 (1, 3, 112, 112)

# 转换为 TorchScript
traced_model = torch.jit.trace(model_cpu, example_input)

# 保存模型
traced_model.save('adaface.pt')


# 导出为 ONNX 格式
#onnx_file_path = 'adaface.onnx'  # 输出文件名
#torch.onnx.export(model, example_input, onnx_file_path,
#                  export_params=True)
                  #opset_version=11,  # ONNX 版本
                  #do_constant_folding=True,  # 是否进行常量折叠
                  #input_names=['input'],  # 输入名称
                  #output_names=['output'],  # 输出名称
                  #dynamic_axes={'input': {0: 'batch_size'},  # 动态 batch size
                  #              'output': {0: 'batch_size'}})

4. c++推理

4.1 前处理

  • resize人脸图片为112x112
  • 归一化
  • BGR->RGB
  • 转换为tensor
  • N H W C->N C H W
  • reshape 1,3,112,112(模型输入shape)

4.2 推理

  • load model
  • 读取图片
  • 人脸检测对齐
  • 前处理
  • model.forward推理
#include <torch/script.h>
#include <iostream>
#include <memory>
#include <opencv2/opencv.hpp>

torch::Tensor to_input(const cv::Mat& pil_rgb_image) {
    cv::Mat brg_img;
    cv::resize(pil_rgb_image, brg_img, cv::Size(112, 112));
    brg_img.convertTo(brg_img, CV_32FC3, 1.0 / 255.0);
    brg_img = (brg_img - 0.5) / 0.5;
    cv::cvtColor(brg_img, brg_img, cv::COLOR_BGR2RGB);

    torch::Tensor tensor = torch::from_blob(brg_img.data, {1, brg_img.rows, brg_img.cols, 3}, torch::kFloat32);
    tensor = tensor.permute({0, 3, 1, 2});
	tensor = tensor.reshape({1, 3, 112, 112});
	tensor = tensor.to(at::kCPU);

    return tensor;
}

int main() {
    // 模型加载
    torch::jit::script::Module model;
    try {
        model = torch::jit::load("./adaface.pt");
        //model.eval();
        model.to(at::kCPU);
    } catch (const c10::Error& e) {
        std::cerr << "Error loading the model\n";
        return -1;
    }
    // 读取图片
    std::vector<std::string> images;
    getAllFiles("./images", images, {"jpg", "jpeg", "png"});
    // 人脸检测器初始化
	OpenCVFace open_cv_face;
	open_cv_face.Init("./models/face_detection_yunet_2023mar.onnx",
		"./models/face_recognition_sface_2021dec.onnx", 0.9, 0.5);
	
    for (const auto &image_path : images)
    {
        // Load an image using OpenCV
        cv::Mat orig_img = cv::imread(image_path);
        if (orig_img.empty()) {
            std::cerr << "Could not read the image\n";
            return -1;
        }

        auto detect_start = GetCurTimestamp();
        std::vector<cv::Mat> aligned_faces;
		// 人脸检测对齐
    	open_cv_face.detectAndAlign(orig_img, aligned_faces);

        //std::cout<<"detect use time is  "<< (GetCurTimestamp() - detect_start)<<std::endl;
        for (const auto &face:aligned_faces)
        {
            cv::Mat img(face);

        	auto img_tensor = to_input(img);

            // Inference 推理
            std::vector<torch::jit::IValue> inputs;
            inputs.push_back(img_tensor);

            auto output = model.forward(inputs);

            // Check if the output is a tuple
            if (output.isTuple()) {
                auto output_tuple = output.toTuple();
                if (output_tuple->elements().size() > 0) {
                    at::Tensor output_tensor = output_tuple->elements()[0].toTensor();
                    //std::cout << output_tensor << std::endl;
                } else {
                    std::cerr << "Output tuple is empty\n";
                    return -1;
                }
            } else {
                at::Tensor output_tensor = output.toTensor();
                //std::cout << output_tensor << std::endl;
            }
        }
    }
   

    return 0;
}

注意:本代码的人脸检测和对齐使用opencv的Yunet和SFace实现, 地址

4.3 编译运行

4.3.1 写CMakeLists.txt

本工程依赖opencv和libtorch,一并下载解压到/usr/local下即可。

cmake_minimum_required(VERSION 3.22.1)
project(adaface-demo)

set(QMAKE_CXXFLAGS "-std=c++17")
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

include_directories(/usr/local/include)
link_directories(/usr/local/lib)

set(OPENCV_VERSION "4.9.0")
set(OPENCV_INSTALLATION_PATH "/usr/local/opencv4" CACHE PATH "Where to look for OpenCV installation")

# Find OpenCV
find_package(OpenCV ${OPENCV_VERSION} REQUIRED HINTS ${OPENCV_INSTALLATION_PATH})

if (AARCH64)
    set(Torch_DIR /usr/local/libtorch/lib/python3.10/site-packages/torch/share/cmake/Torch)
else ()
    set(Torch_DIR /usr/local/libtorch/share/cmake/Torch)
endif ()

find_package(Torch REQUIRED)
include_directories(${TORCH_INCLUDE_DIRS})

AUX_SOURCE_DIRECTORY(./src DIR_SRCS)
add_executable(adaface-demo ${DIR_SRCS})

target_link_libraries(adaface-demo ${OpenCV_LIBS} ${TORCH_LIBRARIES})

4.3.2 编译

mkdir build
cd build
cmake ..

4.3.3 运行

将模型文件adaface.py拷贝到bin目录下

cd ../bin
./main

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2256449.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows电脑伪关机(快速启动模式),怎么真关机

Windows电脑在关机的时候&#xff0c;进入到一个伪关机的状态&#xff0c;也就是并没有真正的关机&#xff0c;但是在一些系统更新、变更了一些设置&#xff0c;进行重启等操作也会进入到真关机状态 这种一般是开启快速启动模式&#xff0c;开启了快速启动模式功能会在关机的时…

Bellman-Ford 算法详解及应用

Bellman-Ford 算法详解及应用 图24-4 的结构(假设)Bellman-Ford 算法步骤伪代码C 语言实现 Bellman-Ford 算法运行结果分析输出示例(部分)Bellman-Ford 算法是一种用于计算单源最短路径的算法,即从给定的源节点到其他所有节点的最短路径。它可以处理带有负权重的边,但不适…

92.插入排序

一.什么是插入排序 把数据分为有序和无序俩个部分&#xff0c;将无序部分中的一个数据插入到已排好的有序部分中&#xff0c;有序部分从而变成一个新的、排好数据数量增1的有序数据&#xff0c;直到数据全部排序完成。 插入排序一般适用于小型数据。大型数据性能较差。 二.实…

69 mysql 中 is null 的实现

前言 Mysql 中我们偶尔会用到 字段为 NULL 的情况 这时候 我们只能使用查询 “select * from tz_test_02 where field1 is null;” 来进行 field1 字段为 null 的行的查询 然后如果是使用 “select * from tz_test_02 where field1 null;” 你会发现查询 不出数据 但是如…

A1017 基于Java+JSP+SQL Server+servlet的二手购物平台的设计与实现

二手购物平台 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 摘 要 计算机以及网络技术的飞速发展&#xff0c;网络的应用在全国乃至全球日益普及&#xff0c;随着人们的思想水平和生活水平的提高&#xff0c;网络已经是人们必不可少的一部分。人们的…

力扣-图论-6【算法学习day.56】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…

使用PHPUnit使用本地调试代替远程调试,快速提高开发效率

Laravel 是一个在 Linux 环境下表现非常出色的 PHP 框架&#xff0c;但它在 Windows 环境下可能会遇到一些兼容性和配置问题。为了调试或没试的方便可以在 Windows 环境下进行 Laravel PHPUnit进行本地调试和测试。 本地主要针对断点调试效果非常高效。 在 Laravel 中&#x…

动态规划 - 4( 背包问题 10000 字详解 )

一&#xff1a; 背包问题 1.1 01 背包 题目链接&#xff1a;01 背包 import java.util.Scanner;public class Main {public static void main(String[] args) {// 不做空间优化&#xff0c;用 dp 表存下所有状态Scanner sc new Scanner(System.in);// 读入 n 和 Vint n sc.…

关于利用 EtherNet/IP 转 Profinet 网关模块实现罗克韦尔变频器接入西门子 PLC 的配置范例

在现代工业自动化领域&#xff0c;不同品牌设备之间的通信兼容性问题一直是企业面临的挑战之一。某智能工厂为了优化生产流程&#xff0c;提高设备的协同工作效率&#xff0c;决定对其生产线上的控制系统进行升级改造。该生产线中&#xff0c;AB罗克韦尔PowerFlex变频器作为关键…

论文研读|信息科技风险管理模型的主要内容、定位、目标企业、风险管理机制, 以及相应的风险评估流程和风险应对策略

文献来源&#xff1a;[1]李政.商业银行数据中心风险管理研究[D].合肥工业大学[2024-12-08]. 内容总结&#xff1a;风险管理是一项不断发展完善的体系化工作。本章研究了国际上普遍使用的风险管理基本模型、并针对主流的信息科技风险管理的框架进行研究、分析&#xff0c;重点研…

MySQL-DML之数据表操作

文章目录 一. 插入表记录1. 向表中插入部分字段2. 向表中插入所有字段,字段的顺序为创建表时的顺序3. 一次添加多条数据信息 二. 更新表记录1. 更新所有记录的指定字段 更新符号条件记录的指定字段2. 更新符号条件记录的指定字段 三. 删除表记录1. 按条件删除记录2. 清空记录 四…

mac mini 4 上手指南

文章目录 和 mac 初见购机历程外设配置win 系统 适应 mac 系统一些使用体验mac 快捷键 和 mac 初见 最开始用 mac 是小时候用着刷成 windows 的 MacBook 和好朋友一起打游戏&#xff0c;再后来就是上大学&#xff0c;用朋友的 mac 做一些简单的办公 购机历程 我之前 11月2日…

Apache AGE:基于PostgreSQL的图数据库

Apache AGE&#xff08;A Graph Extension&#xff09;是一个基于 PostgreSQL 的图数据库。它以扩展插件的形式提供&#xff0c;可以在利用 PostgreSQL 先进的 SQL 查询功能和事务支持的同时&#xff0c;享受图数据库的灵活性和可扩展性。 Apache AGE 最初由 Bitnine Global In…

关于springBoot+vue项目中配置SSL证书问题

前端可以通过https进行访问 1.前端在访问后端接口时&#xff0c;使用https进行访问&#xff0c;在request.js配置文件中&#xff0c;这个文件是配置axios的基本请求的&#xff0c;在基础请求地址中改为https方式 2.需要在Linux中的nginx中配置ssl证书&#xff0c;具体请参考&…

华为、华三交换机纯Web下如何创关键VLANIF、操作STP参数

华为交换机WEB操作 使用的是真机S5735&#xff0c;目前主流的版本都适用&#xff08;V1R5~V2R1的就不在列了&#xff0c;版本太老了&#xff0c;界面完全不一样&#xff0c;这里调试线接的console口&#xff0c;电脑的网络接在ETH口&#xff09; 「模拟器、工具合集」复制整段内…

二分查找(带图详解)

优选算法系列 文章目录 优选算法系列前言一、二分查找的思想二、算法使用小总结 三、代码实现四、二分查找拓展4.1、查找第一次出现的target小总结 4.2、target最后出现的位置小总结 五、代码总结 前言 在这篇博客中&#xff0c;我会给大家分享二分查找及其扩展。 这是链接-&…

【C#】NET 9中LINQ的新特性-CountBy

前言 在 .NET 中,使用 LINQ 对元素进行分组并计算它们的出现次数时,需要通过两个步步骤。首先,使用 GroupBy方法根据特定键对元素进行分类。然后,再计算每个组元素包含个数。而随着 .NET 9 版本发布,引入了一些新特性。其中 LINQ 引入了一种新的方法 CountBy,本文一起来了…

[SWPUCTF 2022 新生赛]funny_php

进入靶场环境 <?phpsession_start();highlight_file(__FILE__);if(isset($_GET[num])){if(strlen($_GET[num])<3&&$_GET[num]>999999999){echo ":D";$_SESSION[L1] 1;}else{echo ":C";}}if(isset($_GET[str])){$str preg_replace(/NS…

2024-10-13-B fd 重定向 缓冲区

1 一切皆文件 1.1 虚拟文件系统 在系统层面&#xff0c;做了一层软件的封装&#xff0c;struct file 里有操作表&#xff08;即函数指针的集合&#xff09;&#xff0c;可以调用底层的读写方法。虚拟文件系统&#xff08;VFS&#xff09;是一种神奇的抽象&#xff0c;它使得…

调整数组顺序使奇数位于偶数前面

题目 输入一个整数数组&#xff0c;调整数组中数字的顺序&#xff0c;使得所有奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分。要求时间复杂度为O(n) 解法 双指针i和j 指针i起点是数组起点&#xff0c;当i检测到偶数时停下。j的起点时数组终点&#xff0c;…