高级用法#

本节为高级用户详细介绍推理脚本。

确保提供的客户端软件在 PYTHONPATH 中,并运行以下命令来设置客户端。

import os
import sys
import grpc

sys.path.append(os.path.join(os.getcwd(), "../interfaces"))
# Importing gRPC compiler auto-generated maxine eyecontact library
from eye_contact import eyecontact_pb2, eyecontact_pb2_grpc

NIM 调用使用双向 gRPC 流。要生成请求数据流,请定义一个 Python 生成器函数。这也称为 Python 迭代器,形式为一个简单的函数,在调用后产生结果。yield 返回要流式传输的块。流中的第一项用于配置对象,该对象设置 NVIDIA Maxine 眼神交流功能参数。

def generate_request_for_inference(
    input_filepath: str = "input.mp4", params: dict = {}
):
    """Generator to produce the request data stream
    Args:
      input_filepath: Path to input file
      params: Parameters for the feature
    """
    DATA_CHUNKS = 64 * 1024  # bytes, we send the mp4 file in 64KB chunks
    if params:  # if params is supplied, the first item in the input stream is a config object with parameters
        yield eyecontact_pb2.RedirectGazeRequest(
            config=eyecontact_pb2.RedirectGazeConfig(**params)
        )
    with open(input_filepath, "rb") as fd:
        while True:
            buffer = fd.read(DATA_CHUNKS)
            if buffer == b"":
                break
            yield eyecontact_pb2.RedirectGazeRequest(video_file_data=buffer)


以下参数可在此 NIM 中使用

  • temporal - (UINT32) 用于控制时间滤波的标志(默认 0xffffffff)。设置为 true 时,眼神交流的地标计算将进行时间优化。

  • detect_closure - (UINT32) 用于切换眼睛闭合和遮挡检测的标志。值为 0 或 1。(默认 0)。

  • eye_size_sensitivity - (UINT32) 眼睛大小敏感度参数,一个介于 2 到 6 之间的整数值(默认 3)

  • enable_lookaway - (UINT32) 用于切换视线移开功能的标志。如果设置为开启,眼睛会偶尔被重定向到随机看向别处一段时间,以避免凝视。值为 0 或 1。(默认 0)

  • lookaway_max_offset - (UINT32) 随机看向别处时,注视偏移角(度)的最大值,一个介于 1 到 10 之间的整数值(默认 5)

  • lookaway_interval_min - (UINT32) 随机看向别处发生的最小帧数限制,一个介于 1 到 600 之间的整数值(默认 100)

  • lookaway_interval_range - (UINT32) 用于选择随机看向别处发生的帧数范围,一个介于 1 到 600 之间的整数值(默认 250)

  • gaze_pitch_threshold_low - (FP32) 注视俯仰角阈值(度),在该阈值下,重定向开始从远离相机过渡到估计的注视方向,浮点数,介于 10 到 35 之间(默认 20)

  • gaze_pitch_threshold_high - (FP32) 注视俯仰角阈值(度),在该阈值下,重定向等于估计的注视方向,浮点数,介于 10 到 35 之间(默认 30)

  • gaze_yaw_threshold_low - (FP32) 注视偏航角阈值(度),在该阈值下,重定向开始从远离相机过渡到估计的注视方向,浮点数,介于 10 到 35 之间(默认 20)

  • gaze_yaw_threshold_high - (FP32) 注视偏航角阈值(度),在该阈值下,重定向等于估计的注视方向,浮点数,介于 10 到 35 之间(默认 30)

  • head_pitch_threshold_low - (FP32) 头部姿势俯仰角阈值(度),在该阈值下,重定向开始从远离相机过渡到估计的注视方向,浮点数,介于 10 到 35 之间(默认 15)

  • head_pitch_threshold_high - (FP32) 头部姿势俯仰角阈值(度),在该阈值下,重定向等于估计的注视方向,浮点数,介于 10 到 35 之间(默认 25)

  • head_yaw_threshold_low - (FP32) 头部姿势偏航角阈值(度),在该阈值下,重定向开始从远离相机过渡到估计的注视方向,浮点数,介于 10 到 35 之间(默认 25)

  • head_yaw_threshold_high - (FP32) 头部姿势偏航角阈值(度),在该阈值下,重定向等于估计的注视方向,浮点数,介于 10 到 35 之间(默认 30)

在调用 NIM 之前,定义一个处理传入流并将其写入输出文件的函数。有关此算法技术方面的更多详细信息,请参阅技术博客

from typing import Iterator

def write_output_file_from_response(
    response_iter: Iterator[eyecontact_pb2.RedirectGazeResponse],
    output_filepath: str = "output.mp4",
) -> None:
    """Function to write the output file from the incoming gRPC data stream.
    Args:
      response_iter: Responses from the server
      output_filepath: Path to output file
    """
    with open(output_filepath, "wb") as fd:
        for response in response_iter:
            fd.write(response.video_file_data)


现在我们已经设置了请求生成器和输出迭代器,连接到 NIM 并调用它。输入文件路径在变量 input_filepath 中,输出文件写入在变量 output_filepath 中的位置。params 是一个 Python 字典,其中包含功能参数名称和值对。如果 params 为空,则使用默认值。

等待消息确认函数调用已完成,然后再检查输出文件。在下面的代码片段中填写目标主机的正确主机和端口

import time

input_filepath = "../assets/sample_input.mp4"
output_filepath = "output.mp4"
params = {}
# params = {"eye_size_sensitivity": 4, "detect_closure": 1 } # example of setting parameters

with grpc.insecure_channel(target="localhost:8004") as channel:
    try:
        stub = eyecontact_pb2_grpc.MaxineEyeContactServiceStub(channel)
        start_time = time.time()
        responses = stub.RedirectGaze(
            generate_request_for_inference(input_filepath=input_filepath, params=params)
        )
        if params:
            _ = next(responses)  # if we passed the config, the first output
                                # in the stream will be an echo which we will ignore
        write_output_file_from_response(
            response_iter=responses, output_filepath=output_filepath
        )
        end_time = time.time()
        print(
            f"Function invocation completed in {end_time-start_time:.2f}s, the output file is generated."
        )
    except BaseException as e:
        print(e)


多路并发输入#

要在多输入并发模式下运行服务器,请在服务器容器中将环境变量 MAXINE_MAX_CONCURRENCY_PER_GPU 设置为大于 1 的整数。然后,服务器将接受每个 GPU 的并发输入,数量由 MAXINE_MAX_CONCURRENCY_PER_GPU 变量指定。

由于 Triton 在所有 GPU 上平均分配工作负载,因此如果有 NUM_GPUS 个 GPU,则服务器支持的并发输入总数将为 NUM_GPUS * MAXINE_MAX_CONCURRENCY_PER_GPU

模型缓存#

当容器首次启动时,它将从 NGC 下载所需的模型。为了避免在后续运行时下载模型,您可以使用缓存目录在本地缓存它们

# Create the cache directory on the host machine
export LOCAL_NIM_CACHE=~/.cache/nim
mkdir -p "$LOCAL_NIM_CACHE"
chmod 777 $LOCAL_NIM_CACHE

# Run the container with the cache directory mounted in the appropriate location
docker run -it --rm --name=maxine-eye-contact-nim \
  --net host \
  --runtime=nvidia \
  --gpus all \
  --shm-size=8GB \
  -e NGC_API_KEY=$NGC_API_KEY \
  -e MAXINE_MAX_CONCURRENCY_PER_GPU=1 \
  -e NIM_HTTP_API_PORT=9000 \
  -e NIM_GRPC_API_PORT=50051 \
  -p 9000:9000 \
  -p 50051:50051 \
  -v "$LOCAL_NIM_CACHE:/home/nvs/.cache/nim" \
  nvcr.io/nim/nvidia/maxine-eye-contact:latest