π [Fix] a bug in deploying TensorRT model
Browse files- yolo/config/model/v9-c.yaml +1 -1
- yolo/lazy.py +1 -1
- yolo/model/module.py +1 -1
- yolo/model/yolo.py +6 -4
- yolo/tools/drawer.py +2 -2
- yolo/utils/bounding_box_utils.py +5 -3
- yolo/utils/deploy_utils.py +3 -5
yolo/config/model/v9-c.yaml
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
anchor:
|
2 |
reg_max: 16
|
3 |
-
|
4 |
|
5 |
model:
|
6 |
backbone:
|
|
|
1 |
anchor:
|
2 |
reg_max: 16
|
3 |
+
strides: [8, 16, 32]
|
4 |
|
5 |
model:
|
6 |
backbone:
|
yolo/lazy.py
CHANGED
@@ -25,7 +25,7 @@ def main(cfg: Config):
|
|
25 |
model = FastModelLoader(cfg).load_model()
|
26 |
else:
|
27 |
model = create_model(cfg.model, class_num=cfg.class_num, weight_path=cfg.weight)
|
28 |
-
|
29 |
|
30 |
vec2box = Vec2Box(model, cfg.image_size, device)
|
31 |
|
|
|
25 |
model = FastModelLoader(cfg).load_model()
|
26 |
else:
|
27 |
model = create_model(cfg.model, class_num=cfg.class_num, weight_path=cfg.weight)
|
28 |
+
model = model.to(device)
|
29 |
|
30 |
vec2box = Vec2Box(model, cfg.image_size, device)
|
31 |
|
yolo/model/module.py
CHANGED
@@ -105,7 +105,7 @@ class Anchor2Vec(nn.Module):
|
|
105 |
def forward(self, anchor_x: Tensor) -> Tensor:
|
106 |
anchor_x = rearrange(anchor_x, "B (P R) h w -> B R P h w", P=4)
|
107 |
vector_x = anchor_x.softmax(dim=1)
|
108 |
-
vector_x = self.anc2vec(vector_x)
|
109 |
return anchor_x, vector_x
|
110 |
|
111 |
|
|
|
105 |
def forward(self, anchor_x: Tensor) -> Tensor:
|
106 |
anchor_x = rearrange(anchor_x, "B (P R) h w -> B R P h w", P=4)
|
107 |
vector_x = anchor_x.softmax(dim=1)
|
108 |
+
vector_x = self.anc2vec(vector_x)[:, 0]
|
109 |
return anchor_x, vector_x
|
110 |
|
111 |
|
yolo/model/yolo.py
CHANGED
@@ -26,13 +26,15 @@ class YOLO(nn.Module):
|
|
26 |
self.layer_map = get_layer_map() # Get the map Dict[str: Module]
|
27 |
self.model: List[YOLOLayer] = nn.ModuleList()
|
28 |
self.build_model(model_cfg.model)
|
|
|
29 |
|
30 |
def build_model(self, model_arch: Dict[str, List[Dict[str, Dict[str, Dict]]]]):
|
31 |
self.layer_index = {}
|
32 |
output_dim, layer_idx = [3], 1
|
33 |
logger.info(f"π Building YOLO")
|
34 |
for arch_name in model_arch:
|
35 |
-
|
|
|
36 |
for layer_idx, layer_spec in enumerate(model_arch[arch_name], start=layer_idx):
|
37 |
layer_type, layer_info = next(iter(layer_spec.items()))
|
38 |
layer_args = layer_info.get("args", {})
|
@@ -45,7 +47,6 @@ class YOLO(nn.Module):
|
|
45 |
layer_args["in_channels"] = output_dim[source]
|
46 |
if "Detection" in layer_type:
|
47 |
layer_args["in_channels"] = [output_dim[idx] for idx in source]
|
48 |
-
if "Detection" in layer_type or "Anchor2Box" in layer_type:
|
49 |
layer_args["num_classes"] = self.num_classes
|
50 |
|
51 |
# create layers
|
@@ -134,6 +135,7 @@ def create_model(model_cfg: ModelConfig, weight_path: Optional[str], class_num:
|
|
134 |
if os.path.exists(weight_path):
|
135 |
# TODO: fix map_location
|
136 |
model.model.load_state_dict(torch.load(weight_path), strict=False)
|
137 |
-
logger.info("β
Success load model weight")
|
138 |
-
|
|
|
139 |
return model
|
|
|
26 |
self.layer_map = get_layer_map() # Get the map Dict[str: Module]
|
27 |
self.model: List[YOLOLayer] = nn.ModuleList()
|
28 |
self.build_model(model_cfg.model)
|
29 |
+
self.strides = getattr(model_cfg.anchor, "strides", None)
|
30 |
|
31 |
def build_model(self, model_arch: Dict[str, List[Dict[str, Dict[str, Dict]]]]):
|
32 |
self.layer_index = {}
|
33 |
output_dim, layer_idx = [3], 1
|
34 |
logger.info(f"π Building YOLO")
|
35 |
for arch_name in model_arch:
|
36 |
+
if model_arch[arch_name]:
|
37 |
+
logger.info(f" ποΈ Building {arch_name}")
|
38 |
for layer_idx, layer_spec in enumerate(model_arch[arch_name], start=layer_idx):
|
39 |
layer_type, layer_info = next(iter(layer_spec.items()))
|
40 |
layer_args = layer_info.get("args", {})
|
|
|
47 |
layer_args["in_channels"] = output_dim[source]
|
48 |
if "Detection" in layer_type:
|
49 |
layer_args["in_channels"] = [output_dim[idx] for idx in source]
|
|
|
50 |
layer_args["num_classes"] = self.num_classes
|
51 |
|
52 |
# create layers
|
|
|
135 |
if os.path.exists(weight_path):
|
136 |
# TODO: fix map_location
|
137 |
model.model.load_state_dict(torch.load(weight_path), strict=False)
|
138 |
+
logger.info("β
Success load model & weight")
|
139 |
+
else:
|
140 |
+
logger.info("β
Success load model")
|
141 |
return model
|
yolo/tools/drawer.py
CHANGED
@@ -13,7 +13,7 @@ def draw_bboxes(
|
|
13 |
img: Union[Image.Image, torch.Tensor],
|
14 |
bboxes: List[List[Union[int, float]]],
|
15 |
*,
|
16 |
-
idx2label: Optional[list],
|
17 |
):
|
18 |
"""
|
19 |
Draw bounding boxes on an image.
|
@@ -47,7 +47,7 @@ def draw_bboxes(
|
|
47 |
draw.rounded_rectangle(bbox, outline=(*color_map, 200), radius=5, width=2)
|
48 |
draw.rounded_rectangle(bbox, fill=(*color_map, 100), radius=5)
|
49 |
|
50 |
-
class_text = str(idx2label[int(class_id)] if idx2label else class_id)
|
51 |
label_text = f"{class_text}" + (f" {conf[0]: .0%}" if conf else "")
|
52 |
|
53 |
text_bbox = font.getbbox(label_text)
|
|
|
13 |
img: Union[Image.Image, torch.Tensor],
|
14 |
bboxes: List[List[Union[int, float]]],
|
15 |
*,
|
16 |
+
idx2label: Optional[list] = None,
|
17 |
):
|
18 |
"""
|
19 |
Draw bounding boxes on an image.
|
|
|
47 |
draw.rounded_rectangle(bbox, outline=(*color_map, 200), radius=5, width=2)
|
48 |
draw.rounded_rectangle(bbox, fill=(*color_map, 100), radius=5)
|
49 |
|
50 |
+
class_text = str(idx2label[int(class_id)] if idx2label else int(class_id))
|
51 |
label_text = f"{class_text}" + (f" {conf[0]: .0%}" if conf else "")
|
52 |
|
53 |
text_bbox = font.getbbox(label_text)
|
yolo/utils/bounding_box_utils.py
CHANGED
@@ -9,6 +9,7 @@ from torch import Tensor
|
|
9 |
from torchvision.ops import batched_nms
|
10 |
|
11 |
from yolo.config.config import MatcherConfig, ModelConfig, NMSConfig
|
|
|
12 |
|
13 |
|
14 |
def calculate_iou(bbox1, bbox2, metrics="iou") -> Tensor:
|
@@ -264,8 +265,8 @@ class BoxMatcher:
|
|
264 |
|
265 |
|
266 |
class Vec2Box:
|
267 |
-
def __init__(self, model, image_size, device
|
268 |
-
if
|
269 |
logger.info("π§Έ Found no anchor, Make a dummy test for auto-anchor size")
|
270 |
dummy_input = torch.zeros(1, 3, *image_size).to(device)
|
271 |
dummy_output = model(dummy_input)
|
@@ -274,7 +275,8 @@ class Vec2Box:
|
|
274 |
_, _, *anchor_num = predict_head[2].shape
|
275 |
anchors_num.append(anchor_num)
|
276 |
else:
|
277 |
-
|
|
|
278 |
anchor_grid, scaler = generate_anchors(image_size, anchors_num)
|
279 |
self.anchor_grid, self.scaler = anchor_grid.to(device), scaler.to(device)
|
280 |
self.anchor_norm = (anchor_grid / scaler[:, None])[None].to(device)
|
|
|
9 |
from torchvision.ops import batched_nms
|
10 |
|
11 |
from yolo.config.config import MatcherConfig, ModelConfig, NMSConfig
|
12 |
+
from yolo.model.yolo import YOLO
|
13 |
|
14 |
|
15 |
def calculate_iou(bbox1, bbox2, metrics="iou") -> Tensor:
|
|
|
265 |
|
266 |
|
267 |
class Vec2Box:
|
268 |
+
def __init__(self, model: YOLO, image_size, device):
|
269 |
+
if model.strides is None:
|
270 |
logger.info("π§Έ Found no anchor, Make a dummy test for auto-anchor size")
|
271 |
dummy_input = torch.zeros(1, 3, *image_size).to(device)
|
272 |
dummy_output = model(dummy_input)
|
|
|
275 |
_, _, *anchor_num = predict_head[2].shape
|
276 |
anchors_num.append(anchor_num)
|
277 |
else:
|
278 |
+
logger.info(f"πΆ Found anchor {model.strides}")
|
279 |
+
anchors_num = [[image_size[0] // stride, image_size[0] // stride] for stride in model.strides]
|
280 |
anchor_grid, scaler = generate_anchors(image_size, anchors_num)
|
281 |
self.anchor_grid, self.scaler = anchor_grid.to(device), scaler.to(device)
|
282 |
self.anchor_norm = (anchor_grid / scaler[:, None])[None].to(device)
|
yolo/utils/deploy_utils.py
CHANGED
@@ -30,9 +30,7 @@ class FastModelLoader:
|
|
30 |
return self._load_trt_model()
|
31 |
elif self.compiler == "deploy":
|
32 |
self.cfg.model.model.auxiliary = {}
|
33 |
-
return create_model(
|
34 |
-
self.cfg.model, class_num=self.cfg.class_num, weight_path=self.cfg.weight, device=self.device
|
35 |
-
)
|
36 |
|
37 |
def _load_onnx_model(self):
|
38 |
from onnxruntime import InferenceSession
|
@@ -91,9 +89,9 @@ class FastModelLoader:
|
|
91 |
from torch2trt import torch2trt
|
92 |
|
93 |
model = create_model(self.cfg.model, class_num=self.cfg.class_num, weight_path=self.cfg.weight).eval()
|
94 |
-
dummy_input = torch.ones((1, 3, *self.cfg.image_size))
|
95 |
logger.info(f"β»οΈ Creating TensorRT model")
|
96 |
-
model_trt = torch2trt(model, [dummy_input])
|
97 |
torch.save(model_trt.state_dict(), self.model_path)
|
98 |
logger.info(f"π₯ TensorRT model saved to {self.model_path}")
|
99 |
return model_trt
|
|
|
30 |
return self._load_trt_model()
|
31 |
elif self.compiler == "deploy":
|
32 |
self.cfg.model.model.auxiliary = {}
|
33 |
+
return create_model(self.cfg.model, class_num=self.cfg.class_num, weight_path=self.cfg.weight)
|
|
|
|
|
34 |
|
35 |
def _load_onnx_model(self):
|
36 |
from onnxruntime import InferenceSession
|
|
|
89 |
from torch2trt import torch2trt
|
90 |
|
91 |
model = create_model(self.cfg.model, class_num=self.cfg.class_num, weight_path=self.cfg.weight).eval()
|
92 |
+
dummy_input = torch.ones((1, 3, *self.cfg.image_size)).cuda()
|
93 |
logger.info(f"β»οΈ Creating TensorRT model")
|
94 |
+
model_trt = torch2trt(model.cuda(), [dummy_input])
|
95 |
torch.save(model_trt.state_dict(), self.model_path)
|
96 |
logger.info(f"π₯ TensorRT model saved to {self.model_path}")
|
97 |
return model_trt
|