1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| """ PyTorch 模型导出 ONNX
关键要求: 1. 动态输入尺寸(batch, height, width) 2. 算子兼容性检查 3. 简化模型(去除后处理) """
import torch import torch.nn as nn import onnx import onnxsim
class DMSModel(nn.Module): """示例 DMS 模型(简化版)""" def __init__(self): super().__init__() self.backbone = nn.Sequential( nn.Conv2d(3, 32, 3, padding=1), nn.BatchNorm2d(32), nn.ReLU(inplace=True), nn.Conv2d(32, 64, 3, stride=2, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.Conv2d(64, 128, 3, stride=2, padding=1), nn.BatchNorm2d(128), nn.ReLU(inplace=True), ) self.keypoint_head = nn.Conv2d(128, 68, 1) self.class_head = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(128, 64), nn.ReLU(inplace=True), nn.Linear(64, 3) ) def forward(self, x): feat = self.backbone(x) keypoints = self.keypoint_head(feat) state = self.class_head(feat) return keypoints, state
def export_to_onnx(model, output_path, input_size=(1, 3, 224, 224)): """导出模型到 ONNX Args: model: PyTorch 模型 output_path: 输出路径 input_size: 输入尺寸 (N, C, H, W) """ model.eval() dummy_input = torch.randn(*input_size) dynamic_axes = { 'input': { 0: 'batch_size', 2: 'height', 3: 'width' }, 'keypoints': { 0: 'batch_size' }, 'state': { 0: 'batch_size' } } torch.onnx.export( model, dummy_input, output_path, input_names=['input'], output_names=['keypoints', 'state'], dynamic_axes=dynamic_axes, opset_version=13, do_constant_folding=True ) onnx_model = onnx.load(output_path) onnx.checker.check_model(onnx_model) print(f"✓ ONNX 模型验证通过: {output_path}") onnx_model_simplified = onnxsim.simplify(onnx_model) onnx.save(onnx_model_simplified, output_path) print(f"✓ ONNX 模型已简化") return output_path
if __name__ == "__main__": model = DMSModel() export_to_onnx(model, "dms_model.onnx")
|