Repository: ultralytics/ultralytics

Issue:
Help Wanted 🙏 YOLOv8 Conda Distribution Implementation
### Call for Community Contributions

We're calling on the community to help us implement YOLOv8 on conda and create a github actions workflow for deployment on version increase. This will make it easier for users to install and use YOLOv8, as well as keep up to date with the latest releases. We have an existing pip deploy workflow that automatically publishes a new `ultralytics` package to pypi when a push to main increments a patch version by + 0.0.1. You can see this action here: 

https://github.com/ultralytics/ultralytics/blob/ef03e6732aecc91134275a3f5a62f2e0f82ab4bf/.github/workflows/publish.yml#L1-L69

**Requirements:**

- Experience with conda distribution and packaging
- Experience with Github Actions
- Familiarity with YOLOv8 and its dependencies
- Strong problem-solving skills

**Expected Deliverables:**

- YOLOv8 conda package that can be easily installed
- Github Actions workflow for deployment on version increase
- Documentation on how to install and use the conda package

We welcome contributions from anyone interested in helping us achieve this goal. Let's work together to make YOLOv8 more accessible to everyone!

Originally raised in https://github.com/ultralytics/ultralytics/issues/304



Discussion:
I've started the process to get `ultralytics` on conda-forge, see https://github.com/conda-forge/staged-recipes/pull/22721. I've added @glenn-jocher, @AyushExel, and @Laughing-q to the list of proposed maintainers (along with myself)... let me know if that list should be different.

Currently, the only thing blocking that PR is the fact that the `thop` dependency is not available on conda-forge yet. `thop` does not have an sdist published to PyPI either, so I'm not sure how to get it on conda-forge. I've submitted https://github.com/Lyken17/pytorch-OpCounter/pull/204 to change that, hoping that gets merged soon.

Alternatively, Is the dependency on `thop` necessary? Can `ultralytics` be updated to only use `thop` if available, and fall back to no profiling support if `thop` isn't available?

With the way conda-forge is set up, no changes should be necessary to this repo's GitHub Actions setup... once a new version of `ultralytics` is published to PyPI, the automation around conda-forge handles grabbing that release off PyPI and publishing it to conda-forge.
@abraha2d thank you for updating us on the progress you've made to get `ultralytics` on conda-forge. We appreciate your efforts in proposing the list of maintainers, which seems fine for now. That's great to hear that the only thing holding the PR back is the `thop` dependency, and we will have to wait until there is a published sdist on PyPI or a successful merge on https://github.com/Lyken17/pytorch-OpCounter/pull/204.

Regarding the dependency of `thop`, we will check if this is necessary for YOLOv8, and if not, we can consider updating it to only use `thop` when it's available and fallback when it's not.

Additionally, we appreciate your feedback on the GitHub Actions setup and how the process for conda-forge works. Please keep us posted on updates, and we're committed to making `ultralytics` more accessible to everyone.
@abraha2d ok I've looked into this some more. Unfortunately thop does not appear to be maintained. I've submitted a [PR](https://github.com/Lyken17/pytorch-OpCounter/pull/201) myself about 2 months ago for a warning that's started appearing and it's gone unanswered, so we may need to search for alternatives. 

I tried to create a native torch FLOPs profiler [here](https://github.com/ultralytics/ultralytics/pull/2369), but unfortunately it's very verbose, i.e.

```
STAGE:2023-05-02 21:50:04 33874:980425 ActivityProfilerController.cpp:311] Completed Stage: Warm Up
STAGE:2023-05-02 21:50:04 33874:980425 ActivityProfilerController.cpp:317] Completed Stage: Collection
STAGE:2023-05-02 21:50:04 33874:980425 ActivityProfilerController.cpp:321] Completed Stage: Post Processing
```

We could:

- Make thop optional, i.e. if it's not installed, FLOPs are not computed.
- Figure out how to silence the native FLOPs above
- Find an alternative
- Fork thop and submit a new package to pypi, i.e. `ultralytics-thop`

Can you take a look around at the options and see what the best route is?



Hi @glenn-jocher, gracefully falling back to no FLOPs computation if thop is not installed is probably the quickest way to get this PR through. If you agree, I can get a PR up for that, and we can get this up on conda-forge once that's merged.
I can also take a look at the native profiler as that might be the best option long-term, given that `thop` is unmaintained.
@abraha2d ok let's move forward with your idea. Can you submit a PR for thops profiling to return None if thop is not installed? Then we can comment it in requirements.txt. If it is installed users will see FLOPs, if not then no FLOPs will be show, nice and simple, and then we can start with the Conda distribution :)

Resolving patch:
diff --git a/ultralytics/nn/tasks.py b/ultralytics/nn/tasks.py
--- a/ultralytics/nn/tasks.py
+++ b/ultralytics/nn/tasks.py
@@ -4,7 +4,6 @@
 from copy import deepcopy
 from pathlib import Path
 
-import thop
 import torch
 import torch.nn as nn
 
@@ -18,6 +17,11 @@
 from ultralytics.yolo.utils.torch_utils import (fuse_conv_and_bn, fuse_deconv_and_bn, initialize_weights,
                                                 intersect_dicts, make_divisible, model_info, scale_img, time_sync)
 
+try:
+    import thop
+except ImportError:
+    thop = None
+
 
 class BaseModel(nn.Module):
     """
diff --git a/ultralytics/yolo/utils/torch_utils.py b/ultralytics/yolo/utils/torch_utils.py
--- a/ultralytics/yolo/utils/torch_utils.py
+++ b/ultralytics/yolo/utils/torch_utils.py
@@ -11,7 +11,6 @@
 from typing import Union
 
 import numpy as np
-import thop
 import torch
 import torch.distributed as dist
 import torch.nn as nn
@@ -21,6 +20,11 @@
 from ultralytics.yolo.utils import DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, RANK, __version__
 from ultralytics.yolo.utils.checks import check_version
 
+try:
+    import thop
+except ImportError:
+    thop = None
+
 TORCHVISION_0_10 = check_version(torchvision.__version__, '0.10.0')
 TORCH_1_9 = check_version(torch.__version__, '1.9.0')
 TORCH_1_11 = check_version(torch.__version__, '1.11.0')
@@ -193,7 +197,7 @@ def get_flops(model, imgsz=640):
         p = next(model.parameters())
         stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32  # max stride
         im = torch.empty((1, p.shape[1], stride, stride), device=p.device)  # input image in BCHW format
-        flops = thop.profile(deepcopy(model), inputs=[im], verbose=False)[0] / 1E9 * 2  # stride GFLOPs
+        flops = thop.profile(deepcopy(model), inputs=[im], verbose=False)[0] / 1E9 * 2 if thop else 0  # stride GFLOPs
         imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz]  # expand if int/float
         flops = flops * imgsz[0] / stride * imgsz[1] / stride  # 640x640 GFLOPs
         return flops
@@ -378,7 +382,7 @@ def profile(input, ops, n=10, device=None):
             m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m
             tf, tb, t = 0, 0, [0, 0, 0]  # dt forward, backward
             try:
-                flops = thop.profile(m, inputs=[x], verbose=False)[0] / 1E9 * 2  # GFLOPs
+                flops = thop.profile(m, inputs=[x], verbose=False)[0] / 1E9 * 2 if thop else 0  # GFLOPs
             except Exception:
                 flops = 0
 


Test patch: