# YOLOv4, YOLOv4-tiny and YOLOv4x-mish ONNX Conversion ## Prerequisites ### 1. Model files (cfg + weights) The Darknet `.cfg` files are already provided in [opencv_extra/testdata/dnn](https://github.com/opencv/opencv_extra/tree/master/testdata/dnn) (`yolov4.cfg`, `yolov4-tiny-2020-12.cfg`, `yolov4x-mish.cfg`). Download the matching `.weights` files using the OpenCV test data download script: ```bash git clone https://github.com/opencv/opencv_extra.git cd opencv_extra/testdata/dnn python download_models.py YOLOv4 YOLOv4-tiny-2020-12 YOLOv4x-mish ``` ### 2. Python environment for `pytorch-YOLOv4` The conversion uses [`pytorch-YOLOv4`](https://github.com/Tianxiaomo/pytorch-YOLOv4). Create a Python environment with the required dependencies: Supported Python versions: **3.7 – 3.10**. ```bash conda create -n python=<3.7-3.10> -y conda activate pip install "torch<2.4" "torchvision<0.19" "numpy<2" onnx onnxruntime onnxscript ``` --- ## Conversion of YOLOv4 to ONNX ```bash git clone https://github.com/Tianxiaomo/pytorch-YOLOv4.git cd pytorch-YOLOv4 # Convert (dynamic batch, batch_size=0) python -c "from tool.darknet2onnx import transform_to_onnx; transform_to_onnx('yolov4.cfg', 'yolov4.weights', 0)" ``` --- ## Conversion of YOLOv4-tiny to ONNX ```bash git clone https://github.com/Tianxiaomo/pytorch-YOLOv4.git cd pytorch-YOLOv4 # Convert YOLOv4-tiny (dynamic batch, batch_size=0) python -c "from tool.darknet2onnx import transform_to_onnx; transform_to_onnx('yolov4-tiny-2020-12.cfg', 'yolov4-tiny.weights', 0)" ``` --- ## Conversion of YOLOv4x-mish to ONNX ### Why it differs from YOLOv4 The `yolov4x-mish.cfg` uses `new_coords=1` — a Scaled-YOLOv4 optimization. The network is trained to output values directly in the `[0, 1]` range (no sigmoid needed) and uses a squared formula `(t_w * 2)² * anchor` for width/height instead of `exp(t_w) * anchor`. This is more numerically stable for large models. ### The Issue The `pytorch-YOLOv4` converter was written for the original YOLOv4 (`new_coords=0`) and always applies `sigmoid` + `exp`. With `new_coords=1` weights, `sigmoid` gets applied on top of already-activated values, squishing confidences from ~0.93 down to ~0.36. As a result, the model produces garbage detections. ### The Fix (Modified scripts provided) To resolve this, modified versions of **`darknet2pytorch.py`** and **`yolo_layer.py`** are provided in this repository. These scripts include the following patches: * **`darknet2pytorch.py`**: Properly reads the `new_coords` flag from the `.cfg`. * **`yolo_layer.py`**: Skips the redundant sigmoid activation for `xy/obj/cls` and implements the squared `wh` formula when `new_coords=1` is detected. ### Conversion Steps ```bash git clone https://github.com/Tianxiaomo/pytorch-YOLOv4.git cd pytorch-YOLOv4 # [!] Replace tool/darknet2pytorch.py and tool/yolo_layer.py with the patched # versions from this repository before running the conversion. # Convert YOLOv4x-mish (dynamic batch, batch_size=0) python -c "from tool.darknet2onnx import transform_to_onnx; transform_to_onnx('yolov4x-mish.cfg', 'yolov4x-mish.weights', 0)" ``` --- ## Usage A demo script is provided to run inference using OpenCV DNN: ```bash # YOLOv4 (input size: 608x608) python demo.py --model yolov4.onnx --image example_outputs/input.jpg --output example_outputs/yolov4_output.jpg # YOLOv4-tiny (input size: 416x416) python demo.py --model yolov4-tiny.onnx --image example_outputs/input.jpg --output example_outputs/yolov4-tiny_output.jpg # YOLOv4x-mish (input size: 640x640) python demo.py --model yolov4x-mish.onnx --image example_outputs/input.jpg --output example_outputs/yolov4x-mish_output.jpg ``` The demo prints the detected COCO classes, confidence scores, and bounding boxes, and saves an annotated output image. --- ## License See [License.txt](./License.txt) — This conversion tool is based on [pytorch-YOLOv4](https://github.com/Tianxiaomo/pytorch-YOLOv4) (Apache-2.0). Original YOLOv4 model weights and configuration are released by Alexey Bochkovskiy ([AlexeyAB/darknet](https://github.com/AlexeyAB/darknet)).