gRPC基本用法:以人脸识别为例,搭建一个简单的gRPC服务

news2024/11/25 2:53:57
标题

0. gRPC简介

相关网站:

中文文档:gRPC 官方文档中文版_V1.0

官网:gRPC

介绍(以下引自官方文档中文版中的介绍):

gRPC是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

在我们需要对外提供某些服务时,通常有几个选择:Django、Flask、gRPC,他们都可以将你的算法或者其他服务封装起来,以接口的形式对外提供服务。

本文以人脸识别服务为例,介绍一下gRPC这个框架。

1. 协议的定义与生成

1.1 编写proto文档,定义相关字段

syntax = "proto3";

package api.product.pft.v1.face;


// 搜索人脸请求
message SearchFaceReq {
    repeated float feats = 1;
}

// 搜索人脸响应
message SearchFaceReply {
    string student_id = 2;
}


service API {
  rpc SearchFace (SearchFaceReq) returns (SearchFaceReply) {}
}

1.2 生成序列化文档

# xx为第1步编写的协议文件名称,将path/to/xx.proto改为你的协议文件地址
python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. path/to/xx.proto

2. 编写服务程序和测试程序

通常server和client是分开的,比如在服务器只需要server相关代码,启动之后就一直在监听有无请求,而client一般在用户端定义并使用,通过连接到服务器,调用服务接口来完成人脸识别功能。

server.py:

import time
import grpc
from concurrent import futures
import logging
import cv2
import glob
import os
import sys
import numpy as np

sys.path.insert(0, os.getcwd())
sys.path.insert(0, 'ai_bridge')

from ..proto import face_pb2, face_pb2_grpc
from ..utils.tools import img_binary_to_cv, img_cv_to_binary

# from py_imo_core import api as pic
# from configs import auth

logging.basicConfig(
    format='%(levelname)s %(asctime)s [%(filename)s:%(lineno)d] %(message)s',
    level=logging.DEBUG
)


class FaceServicer(face_pb2_grpc.APIServicer):
    def __init__(self, features_dir="data/faces/*.npy", thres=0.8):
        feature_paths = sorted(glob.glob(features_dir))
        features, face_ids = [], []
        for feature_path in feature_paths:
            face_id = int(os.path.split(feature_path)[-1].split('.')[0])
            face_ids.append(face_id)
            feature = np.load(feature_path)
            features.append(feature / np.linalg.norm(feature))

        self.features = np.asarray(features)
        self.face_ids = face_ids

        self.thres = thres

    def SearchFace(self, request, context):
        logging.info("Got request!".format())
        feature = np.asarray(request.feats)
        feature = feature / np.linalg.norm(feature)
        print(len(feature))

        # 人脸比对,得到face_id
        scores = np.dot(self.features, feature.T)
        face_id = self.face_ids[np.argmax(scores)] if np.max(scores) >= self.thres else ''
        print("face rec result: id:{}, score:{}".format(face_id, np.max(scores)))

        reply = self._pase_reply(face_id)
        return reply

    def _pase_reply(self, face_id):
        reply = face_pb2.SearchFaceReply(
            student_id=str(face_id)
        )
        return reply


class Server(object):
    def __init__(self, algo_kwargs, ip_port='0.0.0.0:50051', max_workers=10, options=None):
        self.ip_port = ip_port
        self.max_workers = max_workers
        self.options = options
        self.face_server = FaceServicer(**algo_kwargs)

    def run(self):
        server = grpc.server(futures.ThreadPoolExecutor(max_workers=self.max_workers), options=self.options)
        face_pb2_grpc.add_APIServicer_to_server(self.face_server, server)
        server.add_insecure_port(self.ip_port)
        server.start()
        logging.info('listening on %s...' % self.ip_port)
        server.wait_for_termination()

client.py:

import grpc

from ..proto import face_pb2, face_pb2_grpc


class Client(object):
    def __init__(self, ip_port='0.0.0.0:50051', options=None):
        self.ip_port = ip_port
        self.options = options
        self.channel = grpc.insecure_channel(ip_port, options=options)
        self.stub = face_pb2_grpc.APIStub(self.channel)

    def Exec(self, req):
        reply = self.stub.SearchFace(req)
        return reply

3. 编写服务启动脚本、客户端启动脚本

与server和client一一对应,且同样是在不同的端进行使用。

run_server.py:

import os
import sys;

sys.path.insert(0, os.getcwd())

from api.core.server import Server


def main():
    MAX_MESSAGE_LENGTH = 1024 * 1024 * 1024

    algo_kwargs = dict(
        features_dir="data/faces/*.npy"
    )
    server = Server(
        algo_kwargs,
        ip_port='0.0.0.0:50053',
        options=[
            ('grpc.max_send_message_length', MAX_MESSAGE_LENGTH),
            ('grpc.max_receive_message_length', MAX_MESSAGE_LENGTH),
        ]
    )
    server.run()


if __name__ == '__main__':
    main()

run_client.py:

import logging
import time
import cv2
import numpy as np
import glob
import os
import sys

sys.path.insert(0, os.getcwd())
logging.basicConfig(
    format='%(levelname)s %(asctime)s [%(filename)s:%(lineno)d] %(message)s',
    level=logging.DEBUG
)

from api.core.client import Client
from api.proto import face_pb2


def main():
    MAX_MESSAGE_LENGTH = 1024 * 1024 * 1024
    client = Client(
        # ip_port='www.aimall-cd.cn:8036',
        ip_port='0.0.0.0:50050',
        options=[
            ('grpc.max_send_message_length', MAX_MESSAGE_LENGTH),
            ('grpc.max_receive_message_length', MAX_MESSAGE_LENGTH),
        ]
    )

    feature = np.load("data/faces/20001.npy")
    req = face_pb2.ExecReq(
        feature=[f for f in feature],
    )
    reply = client.Exec(req)

    # parse gRPC result
    face_id = reply.face_id

    print(face_id)


if __name__ == '__main__':
    main()

4. 后台启动server服务,运行利用client进行测试

先启动server:

# 启动上面编写的run_server脚本
python /path/to/run_server.py

        然后,启动client,即可得到测试结果:

# 启动上面编写的run_client脚本
python /path/to/run_client.py

5. 本文所有代码已打包放在github

欢迎大家使用,并给个star:

GitHub - aiLiwensong/grpc_face_recognition: gRPC Demo: Taking facial recognition as an example

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

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

相关文章

LANDSAT_7/02/T1/RAW的Landsat7_C2_RAW类数据集

Landsat7_C2_RAW是指Landsat 7卫星的数据集,采用的是Collection 2级别的数据处理方法,对应的是Tier 1级别的原始数据(RAW)。该数据集包括了Landsat 7卫星从1999年4月15日开始的所有数据,共涵盖了全球范围内的陆地和海洋…

性格内向怎么办?如何改变性格内向?

性格内向和外向并没有优劣之分,性格内向也不是坏事,但从人际交往和事务处理的角度来看,内向性格确实不如外向的有优势,所以这也是很多人希望改变自己内向性格的原因。 此外性格内向也容易称为心理问题的替代词,比如&a…

Data Mining数据挖掘—2. Classification分类

3. Classification Given a collection of records (training set) – each record contains a set of attributes – one of the attributes is the class (label) that should be predicted Find a model for class attribute as a function of the values of other attribu…

【Linux】进程间通信之共享内存/消息队列/信号量

文章目录 一、共享内存的概念及原理二、共享内存相关接口说明1.shmget函数2.ftok函数3.shmat函数4.shmdt函数5.shmctl函数 三、用共享内存实现server&client通信1.shm_server.cc2.shm_client.cc3.comm.hpp4.查看ipc资源及其特征5.共享内存的优缺点6.共享内存的数据结构 四、…

ADAudit Plus:强大的网络安全卫士

随着数字化时代的不断发展,企业面临着越来越复杂和多样化的网络安全威胁。在这个信息爆炸的时代,保护组织的敏感信息和确保网络安全已经成为企业发展不可或缺的一环。为了更好地管理和监控网络安全,ADAudit Plus应运而生,成为网络…

【队列】数据也得排队

目录 引言 队列的概念 队列的实现 单向链表队列 结构 初始化 入队 出队 取队头 取队尾 求个数 判空 内存释放 总结 引言 队列,这个看似普通的数据结构,其实隐藏着无尽的趣味和巧思。就像单向链表这把神奇的魔法钥匙,它能打开队…

解决Git提交错误分支

如果 Git 提交到错误的分支&#xff0c;可以通过以下步骤将其转移到正确的分支上&#xff1a; 1.检查当前所在的分支&#xff0c;可以通过 git branch 命令查看。 git branch2.切换到正确的分支&#xff0c;可以通过 git checkout <正确的分支名> 命令进行切换。 git …

vue3-vite前端快速入门教程 vue-element-admin

Vue3快速入门学习 初始化项目 # 创建项目 npm create vitelatest my-vue-app -- --template vue # 安装依赖 npm i # 运行 npm run dev 模板语法 文本插值​ 最基本的数据绑定形式是文本插值&#xff0c;它使用的是“Mustache”语法 (即双大括号)&#xff1a; <span&g…

三相不平衡电压的正负序分析

1、什么是正负序&#xff1f; ABC 正序 ACB 负序 2、在abc坐标系下 接着利用矢量的旋转消去其它分量。。。 同理&#xff0c;得到其它的所有正负序的分量abc 3、在α/β坐标系下&#xff0c; 依次算出正负序的α/β来表示的abc 有一点需要特别注意&#xff0c;可以看到…

贪心其实很简单

关卡名 认识贪心思想 我会了✔️ 内容 1.复习一维数组&#xff0c;对数组进行多轮插入或者删除时会频繁移动数据&#xff0c;理解双指针是如何避免该问题的 ✔️ 2.理解滑动窗口的原理和适用场景 ✔️ 3.掌握窗口变与不变的两种情况是如何用来解题的 ✔️ 1.难以解释的贪心…

基于SpringBoot+Vue前后端分离的商城管理系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

【Linux】进程周边001之进程概念

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.基本概念 2.描述进程-PCB…

贪心算法及相关题目

贪心算法概念 贪心算法是指&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;算法得到的是在某种意义上的局部最优解 。 贪心算法性质&#xff08;判断是否可以使用贪心算法&#xff09; 1、贪…

【SpringBoot教程】SpringBoot 创建定时任务(配合数据库动态执行)

作者简介&#xff1a;大家好&#xff0c;我是撸代码的羊驼&#xff0c;前阿里巴巴架构师&#xff0c;现某互联网公司CTO 联系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗…

DDD系列 - 第6讲 仓库Repository及Mybatis、JPA的取舍(一)

目录 一、领域层定义仓库接口1.1 设计聚合1.2 定义仓库Repository接口二 、基础设施层实现仓库接口2.1 设计数据库2.2 集成Mybatis2.3 引入Convetor2.4 实现仓库三、回顾一、领域层定义仓库接口 书接上回,之前通过一个关于拆解、微服务、面向对象的故事,向大家介绍了如何从微…

mysql中的DQL查询

表格为&#xff1a; DQL 基础查询 语法&#xff1a;select 查询列表 from 表名&#xff1a;&#xff08;查询的结果是一个虚拟表格&#xff09; -- 查询指定的列 SELECT NAME,birthday,phone FROM student -- 查询所有的列 * 所有的列&#xff0c; 查询结果是虚拟的表格&am…

【GlobalMapper精品教程】067:基于无人机航拍照片快速创建正射影像图

文章目录 一、加载无人机照片二、创建正射影像三、导出正射影像四、worldImagery比对一、加载无人机照片 打开globalmapper软件,点击打开数据文件。 选择配套实验数据data067.rar中的影像,Ctrl+A全选。 在globalmapper中,可以直接将照片加载为如下样式。 二、创建正射影像 …

深入理解网络中断:原理与应用

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

[GPT]Andrej Karpathy微软Build大会GPT演讲(下)--该如何使用GPT助手

该如何使用GPT助手--将GPT助手模型应用于问题 现在我要换个方向,让我们看看如何最好地将 GPT 助手模型应用于您的问题。 现在我想在一个具体示例的场景里展示。让我们在这里使用一个具体示例。 假设你正在写一篇文章或一篇博客文章,你打算在最后写这句话。 加州的人口是阿拉…

【参天引擎】华为参天引擎内核架构专栏开始更新了,多主分布式数据库的特点,类oracle RAC国产数据开始出现了

cantian引擎的介绍 ​专栏内容&#xff1a; 参天引擎内核架构 本专栏一起来聊聊参天引擎内核架构&#xff0c;以及如何实现多机的数据库节点的多读多写&#xff0c;与传统主备&#xff0c;MPP的区别&#xff0c;技术难点的分析&#xff0c;数据元数据同步&#xff0c;多主节点的…