c++人脸识别项目,满足工业界对于人脸识别系统的高标准需求!(一)

目录

引言: 

环境构建(本文使用cmake,开发环境ubuntu22.04,IDE为clion)

项目文件构造

 CMakeLists.txt编写

简单头文件

最初成员函数实现 

add函数实现思路

search函数实现思路

main函数简单实现

思路

添加环境之后的main函数实现

需要创建的对象

如何获取add和search需要的数据

初步可运行的main

第一次运行:

 添加和搜索同一张图片

不同图片测试 

总结


引言: 

在工业界,C++因其高性能、灵活性和对底层硬件的良好控制,一直是实现计算机视觉和机器学习任务的热门语言,尤其是在需要高性能计算的场景下。而FAISS(Facebook AI Similarity Search)作为一个高效的相似性搜索库,专为大规模特征向量的相似性搜索和聚类任务设计,尤其擅长处理高维向量空间中的近似最近邻搜索问题,这在人脸识别中尤为重要,因为人脸识别常常涉及到在大型特征数据库中快速查找最相似的人脸特征。

尽管Python因其实现简便快捷,也是机器学习和AI领域广泛使用的语言,但在对性能有严格要求的工业级应用中,C++与FAISS的组合由于其卓越的性能表现,成为追求极致效率和资源利用的首选。尤其是在处理大规模数据集和实时性要求高的应用场景下,C++的底层优化能力和FAISS的高效算法相结合,能够满足工业界对于人脸识别系统的高标准需求。今天我将从零开始,带着大家利用c++使用faiss库来实现一个人脸识别项目。在人脸识别之前还需要进行人脸检测和人脸特征提取,这部分会在以后的文章提到,后面会直接使用

环境构建(本文使用cmake,开发环境ubuntu22.04,IDE为clion)

项目文件构造

先在IDE中创建入下图所示的项目文件,include用来存放需要的头文件,src存放源文件

 CMakeLists.txt编写

cmake_minimum_required(VERSION 3.20)# 设置CMake的最低版本要求为3.20(这个可以根据自己的情况来)project(AnnTest)# 定义一个名为AnnTest的项目set(CMAKE_CXX_STANDARD 17) # 设置C++源码的编译标准为C++17
set(CMAKE_THREAD_LIBS_INIT "-lpthread") # 设置线程库为pthread,用于支持多线程编程set(CMAKE_CHARACTER_SET utf-8)# 设置CMake的字符集为utf-8,用于处理非ASCII字符的源文件或输出
set(CMAKE_CUDA_ARCHITECTURES 75) # 针对CUDA编译设置,指定CUDA架构为7.5
set(CMAKE_CUDA_COMPILER /usr/local/cuda-11.8/bin/nvcc)# 设置CUDA编译器路径为CUDA 11.8的nvccfind_package(CUDA REQUIRED) # 查找并配置CUDA支持
find_library(CUDA_CUBLAS_LIBRARY NAMES libcublas.so.11 PATHS /usr/local/cuda/lib64)
# 查找名为libcublas.so.11的库文件,指定搜索路径为/usr/local/cuda/lib64set(SERVER_LIB/usr/local/lib/libfaiss.a/usr/local/faiss/lib/libfaiss_gpu.a) # 定义一个名为SERVER_LIB的变量,包含需要链接的FAISS库文件路径(这个一定要有)add_executable(AnnTest main.cpp) #添加一个可执行文件目标AnnTest,源文件为main.cpptarget_link_libraries(AnnTest PRIVATE ${SERVER_LIB})## 将之前定义的SERVER_LIB库链接到AnnTest目标上,链接类型为PRIVATE

不懂的可以看我后面的注释,。faiss库可以去官方网站上下载的,懒得下的可以点个赞私信我发你

简单头文件

声明一个类(拷贝构造,析构函数和拷贝赋值先使用默认的)

#ifndef ANNTEST_ANN_H
#define ANNTEST_ANN_H
class ANN {
public:ANN();~ANN();
public:void add();bool search();void erase();
private:
};
#endif //ANNTEST_ANN_H

在上面的代码中我们先构建了最基本的三个功能成员函数,增加,搜索和删除人脸。下面我们会通过实现每一个函数需要的成员变量,来把这个类设计完整

最初成员函数实现 

add函数实现思路

这里我的add函数要实现人脸的录入,也就是要调用faiss中录入人脸的API,我这里使用的有四种方式:faiss库中的IndexFlatL2,gpu::GpuIndexFlatL2,IndexFlatIP,gpu::GpuIndexFlatIP都有一个add函数用来添加人脸信息,由此添加四个成员变量(这四个成员都是类对象,使用指针来声明)。

#include <faiss/IndexFlat.h>
#include <faiss/gpu/GpuIndexFlat.h>
#include <memory>
class ANN {
public:ANN();~ANN();
public:void add();bool search();void erase();
private:std::unique_ptr<faiss::IndexFlatL2> euclideanIndex;std::unique_ptr<faiss::gpu::GpuIndexFlatL2> euclideanGPUIndex;std::unique_ptr<faiss::IndexFlatIP> cosineIndex;std::unique_ptr<faiss::gpu::GpuIndexFlatIP> cosineGPUIndex;
};

四个成员变量,IndexFlatL2表示使用欧氏距离,IndexFlatIP表示使用cos距离,带gpu表示使用gpu。 所以增加成员变量来判断是否使用GPU以及使用哪种计算方式

enum CalculatingMethod{Euclidean,Cosine
};
class ANN {
public:ANN();~ANN();
public:void add(std::unique_ptr<float[]> data);bool search();void erase();
private:CalculatingMethod method;bool useGPU = false;std::unique_ptr<faiss::IndexFlatL2> euclideanIndex;std::unique_ptr<faiss::gpu::GpuIndexFlatL2> euclideanGPUIndex;std::unique_ptr<faiss::IndexFlatIP> cosineIndex;std::unique_ptr<faiss::gpu::GpuIndexFlatIP> cosineGPUIndex;
};

然后在构造函数中根据不同的情况生成不同的类对象

ANN::ANN(int dimension,int kValue, float threshold, bool useGPU,int gpuDevice,CalculatingMethod method):
dimension(dimension),kValue(kValue), threshold(threshold), useGPU(useGPU),gpuDevice(gpuDevice) {if(this->method == Euclidean){if(this->useGPU){faiss::gpu::GpuIndexFlatConfig config;config.device = gpuDevice;faiss::gpu::StandardGpuResources gpuResources;this->euclideanGPUIndex = std::make_shared<faiss::gpu::GpuIndexFlatL2>(&gpuResources,this->dimension,config);}else{this->euclideanIndex = std::make_shared<faiss::IndexFlatL2>(this->dimension);}}else{if(this->useGPU){faiss::gpu::GpuIndexFlatConfig config;config.device = gpuDevice;faiss::gpu::StandardGpuResources gpuResources;this->cosineGPUIndex = std::make_shared<faiss::gpu::GpuIndexFlatIP>(&gpuResources,this->dimension,config);}else{this->cosineIndex = std::make_shared<faiss::IndexFlatIP>(this->dimension);}}}

dimension这里是我们要对比的特征向量的维度。 

然后关于faiss的add函数

void add(idx_t, const float* x) override;

需要两个参数,第一个为要添加的数量,这里我默认为1,第一个为添加的数据。修改我们自己的add函数

void add(const std::unique_ptr<float[]>& data);

定义我们的最初的add函数

void ANN::add(const std::shared_ptr<float[]>& data) {if(this->method==Cosine){this->useGPU ? this->cosineGPUIndex->add(1,data.get()) : this->cosineIndex->add(1,data.get());}else{this->useGPU ? this->euclideanGPUIndex->add(1,data.get()) : this->euclideanIndex->add(1,data.get());}
}

search函数实现思路

为了验证我们最初的add函数是否能成功添加,我们需要在来一个最初的search函数,与add函数相同,在faiss库中也有相同的search API,

void search(idx_t n,const float* x,idx_t k,float* distances,idx_t* labels,const SearchParameters* params = nullptr) const override;

一个个来,n代表你要查询几个,一般我设为1,x为要查询的人脸信息,k为最相近的结果你要几个,distances用于接收查询结果中每个查询向量对应最近邻居的距离,大小最少要n*k,labels用于接收每个查询向量的最近邻居的索引或标识符。数组大小同样至少需要n*k,params这是一个可选参数,允许用户指定额外的搜索参数,比如搜索时的GPU设备选择、搜索策略等。如果不提供(即保持默认值),则使用索引或库的默认设置

k的值我作为成员变量(我这里取5),distances和labels我们创建一个

bool ANN::search(const std::shared_ptr<float[]>& data) {std::vector<long> lables(this->kValue);std::vector<float> distances(this->kValue);if(this->method==Cosine){this->useGPU ? this->cosineGPUIndex->search(1,data.get(),this->kValue,distances.data(),lables.data()): this->cosineIndex->search(1,data.get(),this->kValue,distances.data(),lables.data());}else{this->useGPU ? this->euclideanGPUIndex->search(1,data.get(),this->kValue,distances.data(),lables.data()): this->euclideanIndex->search(1,data.get(),this->kValue,distances.data(),lables.data());}}

这里和上面的add很相似,然后我们说了,结果都在 distances和labels中,所以:

bool ANN::search(const std::shared_ptr<float[]>& data) {std::vector<long> lables(this->kValue);std::vector<float> distances(this->kValue);if(this->method==Cosine){this->useGPU ? this->cosineGPUIndex->search(1,data.get(),this->kValue,distances.data(),lables.data()): this->cosineIndex->search(1,data.get(),this->kValue,distances.data(),lables.data());}else{this->useGPU ? this->euclideanGPUIndex->search(1,data.get(),this->kValue,distances.data(),lables.data()): this->euclideanIndex->search(1,data.get(),this->kValue,distances.data(),lables.data());}for(int i=0;i<this->kValue;i++){long index = lables.at(i);float distance = distances.at(i);if(this->method==Cosine){if(index>=0&&distance>this->threshold){std::cout<<"查询到人脸,"<<"distance:"<<distance<<"index:"<<index<<std::endl;return true;}else{std::cout<<"未查询到人脸,"<<"distance:"<<distance<<"index:"<<index<<std::endl;return false;}}else{if(index>=0&&distance<this->threshold){std::cout<<"查询到人脸,"<<"distance:"<<distance<<"index:"<<index<<std::endl;return true;}else{std::cout<<"未查询到人脸,"<<"distance:"<<distance<<"index:"<<index<<std::endl;return false;}}}
}

根据计算方式的不同,对结果的判断也不同,判断到人脸后先直接打印数据即可,由此,最初的search函数写完了,模型里面没有数据时index=-1,所以加一层判断。

main函数简单实现

思路

先在有了增加和搜索的函数,我们要实现这个人脸的识别,无非就是,利用增加函数增加一个人脸,然后指定一个评分,再使用搜索函数,能搜索到人脸,则人脸识别成功,成功之后可以联动其它相关操作--比如开门。如下:

#include "ANN.h"
std::shared_ptr<ANN> ann;int main() {ann = std::make_shared<ANN>(5,0.6,1);
//    ann->add();return 0;
}

上面的代码中定义了需要五个最相近的人脸,评分阈值取0.6(cos距离),使用GPU,但是,写到add函数的时候我们会发现,它需要我们传入一个人脸数据(这是一个抽象的说法,其实是一个float数组的智能指针对象),所以这里我们需要像之前提到的那样直接使用人脸检测和人脸特征提取的代码,修改一下cmakelists:

cmake_minimum_required(VERSION 3.20)
#project(test)
project(AnnTest)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")set(CMAKE_CHARACTER_SET utf-8)
set(CMAKE_CUDA_ARCHITECTURES 75)
set(CMAKE_CUDA_COMPILER /usr/local/cuda-11.8/bin/nvcc)find_package(CUDA REQUIRED)
find_library(CUDA_CUBLAS_LIBRARY NAMES libcublas.so.11 PATHS /usr/local/cuda/lib64)find_package(Pugixml REQUIRED)set(MTCNN_SOURCESsrc/mtcnn/detector.cppinclude/mtcnn/face.hsrc/mtcnn/onet.cppsrc/mtcnn/pnet.cpp src/mtcnn/rnet.cppinclude/mtcnn/detector.h include/mtcnn/helpers.h include/mtcnn/onet.h include/mtcnn/pnet.h include/mtcnn/rnet.hsrc/FaceDetectionManager.cpp include/FaceANNThread.h src/FaceANNThread.cpp src/FaceInputHandler.cppinclude/MQTTClient.h src/MQTTClient.cpp src/MQTTClientManager.cpp src/AlgorithmHttpServer.cppinclude/AlgorithmHttpServer.h include/log.h include/g3sinks/LogRotate.h include/g3sinks/LogRotateUtility.hinclude/g3sinks/LogRotateWithFilter.h src/LogRotate.cpp src/LogRotateHelper.ipp src/LogRotateUtility.cppsrc/LogRotateWithFilter.cpp)list(APPEND CMAKE_PREFIX_PATH "/mnt/data/software/libtorch/share/cmake")
set(Torch_DIR /mnt/data/software/libtorch/share/cmake/Torch)
find_package(Torch REQUIRED)
message(STATUS "TORCH_LIBRARIES = ${TORCH_LIBRARIES}")
message(STATUS "TORCH_INCLUDES = ${TORCH_INCLUDE_DIRS}")find_package(g3log CONFIG REQUIRED)set(OpenCV_INCLUDE_DIRS "/mnt/data/software/opencv4")
message(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")
include_directories(${OpenCV_INCLUDE_DIRS})include_directories(${PROJECT_SOURCE_DIR}/include)include_directories(/usr/local/paho/include)
include_directories(${Torch_INCLUDE_DIRS})
link_directories(/mnt/data/software/Poco)
link_directories(/mnt/data/software/hkSDK/lib)
include_directories(/mnt/data/software/hkSDK/include)include_directories(/mnt/data/software/github/CppServer/include)
include_directories(/mnt/data/software/github/CppServer/modules/CppCommon/include)
include_directories(/mnt/data/software/github/CppServer/modules/CppCommon/modules/fmt/include/)
include_directories(/mnt/data/software/github/CppServer/modules/asio/asio/include/)
link_directories(/mnt/data/software/github/CppServer/bin/)
link_directories(/mnt/data/software/github/g3log/build)find_package(Poco REQUIRED Data)
message(STATUS "Poco_Data_LIBS = ${Poco}")set(SERVER_LIB/mnt/data/software/github/CppServer/bin/libasio.a/usr/local/lib/libfaiss.a/usr/local/faiss/lib/libfaiss_gpu.a/usr/lib/gcc/x86_64-linux-gnu/11/libgfortran.so/lib/x86_64-linux-gnu/libopenblas.so.0)
set(WEB_LIB/mnt/data/software/github/CppServer/bin/libasio.a)set(OpenCV_LIBS /mnt/data/software/github/opencv-4.8.0/build/lib/libopencv_img_hash.so.4.8.0/mnt/data/software/github/opencv-4.8.0/build/lib/libopencv_sfm.so.4.8.0/mnt/data/software/github/opencv-4.8.0/build/lib/libopencv_world.so.4.8.0/mnt/data/software/github/opencv-4.8.0/build/lib/libopencv_img_hash.so.408/mnt/data/software/github/opencv-4.8.0/build/lib/libopencv_sfm.so.408/mnt/data/software/github/opencv-4.8.0/build/lib/libopencv_world.so.408)add_executable(AnnTest main.cpp include/ANN.h src/ANN.cppinclude/faceRecognizer/FaceNetRecognizer.h include/FaceRecognition.hinclude/mtcnn/detector.h src/mtcnn/detector.cpp include/mtcnn/face.h include/mtcnn/onet.hinclude/mtcnn/pnet.h include/mtcnn/rnet.h src/mtcnn/onet.cpp src/mtcnn/pnet.cpp src/mtcnn/rnet.cppsrc/FaceRecognition.cpp include/faceRecognizer/FaceRecognizerFactory.hsrc/faceRecognizer/FaceNetRecognizer.cpp include/FacePreprocess.h src/faceCommon.cpp)
target_link_libraries(AnnTest PRIVATE ${TORCH_LIBRARIES} ${OpenCV_LIBS} ${SERVER_LIB}  ${WEB_LIB} ${CUDA_CUBLAS_LIBRARY}-llapack -lblas -luuid -lssl -lcrypto-Wl,--copy-dt-needed-entries)

增加的东西可能有点多,主要环境是增加了libtorch和opencv,然后add_executable后面除了我们一开始写的那三个函数外,后面都是用来做人脸检测和特征提取的代码,最后项目的结构如下

这些增加的源码我会在有时间时更新文章来和大家一起写,如果有需要这段源码的同学可以点击人脸检测源码 。

添加环境之后的main函数实现

需要创建的对象

我们自己创建了一个ANN类,然后在我后续的代码中,还需要添加一个人脸检测类以及人脸特征类:如下

std::string modelPath = "/home/zlzg01/ly/AnnTest/bin/models";
std::shared_ptr<ANN> ann;
std::shared_ptr<FaceRecognition> globalFaceDetector = std::make_shared<FaceNetRecognizer>(modelPath);
std::shared_ptr<std::vector<Face>> faces = std::make_shared<std::vector<Face>>();

这些类在人脸检测的源码中都有具体的实现。

如何获取add和search需要的数据

这里globalFaceDetector为我们的检测器,大家暂时先记住使用它之前需要对它调用initDetection函数来初始化,然后它里面有一个getFaces方法,把我们的图片和face类作为参数放进去,就可以完成人脸的检测,face类中有一个getFeaturesData方法来获取人脸的特征值,这个就是我们自己实现的函数需要的参数,具体代码如下:

ann = std::make_shared<ANN>(512, 1, 0.6, 1, 0);
std::string path = "/yourPath/bb.jpg";
cv::Mat img = getImageMat(path);
std::string preLoadFile1 = modelPath + "/test_face1.jpg";
std::string preLoadFile2 = modelPath + "/test_face2.jpg";
bool success = globalFaceDetector->initDetection(preLoadFile1, preLoadFile2);
globalFaceDetector->getFaces(img, *faces);
auto features = faces->at(0).getFeaturesData();
ann->add(features);
ann->search(features);

上面的代码函数调用的流程和我说的一样,先创建我们的模型类,维度512,搜索1个最近的,阈值0.6,使用GPU,GPU使用第0块,getImageMat函数如下:

cv::Mat getImageMat(const std::string& path){std::string imagePath = path;return cv::imread(imagePath,cv::IMREAD_COLOR);
}

然后我们的检测模型一开始是需要做预热的所以 

std::string preLoadFile1 = modelPath + "/test_face1.jpg";
std::string preLoadFile2 = modelPath + "/test_face2.jpg";
bool success = globalFaceDetector->initDetection(preLoadFile1, preLoadFile2)

初步可运行的main

把上面所说的内容整合一下,再导入后面加上的源码头文件代码如下:

//
// Created by zlzg01 on 24-6-20.
//
#include "ANN.h"
#include "mtcnn/face.h"
#include "FaceRecognition.h"
#include "faceCommon.h"
#include "faceRecognizer/FaceNetRecognizer.h"std::string modelPath = "/yourPath/bin/models";
std::shared_ptr<ANN> ann;
std::shared_ptr<FaceRecognition> globalFaceDetector = std::make_shared<FaceNetRecognizer>(modelPath);
std::shared_ptr<std::vector<Face>> faces = std::make_shared<std::vector<Face>>();
std::shared_ptr<std::vector<Face>> faces2 = std::make_shared<std::vector<Face>>();
cv::Mat getImageMat(const std::string& path){std::string imagePath = path;return cv::imread(imagePath,cv::IMREAD_COLOR);
}void cleanup() {// 显式释放共享指针ann.reset();globalFaceDetector.reset();
}int main() {try {ann = std::make_shared<ANN>(512, 5, 0.6, 1, 0);std::string path = "/yourPath/bb.jpg";std::string path2 = "/yourPath/download.jpg";cv::Mat img = getImageMat(path);cv::Mat img2 = getImageMat(path2);
//        std::shared_ptr<cv::Mat> imgs = std::make_shared<cv::Mat>(img);std::string preLoadFile1 = modelPath + "/test_face1.jpg";std::string preLoadFile2 = modelPath + "/test_face2.jpg";bool success = globalFaceDetector->initDetection(preLoadFile1, preLoadFile2);if (!success) {int errorCode = globalFaceDetector->getErrorCode();std::string errorString = globalFaceDetector->getErrorString();}globalFaceDetector->getFaces(img, *faces);globalFaceDetector->getFaces(img2, *faces2);auto features = faces->at(0).getFeaturesData();auto features2 = faces2->at(0).getFeaturesData();ann->add(features);ann->search(features2);cleanup();return 0;}catch (const cv::Exception& e) {std::cerr << "OpenCV error: " << e.what() << std::endl;cleanup();return -1;} catch (const std::exception& e) {std::cerr << "Standard exception: " << e.what() << std::endl;cleanup();return -1;} catch (...) {std::cerr << "Unknown exception occurred." << std::endl;cleanup();return -1;}
}

除了ANN的头文件后面都是我们检测源码中会有的,main函数的内容和之前差不多,只是加上了异常处理的内容,然后使用了两张不同的图片,我的检测代码的思路是

  1. 先什么图片特征都不添加,直接进行检测,看检测结果
  2. 添加一张图片,检测同一张图片看结果
  3. 添加一张图片,检测另一张图片看结果

 其实主要就是控制add函数的使用和add,search函数中的参数

第一次运行:

ann = std::make_shared<ANN>(512, 5, 0.6, 1, 0);std::string path = "/yourPath/bb.jpg";std::string path2 = "/yourPath/download.jpg";cv::Mat img = getImageMat(path);cv::Mat img2 = getImageMat(path2);
//        std::shared_ptr<cv::Mat> imgs = std::make_shared<cv::Mat>(img);std::string preLoadFile1 = modelPath + "/test_face1.jpg";std::string preLoadFile2 = modelPath + "/test_face2.jpg";bool success = globalFaceDetector->initDetection(preLoadFile1, preLoadFile2);if (!success) {int errorCode = globalFaceDetector->getErrorCode();std::string errorString = globalFaceDetector->getErrorString();}globalFaceDetector->getFaces(img, *faces);globalFaceDetector->getFaces(img2, *faces2);auto features = faces->at(0).getFeaturesData();auto features2 = faces2->at(0).getFeaturesData();//ann->add(features);ann->search(features);cleanup();return 0;

结果如下:

无结果是index会为-1.

 添加和搜索同一张图片

ann->add(features);
ann->search(features);

结果

这里准确率直接给了1,有时候会是0.9999...,毕竟是同一张人脸图片

不同图片测试 

ann->add(features);
ann->search(features2);

结果

这里是查询不到,然后准确率也给的很低

总结

到这里我们对模型的验证也初步完成了,有源码的同学也可以自己尝试使用更多的人脸来测试(源码获取点这里),在识别成功后就可以联动一些开门,拍照等操作了。然后大家也可能会发现一个问题,模型一开始录入了,但是程序重启之后又清零了,大家可以思考一下这个问题应该怎么解决,后面我会继续更新来和大家一起优化这个代码,然后大家对上面的代码有什么问题的可以下方留言(趁我现在还记得)。然后如果是缺少opencv和faiss环境自己懒得安装的,可以点赞后私信我。

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

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

相关文章

Spring Boot集成qwen:0.5b实现对话功能

1.什么是qwen:0.5b&#xff1f; 模型介绍&#xff1a; Qwen1.5是阿里云推出的一系列大型语言模型。 Qwen是阿里云推出的一系列基于Transformer的大型语言模型&#xff0c;在大量数据&#xff08;包括网页文本、书籍、代码等&#xff09;进行了预训练。 硬件要求&#xff1a;…

Spring Web MVC入门(2)(请求2)

目录 1.传递JSON数据 传递JSON对象 2.获取URL中的参数PathVariable 3.上传文件RequestPart 4.获取Cookie/Session (1)获取Cookie 简洁获取Cookie (2)获取Session Sesson读取 简洁获取Session(1) 简洁获取Session(2) 5.获取Header 简洁获取Header 1.传递JSON数据 J…

大模型计算及GPU相关概念记录

浮点运算 算力最基本的计量单位是 FLOPS&#xff0c;英文 Floating-point Operations Per Second&#xff0c;即每秒执行的浮点运算次数。浮点运算其实就是带小数的加减乘除运算。 算力的计量单位&#xff0c;除了 FLOPS&#xff0c;从小到大还有&#xff1a; KFLOPS&#x…

新建一个git仓库并且把已有项目推送到git远程仓库

总贴 1. 创建一个空项目&#xff0c;不会看新建仓库 2. 克隆这个项目到某个文件夹去&#xff0c;比如我想克隆到我的E盘的code下面 3. 我的这个文件夹下面是有东西的&#xff0c;一点都不影响 . 4. 用命令行进入这个文件夹 命令行已经显示了已经在E盘下面code文件夹, 不会…

【TortoiseGitPlink提示输入密码解决方法】

问题&#xff1a;TortoiseGitPlink提示输入密码 解决方案 参考链接&#xff1a;TortoiseGitPlink提示输入密码解决方法 但后半部分和上文不同&#xff0c;点击图中 Load Putty Key 即可。

CrowdStrike更新导致蓝屏事件

1. 事件描述 网络上发现大量企业Windows系统主机出现BSOD&#xff08;Bluescreen of Death&#xff09;并循环重启。 观察蓝屏信息&#xff0c;发现造成蓝屏的程序均是csagent.sys&#xff0c;该程序为CrowdStrike终端安全软件组件。 经确认&#xff0c;CrowdStrike是造成本…

第5章 单片机的中断系统

5.1 中断的概念 5.2 中断控制系统 5.3 中断处理过程 5.4 中断的编程及应用举例 5.1 中断的概念 日常生活的中断现象举例 中断是指在突发事件到来时先中止当前正在进行的工作&#xff0c;转而去处理突发事件。待处理完成后&#xff0c;再返回到原先被中止的工作处&#xff…

【STM32】LED闪烁LED流水灯蜂鸣器(江科大)

LED正极&#xff1a;外部长脚、内部较小 LED负极&#xff1a;外部短脚、内部较大 LED电路 限流电阻&#xff1a;保护LED&#xff0c;调节LED亮度&#xff08;本实验用面包板为了方便&#xff0c;省去了限流电阻&#xff0c;设计电路时要加上&#xff09; 左上图&#xff1a;低…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第三十六章 Linux驱动初探

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

阿尔泰科技工业电脑IPC-8363工控机

概述&#xff1a; IPC-8363是一款支持 LGA 1200 Intel 10th/11th Generation Core™ i9/i7/i5/i3, Celeron and Pentium processor 的工业电脑。配置2组独立 SO-DIMM DDR4 2666/2933MHz内存&#xff0c;最大可扩展至128GB。 主要技术指标&#xff1a; 产品图示&#xff1a; 系…

Codeforces Round 672 (Div. 2) C1. Pokémon Army (easy version) (DP)

不知道能不能用贪心&#xff0c;反正我是没看出来&#xff0c;所以用DP求解。 首先分析一下题意&#xff0c;我们要在一段序列中取出一段子序列&#xff0c;然后让这段子序列按顺序逐个先加后减最终得到的结果最大。 如果要用DP&#xff0c;那么我们首先就要思考怎么表示状态…

Apache SeaTunnel——OLAP 引擎的数据动脉

导读本文将分享如何利用 Apache SeaTunnel 将各个业务系统的数据同步到 OLAP 引擎。 主要内容包括以下六大部分&#xff1a; 1. Apache SeaTunnel 项目介绍 2. Apache SeaTunnel 核心功能 3.SeaTunnel 在 OLAP 场景下的应用 4. 社区近期计划 5. WhaleTunnel 产品特性 6. …

idea怎么配置gradle多个版本

1.背景 gradle版本很多,而且很多时候版本是不兼容的,我们希望拉取下来的代码就包含已经配置好的版本,而不是去配置本机的gradle版本..... 意思就是要实现项目A可以用6.X版本 项目B可以使用7.X版本 项目C可以用9.X版本..... 2.配置方式 步骤一:项目根路径下保留一个文件夹…

MySQL事务管理详解:特性、问题与解决方案

什么是事务&#xff1f; 事务是一个不可分割的数据库操作序列&#xff0c;也是数据库并发控制的基本单位&#xff0c;其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作&#xff0c;要么都执行&#xff0c;要么都不执行。 事务的四大特…

Docker搭建Harbor

1.什么是Harbor Harbor 是 vMware 公司开源的企业级 Docker 〖egistry 项日&#xff0c;其日标是帮助用户迅速搭建一个企业级的 Docker Registry 服务。Harbor以 Docker 公司开源的 Registry 为基础&#xff0c;提供了图形管理UI 、基于角色的访问控制(Role Based Accesscontr…

活动回顾 | AutoMQ 联合 GreptimeDB 共同探讨新能源汽车数据基础设施

7 月 13 日&#xff0c;AutoMQ 携手 GreptimeDB“新能源汽车数据基础设施” 主题 meetup 在上海圆满落幕。本次论坛多角度探讨如何通过创新的数据管理和存储架构&#xff0c;提升汽车系统的性能、安全性和可靠性&#xff0c;从而驱动行业的持续发展和创新&#xff0c;涵盖 Auto…

PHP萌宠之家微信小程序系统源码

&#x1f43e;萌宠之家微信小程序&#x1f43e; —— 铲屎官们的温馨小窝✨ &#x1f3e0;【一键开启萌宠乐园】&#x1f3e0; 亲们&#xff0c;是不是每次刷手机都忍不住想看看那些软萌可爱的毛孩子&#xff1f;现在&#xff0c;有了“萌宠之家”微信小程序&#xff0c;你的…

LeetCode 3112.访问消失节点的最少时间:单源最短路的Dijkstra算法

【LetMeFly】3112.访问消失节点的最少时间&#xff1a;单源最短路的Dijkstra算法 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-time-to-visit-disappearing-nodes/ 给你一个二维数组 edges 表示一个 n 个点的无向图&#xff0c;其中 edges[i] [ui, vi, l…

【深度学习】【Lora训练4】StabelDiffusion,人物lora训练

启动&#xff1a; docker run -it --gpus all --net host -v /ssd/xiedong/xiezhenceshi/lora_train:/ssd/xiedong/xiezhenceshi/lora_train kevinchina/deeplearning:pytorch2.3.0-cuda12.1-cudnn8-devel-xformers-lora-train bashrootgpu16:/workspace/lora-scripts# python…

6. JavaSE ——【深入理解Java中的按位运算符】

&#x1f4bb; 开场白 欢迎来到我的技术博客&#xff01;在这里&#xff0c;我们将一起探索编程的奥秘&#xff0c;分享代码的智慧&#xff0c;让技术改变生活。让我们开始这段精彩的旅程吧&#xff01;&#x1f680;&#x1f4bb;&#x1f310; &#x1f4d6;个人主页&#xf…