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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4.qml 3D-Light、DirectionalLight、PointLight、SpotLight、AxisHelper类深入学习

今天我们学习灯光类 首先来学习Light类,它是所有灯光的虚基类,该类是无法创建的,主要是为子类提供很多公共属性。 常用属性如下所示: ambientColor : color,该属性定义在被该光照亮之前应用于材质的环境颜色。默认值…

neo4j如何创建多个数据库

1.在neo4j的压缩包解压位置找到neo4j.conf文件 "D:\neo4j\neo4j-community-3.5.5\conf\neo4j.conf"2.修改文件 新增dbms.activate_database**.db 再重新neo4j打开网页就进入到新建的数据库中 如果要切换,就把原来的注释掉就可以

Python移动未标注的图片数据集

Python移动未标注的图片数据集 前言前提条件相关介绍实验环境Python移动未标注的图片数据集情况一:有图,无标注文件代码实现输出结果 情况二:有图,有标注文件,但标注信息为空代码实现输出结果 情况一与情况二同时都考虑…

Leetcode 455 分发饼干

题意理解: 小孩的饭量: [1,2,7,10] 饼的大小: [1,3,5,7] 当饼的大小>小孩饭量时,小孩就能够吃饱。 求如何分配饼让更多的小孩子能够吃饱。 解题思路: 两种思路: 先把胃口小的孩子用较小的饼来喂饱—…

ida脚本环境开发配置idapythonidacpp三端环境(win,mac,linux)

ida脚本也有一段时间了,一直有个痛点是找不到比较好的方法热重载脚本来实时改动生效,导致开发效率老慢了。固总结下比较友好的环境搭配 使用ida热加载插件让你开发脚本更高效 github地址: GitHub - 0xeb/ida-qscripts: An IDA plugin to increase productivity when developi…

MATLAB 系统辨识 + PID 自动调参

MATLAB 系统辨识 PID 自动调参 Matlab R2021b下载安装详细教程Chapter1 MATLAB 系统辨识 PID 自动调参1. 导入数据2. 系统辨识3. PID 自动调参 Chapter2 MATLAB系统辨识Chapter3 【MATLAB】使用系统辨识工具箱(System Identification)建模Chapter4 matlab系统辨识工具箱及其反…

探索 Coinbase 二层链 Base 的潜力与风险

作者:lesleyfootprint.network 在不断变化的加密货币领域,Coinbase 已经确立了自己领先中心化交易所(CEX)的地位。然而,Coinbase 坚信去中心化是创造一个开放、全球范围内对每个人都可访问的加密经济的关键&#xff0…

Go map转json

今天分享的知识是 Go 接口。如果本文对你有帮助,不妨点个赞,如果你是 Go 语言初学者,不妨点个关注,一起成长一起进步,如果本文有错误的地方,欢迎指出! 但当有的场景,要返回哪些字段…

工作记录-------实现实时排行榜的各种方法---12.14

实时积分排行榜 需求 提供一个用户积分排行榜–为 实时总积分榜, 只取前 10 名 。所有用户都能够查看当前排行榜,以及查看自己的 实时总积分排名 设计实现 先看下数据库的结构,总共有 2 个表:用户表 和 用户积分表。 用户表存储了用户信息,以及用户的总积分(实时更新…

电商控制台前台整合优化

前台逻辑 显示商品菜单输入id,进入某个商品检测登录和注册 根据登录和注册的状态,订单或者是购物车都需要登录。 登录:生成订单(先生成订单表,再生成订单详情表) 开发直接购买,加入购物车, …

计算机毕业设计 基于SpringBoot的日常办公用品直售推荐系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

做性能测试必须掌握的基本概念和套路

经常听到人说,做个性能优化,吞吐量越高越好;或者做个性能测试,目标TPS是50000。可实际拿到这个信息,能够做性能测试吗?这个目标足够清晰吗?事实上,在我看来,未定义清晰 …

Ubuntu18.04.6下安装opencv库及OpenCV安装libjasper-dev依赖包错误

目录 01 解压安装包 02 安装cmake和依赖库 03 配置编译环境 01 解压安装包 创建一个名为Opencv的文件夹 mkdir opencv 将源码的压缩包复制到opencv目录下 将压缩包解压到opencv文件夹(指定一个文件夹) unzip opencv-3.4.11.zip -d opencv02 安装cm…

Web3.0:抗寻租的互联网平台经济

在数字世界的荒蛮时代,人类的数字大迁徙,纷乱而芜杂,充满着未知与蒙昧。 我们致敬先行者,感恩在黑暗中点亮火把,在泥泞中探索前行的道路。 我们以先行者为师,承续他们的智慧与勇气,在人类数字大…

【强化学习-读书笔记】动态规划(策略评估、价值迭代、策略迭代算法)

参考 Reinforcement Learning, Second Edition An Introduction By Richard S. Sutton and Andrew G. Barto动态规划 (Dynamic Programming, DP) 是一类优化方法,在给定一个用马尔可夫决策过程 (MDP) 描述的完备环境模型的情况下,其可以计算最优的策…

【Jeecg Boot 3 - 保姆级】第1节 docker + redis + nginx + redis一键安装启动

一、前言 ▶ JEECG-BOOT 开源版难以吃透的原因 ▶ 为了针对上面痛点,笔者做了如下安排 ▶ 你能收获什么 二、效果(第一节效果) ▶ 启动后端 > 日志 > 接口文档 ▶ 启动前端 三、准备工作 四、实战 ▶ 1、服务器安装 Stag…

RF模块是如何工作的?

射频(RF)模块使用无线电频率工作,这个频率范围在30kHz到300kHz之间变化。 在这个射频系统中,数字数据被表示为载波波幅度的变化。这种调制类型是振幅移位键。 这个射频模块是射频发射器和接收器的组合,发射器接收器对的…

读书笔记-《数据结构与算法》-摘要6[快速排序]

快速排序 核心:快排是一种采用分治思想的排序算法,大致分为三个步骤。 定基准——首先随机选择一个元素最为基准划分区——所有比基准小的元素置于基准左侧,比基准大的元素置于右侧递归调用——递归地调用此切分过程 快排的实现与『归并排…

伪距单点定位概念与原理、算例分析

目录 一、概念与原理 1.伪距观测值 2.为何被称为"伪距" ? 3.单点定位的概念 4.伪距单点定位的原理 5.伪距单点定位的优缺点 二、伪距观测方程 三、伪距观测方程线性化 1.泰勒级数展开 2.得到线性化后的观测方程 3.在某历元接收机同时观测n颗卫星&#xf…

视频号小店需要缴纳保证金吗?保证金缴纳标准,不懂的快来看!

我是电商珠珠 入驻视频号小店,需要缴纳保证金吗?具体缴纳多少?... 这是想要入驻视频号小店的热门话题,今天我就来给大家一一讲明白。 想要入驻视频号小店,就必须要缴纳保证金。保证金是平台为了约束商家的行为&…