-
-
Notifications
You must be signed in to change notification settings - Fork 458
Add support for YOLO-World #522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
YuhyunNa
wants to merge
2
commits into
marcoslucianops:master
Choose a base branch
from
YuhyunNa:add-yolo-world
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| [property] | ||
| gpu-id=0 | ||
| net-scale-factor=0.0039215697906911373 | ||
| model-color-format=0 | ||
| onnx-file=yolov8l-worldv2.onnx | ||
| model-engine-file=model_b1_gpu0_fp32.engine | ||
| #int8-calib-file=calib.table | ||
| labelfile-path=labels.txt | ||
| batch-size=1 | ||
| network-mode=0 | ||
| num-detected-classes=80 | ||
| interval=0 | ||
| gie-unique-id=1 | ||
| process-mode=1 | ||
| network-type=0 | ||
| cluster-mode=2 | ||
| maintain-aspect-ratio=1 | ||
| symmetric-padding=1 | ||
| #workspace-size=2000 | ||
| parse-bbox-func-name=NvDsInferParseYolo | ||
| #parse-bbox-func-name=NvDsInferParseYoloCuda | ||
| custom-lib-path=nvdsinfer_custom_impl_Yolo/libnvdsinfer_custom_impl_Yolo.so | ||
| engine-create-func-name=NvDsInferYoloCudaEngineGet | ||
|
|
||
| [class-attrs-all] | ||
| nms-iou-threshold=0.45 | ||
| pre-cluster-threshold=0.25 | ||
| topk=300 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| # YOLO World usage | ||
|
|
||
| **NOTE**: The yaml file is not required. | ||
|
|
||
| * [Convert model](#convert-model) | ||
| * [Compile the lib](#compile-the-lib) | ||
| * [Edit the config_infer_primary_yoloWorld file](#edit-the-config_infer_primary_yoloWorld-file) | ||
| * [Edit the deepstream_app_config file](#edit-the-deepstream_app_config-file) | ||
| * [Testing the model](#testing-the-model) | ||
|
|
||
| ## | ||
|
|
||
| ### Convert model | ||
|
|
||
| #### 1. Download the YOLO World repo and install the requirements | ||
|
|
||
| ``` | ||
| git clone https://github.com/ultralytics/ultralytics.git | ||
| cd ultralytics | ||
| pip3 install -r requirements.txt | ||
| python3 setup.py install | ||
| pip3 install onnx onnxsim onnxruntime | ||
| ``` | ||
|
|
||
| **NOTE**: It is recommended to use Python virtualenv. | ||
|
|
||
| #### 2. Copy conversor | ||
|
|
||
| Copy the `export_yoloWorld.py` file from `DeepStream-Yolo/utils` directory to the `ultralytics` folder. | ||
|
|
||
| #### 3. Download the model | ||
|
|
||
| Download the `pt` file from [YOLO-World](https://docs.ultralytics.com/models/yolo-world/#key-features) releases (example for yolov8l-worldv2.pt) | ||
|
|
||
| ``` | ||
| wget https://github.com/ultralytics/assets/releases/download/v8.1.0/yolov8l-worldv2.pt | ||
| ``` | ||
|
|
||
| **NOTE**: You can use your custom model. | ||
|
|
||
| #### 4. Convert model | ||
|
|
||
| Generate the ONNX model file (example for yolov8l-worldv2.pt) | ||
|
|
||
| ``` | ||
| python3 export_yoloWorld.py -w yolov8l-worldv2.pt --dynamic --simplify | ||
| ``` | ||
|
|
||
| **NOTE**: To set custom classes | ||
| ``` | ||
| python3 export_yoloWorld.py -w yolov8l-worldv2.pt --dynamic --simplify --custom-classes "person, dachshund, navy tie" | ||
| ``` | ||
|
|
||
| **NOTE**: To change the inference size (defaut: 640) | ||
|
|
||
| ``` | ||
| -s SIZE | ||
| --size SIZE | ||
| -s HEIGHT WIDTH | ||
| --size HEIGHT WIDTH | ||
| ``` | ||
|
|
||
| Example for 1280 | ||
|
|
||
| ``` | ||
| -s 1280 | ||
| ``` | ||
|
|
||
| or | ||
|
|
||
| ``` | ||
| -s 1280 1280 | ||
| ``` | ||
|
|
||
| **NOTE**: To simplify the ONNX model (DeepStream >= 6.0) | ||
|
|
||
| ``` | ||
| --simplify | ||
| ``` | ||
|
|
||
| **NOTE**: To use dynamic batch-size (DeepStream >= 6.1) | ||
|
|
||
| ``` | ||
| --dynamic | ||
| ``` | ||
|
|
||
| **NOTE**: To use static batch-size (example for batch-size = 4) | ||
|
|
||
| ``` | ||
| --batch 4 | ||
| ``` | ||
|
|
||
| **NOTE**: If you are using the DeepStream 5.1, remove the `--dynamic` arg and use opset 12 or lower. The default opset is 16. | ||
|
|
||
| ``` | ||
| --opset 12 | ||
| ``` | ||
|
|
||
| #### 5. Copy generated files | ||
|
|
||
| Copy the generated ONNX model file and labels.txt file (if generated) to the `DeepStream-Yolo` folder. | ||
|
|
||
| ## | ||
|
|
||
| ### Compile the lib | ||
|
|
||
| Open the `DeepStream-Yolo` folder and compile the lib | ||
|
|
||
| * DeepStream 6.3 on x86 platform | ||
|
|
||
| ``` | ||
| CUDA_VER=12.1 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| * DeepStream 6.2 on x86 platform | ||
|
|
||
| ``` | ||
| CUDA_VER=11.8 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| * DeepStream 6.1.1 on x86 platform | ||
|
|
||
| ``` | ||
| CUDA_VER=11.7 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| * DeepStream 6.1 on x86 platform | ||
|
|
||
| ``` | ||
| CUDA_VER=11.6 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| * DeepStream 6.0.1 / 6.0 on x86 platform | ||
|
|
||
| ``` | ||
| CUDA_VER=11.4 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| * DeepStream 5.1 on x86 platform | ||
|
|
||
| ``` | ||
| CUDA_VER=11.1 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| * DeepStream 6.3 / 6.2 / 6.1.1 / 6.1 on Jetson platform | ||
|
|
||
| ``` | ||
| CUDA_VER=11.4 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| * DeepStream 6.0.1 / 6.0 / 5.1 on Jetson platform | ||
|
|
||
| ``` | ||
| CUDA_VER=10.2 make -C nvdsinfer_custom_impl_Yolo | ||
| ``` | ||
|
|
||
| ## | ||
|
|
||
| ### Edit the config_infer_primary_yoloWorld file | ||
|
|
||
| Edit the `config_infer_primary_yoloWorld.txt` file according to your model (example for yolov8l-worldv2.pt with 80 classes) | ||
|
|
||
| ``` | ||
| [property] | ||
| ... | ||
| onnx-file=yolov8l-worldv2.onnx | ||
| ... | ||
| num-detected-classes=80 | ||
| ... | ||
| parse-bbox-func-name=NvDsInferParseYolo | ||
| ... | ||
| ``` | ||
|
|
||
| **NOTE**: The **YOLOv8** resizes the input with center padding. To get better accuracy, use | ||
|
|
||
| ``` | ||
| [property] | ||
| ... | ||
| maintain-aspect-ratio=1 | ||
| symmetric-padding=1 | ||
| ... | ||
| ``` | ||
|
|
||
| ## | ||
|
|
||
| ### Edit the deepstream_app_config file | ||
|
|
||
| ``` | ||
| ... | ||
| [primary-gie] | ||
| ... | ||
| config-file=config_infer_primary_yoloWorld.txt | ||
| ``` | ||
|
|
||
| ## | ||
|
|
||
| ### Testing the model | ||
|
|
||
| ``` | ||
| deepstream-app -c deepstream_app_config.txt | ||
| ``` | ||
|
|
||
| **NOTE**: The TensorRT engine file may take a very long time to generate (sometimes more than 10 minutes). | ||
|
|
||
| **NOTE**: For more information about custom models configuration (`batch-size`, `network-mode`, etc), please check the [`docs/customModels.md`](customModels.md) file. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| import os | ||
| import sys | ||
| import argparse | ||
| import warnings | ||
| import onnx | ||
| import torch | ||
| import torch.nn as nn | ||
| from copy import deepcopy | ||
| from ultralytics import YOLOWorld | ||
| from ultralytics.utils.torch_utils import select_device | ||
| from ultralytics.nn.modules import C2f, WorldDetect | ||
|
|
||
|
|
||
| class DeepStreamOutput(nn.Module): | ||
| def __init__(self): | ||
| super().__init__() | ||
|
|
||
| def forward(self, x): | ||
| x = x.transpose(1, 2) | ||
| boxes = x[:, :, :4] | ||
| scores, classes = torch.max(x[:, :, 4:], 2, keepdim=True) | ||
| classes = classes.float() | ||
| return boxes, scores, classes | ||
|
|
||
|
|
||
| def suppress_warnings(): | ||
| warnings.filterwarnings('ignore', category=torch.jit.TracerWarning) | ||
| warnings.filterwarnings('ignore', category=UserWarning) | ||
| warnings.filterwarnings('ignore', category=DeprecationWarning) | ||
|
|
||
|
|
||
| def yolow_export(model, device): | ||
| for p in model.parameters(): | ||
| p.requires_grad = False | ||
| model.eval() | ||
| model.float() | ||
| model = model.fuse() | ||
| for k, m in model.named_modules(): | ||
| if isinstance(m, WorldDetect): | ||
| m.dynamic = False | ||
| m.export = True | ||
| m.format = 'onnx' | ||
| elif isinstance(m, C2f): | ||
| m.forward = m.forward_split | ||
| return model | ||
|
|
||
|
|
||
| def main(args): | ||
| suppress_warnings() | ||
|
|
||
| print('\nStarting: %s' % args.weights) | ||
|
|
||
| print('Opening YOLO World model\n') | ||
|
|
||
| model = YOLOWorld(args.weights) | ||
| print(f"{'#'*10} Original Model Names {'#'*10}\n{model.names}\n") | ||
|
|
||
|
|
||
| # set custom classes | ||
| if args.custom_classes is not None: | ||
| custom_class_list = [item.strip() for item in args.custom_classes.split(',')] | ||
|
|
||
| model.set_classes(custom_class_list) | ||
| model.model.txt_feats = model.model.txt_feats.detach() | ||
| print(f"{'#'*10} Custom Model Names {'#'*10}\n{model.names}\n") | ||
|
|
||
|
|
||
| # create labels.txt | ||
| if len(model.names.keys()) > 0: | ||
| print('\nCreating labels.txt file') | ||
| f = open('labels.txt', 'w') | ||
| for name in model.names.values(): | ||
| f.write(name + '\n') | ||
| f.close() | ||
|
|
||
|
|
||
| device = select_device('cpu') | ||
| model = deepcopy(model.model).to(device) | ||
| model = yolow_export(model, device) | ||
|
|
||
| model = nn.Sequential(model, DeepStreamOutput()) | ||
|
|
||
| img_size = args.size * 2 if len(args.size) == 1 else args.size | ||
|
|
||
| onnx_input_im = torch.zeros(args.batch, 3, *img_size).to(device) | ||
| onnx_output_file = os.path.basename(args.weights).split('.pt')[0] + '.onnx' | ||
|
|
||
| dynamic_axes = { | ||
| 'input': { | ||
| 0: 'batch' | ||
| }, | ||
| 'boxes': { | ||
| 0: 'batch' | ||
| }, | ||
| 'scores': { | ||
| 0: 'batch' | ||
| }, | ||
| 'classes': { | ||
| 0: 'batch' | ||
| } | ||
| } | ||
|
|
||
| print('\nExporting the model to ONNX') | ||
| torch.onnx.export(model, onnx_input_im, onnx_output_file, verbose=False, opset_version=args.opset, | ||
| do_constant_folding=True, input_names=['input'], output_names=['boxes', 'scores', 'classes'], | ||
| dynamic_axes=dynamic_axes if args.dynamic else None) | ||
|
|
||
| if args.simplify: | ||
| print('Simplifying the ONNX model') | ||
| import onnxsim | ||
| model_onnx = onnx.load(onnx_output_file) | ||
| model_onnx, _ = onnxsim.simplify(model_onnx) | ||
| onnx.save(model_onnx, onnx_output_file) | ||
|
|
||
| print('Done: %s\n' % onnx_output_file) | ||
|
|
||
|
|
||
| def parse_args(): | ||
| parser = argparse.ArgumentParser(description='DeepStream YOLO World conversion') | ||
| parser.add_argument('-w', '--weights', required=True, help='Input weights (.pt) file path (required)') | ||
| parser.add_argument('-s', '--size', nargs='+', type=int, default=[640], help='Inference size [H,W] (default [640])') | ||
| parser.add_argument('--opset', type=int, default=16, help='ONNX opset version') | ||
| parser.add_argument('--simplify', action='store_true', help='ONNX simplify model') | ||
| parser.add_argument('--dynamic', action='store_true', help='Dynamic batch-size') | ||
| parser.add_argument('--batch', type=int, default=1, help='Static batch-size') | ||
| parser.add_argument('--custom-classes', type=str, help='Define custom classes, separated by comma') | ||
|
|
||
| args = parser.parse_args() | ||
| if not os.path.isfile(args.weights): | ||
| raise SystemExit('Invalid weights file') | ||
| if args.dynamic and args.batch > 1: | ||
| raise SystemExit('Cannot set dynamic batch-size and static batch-size at same time') | ||
| return args | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| args = parse_args() | ||
| sys.exit(main(args)) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solut60@icloud.com