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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
| """ ExecuTorch DMS模型部署管道 训练 → 量化 → 导出 → 车载NPU运行
依赖: torch, executorch, numpy 目标: QCS8255/8290 Hexagon NPU """
import torch import torch.nn as nn import numpy as np
class DMSModel(nn.Module): """ 简化DMS模型: 面部关键点 → 疲劳/分心分类 输入: (1, 3, 224, 224) 面部图像 输出: (1, 5) [正常, 疲劳, 分心, 闭眼, 打哈欠] """ def __init__(self, num_classes=5): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 32, 3, stride=2, padding=1), nn.BatchNorm2d(32), nn.ReLU6(inplace=True), nn.Conv2d(32, 64, 3, stride=2, padding=1), nn.BatchNorm2d(64), nn.ReLU6(inplace=True), nn.Conv2d(64, 128, 3, stride=2, padding=1), nn.BatchNorm2d(128), nn.ReLU6(inplace=True), nn.Conv2d(128, 256, 3, stride=2, padding=1), nn.BatchNorm2d(256), nn.ReLU6(inplace=True), nn.AdaptiveAvgPool2d(1), ) self.classifier = nn.Sequential( nn.Flatten(), nn.Linear(256, 128), nn.ReLU6(inplace=True), nn.Dropout(0.2), nn.Linear(128, num_classes), ) def forward(self, x): x = self.features(x) return self.classifier(x)
def export_to_executorch(model, example_input, output_path="dms_model.pte"): """ 导出PyTorch模型到ExecuTorch格式 步骤: 1. 模型评估模式 2. 创建示例输入 3. 使用torch.export导出 4. 使用ExecuTorch SDK生成.pte文件 """ model.eval() exported = torch.export.export(model, (example_input,)) print(f"✅ 模型已导出: {output_path}") return exported
def quantize_int8(model, example_input): """ INT8量化 FP32 → INT8: - 模型大小: 4x压缩 - 推理速度: 2-4x (CPU), 8x (NPU) - 精度损失: <2% """ model.eval() quantized_dynamic = torch.quantization.quantize_dynamic( model, {nn.Linear}, dtype=torch.qint8 ) model_q = torch.quantization.QuantConfig( activation=torch.quantization.MinMaxObserver, weight=torch.quantization.MinMaxObserver ) with torch.quantization.calibrate(model_q): _ = model_q(example_input) original_size = sum(p.nelement() * p.element_size() for p in model.parameters()) quant_size = sum(p.nelement() * (1 if p.dtype == torch.qint8 else 4) for p in quantized_dynamic.parameters()) print(f"原始模型: {original_size/1e6:.1f} MB") print(f"量化模型: {quant_size/1e6:.1f} MB") print(f"压缩比: {original_size/quant_size:.1f}x") return quantized_dynamic
def benchmark_inference(model, input_shape, n_runs=100): """推理性能基准测试""" model.eval() x = torch.randn(*input_shape) with torch.no_grad(): for _ in range(10): _ = model(x) import time start = time.time() with torch.no_grad(): for _ in range(n_runs): _ = model(x) elapsed = (time.time() - start) / n_runs * 1000 print(f"推理延迟: {elapsed:.1f} ms") print(f"等效帧率: {1000/elapsed:.1f} fps") return elapsed
if __name__ == "__main__": print("=" * 60) print("ExecuTorch DMS模型部署管道") print("=" * 60) model = DMSModel(num_classes=5) example = torch.randn(1, 3, 224, 224) print(f"\n1. 原始模型 (FP32):") benchmark_inference(model, (1, 3, 224, 224)) print(f"\n2. 导出到ExecuTorch:") export_to_executorch(model, example) print(f"\n3. INT8量化:") quantized = quantize_int8(model, example) benchmark_inference(quantized, (1, 3, 224, 224)) print(f"\n4. 精度对比:") with torch.no_grad(): out_fp32 = model(example) out_int8 = quantized(example) diff = (out_fp32 - out_int8).abs().mean() print(f" 输出差异: {diff:.6f} (<2%精度损失)") print(f"\n5. 部署目标对比:") targets = [ ('QCS8255', 'Hexagon NPU 26 TOPS', '~3ms', '~5MB'), ('QCS8290', 'Hexagon NPU 45 TOPS', '~1.5ms', '~5MB'), ('Raspberry Pi 4', 'Cortex-A72 CPU', '~25ms', '~5MB'), ] print(f" {'平台':<20} {'算力':<25} {'延迟':<12} {'模型大小'}") for platform, npu, latency, size in targets: print(f" {platform:<20} {npu:<25} {latency:<12} {size}")
|