# 优化FPS与延迟

下表显示了在OAK相机上使用USB 3.2 Gen 1（5
Gbps）连接时的预期性能。这些测试中禁用了XLink分块（pipeline.setXLinkChunkSize(0)）。示例代码请参阅[延迟测量](https://docs.luxonis.com/software/depthai/examples/latency_measurement.md)。

> 要启用10Gbps USB3模式（使用
> **USB 3.2 Gen 2**
> 兼容线缆时），您需要在
> [设备](https://docs.luxonis.com/software/depthai-components/device.md)
> 构造函数中显式设置：
> ```python
> with dai.Device(pipeline, maxUsbSpeed=dai.UsbSpeed.SUPER_PLUS) as device:
> ```

| 指标 | 分辨率 | FPS | 设定FPS | 延迟[ms] | 带宽 | 直方图 |
| --- | --- | --- | --- | --- | --- | --- |
| 彩色(isp) | 1080P | 60 | 60 | 33 | 1.5 Gbps |
[链接](https://user-images.githubusercontent.com/18037362/162675407-77882498-5bf1-4af8-b779-9b9e8321af57.png) |
| 彩色(isp) | 4K | 28.5 | 30 | 150 | 2.8 Gbps |
[链接](https://user-images.githubusercontent.com/18037362/162675403-f3c5a4c3-1f7d-4acc-a5d5-f5aecff5a66a.png) |
| 彩色(isp) | 4K | 26 | 26 | 83 (标准差: 3.6) | 2.6 Gbps | / |
| 单目 | 720P/800P | 120 | 120 | 24.5 | 442/482 Mbps |
[链接](https://user-images.githubusercontent.com/18037362/162675400-b19f1e2c-bee0-4482-a861-39481bf2e35e.png) |
| 单目 | 400P | 120 | 120 | 7.5 | 246 Mbps |
[链接](https://user-images.githubusercontent.com/18037362/162675393-e3fb08fb-0f17-49d0-85d0-31ae7b5af0f9.png) |

以下是相同的测试，但使用了OAK PoE相机，该相机通过千兆以太网连接。相机直接连接到计算机，中间没有交换机或路由器。电源通过M8连接器提供。

 * [oak_bandwidth_test.py](https://github.com/luxonis/oak-examples/tree/master/random-scripts#oak-bandwidth-test) 结果：下行797
   mbps，上行264 mbps。
 * [oak_latency_test.py](https://github.com/luxonis/oak-examples/tree/master/random-scripts#oak-latency-test) 结果：平均延迟5.2
   ms，标准差6.2。

| 指标 | 分辨率 | FPS | 设定FPS | PoE延迟[ms] | USB延迟[ms] | 带宽 |
| --- | --- | --- | --- | --- | --- | --- |
| 彩色(isp) | 1080P | 25 | 25 | 51 | 33 标准差: 0.8 | 622 Mbps |
| 彩色(isp) | 4K | 8 | 8 | 148 | 80 标准差: 1.2 | 530 Mbps |
| 彩色(isp) | 4K | 8.5 | 10 | 530 | 80 标准差: 1.3 | 663 Mbps |
| 单目 | 400P | 90 | 90 | 12 标准差: 5.0 | 8 标准差: 0.47 | 184 Mbps |
| 单目 | 400P | 110 | 110 | 16 标准差: 9.4 | 8 标准差: 0.45 | 225 Mbps |

由于带宽限制，我们在PoE测量中设置了较低的FPS。例如，4K 8 FPS的延迟为150ms，而4K 10FPS的延迟为530ms，因为链路已饱和。

 * 延迟 是从帧时间戳（imgFrame.getTimestamp()）到主机收到帧的时间戳（dai.Clock.now()）的测量时间。
 * 直方图 显示了帧到达主机的时间变化。Y轴表示在该时间点出现的帧数，X轴表示微秒。
 * 带宽 是以指定分辨率和FPS传输帧所需的计算带宽。

## 编码帧

| 指标 | 分辨率 | FPS | 设定FPS | 到达主机时间[ms] | 直方图 |
| --- | --- | --- | --- | --- | --- |
| 彩色视频 H.265 | 4K | 28.5 | 30 | 210 |
[链接](https://user-images.githubusercontent.com/18037362/162675386-a59a58d1-1d5c-4c82-89d8-12882926425b.png) |
| 彩色视频 MJPEG | 4K | 30 | 30 | 71 |
[链接](https://user-images.githubusercontent.com/18037362/162675384-64842bd6-f5e7-4b40-adf4-39b9c25d1c89.png) |
| 彩色视频 H.265 | 1080P | 60 | 60 | 42 |
[链接](https://user-images.githubusercontent.com/18037362/162675356-c7c86730-63cd-4de8-bad6-4e1484b29ca5.png) |
| 彩色视频 MJPEG | 1080P | 60 | 60 | 31 |
[链接](https://user-images.githubusercontent.com/18037362/162675371-62aadb93-20f0-4838-9aab-727fb1bfe6f4.png) |
| 单目 H.265 | 800P | 60 | 60 | 23.5 |
[链接](https://user-images.githubusercontent.com/18037362/162675318-92a8541b-424c-49b1-8ec4-6d9e0170410a.png) |
| 单目 MJPEG | 800P | 60 | 60 | 22.5 |
[链接](https://user-images.githubusercontent.com/18037362/162675328-20afbe8f-4587-4263-8981-919e5a8811c7.png) |
| 单目 H.265 | 400P | 120 | 120 | 7.5 |
[链接](https://user-images.githubusercontent.com/18037362/162675345-dfb4d04a-5d3a-4f84-81e9-dfc091bc00b5.png) |
| 单目 MJPEG | 400P | 120 | 120 | 7.5 |
[链接](https://user-images.githubusercontent.com/18037362/162675335-2e5a9581-972a-448c-b650-6b6d076a04b8.png) |

您还可以通过使用DepthAI的[零拷贝](https://github.com/luxonis/depthai-core/tree/message_zero_copy)分支来减少帧延迟。这将传递指针（在XLink层面）到cv2.Mat，而不是执行内存复制（如当前所做），因此性能提升取决于您使用的图像大小。（注意：API有所不同，并非message_zero_copy分支上的所有功能都可用。）

## PoE 延迟

在 PoE 上，延迟可能会因多种因素而有很大差异：

 * 网络本身。例如，如果您处于拥有许多节点的大型网络中，延迟会比使用直接连接更高。
 * 存在带宽的瓶颈：
   * 也许某些网络链路是10mbps/100mbps而不是完整的1gbps（由于交换机/网卡等原因）。您可以使用 [PoE
     测试脚本](https://github.com/luxonis/oak-examples/tree/master/random-scripts#poe-test-script) 进行测试（speed 应为1000）。
   * 网络/计算机被其他流量饱和。您可以使用 [OAK 带宽测试](https://github.com/luxonis/oak-examples/tree/master/random-scripts#oak-bandwidth-test)
     脚本测试实际带宽。在直接连接下，我得到了约800mbps下行和约210mbps上行。
 * 计算机的网卡设置，[文档在此](https://docs.luxonis.com/hardware/platform/deploy/poe-deployment-guide.md#network-interface-controller-settings)
 * 100% 的 OAK Leon CSS (CPU) 使用率。Leon CSS 核心处理 POE
   通信（[文档见此处](https://docs.luxonis.com/hardware/platform/rvc/rvc2.md#hardware-blocks-and-accelerators)），如果 CPU
   使用率达到100%，它将无法以应有的速度处理通信。解决方法： 请参阅 [CPU 使用率](https://docs.luxonis.com/software/depthai/debugging.md) 文档。
 * 另一种潜在的改善 PoE 延迟的方法是微调网络设置，如 MTU、TCP
   窗口大小等（更多信息请参见[此处](https://docs.luxonis.com/hardware/platform/deploy/poe-deployment-guide.md#advance-network-settings)）

## 带宽

对于大型未编码帧，即使在30FPS下，也很快会饱和带宽，尤其是在 PoE 设备（1gbps链路）上：

```bash
4K NV12/YUV420 frames: 3840 * 2160 * 1.5 * 30fps * 8bits = 3 gbps
1080P NV12/YUV420 frames: 1920 * 1080 * 1.5 * 30fps * 8bits = 747 mbps
720P NV12/YUV420 frames: 1280 * 720 * 1.5 * 30fps * 8bits = 331 mbps

1080P RGB frames: 1920 * 1080 * 3 * 30fps * 8bits = 1.5 gbps

800P depth frames: 1280 * 800 * 2 * 30fps * 8bits = 492 mbps
400P depth frames: 640 * 400 * 2 * 30fps * 8bits = 123 mbps

800P mono frames: 1280 * 800 * 1 * 30fps * 8bits = 246 mbps
400P mono frames: 640 * 400 * 1 * 30fps * 8bits = 62 mbps
```

公式中的第三个值是字节/像素，对于 NV12/YUV420 为1.5，RGB 为3，深度帧为2，单色（灰度）帧为1。对于视差帧，它可以是1（正常模式）或2（亚像素模式）。

减少带宽的几种选项：

 * 在设备上使用 [VideoEncoder](https://docs.luxonis.com/software/depthai-components/nodes/video_encoder.md) 编码帧（H.264、H.265、MJPEG）
 * 减少FPS/分辨率/流数量

## 测量操作时间

如果用户将 depthai 级别设置为 trace（参见 [DepthAI 调试级别](https://docs.luxonis.com/software/depthai/debugging.md)），depthai 将记录每个节点/进程的操作时间，如下所示。

```bash
[SpatialDetectionNetwork(1)] [trace] SpatialDetectionNetwork syncing took '70.39142' ms.
[StereoDepth(4)] [trace] Warp node took '2.2945' ms.
[system] [trace] EV:0,S:0,IDS:27,IDD:10,TSS:2,TSN:601935518
[system] [trace] EV:0,S:1,IDS:27,IDD:10,TSS:2,TSN:602001382
[StereoDepth(4)] [trace] Stereo took '12.27392' ms.
[StereoDepth(4)] [trace] 'Median+Disparity to depth' pipeline took '0.86295' ms.
[StereoDepth(4)] [trace] Stereo post processing (total) took '0.931422' ms.
[SpatialDetectionNetwork(1)] [trace] NeuralNetwork inference took '62.274784' ms.
[StereoDepth(4)] [trace] Stereo rectification took '2.686294' ms.
[MonoCamera(3)] [trace] Mono ISP took '1.726888' ms.
[system] [trace] EV:0,S:0,IDS:20,IDD:25,TSS:2,TSN:616446812
[system] [trace] EV:0,S:1,IDS:20,IDD:25,TSS:2,TSN:616489715
[SpatialDetectionNetwork(1)] [trace] DetectionParser took '3.464118' ms.
```

## 运行 NN 时减少延迟

在上面的示例中，我们仅传输帧，没有在 OAK 相机上做其他事情。本节将重点介绍在 OAK 上同时运行 NN 模型时如何减少延迟。

### 增加 NN 资源

减少延迟的一个选项是增加 NN 资源。这可以通过更改分配的 NCE 和 SHAVE
数量来实现（参见硬件加速器[文档](https://docs.luxonis.com/hardware/platform/rvc/rvc2.md#hardware-blocks-and-accelerators)）。[编译工具](https://docs.luxonis.com/software/ai-inference/conversion.md#compile-tool)
可以编译模型以使用更多 SHAVE 核心。要分配更多 NCE，您可以使用以下 API：

```python
import depthai as dai

pipeline = dai.Pipeline()
# nn = pipeline.createNeuralNetwork()
# nn = pipeline.create(dai.node.MobileNetDetectionNetwork)
nn = pipeline.create(dai.node.YoloDetectionNetwork)
nn.setNumInferenceThreads(1) # 默认使用2个线程
nn.setNumNCEPerInferenceThread(2) # 默认每个线程使用1个NCE
```

模型在使用2个线程（每个线程1个NCE）时通常以最大FPS运行，并为AVAILABLE_SHAVES / 2编译模型。

YoloV7-tiny的FPS与延迟对比示例：

| NN资源 | 相机FPS | 延迟 | NN FPS |
| --- | --- | --- | --- |
| **6 SHAVEs, 2个线程（每线程1个NCE）** | 15 | 155 ms | 15 |
| 6 SHAVEs, 2个线程（每线程1个NCE） | 14 | 149 ms | 14 |
| 6 SHAVEs, 2个线程（每线程1个NCE） | 13 | 146 ms | 13 |
| 6 SHAVEs, 2个线程（每线程1个NCE） | 10 | 141 ms | 10 |
| **13 SHAVEs, 1个线程（每线程2个NCE）** | 30 | 145 ms | 11.6 |
| 13 SHAVEs, 1个线程（每线程2个NCE） | 12 | 128 ms | 12 |
| 13 SHAVEs, 1个线程（每线程2个NCE） | 10 | 118 ms | 10 |

### 降低相机FPS以匹配NN FPS

降低FPS以不超过NN的能力通常能提供最佳的延迟性能，因为NN可以在新帧可用时立即开始推理。

例如，在15 FPS时，总延迟约为70 ms，从捕获时间（曝光结束和MIPI读出开始）开始测量。

这段时间包括：

 * MIPI读出
 * ISP处理
 * 预览后处理
 * NN处理
 * 传输到主机
 * 最后，直至到达应用程序的额外延迟

注意：如果将FPS略微提高至19..21 FPS，会出现约10ms的额外延迟，我们认为这与固件有关。我们正在积极寻找降低延迟的改进方案。

### NN输入队列大小与阻塞行为

如果应用程序设置了detNetwork.input.setBlocking(False)，但队列大小未改变，以下调整可能有助于改善延迟性能：

通过添加detNetwork.input.setQueueSize(1)，同时将相机FPS调回40，我们得到约80.. 105ms的延迟。导致非确定性的原因之一是相机的产生速率（25ms帧间隔）与NN完成并可接受新帧处理的速率不匹配。
