| |
| import torch |
| from ultralytics import YOLO |
| from ultralytics.nn.modules.head import Segment |
| import os |
| import shutil |
|
|
|
|
| def npu_segment_forward(self, x): |
| """ |
| YOLOv8 Segment Head Modified for NPU. |
| |
| YOLOv8 Segment structure (NOT end2end): |
| - cv2: box regression layers (DFL, out channels = 4 * reg_max = 64) |
| - cv3: classification layers (out channels = nc = 80) |
| - cv4: mask coefficient layers (out channels = nm = 32) |
| - proto: Proto module for generating mask prototypes |
| |
| Output: |
| List of Tensors (10 items: 3 scales * 3 outputs + 1 proto), NHWC for detection, NCHW for proto |
| [ |
| Scale1_Box_Raw (B, 80, 80, 4*reg_max), <-- raw DFL box logits |
| Scale1_Cls_Raw (B, 80, 80, nc), <-- class scores (raw logits), nc=80 |
| Scale1_Mask_Raw (B, 80, 80, nm), <-- mask coefficients, nm=32 |
| Scale2_Box_Raw (B, 40, 40, 4*reg_max), |
| Scale2_Cls_Raw (B, 40, 40, nc), |
| Scale2_Mask_Raw (B, 40, 40, nm), |
| Scale3_Box_Raw (B, 20, 20, 4*reg_max), |
| Scale3_Cls_Raw (B, 20, 20, nc), |
| Scale3_Mask_Raw (B, 20, 20, nm), |
| Proto (B, nm, H, W), <-- mask prototypes (160x160 for 640 input) |
| ] |
| """ |
| if not isinstance(x, (list, tuple)): |
| x = [x] |
|
|
| res = [] |
|
|
| box_layers = self.cv2 |
| cls_layers = self.cv3 |
| mask_layers = self.cv4 |
|
|
| for i in range(self.nl): |
| |
| bboxes = box_layers[i](x[i]).permute(0, 2, 3, 1) |
|
|
| |
| scores = cls_layers[i](x[i]).permute(0, 2, 3, 1) |
|
|
| |
| masks = mask_layers[i](x[i]).permute(0, 2, 3, 1) |
|
|
| res.append(bboxes) |
| res.append(scores) |
| res.append(masks) |
|
|
| |
| proto = self.proto(x[0]) |
| res.append(proto) |
|
|
| return res |
|
|
|
|
| def batch_export_yolov8_seg(): |
| variants = ['n', 's', 'm', 'l', 'x'] |
| imgsz = 640 |
|
|
| |
| Segment.forward = npu_segment_forward |
| print("Monkey patch applied for Segment: Output Layout forced to NHWC + Proto.") |
|
|
| for v in variants: |
| model_name = f"yolov8{v}-seg" |
| pt_path = f"{model_name}.pt" |
| onnx_final_name = f"{model_name}_640x640.onnx" |
| print(f"\n--- Processing {model_name} ---") |
| try: |
| |
| model = YOLO(pt_path) |
|
|
| |
| Segment.forward = npu_segment_forward |
|
|
| |
| if hasattr(model.model, 'model') and len(model.model.model) > 0: |
| head = model.model.model[-1] |
| if isinstance(head, Segment): |
| head.forward = lambda x: npu_segment_forward(head, x) |
|
|
| |
| exported_path = model.export( |
| format="onnx", |
| imgsz=imgsz, |
| dynamic=False, |
| opset=11, |
| simplify=True, |
| nms=False |
| ) |
|
|
| |
| if exported_path: |
| shutil.move(exported_path, onnx_final_name) |
| print(f"Success: {onnx_final_name}") |
| except Exception as e: |
| print(f"Failed to export {model_name}: {e}") |
| import traceback |
| traceback.print_exc() |
|
|
|
|
| if __name__ == "__main__": |
| batch_export_yolov8_seg() |
|
|