EXPERIMENT / 配套代码

main.py

← 返回文章
下载代码

在项目根目录执行;下载包解压后,在解压目录执行 python3 main.py。

cd 'content/posts/AI-深度学习/嵌入式视觉模型进阶/13-检测器导出对照与其他结构路线/code' && python3 main.py
"""导出多输出检测头并逐张量对照,认识 SSD、DETR 与后处理边界。"""

from pathlib import Path
from tempfile import TemporaryDirectory
import numpy as np
import torch
from torch import nn
import onnx, onnxruntime as ort


class Head(nn.Module):
    def __init__(self):
        super().__init__()
        self.feature = nn.Conv2d(3, 8, 3, 4, 1)
        self.cls = nn.Conv2d(8, 2, 1)
        self.box = nn.Conv2d(8, 4, 1)

    def forward(self, x):
        x = torch.relu(self.feature(x))
        return self.cls(x), self.box(x)


def main():
    torch.manual_seed(7)
    torch.set_num_threads(2)
    net = Head().eval()
    with TemporaryDirectory() as d:
        path = Path(d) / "head.onnx"
        x = torch.rand(1, 3, 32, 32)
        torch.onnx.export(
            net,
            (x,),
            str(path),
            input_names=["images"],
            output_names=["classes", "boxes"],
            opset_version=17,
            dynamo=False,
        )
        onnx.checker.check_model(onnx.load(path))
        session = ort.InferenceSession(str(path), providers=["CPUExecutionProvider"])
        for seed in [7, 8, 9]:
            torch.manual_seed(seed)
            x = torch.rand(1, 3, 32, 32)
            with torch.inference_mode():
                expected = net(x)
            actual = session.run(None, {"images": x.numpy()})
            for name, a, b in zip(["classes", "boxes"], actual, expected):
                np.testing.assert_allclose(a, b.numpy(), rtol=1e-4, atol=1e-5)
                print(
                    seed, name, a.shape, "max error", float(np.abs(a - b.numpy()).max())
                )


if __name__ == "__main__":
    main()