henry000 commited on
Commit
2d52a7f
Β·
2 Parent(s): 1504257 7a28749

πŸ”€ [Merge] branch 'DEPLOY' into SETUP

Browse files
README.md CHANGED
@@ -47,7 +47,7 @@ pip install -r requirements.txt
47
  | ------------------ | :---------: | :-------: | :-------: |
48
  | PyTorch | v1.12 | v2.3+ | v1.12 |
49
  | ONNX | βœ… | βœ… | - |
50
- | TensorRT | πŸ§ͺ | πŸ§ͺ | - |
51
  | OpenVINO | - | πŸ§ͺ | ❔ |
52
 
53
  </td></tr> </table>
 
47
  | ------------------ | :---------: | :-------: | :-------: |
48
  | PyTorch | v1.12 | v2.3+ | v1.12 |
49
  | ONNX | βœ… | βœ… | - |
50
+ | TensorRT | βœ… | - | - |
51
  | OpenVINO | - | πŸ§ͺ | ❔ |
52
 
53
  </td></tr> </table>
examples/notebook_TensorRT.ipynb ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "import os\n",
10
+ "import sys\n",
11
+ "from pathlib import Path\n",
12
+ "\n",
13
+ "import torch\n",
14
+ "from PIL import Image \n",
15
+ "from loguru import logger\n",
16
+ "from omegaconf import OmegaConf\n",
17
+ "\n",
18
+ "project_root = Path().resolve().parent\n",
19
+ "sys.path.append(str(project_root))\n",
20
+ "\n",
21
+ "from yolo import AugmentationComposer, bbox_nms, create_model, custom_logger, draw_bboxes, Vec2Box\n",
22
+ "from yolo.config.config import NMSConfig"
23
+ ]
24
+ },
25
+ {
26
+ "cell_type": "code",
27
+ "execution_count": null,
28
+ "metadata": {},
29
+ "outputs": [],
30
+ "source": [
31
+ "MODEL = \"v9-c\"\n",
32
+ "DEVICE = \"cuda:0\"\n",
33
+ "\n",
34
+ "WEIGHT_PATH = f\"../weights/{MODEL}.pt\" \n",
35
+ "TRT_WEIGHT_PATH = f\"../weights/{MODEL}.trt\"\n",
36
+ "MODEL_CONFIG = f\"../yolo/config/model/{MODEL}.yaml\"\n",
37
+ "\n",
38
+ "IMAGE_PATH = \"../demo/images/inference/image.png\"\n",
39
+ "IMAGE_SIZE = (640, 640)\n",
40
+ "\n",
41
+ "custom_logger()\n",
42
+ "device = torch.device(DEVICE)\n",
43
+ "image = Image.open(IMAGE_PATH)"
44
+ ]
45
+ },
46
+ {
47
+ "cell_type": "code",
48
+ "execution_count": null,
49
+ "metadata": {},
50
+ "outputs": [],
51
+ "source": [
52
+ "if os.path.exists(TRT_WEIGHT_PATH):\n",
53
+ " from torch2trt import TRTModule\n",
54
+ "\n",
55
+ " model_trt = TRTModule()\n",
56
+ " model_trt.load_state_dict(torch.load(TRT_WEIGHT_PATH))\n",
57
+ "else:\n",
58
+ " from torch2trt import torch2trt\n",
59
+ "\n",
60
+ " with open(MODEL_CONFIG) as stream:\n",
61
+ " cfg_model = OmegaConf.load(stream)\n",
62
+ "\n",
63
+ " model = create_model(cfg_model, weight_path=WEIGHT_PATH)\n",
64
+ " model = model.to(device).eval()\n",
65
+ "\n",
66
+ " dummy_input = torch.ones((1, 3, 640, 640)).to(device)\n",
67
+ " logger.info(f\"♻️ Creating TensorRT model\")\n",
68
+ " model_trt = torch2trt(model, [dummy_input])\n",
69
+ " torch.save(model_trt.state_dict(), TRT_WEIGHT_PATH)\n",
70
+ " logger.info(f\"πŸ“₯ TensorRT model saved to oonx.pt\")\n",
71
+ "\n",
72
+ "transform = AugmentationComposer([], IMAGE_SIZE)\n",
73
+ "vec2box = Vec2Box(model_trt, IMAGE_SIZE, device)\n"
74
+ ]
75
+ },
76
+ {
77
+ "cell_type": "code",
78
+ "execution_count": null,
79
+ "metadata": {},
80
+ "outputs": [],
81
+ "source": [
82
+ "image, bbox = transform(image, torch.zeros(0, 5))\n",
83
+ "image = image.to(device)[None]"
84
+ ]
85
+ },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "with torch.no_grad():\n",
93
+ " predict = model_trt(image)\n",
94
+ " predict = vec2box(predict[\"Main\"])\n",
95
+ "predict_box = bbox_nms(predict[0], predict[2], NMSConfig(0.5, 0.5))\n",
96
+ "draw_bboxes(image, predict_box)"
97
+ ]
98
+ },
99
+ {
100
+ "cell_type": "markdown",
101
+ "metadata": {},
102
+ "source": [
103
+ "Sample Output:\n",
104
+ "\n",
105
+ "![image](../demo/images/output/visualize.png)"
106
+ ]
107
+ }
108
+ ],
109
+ "metadata": {
110
+ "kernelspec": {
111
+ "display_name": "yolomit",
112
+ "language": "python",
113
+ "name": "python3"
114
+ },
115
+ "language_info": {
116
+ "codemirror_mode": {
117
+ "name": "ipython",
118
+ "version": 3
119
+ },
120
+ "file_extension": ".py",
121
+ "mimetype": "text/x-python",
122
+ "name": "python",
123
+ "nbconvert_exporter": "python",
124
+ "pygments_lexer": "ipython3",
125
+ "version": "3.1.undefined"
126
+ }
127
+ },
128
+ "nbformat": 4,
129
+ "nbformat_minor": 2
130
+ }
yolo/config/model/v9-c.yaml CHANGED
@@ -1,6 +1,6 @@
1
  anchor:
2
  reg_max: 16
3
- anchors: [8, 16, 32]
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
- model = model.to(device)
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).squeeze(1)
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
- logger.info(f" πŸ—οΈ Building {arch_name}")
 
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
@@ -135,6 +136,7 @@ def create_model(model_cfg: ModelConfig, weight_path: Optional[str], class_num:
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
-
 
140
  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
 
136
  if os.path.exists(weight_path):
137
  # TODO: fix map_location
138
  model.model.load_state_dict(torch.load(weight_path), strict=False)
139
+ logger.info("βœ… Success load model & weight")
140
+ else:
141
+ logger.info("βœ… Success load model")
142
  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, anchors: list = None):
268
- if anchors is None:
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
- anchors_num = [[image_size[0] / anchor, image_size[0] / anchor] for anchor in anchors]
 
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