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
| import torch import torch.nn as nn
class FaceKeypointModel(nn.Module): """ 人脸关键点检测模型(简化版) 输入: (1, 3, 48, 48) RGB 图像 输出: (1, 136, 2) 68个关键点坐标 """ def __init__(self): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(), nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(), nn.Conv2d(128, 128, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2), ) self.regressor = nn.Sequential( nn.Linear(128 * 6 * 6, 256), nn.ReLU(), nn.Linear(256, 136 * 2) ) def forward(self, x): feat = self.features(x) feat = feat.flatten(1) kpts = self.regressor(feat) return kpts.view(-1, 68, 2)
def export_to_onnx(model, output_path, input_size=(1, 3, 48, 48)): """导出为 ONNX 格式""" model.eval() dummy = torch.randn(*input_size) torch.onnx.export( model, dummy, output_path, input_names=['input'], output_names=['keypoints'], dynamic_axes={ 'input': {0: 'batch'}, 'keypoints': {0: 'batch'} }, opset_version=14, ) print(f"ONNX 模型已导出: {output_path}") import onnxruntime as ort sess = ort.InferenceSession(output_path) input_name = sess.get_inputs()[0].name result = sess.run(None, {input_name: dummy.numpy()}) print(f"ONNX 输出形状: {result[0].shape}") with torch.no_grad(): torch_out = model(dummy) max_diff = (torch_out.numpy() - result[0]).max() print(f"PyTorch vs ONNX 最大差异: {max_diff:.6f}") assert max_diff < 1e-5, "导出一致性验证失败!" print("✅ 导出一致性验证通过")
model = FaceKeypointModel() export_to_onnx(model, "face_keypoints.onnx")
|