借助 NVIDIA 视觉编程接口库(VPI),您可以更有效地利用 Jetson Thor 的计算性能。
构建自主机器人需要具备可靠且低延迟的视觉感知能力,以实现在动态环境中的深度估计、障碍物识别、定位与导航。这些功能对计算性能有较高要求。NVIDIA Jetson 平台虽为深度学习提供了强大的 GPU 支持,但随着 AI 模型复杂性的提升以及对实时性能的更高需求,GPU 可能面临过载风险。若将所有感知任务完全依赖 GPU 执行,不仅容易造成性能瓶颈,还可能导致功耗上升和散热压力加剧,这在功耗受限且散热条件有限的移动机器人应用中尤为突出。
为解决上述挑战,NVIDIA Jetson 平台将高性能 GPU 与专用硬件加速器相结合。Jetson AGX Orin 和 Jetson Thor 等平台均配备专用硬件加速器,专为高效执行图像处理和计算机视觉任务而设计,从而释放 GPU 资源,使其能够专注于处理更复杂的深度学习工作负载。NVIDIA 视觉编程接口(VPI)进一步充分激活了不同类型硬件加速器的性能潜力。
在本博客中,我们将探讨使用这些加速器的优势,并详细介绍开发者如何通过 VPI 充分发挥 Jetson 平台的性能潜力。作为示例,我们将展示如何运用这些加速器开发一个用于立体视差的低延迟、低功耗的感知应用。首先,我们将构建单路立体摄像头的工作流,随后扩展至多流工作流,在 Thor T5000 上支持 8 路立体摄像头同时以 30 FPS 运行,其性能相较 Orin AGX 64 GB 提升至 10 倍。
在开始开发之前,让我们快速了解 Jetson 平台提供的各类加速器,它们的优势所在,能够支持哪些应用场景,以及 VPI 如何为开发提供助力。
除了 GPU 之外,Jetson 还配备了哪些其他加速器?
Jetson 设备配备了强大的 GPU,适用于深度学习任务,但随着 AI 复杂性的提升,对 GPU 资源的高效管理变得愈发重要。Jetson 为计算机视觉(CV)工作负载提供了专用的硬件加速引擎。这些引擎与 GPU 协同工作,在保持灵活性的同时,显著提升了计算效率。通过 VPI,开发者可以更便捷地访问这些硬件资源,简化实验流程并实现高效的负载分配。

图 1:面向 Jetson 开发者的视觉编程接口(VPI)
下面我们逐一深入了解每个加速器,以及其用途与优势。
可编程视觉加速器 (PVA) :
PVA 是一款可编程的数字信号处理(DSP)引擎,配备超过 1024 位的单指令多数据(SIMD)单元,以及支持灵活直接内存访问(DMA)的本地内存,专为视觉和图像处理任务优化,具备出色的每瓦性能。它能够与 CPU、GPU 及其他加速器异步运行,除 NVIDIA Jetson Nano 外,其他所有 Jetson 平台均配备该加速器。
通过 VPI,开发者可以调用现成的算法,如 AprilTag 检测、物体追踪,和立体视差估计。对于需要自定义算法的场景,Jetson 开发者现在还可使用 PVA SDK,该 SDK 提供了 C/C++ API 及相关工具,支持直接在 PVA 上开发视觉算法。
光流加速器 (OFA) :
OFA 是一种固定功能的硬件加速器,用于基于立体摄像头对的数据,计算光流和立体视差。OFA 支持两种工作模式:在视差模式下,通过处理立体摄像头的左右校正图像来生成视差图;在光流模式下,则用于估算连续两帧之间的二维运动矢量。
视频和图像合成器 (VIC) :
VIC 是 Jetson 设备中的一种专用硬件加速器,具备固定功能,能够高效节能地处理图像缩放、重映射、扭曲、色彩空间转换和降噪等基础图像处理任务。
哪些用例可以从这些加速器中获益?
在某些场景下,开发者可能会考虑采用 GPU 以外的解决方案,以更好地满足特定应用的需求。
GPU 资源过载应用: 为实现高效运行,开发者应优先将深度学习(DL)工作负载分配给 GPU,同时利用 VPI 将计算机视觉任务卸载至 PVA、OFA 或 VIC 等专用加速器。例如,DeepStream 的 Multi+ Object Tracker 在 Orin AGX 平台上若仅依赖 GPU,可处理 12 路视频流;而通过引入 PVA 实现负载均衡后,支持的视频流数量可提升至 16 路。
功耗敏感型应用: 在哨兵模式(sentry mode)或持续监控等场景中,将主要计算任务转移至低功耗加速器(如 PVA、OFA、VIC),有助于显著提升效率。
存在热限制的工业应用: 在高温运行环境下,合理分配任务至各类加速器可有效降低 GPU 负载,减少因过热导致的性能节流,从而在限定的热预算内维持稳定的延迟与吞吐表现。
如何使用 VPI 解锁所有加速器
VPI 提供了一个统一且灵活的框架,使开发者能够在 Jetson 模组、工作站或配备独立 GPU 的 PC 等不同平台上无缝访问加速器。
现在,我们来看一个综合运用上述内容的示例。
示例:立体视觉工作流
现代机器人系统通常采用被动立体视觉技术实现对周围环境的三维感知。因此,计算立体视差图成为构建复杂感知系统的关键环节。本文将介绍一个示例流程,帮助开发者生成立体视差图及其对应的置信度图。同时,我们将展示如何利用 VPI 提供的各类加速器,构建低延迟、高能效的处理工作流。

图 2:在 Jetson 多加速器上部署的立体视觉流程示意图。PVA+:可编程视觉阵列;VIC:视频与图像合成器;OFA:光流加速器。
在 CPU 上进行预处理:预处理步骤可以在 CPU 上运行,因为它只发生一次。该步骤计算一个校正映射(rectification map),用于纠正立体相机帧中的镜头畸变。
在 VIC 上进行重映射:这一步骤使用预计算的校正映射对相机帧去畸变并对齐,确保两条光轴水平且平行。VPI 支持多项式与鱼眼畸变模型,并允许开发者定义自定义 warp 映射。更多细节可参考 Remap 文档。
在 OFA 上计算立体视差:校正后的图像对作为半全局匹配(SGM)算法的输入。在实际应用中,SGM 可能会产生噪声或错误的视差值。通过生成置信度图,可以剔除低置信度的视差估计,从而提升结果质量。有关 SGM 算法及其支持参数的更多信息,请参阅 立体视差文档。
在 PVA 上生成置信度图:VPI 提供三种置信度图模式:绝对值(Absolute)、相对值(Relative)和推理(Inference)。绝对值和相对值模式需要两个 OFA 通道(左/右视差)并结合 PVA 的交叉检查机制;而推理模式仅需一个 OFA 通道,并在 PVA 上运行一个轻量级 CNN(包含两个卷积层和两个非线性激活层)。跳过置信度计算虽然速度较快,但会产生噪声视差图;相比之下,采用相对值或推理模式可显著提升视差结果的精度与可靠性。
VPI 的统一内存架构避免了跨引擎的不必要数据复制,其异步流与事件机制使开发者能够提前规划任务负载和同步点。由硬件管理的调度支持跨引擎并行执行,既释放了 CPU 资源,又通过高效的流式流程设计避免了延迟。
使用 VPI 构建高性能立体视差工作流
开始使用 Python API
本教程介绍如何使用 VPI Python API 实现基础的立体视差工作流,且无需进行图像重映射。
需要提前准备:
NVIDIA Jetson 设备(例如 Jetson AGX Thor)
通过 NVIDIA SDK Manager 或 apt 安装 VPI
Python 库:vpi、numpy、Pillow、opencv-python
在本教程中,我们将:
加载左右立体图像
转换图像格式以适配处理需求
同步数据流,确保信息准备就绪
执行立体匹配算法以计算视差
对输出结果进行后处理并保存
设置和初始化
第一步是导入所需的库并创建 VPIStream 对象。VPIStream 充当命令队列,可用于提交任务以实现异步执行。为了演示并行处理,我们将使用两个流。
import vpi import numpy as np from PIL import Image from argparse import ArgumentParser # Create two streams for parallel processing streamLeft = vpi.Stream() streamRight = vpi.Stream()
streamLeft 用于处理左侧图像,streamRight 用于处理右侧图像。
加载和转换图像
VPI 的 Python API 可直接使用 NumPy 数组。我们首先通过 Pillow 加载图像,然后利用 VPI 的 asimage 函数将其封装为 VPI 图像对象。接着,将图像转换为适用于立体匹配算法的格式。在本例中,图像将从 RGBA8 格式转换为 Y8_ER_BL 格式(即 8 位灰度、块线性布局)。
# Load images and wrap them in VPI images left_img = np.asarray(Image.open(args.left)) right_img = np.asarray(Image.open(args.right)) left = vpi.asimage(left_img) right = vpi.asimage(right_img) # Convert images to Y8_ER_BL format in parallel on different backends left = left.convert(vpi.Format.Y8_ER_BL, scale=1, stream=streamLeft, backend=vpi.Backend.VIC) right = right.convert(vpi.Format.Y8_ER_BL, scale=1, stream=streamRight, backend=vpi.Backend.CUDA)
左侧图像通过 streamLeft 提交至 VIC 后端进行处理,右侧图像则通过 streamRight 提交给 NVIDIA CUDA 后端。这种设计使得两项操作能够在不同的硬件单元上并行执行,充分体现了 VPI 的核心优势。
同步并执行立体差异
在执行立体差异计算之前,必须确保两张图像均已准备就绪。我们调用 streamLeft.sync() 来阻塞主线程,直至左侧图像的转换完成。随后,便可向 streamRight 提交 vpi.stereodisp 操作。
# Synchronize streamLeft to ensure the left image is ready streamLeft.sync() # Submit the stereo disparity operation on streamRight disparityS16 = vpi.stereodisp(left, right, backend=vpi.Backend.OFA|vpi.Backend.PVA|vpi.Backend.VIC, stream=streamRight)
立体差异算法在 VPI 后端(OFA、PVA、VIC)的组合上运行,以充分利用专用硬件,最终生成一张 S16 格式的差异图,用于表示两幅图像中对应像素之间的水平偏移。
后处理和可视化
对原始差异图进行后处理以实现可视化时,将Q10.5定点格式表示的差异值缩放到0-255范围内并保存。
# Post-process the disparity map
# Convert Q10.5 to U8 and scale for visualization
disparityU8 = disparityS16.convert(vpi.Format.U8, scale=255.0/(32*128), stream=streamRight, backend=vpi.Backend.CUDA)
# make accessible in cpu
disparityU8 = disparityU8.cpu()
#save with pillow
d_pil = Image.fromarray(disparityU8)
d_pil.save('./disparity.png')
最后一步是将原始数据转换为人类可读的图像,其中灰度值代表深度信息。
使用 C++ API 的多流差异工作流
先进的机器人技术依赖于高吞吐量,而 VPI 通过并行多流传输实现了这一需求。凭借简洁的 API 与硬件加速器的高效结合,VPI 使开发者能够构建快速且可靠的视觉处理流程——与波士顿动力(Boston Dynamics)新一代机器人系统的处理流程相似。
VPI 采用 VPIStream 对象,这些对象作为先进先出(FIFO)的命令队列,可异步地向后端提交任务,从而实现不同硬件单元上的并行运算执行(异步流)。
对于任务关键、追求极致性能的应用,VPI 的 C++ API 是理想之选。
以下代码片段源自 C++ 基准测试,用于演示多流立体视差工作流的构建与执行过程。该示例通过 SimpleMultiStreamBenchmark C++ 应用实现:首先预生成合成的 NV12_BL 格式图像,以消除运行时生成数据带来的开销;随后并行处理多个数据流,并测量每秒帧数(FPS)以评估吞吐性能。此外,该工具支持保存输入图像以及差异图和置信度图,便于调试分析。通过预生成数据的方式,本示例可有效模拟高速实时工作负载场景。
资源配置、对象声明与初始化
我们首先声明并初始化 VPI 中执行该流水线所需的全部对象,包括创建流、输入/输出图像以及立体视觉处理所需的有效载荷。由于立体算法的输入图像格式为 NV12_BL,因此我们将其与 Y8_Er 图像类型一同设置为中间格式转换的格式。
int totalIterations = itersPerStream * numStreams; std::vectorleftInputs(numStreams), rightInputs(numStreams), confidences(numStreams), leftTmps(numStreams), rightTmps(numStreams); std::vector leftOuts(numStreams), rightOuts(numStreams), disparities(numStreams); std::vector stereoPayloads(numStreams); std::vector streamsLeft(numStreams), streamsRight(numStreams); std::vector events(numStreams); int width = cvImageLeft.cols; int height = cvImageLeft.rows; int vic_pva_ofa = VPI_BACKEND_VIC | VPI_BACKEND_OFA | VPI_BACKEND_PVA; VPIStereoDisparityEstimatorCreationParams stereoPayloadParams; VPIStereoDisparityEstimatorParams stereoParams; CHECK_STATUS(vpiInitStereoDisparityEstimatorCreationParams(&stereoPayloadParams)); CHECK_STATUS(vpiInitStereoDisparityEstimatorParams(&stereoParams)); stereoPayloadParams.maxDisparity = 128; stereoParams.maxDisparity= 128; stereoParams.confidenceType = VPI_STEREO_CONFIDENCE_RELATIVE; for (int i = 0; i < numStreams; i++) { CHECK_STATUS(vpiImageCreateWrapperOpenCVMat(cvImageLeft, 0, &leftInputs[i])); CHECK_STATUS(vpiImageCreateWrapperOpenCVMat(cvImageRight, 0, &rightInputs[i])); CHECK_STATUS(vpiStreamCreate(0, &streamsLeft[i])); CHECK_STATUS(vpiStreamCreate(0, &streamsRight[i])); CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_Y8_ER, 0, &leftTmps[i])); CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_NV12_BL, 0, &leftOuts[i])); CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_Y8_ER, 0, &rightTmps[i])); CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_NV12_BL, 0, &rightOuts[i])); CHECK_STATUS(vpiCreateStereoDisparityEstimator(vic_pva_ofa, width, height, VPI_IMAGE_FORMAT_NV12_BL, &stereoPayloadParams, &stereoPayloads[i])); CHECK_STATUS(vpiEventCreate(0, &events[i])); } int outCount = saveOutput ? (numStreams * itersPerStream) : numStreams; disparities.resize(outCount); confidences.resize(outCount); for (int i = 0; i < outCount; i++) { CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_S16, 0, &disparities[i])); CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_U16, 0, &confidences[i])); }
转换图像格式
我们使用 VPI 的 C API 为每个流提交图像转换操作,将来自摄像头的 NV12_BL 输入模拟帧进行格式转换。
for (int i = 0; i < numStreams; i++)
{
CHECK_STATUS(vpiSubmitConvertImageFormat(streamsLeft[i], VPI_BACKEND_CPU, leftInputs[i], leftTmps[i], NULL));
CHECK_STATUS(vpiSubmitConvertImageFormat(streamsLeft[i], VPI_BACKEND_VIC, leftTmps[i], leftOuts[i], NULL));
CHECK_STATUS(vpiEventRecord(events[i], streamsLeft[i]));
CHECK_STATUS(vpiSubmitConvertImageFormat(streamsRight[i], VPI_BACKEND_CPU, rightInputs[i], rightTmps[i], NULL));
CHECK_STATUS(vpiSubmitConvertImageFormat(streamsRight[i], VPI_BACKEND_VIC, rightTmps[i], rightOuts[i], NULL));
CHECK_STATUS(vpiStreamWaitEvent(streamsRight[i], events[i]));
}
for (int i = 0; i < numStreams; i++)
{
CHECK_STATUS(vpiStreamSync(streamsLeft[i]));
CHECK_STATUS(vpiStreamSync(streamsRight[i]));
}
我们将操作分别提交到两个独立流的不同硬件上,具体类型由输入/输出图像的类型推断得出。此次,我们还将在左侧流完成转换操作后记录一个 VPIEvent。VPIEvent 是一种 VPI 对象,能够在流录制过程中等待另一个流完成所有操作。通过这种方式,我们可以让右侧流等待左侧流的转换操作完成,而无需阻塞调用线程(即主线程),从而实现多个左侧流与右侧流的并行执行。
同步并执行立体差异
我们通过 VPI 的 C API 提交立体匹配计算任务,并使用 std::chrono 对其性能进行基准测试。
auto benchmarkStart = std::chrono::high_resolution_clock::now();
for (int iter = 0; iter < itersPerStream; iter++)
{
for (int i = 0; i < numStreams; i++)
{
int dispIdx = saveOutput ? (i * itersPerStream + iter) : i;
CHECK_STATUS(vpiSubmitStereoDisparityEstimator(streamsRight[i], vic_pva_ofa, stereoPayloads[i], leftOuts[i],
rightOuts[i], disparities[dispIdx], confidences[dispIdx],
&stereoParams));
}
}
// ====================
// End Benchmarking
for (int i = 0; i < numStreams; i++)
{
CHECK_STATUS(vpiStreamSync(streamsRight[i]));
}
auto benchmarkEnd = std::chrono::high_resolution_clock::now();
我们继续使用 confidenceMap 提交计算任务,并生成结果差异图。同时,停止基准测试计时器,记录转换和生成差异所耗的时间。在向所有流提交任务后,显式同步各个流,以确保调用线程在提交过程中不会被阻塞。
后处理和清理
我们利用 VPI 的 C API 与 OpenCV 的互操作性对差异图进行后处理,并在每次迭代循环中将其保存。可根据需要选择保留输出数据以供检查,循环结束后再清理相关对象。
// ====================
// Save Outputs
if (saveOutput)
{
for (int i = 0; i < numStreams * itersPerStream; i++)
{
VPIImageData dispData, confData;
cv::Mat cvDisparity, cvDisparityColor, cvConfidence, cvMask;
CHECK_STATUS(
vpiImageLockData(disparities[i], VPI_LOCK_READ, VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR, &dispData));
vpiImageDataExportOpenCVMat(dispData, &cvDisparity);
cvDisparity.convertTo(cvDisparity, CV_8UC1, 255.0 / (32 * stereoParams.maxDisparity), 0);
applyColorMap(cvDisparity, cvDisparityColor, cv::COLORMAP_JET);
CHECK_STATUS(vpiImageUnlock(disparities[i]));
std::ostringstream fpStream;
fpStream << "stream_" << i / itersPerStream << "_iter_" << i % itersPerStream << "_disparity.png";
imwrite(fpStream.str(), cvDisparityColor);
// Confidence output (U16 -> scale to 8-bit and save)
CHECK_STATUS(
vpiImageLockData(confidences[i], VPI_LOCK_READ, VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR, &confData));
vpiImageDataExportOpenCVMat(confData, &cvConfidence);
cvConfidence.convertTo(cvConfidence, CV_8UC1, 255.0 / 65535.0, 0);
CHECK_STATUS(vpiImageUnlock(confidences[i]));
std::ostringstream fpStreamConf;
fpStreamConf << "stream_" << i / itersPerStream << "_iter_" << i % itersPerStream << "_confidence.png";
imwrite(fpStreamConf.str(), cvConfidence);
}
}
// ====================
// Clean Up VPI Objects
for (int i = 0; i < numStreams; i++)
{
CHECK_STATUS(vpiStreamSync(streamsLeft[i]));
CHECK_STATUS(vpiStreamSync(streamsRight[i]));
vpiStreamDestroy(streamsLeft[i]);
vpiStreamDestroy(streamsRight[i]);
vpiImageDestroy(rightInputs[i]);
vpiImageDestroy(leftInputs[i]);
vpiImageDestroy(leftTmps[i]);
vpiImageDestroy(leftOuts[i]);
vpiImageDestroy(rightTmps[i]);
vpiImageDestroy(rightOuts[i]);
vpiPayloadDestroy(stereoPayloads[i]);
vpiEventDestroy(events[i]);
}
// Destroy all disparity and confidence images
for (int i = 0; i < (int)disparities.size(); i++)
{
vpiImageDestroy(disparities[i]);
}
for (int i = 0; i < (int)confidences.size(); i++)
{
vpiImageDestroy(confidences[i]);
}
收集基准测试结果
我们现在能够收集并展示基准测试的结果。
double totalTimeSeconds = totalTime / 1000000.0; double avgTimePerFrame = totalTimeSeconds / totalIterations; double throughputFPS= totalIterations / totalTimeSeconds; std::cout << "\n" << std::string(70, '=') << std::endl; std::cout << "SIMPLE MULTI-STREAM RESULTS" << std::endl; std::cout << std::string(70, '=') << std::endl; std::cout << "Input: RGB8 -> Y8_BL_ER" << std::endl; std::cout << "Total time: " << totalTimeSeconds << " seconds" << std::endl; std::cout << "Avg time per frame: " << (avgTimePerFrame * 1000) << " ms" << std::endl; std::cout << "THROUGHPUT: " << throughputFPS << " FPS" << std::endl; std::cout << std::string(70, '=') << std::endl; std::cout << "THROUGHPUT: " << throughputFPS << " FPS" << std::endl; std::cout << std::string(70, '=') << std::endl;
查看结果
在图像分辨率为 960 × 600、最大视差为 128 的条件下,该方案在 Thor T5000 上以 30 FPS 的帧率运行立体视差估计,同时支持 8 个并行数据流(包括置信度图),且无需占用 GPU 资源。在 MAX_N 功耗模式下,其性能相比 Orin AGX 64 GB 提升至 10 倍。具体性能数据如表 1 所示。
| 立体视差全工作流(相对模式,分辨率:960 × 600,最大差异:128)的帧率(FPS)加速比随流数量变化情况:Orin AGX(64 GB)、Jetson Thor、T5000 分别达到 122、122.5、212、111.9、54.6、58.9、78.3、299.7。 | |||
| 帧率(FPS) | 加速比 | ||
| 流数量 | Orin AGX(64 GB) | Jetson Thor T5000 | |
| 1 | 22 | 122 | 5.5 |
| 2 | 12 | 111 | 9.5 |
| 4 | 6 | 58 | 9.7 |
| 8 | 3 | 29 | 9.7 |
表 1:Orin AGX 与 Thor T5000在 RELATIVE 模式下,立体视差处理流程的对比
波士顿动力如何使用 VPI
作为 Jetson 平台的深度用户,波士顿动力借助视觉编程接口(VPI)来加速其感知系统的处理流程。
VPI 支持无缝访问 Jetson 的专用硬件加速器,提供一系列优化的视觉算法(如 AprilTags 和 SGM 立体匹配),以及 ORB、Harris Corner、Pyramidal LK 等特征检测器,和由 OFA 加速的光流计算。这些技术构成了波士顿动力感知系统的核心,可通过负载均衡同时支撑原型验证与系统优化。通过采用 VPI,工程师能够快速适配硬件更新,显著缩短从开发到实现价值的周期。
要点总结
Jetson Thor 平台以及 VPI 等库在硬件功能上的进步,使开发者能够为边缘端机器人设计出高效且低延迟的解决方案。
通过充分发挥 Jetson 平台上各款可用加速器的独特优势,像波士顿动力这样的机器人公司能够实现高效且可扩展的复杂视觉处理,从而推动智能自主机器人在多种现实应用场景中的落地与发展。
关于作者
Chintan Intwala 是 NVIDIA 核心计算机视觉产品管理团队的成员,专注于构建 AI 赋能的云技术,为各行各业的大型计算机视觉开发者提供支持。在加入 NVIDIA 之前,Chintan 曾在 Adobe 工作,专注于构建 AI/ML 和 AR/Camera 产品及功能。他拥有麻省理工学院斯隆分校 (MIT Sloan) 的 MBA 学位,并已获得超过 25 项美国专利。
Jonas Toelke 是 NVIDIA 核心计算机视觉团队的一员,领导的团队专注于构建经过优化的计算机视觉产品,为各行各业的 TegraSoC 提供支持。加入 NVIDIA 之前,Jonas 曾就职于 Halliburton,专注于构建 AI/ ML 应用以解决石油物理问题。他拥有慕尼黑理工大学工程学博士学位,并已获得 20 项专利。
Colin Tracey 是 NVIDIA 的高级系统软件工程师。他在 Jetson 和 DRIVE 平台的嵌入式计算机视觉库和 SDK 上工作。
Arjun Verma 是 NVIDIA 的系统软件工程师,也是 NVIDIA 嵌入式设备计算机视觉产品的核心开发者。Arjun 最近刚从佐治亚理工学院获得机器学习硕士学位。
全部0条评论
快来发表一下你的评论吧 !