π [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
|