From 187b504d68a6bde804bc0a8d201b58a007cd5a8f Mon Sep 17 00:00:00 2001
From: Glenn Jocher <glenn.jocher@ultralytics.com>
Date: Sat, 2 Sep 2023 20:01:57 +0200
Subject: [PATCH] `ultralytics 8.0.169``TQDM`, `INTERP_LINEAR` and RTDETR
 `load_image()` updates (#4704)

Co-authored-by: Rustem Galiullin <rustemgal@gmail.com>
Co-authored-by: Rustem Galiullin <rustem.galiullin@bayanat.ai>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
---
 .github/workflows/ci.yaml              | 12 ++++++------
 docker/Dockerfile-arm64                |  3 +++
 docker/Dockerfile-cpu                  |  3 +++
 docker/Dockerfile-jetson               |  3 +++
 docker/Dockerfile-python               |  3 +++
 docker/Dockerfile-runner               |  9 +++++----
 ultralytics/__init__.py                |  2 +-
 ultralytics/cfg/models/README.md       | 18 ++++-------------
 ultralytics/data/base.py               | 21 ++++++++++----------
 ultralytics/data/converter.py          |  7 ++++---
 ultralytics/data/dataset.py            | 13 ++++++-------
 ultralytics/data/utils.py              | 11 +++++------
 ultralytics/engine/trainer.py          |  7 +++----
 ultralytics/engine/validator.py        | 10 ++--------
 ultralytics/hub/utils.py               |  7 +++----
 ultralytics/models/fastsam/prompt.py   |  7 +++----
 ultralytics/models/rtdetr/val.py       | 27 ++------------------------
 ultralytics/trackers/README.md         | 10 ++++++----
 ultralytics/utils/__init__.py          | 19 +++++++++++++++++-
 ultralytics/utils/benchmarks.py        |  7 +++----
 ultralytics/utils/callbacks/clearml.py |  1 +
 ultralytics/utils/callbacks/mlflow.py  |  1 +
 ultralytics/utils/downloads.py         | 20 +++++--------------
 23 files changed, 101 insertions(+), 120 deletions(-)

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 1d7da14c..b22ba704 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -128,18 +128,18 @@ jobs:
           python --version
           pip --version
           pip list
-      #- name: Benchmark DetectionModel
-      #  shell: bash
-      #  run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}.pt' imgsz=160 verbose=0.26
+#      - name: Benchmark DetectionModel
+#        shell: bash
+#        run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}.pt' imgsz=160 verbose=0.318
       - name: Benchmark SegmentationModel
         shell: bash
-        run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-seg.pt' imgsz=160 verbose=0.30
+        run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-seg.pt' imgsz=160 verbose=0.286
       - name: Benchmark ClassificationModel
         shell: bash
-        run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-cls.pt' imgsz=160 verbose=0.16
+        run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-cls.pt' imgsz=160 verbose=0.166
       - name: Benchmark PoseModel
         shell: bash
-        run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-pose.pt' imgsz=160 verbose=0.17
+        run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-pose.pt' imgsz=160 verbose=0.185
       - name: Merge Coverage Reports
         run: |
           coverage xml -o coverage-benchmarks.xml
diff --git a/docker/Dockerfile-arm64 b/docker/Dockerfile-arm64
index 93b2b758..516f765b 100644
--- a/docker/Dockerfile-arm64
+++ b/docker/Dockerfile-arm64
@@ -35,5 +35,8 @@ RUN pip install --no-cache -e . thop
 # Run
 # t=ultralytics/ultralytics:latest-arm64 && sudo docker run -it --ipc=host $t
 
+# Pull and Run
+# t=ultralytics/ultralytics:latest-arm64 && sudo docker pull $t && sudo docker run -it --ipc=host $t
+
 # Pull and Run with local volume mounted
 # t=ultralytics/ultralytics:latest-arm64 && sudo docker pull $t && sudo docker run -it --ipc=host -v "$(pwd)"/datasets:/usr/src/datasets $t
diff --git a/docker/Dockerfile-cpu b/docker/Dockerfile-cpu
index e636b48b..e11274b5 100644
--- a/docker/Dockerfile-cpu
+++ b/docker/Dockerfile-cpu
@@ -45,5 +45,8 @@ RUN rm -rf tmp
 # Run
 # t=ultralytics/ultralytics:latest-cpu && sudo docker run -it --ipc=host $t
 
+# Pull and Run
+# t=ultralytics/ultralytics:latest-cpu && sudo docker pull $t && sudo docker run -it --ipc=host $t
+
 # Pull and Run with local volume mounted
 # t=ultralytics/ultralytics:latest-cpu && sudo docker pull $t && sudo docker run -it --ipc=host -v "$(pwd)"/datasets:/usr/src/datasets $t
diff --git a/docker/Dockerfile-jetson b/docker/Dockerfile-jetson
index f18a83f3..d17169da 100644
--- a/docker/Dockerfile-jetson
+++ b/docker/Dockerfile-jetson
@@ -42,5 +42,8 @@ ENV OMP_NUM_THREADS=1
 # Run
 # t=ultralytics/ultralytics:latest-jetson && sudo docker run -it --ipc=host $t
 
+# Pull and Run
+# t=ultralytics/ultralytics:latest-jetson && sudo docker pull $t && sudo docker run -it --ipc=host $t
+
 # Pull and Run with NVIDIA runtime
 # t=ultralytics/ultralytics:latest-jetson && sudo docker pull $t && sudo docker run -it --ipc=host --runtime=nvidia $t
diff --git a/docker/Dockerfile-python b/docker/Dockerfile-python
index d646ae09..b27eae31 100644
--- a/docker/Dockerfile-python
+++ b/docker/Dockerfile-python
@@ -45,5 +45,8 @@ RUN rm -rf tmp
 # Run
 # t=ultralytics/ultralytics:latest-python && sudo docker run -it --ipc=host $t
 
+# Pull and Run
+# t=ultralytics/ultralytics:latest-python && sudo docker pull $t && sudo docker run -it --ipc=host $t
+
 # Pull and Run with local volume mounted
 # t=ultralytics/ultralytics:latest-python && sudo docker pull $t && sudo docker run -it --ipc=host -v "$(pwd)"/datasets:/usr/src/datasets $t
diff --git a/docker/Dockerfile-runner b/docker/Dockerfile-runner
index 35f87130..a10af7a6 100644
--- a/docker/Dockerfile-runner
+++ b/docker/Dockerfile-runner
@@ -8,10 +8,11 @@ FROM ultralytics/ultralytics:latest
 # Set the working directory
 WORKDIR /actions-runner
 
-# Download and unpack the latest runner
-RUN curl -o actions-runner-linux-x64-2.308.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.308.0/actions-runner-linux-x64-2.308.0.tar.gz && \
-    tar xzf actions-runner-linux-x64-2.308.0.tar.gz && \
-    rm actions-runner-linux-x64-2.308.0.tar.gz
+# Download and unpack the latest runner from https://github.com/actions/runner
+RUN FILENAME=actions-runner-linux-x64-2.308.0.tar.gz && \
+    curl -o $FILENAME -L https://github.com/actions/runner/releases/download/v2.308.0/$FILENAME && \
+    tar xzf $FILENAME && \
+    rm $FILENAME
 
 # Install runner dependencies
 ENV RUNNER_ALLOW_RUNASROOT=1
diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py
index f73ef84b..d89edac3 100644
--- a/ultralytics/__init__.py
+++ b/ultralytics/__init__.py
@@ -1,6 +1,6 @@
 # Ultralytics YOLO 🚀, AGPL-3.0 license
 
-__version__ = '8.0.168'
+__version__ = '8.0.169'
 
 from ultralytics.models import RTDETR, SAM, YOLO
 from ultralytics.models.fastsam import FastSAM
diff --git a/ultralytics/cfg/models/README.md b/ultralytics/cfg/models/README.md
index a0edc4b0..1b879bd0 100644
--- a/ultralytics/cfg/models/README.md
+++ b/ultralytics/cfg/models/README.md
@@ -1,19 +1,10 @@
 ## Models
 
-Welcome to the Ultralytics Models directory! Here you will find a wide variety of pre-configured model configuration
-files (`*.yaml`s) that can be used to create custom YOLO models. The models in this directory have been expertly crafted
-and fine-tuned by the Ultralytics team to provide the best performance for a wide range of object detection and image
-segmentation tasks.
+Welcome to the Ultralytics Models directory! Here you will find a wide variety of pre-configured model configuration files (`*.yaml`s) that can be used to create custom YOLO models. The models in this directory have been expertly crafted and fine-tuned by the Ultralytics team to provide the best performance for a wide range of object detection and image segmentation tasks.
 
-These model configurations cover a wide range of scenarios, from simple object detection to more complex tasks like
-instance segmentation and object tracking. They are also designed to run efficiently on a variety of hardware platforms,
-from CPUs to GPUs. Whether you are a seasoned machine learning practitioner or just getting started with YOLO, this
-directory provides a great starting point for your custom model development needs.
+These model configurations cover a wide range of scenarios, from simple object detection to more complex tasks like instance segmentation and object tracking. They are also designed to run efficiently on a variety of hardware platforms, from CPUs to GPUs. Whether you are a seasoned machine learning practitioner or just getting started with YOLO, this directory provides a great starting point for your custom model development needs.
 
-To get started, simply browse through the models in this directory and find one that best suits your needs. Once you've
-selected a model, you can use the provided `*.yaml` file to train and deploy your custom YOLO model with ease. See full
-details at the Ultralytics [Docs](https://docs.ultralytics.com/models), and if you need help or have any questions, feel free
-to reach out to the Ultralytics team for support. So, don't wait, start creating your custom YOLO model now!
+To get started, simply browse through the models in this directory and find one that best suits your needs. Once you've selected a model, you can use the provided `*.yaml` file to train and deploy your custom YOLO model with ease. See full details at the Ultralytics [Docs](https://docs.ultralytics.com/models), and if you need help or have any questions, feel free to reach out to the Ultralytics team for support. So, don't wait, start creating your custom YOLO model now!
 
 ### Usage
 
@@ -37,8 +28,7 @@ model.train(data="coco128.yaml", epochs=100)  # train the model
 
 ## Pre-trained Model Architectures
 
-Ultralytics supports many model architectures. Visit https://docs.ultralytics.com/models to view detailed information
-and usage. Any of these models can be used by loading their configs or pretrained checkpoints if available.
+Ultralytics supports many model architectures. Visit https://docs.ultralytics.com/models to view detailed information and usage. Any of these models can be used by loading their configs or pretrained checkpoints if available.
 
 ## Contributing New Models
 
diff --git a/ultralytics/data/base.py b/ultralytics/data/base.py
index 3fbb82bf..429533dc 100644
--- a/ultralytics/data/base.py
+++ b/ultralytics/data/base.py
@@ -13,9 +13,8 @@ import cv2
 import numpy as np
 import psutil
 from torch.utils.data import Dataset
-from tqdm import tqdm
 
-from ultralytics.utils import DEFAULT_CFG, LOCAL_RANK, LOGGER, NUM_THREADS, TQDM_BAR_FORMAT
+from ultralytics.utils import DEFAULT_CFG, LOCAL_RANK, LOGGER, NUM_THREADS, TQDM
 
 from .utils import HELP_URL, IMG_FORMATS
 
@@ -141,7 +140,7 @@ class BaseDataset(Dataset):
             if self.single_cls:
                 self.labels[i]['cls'][:, 0] = 0
 
-    def load_image(self, i):
+    def load_image(self, i, rect_mode=True):
         """Loads 1 image from dataset index 'i', returns (im, resized hw)."""
         im, f, fn = self.ims[i], self.im_files[i], self.npy_files[i]
         if im is None:  # not cached in RAM
@@ -152,11 +151,13 @@ class BaseDataset(Dataset):
                 if im is None:
                     raise FileNotFoundError(f'Image Not Found {f}')
             h0, w0 = im.shape[:2]  # orig hw
-            r = self.imgsz / max(h0, w0)  # ratio
-            if r != 1:  # if sizes are not equal
-                interp = cv2.INTER_LINEAR if (self.augment or r > 1) else cv2.INTER_AREA
-                im = cv2.resize(im, (min(math.ceil(w0 * r), self.imgsz), min(math.ceil(h0 * r), self.imgsz)),
-                                interpolation=interp)
+            if rect_mode:  # resize long side to imgsz while maintaining aspect ratio
+                r = self.imgsz / max(h0, w0)  # ratio
+                if r != 1:  # if sizes are not equal
+                    w, h = (min(math.ceil(w0 * r), self.imgsz), min(math.ceil(h0 * r), self.imgsz))
+                    im = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR)
+            elif not (h0 == w0 == self.imgsz):  # resize by stretching image to square imgsz
+                im = cv2.resize(im, (self.imgsz, self.imgsz), interpolation=cv2.INTER_LINEAR)
 
             # Add to buffer if training with augmentations
             if self.augment:
@@ -176,7 +177,7 @@ class BaseDataset(Dataset):
         fcn = self.cache_images_to_disk if cache == 'disk' else self.load_image
         with ThreadPool(NUM_THREADS) as pool:
             results = pool.imap(fcn, range(self.ni))
-            pbar = tqdm(enumerate(results), total=self.ni, bar_format=TQDM_BAR_FORMAT, disable=LOCAL_RANK > 0)
+            pbar = TQDM(enumerate(results), total=self.ni, disable=LOCAL_RANK > 0)
             for i, x in pbar:
                 if cache == 'disk':
                     b += self.npy_files[i].stat().st_size
@@ -190,7 +191,7 @@ class BaseDataset(Dataset):
         """Saves an image as an *.npy file for faster loading."""
         f = self.npy_files[i]
         if not f.exists():
-            np.save(f.as_posix(), cv2.imread(self.im_files[i]))
+            np.save(f.as_posix(), cv2.imread(self.im_files[i]), allow_pickle=False)
 
     def check_cache_ram(self, safety_margin=0.5):
         """Check image caching requirements vs available memory."""
diff --git a/ultralytics/data/converter.py b/ultralytics/data/converter.py
index bbcbb2cf..1e3b429e 100644
--- a/ultralytics/data/converter.py
+++ b/ultralytics/data/converter.py
@@ -7,7 +7,8 @@ from pathlib import Path
 
 import cv2
 import numpy as np
-from tqdm import tqdm
+
+from ultralytics.utils import TQDM
 
 
 def coco91_to_coco80_class():
@@ -90,7 +91,7 @@ def convert_coco(labels_dir='../coco/annotations/', use_segments=False, use_keyp
             imgToAnns[ann['image_id']].append(ann)
 
         # Write labels file
-        for img_id, anns in tqdm(imgToAnns.items(), desc=f'Annotations {json_file}'):
+        for img_id, anns in TQDM(imgToAnns.items(), desc=f'Annotations {json_file}'):
             img = images[f'{img_id:d}']
             h, w, f = img['height'], img['width'], img['file_name']
 
@@ -222,7 +223,7 @@ def convert_dota_to_yolo_obb(dota_root_path: str):
         save_dir.mkdir(parents=True, exist_ok=True)
 
         image_paths = list(image_dir.iterdir())
-        for image_path in tqdm(image_paths, desc=f'Processing {phase} images'):
+        for image_path in TQDM(image_paths, desc=f'Processing {phase} images'):
             if image_path.suffix != '.png':
                 continue
             image_name_without_ext = image_path.stem
diff --git a/ultralytics/data/dataset.py b/ultralytics/data/dataset.py
index 515c4823..65fe141b 100644
--- a/ultralytics/data/dataset.py
+++ b/ultralytics/data/dataset.py
@@ -8,9 +8,8 @@ import cv2
 import numpy as np
 import torch
 import torchvision
-from tqdm import tqdm
 
-from ultralytics.utils import LOCAL_RANK, NUM_THREADS, TQDM_BAR_FORMAT, colorstr, is_dir_writeable
+from ultralytics.utils import LOCAL_RANK, NUM_THREADS, TQDM, colorstr, is_dir_writeable
 
 from .augment import Compose, Format, Instances, LetterBox, classify_albumentations, classify_transforms, v8_transforms
 from .base import BaseDataset
@@ -60,7 +59,7 @@ class YOLODataset(BaseDataset):
                                 iterable=zip(self.im_files, self.label_files, repeat(self.prefix),
                                              repeat(self.use_keypoints), repeat(len(self.data['names'])), repeat(nkpt),
                                              repeat(ndim)))
-            pbar = tqdm(results, desc=desc, total=total, bar_format=TQDM_BAR_FORMAT)
+            pbar = TQDM(results, desc=desc, total=total)
             for im_file, lb, shape, segments, keypoint, nm_f, nf_f, ne_f, nc_f, msg in pbar:
                 nm += nm_f
                 nf += nf_f
@@ -107,7 +106,7 @@ class YOLODataset(BaseDataset):
         nf, nm, ne, nc, n = cache.pop('results')  # found, missing, empty, corrupt, total
         if exists and LOCAL_RANK in (-1, 0):
             d = f'Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt'
-            tqdm(None, desc=self.prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT)  # display results
+            TQDM(None, desc=self.prefix + d, total=n, initial=n)  # display results
             if cache['msgs']:
                 LOGGER.info('\n'.join(cache['msgs']))  # display warnings
 
@@ -244,7 +243,7 @@ class ClassificationDataset(torchvision.datasets.ImageFolder):
             im = self.samples[i][3] = cv2.imread(f)
         elif self.cache_disk:
             if not fn.exists():  # load npy
-                np.save(fn.as_posix(), cv2.imread(f))
+                np.save(fn.as_posix(), cv2.imread(f), allow_pickle=False)
             im = np.load(fn)
         else:  # read image
             im = cv2.imread(f)  # BGR
@@ -269,7 +268,7 @@ class ClassificationDataset(torchvision.datasets.ImageFolder):
             nf, nc, n, samples = cache.pop('results')  # found, missing, empty, corrupt, total
             if LOCAL_RANK in (-1, 0):
                 d = f'{desc} {nf} images, {nc} corrupt'
-                tqdm(None, desc=d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT)
+                TQDM(None, desc=d, total=n, initial=n)
                 if cache['msgs']:
                     LOGGER.info('\n'.join(cache['msgs']))  # display warnings
             return samples
@@ -278,7 +277,7 @@ class ClassificationDataset(torchvision.datasets.ImageFolder):
         nf, nc, msgs, samples, x = 0, 0, [], [], {}
         with ThreadPool(NUM_THREADS) as pool:
             results = pool.imap(func=verify_image, iterable=zip(self.samples, repeat(self.prefix)))
-            pbar = tqdm(results, desc=desc, total=len(self.samples), bar_format=TQDM_BAR_FORMAT)
+            pbar = TQDM(results, desc=desc, total=len(self.samples))
             for sample, nf_f, nc_f, msg in pbar:
                 if nf_f:
                     samples.append(sample)
diff --git a/ultralytics/data/utils.py b/ultralytics/data/utils.py
index 2100cef5..3b780f26 100644
--- a/ultralytics/data/utils.py
+++ b/ultralytics/data/utils.py
@@ -15,11 +15,10 @@ from tarfile import is_tarfile
 import cv2
 import numpy as np
 from PIL import Image, ImageOps
-from tqdm import tqdm
 
 from ultralytics.nn.autobackend import check_class_names
-from ultralytics.utils import (DATASETS_DIR, LOGGER, NUM_THREADS, ROOT, SETTINGS_YAML, clean_url, colorstr, emojis,
-                               yaml_load)
+from ultralytics.utils import (DATASETS_DIR, LOGGER, NUM_THREADS, ROOT, SETTINGS_YAML, TQDM, clean_url, colorstr,
+                               emojis, yaml_load)
 from ultralytics.utils.checks import check_file, check_font, is_ascii
 from ultralytics.utils.downloads import download, safe_download, unzip_file
 from ultralytics.utils.ops import segments2boxes
@@ -510,7 +509,7 @@ class HUBDatasetStats:
                                       use_keypoints=self.task == 'pose')
                 x = np.array([
                     np.bincount(label['cls'].astype(int).flatten(), minlength=self.data['nc'])
-                    for label in tqdm(dataset.labels, total=len(dataset), desc='Statistics')])  # shape(128x80)
+                    for label in TQDM(dataset.labels, total=len(dataset), desc='Statistics')])  # shape(128x80)
                 self.stats[split] = {
                     'instance_stats': {
                         'total': int(x.sum()),
@@ -541,7 +540,7 @@ class HUBDatasetStats:
                 continue
             dataset = YOLODataset(img_path=self.data[split], data=self.data)
             with ThreadPool(NUM_THREADS) as pool:
-                for _ in tqdm(pool.imap(self._hub_ops, dataset.im_files), total=len(dataset), desc=f'{split} images'):
+                for _ in TQDM(pool.imap(self._hub_ops, dataset.im_files), total=len(dataset), desc=f'{split} images'):
                     pass
         LOGGER.info(f'Done. All images saved to {self.im_dir}')
         return self.im_dir
@@ -614,7 +613,7 @@ def autosplit(path=DATASETS_DIR / 'coco8/images', weights=(0.9, 0.1, 0.0), annot
             (path.parent / x).unlink()  # remove existing
 
     LOGGER.info(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only)
-    for i, img in tqdm(zip(indices, files), total=n):
+    for i, img in TQDM(zip(indices, files), total=n):
         if not annotated_only or Path(img2label_paths([str(img)])[0]).exists():  # check label
             with open(path.parent / txt[i], 'a') as f:
                 f.write(f'./{img.relative_to(path.parent).as_posix()}' + '\n')  # add image to txt file
diff --git a/ultralytics/engine/trainer.py b/ultralytics/engine/trainer.py
index c95cde23..86e6ebf2 100644
--- a/ultralytics/engine/trainer.py
+++ b/ultralytics/engine/trainer.py
@@ -21,13 +21,12 @@ from torch import distributed as dist
 from torch import nn, optim
 from torch.cuda import amp
 from torch.nn.parallel import DistributedDataParallel as DDP
-from tqdm import tqdm
 
 from ultralytics.cfg import get_cfg, get_save_dir
 from ultralytics.data.utils import check_cls_dataset, check_det_dataset
 from ultralytics.nn.tasks import attempt_load_one_weight, attempt_load_weights
-from ultralytics.utils import (DEFAULT_CFG, LOGGER, RANK, TQDM_BAR_FORMAT, __version__, callbacks, clean_url, colorstr,
-                               emojis, yaml_save)
+from ultralytics.utils import (DEFAULT_CFG, LOGGER, RANK, TQDM, __version__, callbacks, clean_url, colorstr, emojis,
+                               yaml_save)
 from ultralytics.utils.autobatch import check_train_batch_size
 from ultralytics.utils.checks import check_amp, check_file, check_imgsz, print_args
 from ultralytics.utils.dist import ddp_cleanup, generate_ddp_command
@@ -326,7 +325,7 @@ class BaseTrainer:
 
             if RANK in (-1, 0):
                 LOGGER.info(self.progress_string())
-                pbar = tqdm(enumerate(self.train_loader), total=nb, bar_format=TQDM_BAR_FORMAT)
+                pbar = TQDM(enumerate(self.train_loader), total=nb)
             self.tloss = None
             self.optimizer.zero_grad()
             for i, batch in pbar:
diff --git a/ultralytics/engine/validator.py b/ultralytics/engine/validator.py
index 811520b9..6f6d55ee 100644
--- a/ultralytics/engine/validator.py
+++ b/ultralytics/engine/validator.py
@@ -24,12 +24,11 @@ from pathlib import Path
 
 import numpy as np
 import torch
-from tqdm import tqdm
 
 from ultralytics.cfg import get_cfg, get_save_dir
 from ultralytics.data.utils import check_cls_dataset, check_det_dataset
 from ultralytics.nn.autobackend import AutoBackend
-from ultralytics.utils import LOGGER, TQDM_BAR_FORMAT, callbacks, colorstr, emojis
+from ultralytics.utils import LOGGER, TQDM, callbacks, colorstr, emojis
 from ultralytics.utils.checks import check_imgsz
 from ultralytics.utils.ops import Profile
 from ultralytics.utils.torch_utils import de_parallel, select_device, smart_inference_mode
@@ -154,12 +153,7 @@ class BaseValidator:
             model.warmup(imgsz=(1 if pt else self.args.batch, 3, imgsz, imgsz))  # warmup
 
         dt = Profile(), Profile(), Profile(), Profile()
-        n_batches = len(self.dataloader)
-        desc = self.get_desc()
-        # NOTE: keeping `not self.training` in tqdm will eliminate pbar after segmentation evaluation during training,
-        # which may affect classification task since this arg is in yolov5/classify/val.py.
-        # bar = tqdm(self.dataloader, desc, n_batches, not self.training, bar_format=TQDM_BAR_FORMAT)
-        bar = tqdm(self.dataloader, desc, n_batches, bar_format=TQDM_BAR_FORMAT)
+        bar = TQDM(self.dataloader, desc=self.get_desc(), total=len(self.dataloader))
         self.init_metrics(de_parallel(model))
         self.jdict = []  # empty before each val
         for batch_i, batch in enumerate(bar):
diff --git a/ultralytics/hub/utils.py b/ultralytics/hub/utils.py
index e469987a..07da970a 100644
--- a/ultralytics/hub/utils.py
+++ b/ultralytics/hub/utils.py
@@ -9,10 +9,9 @@ import time
 from pathlib import Path
 
 import requests
-from tqdm import tqdm
 
-from ultralytics.utils import (ENVIRONMENT, LOGGER, ONLINE, RANK, SETTINGS, TESTS_RUNNING, TQDM_BAR_FORMAT, TryExcept,
-                               __version__, colorstr, get_git_origin_url, is_colab, is_git_dir, is_pip_package)
+from ultralytics.utils import (ENVIRONMENT, LOGGER, ONLINE, RANK, SETTINGS, TESTS_RUNNING, TQDM, TryExcept, __version__,
+                               colorstr, get_git_origin_url, is_colab, is_git_dir, is_pip_package)
 from ultralytics.utils.downloads import GITHUB_ASSETS_NAMES
 
 PREFIX = colorstr('Ultralytics HUB: ')
@@ -80,7 +79,7 @@ def requests_with_progress(method, url, **kwargs):
     response = requests.request(method, url, stream=True, **kwargs)
     total = int(response.headers.get('content-length', 0))  # total size
     try:
-        pbar = tqdm(total=total, unit='B', unit_scale=True, unit_divisor=1024, bar_format=TQDM_BAR_FORMAT)
+        pbar = TQDM(total=total, unit='B', unit_scale=True, unit_divisor=1024)
         for data in response.iter_content(chunk_size=1024):
             pbar.update(len(data))
         pbar.close()
diff --git a/ultralytics/models/fastsam/prompt.py b/ultralytics/models/fastsam/prompt.py
index 79266e1e..e4657112 100644
--- a/ultralytics/models/fastsam/prompt.py
+++ b/ultralytics/models/fastsam/prompt.py
@@ -8,9 +8,8 @@ import matplotlib.pyplot as plt
 import numpy as np
 import torch
 from PIL import Image
-from tqdm import tqdm
 
-from ultralytics.utils import TQDM_BAR_FORMAT
+from ultralytics.utils import TQDM
 
 
 class FastSAMPrompt:
@@ -87,7 +86,7 @@ class FastSAMPrompt:
              retina=False,
              withContours=True):
         n = len(annotations)
-        pbar = tqdm(annotations, total=n, bar_format=TQDM_BAR_FORMAT)
+        pbar = TQDM(annotations, total=n)
         for ann in pbar:
             result_name = os.path.basename(ann.path)
             image = ann.orig_img
@@ -156,7 +155,7 @@ class FastSAMPrompt:
             save_path.parent.mkdir(exist_ok=True, parents=True)
             cv2.imwrite(str(save_path), img_array)
             plt.close()
-            pbar.set_description('Saving {} to {}'.format(result_name, save_path))
+            pbar.set_description(f'Saving {result_name} to {save_path}')
 
     @staticmethod
     def fast_show_mask(
diff --git a/ultralytics/models/rtdetr/val.py b/ultralytics/models/rtdetr/val.py
index 69c23d08..9b984bed 100644
--- a/ultralytics/models/rtdetr/val.py
+++ b/ultralytics/models/rtdetr/val.py
@@ -2,8 +2,6 @@
 
 from pathlib import Path
 
-import cv2
-import numpy as np
 import torch
 
 from ultralytics.data import YOLODataset
@@ -21,30 +19,9 @@ class RTDETRDataset(YOLODataset):
         super().__init__(*args, data=data, use_segments=False, use_keypoints=False, **kwargs)
 
     # NOTE: add stretch version load_image for rtdetr mosaic
-    def load_image(self, i):
+    def load_image(self, i, rect_mode=False):
         """Loads 1 image from dataset index 'i', returns (im, resized hw)."""
-        im, f, fn = self.ims[i], self.im_files[i], self.npy_files[i]
-        if im is None:  # not cached in RAM
-            if fn.exists():  # load npy
-                im = np.load(fn)
-            else:  # read image
-                im = cv2.imread(f)  # BGR
-                if im is None:
-                    raise FileNotFoundError(f'Image Not Found {f}')
-            h0, w0 = im.shape[:2]  # orig hw
-            im = cv2.resize(im, (self.imgsz, self.imgsz), interpolation=cv2.INTER_LINEAR)
-
-            # Add to buffer if training with augmentations
-            if self.augment:
-                self.ims[i], self.im_hw0[i], self.im_hw[i] = im, (h0, w0), im.shape[:2]  # im, hw_original, hw_resized
-                self.buffer.append(i)
-                if len(self.buffer) >= self.max_buffer_length:
-                    j = self.buffer.pop(0)
-                    self.ims[j], self.im_hw0[j], self.im_hw[j] = None, None, None
-
-            return im, (h0, w0), im.shape[:2]
-
-        return self.ims[i], self.im_hw0[i], self.im_hw[i]
+        return super().load_image(i=i, rect_mode=rect_mode)
 
     def build_transforms(self, hyp=None):
         """Temporary, only for evaluation."""
diff --git a/ultralytics/trackers/README.md b/ultralytics/trackers/README.md
index 843bd224..fee2b819 100644
--- a/ultralytics/trackers/README.md
+++ b/ultralytics/trackers/README.md
@@ -69,7 +69,7 @@ while True:
 
 ## Change tracker parameters
 
-You can change the tracker parameters by eding the `tracker.yaml` file which is located in the ultralytics/cfg/trackers folder.
+You can change the tracker parameters by editing the `tracker.yaml` file which is located in the ultralytics/cfg/trackers folder.
 
 ## Command Line Interface (CLI)
 
@@ -81,6 +81,8 @@ yolo segment track source=... tracker=...
 yolo pose track source=... tracker=...
 ```
 
-By default, trackers will use the configuration in `ultralytics/cfg/trackers`.
-We also support using a modified tracker config file. Please refer to the tracker config files
-in `ultralytics/cfg/trackers`.<br>
+By default, trackers will use the configuration in `ultralytics/cfg/trackers`. We also support using a modified tracker config file. Please refer to the tracker config files in `ultralytics/cfg/trackers`.
+
+## Contributing New Trackers
+
+If you've developed a new tracker architecture or have improvements for existing trackers that you'd like to contribute to the Ultralytics community, please submit your contribution in a new Pull Request. For more details, visit our [Contributing Guide](https://docs.ultralytics.com/help/contributing).
diff --git a/ultralytics/utils/__init__.py b/ultralytics/utils/__init__.py
index 4cedf765..e842294e 100644
--- a/ultralytics/utils/__init__.py
+++ b/ultralytics/utils/__init__.py
@@ -20,6 +20,7 @@ import matplotlib.pyplot as plt
 import numpy as np
 import torch
 import yaml
+from tqdm import tqdm as tqdm_original
 
 from ultralytics import __version__
 
@@ -35,7 +36,7 @@ DEFAULT_CFG_PATH = ROOT / 'cfg/default.yaml'
 NUM_THREADS = min(8, max(1, os.cpu_count() - 1))  # number of YOLOv5 multiprocessing threads
 AUTOINSTALL = str(os.getenv('YOLO_AUTOINSTALL', True)).lower() == 'true'  # global auto-install mode
 VERBOSE = str(os.getenv('YOLO_VERBOSE', True)).lower() == 'true'  # global verbose mode
-TQDM_BAR_FORMAT = '{l_bar}{bar:10}{r_bar}'  # tqdm bar format
+TQDM_BAR_FORMAT = '{l_bar}{bar:10}{r_bar}' if VERBOSE else None  # tqdm bar format
 LOGGING_NAME = 'ultralytics'
 MACOS, LINUX, WINDOWS = (platform.system() == x for x in ['Darwin', 'Linux', 'Windows'])  # environment booleans
 ARM64 = platform.machine() in ('arm64', 'aarch64')  # ARM64 booleans
@@ -106,6 +107,22 @@ os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8'  # for deterministic training
 os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # suppress verbose TF compiler warnings in Colab
 
 
+class TQDM(tqdm_original):
+    """
+    Custom Ultralytics tqdm class with different default arguments.
+
+    Args:
+        (*args): Positional arguments passed to original tqdm.
+        (**kwargs): Keyword arguments, with custom defaults applied.
+    """
+
+    def __init__(self, *args, **kwargs):
+        # Set new default values (these can still be overridden when calling TQDM)
+        kwargs['disable'] = not VERBOSE or kwargs.get('disable', False)  # logical 'and' with default value if passed
+        kwargs.setdefault('bar_format', TQDM_BAR_FORMAT)  # override default value if passed
+        super().__init__(*args, **kwargs)
+
+
 class SimpleClass:
     """
     Ultralytics SimpleClass is a base class providing helpful string representation, error reporting, and attribute
diff --git a/ultralytics/utils/benchmarks.py b/ultralytics/utils/benchmarks.py
index d92d0625..e92a9ae7 100644
--- a/ultralytics/utils/benchmarks.py
+++ b/ultralytics/utils/benchmarks.py
@@ -32,12 +32,11 @@ from pathlib import Path
 
 import numpy as np
 import torch.cuda
-from tqdm import tqdm
 
 from ultralytics import YOLO
 from ultralytics.cfg import TASK2DATA, TASK2METRIC
 from ultralytics.engine.exporter import export_formats
-from ultralytics.utils import ASSETS, LINUX, LOGGER, MACOS, SETTINGS
+from ultralytics.utils import ASSETS, LINUX, LOGGER, MACOS, SETTINGS, TQDM
 from ultralytics.utils.checks import check_requirements, check_yolo
 from ultralytics.utils.files import file_size
 from ultralytics.utils.torch_utils import select_device
@@ -285,7 +284,7 @@ class ProfileModels:
 
         # Timed runs
         run_times = []
-        for _ in tqdm(range(num_runs), desc=engine_file):
+        for _ in TQDM(range(num_runs), desc=engine_file):
             results = model(input_data, imgsz=self.imgsz, verbose=False)
             run_times.append(results[0].speed['inference'])  # Convert to milliseconds
 
@@ -336,7 +335,7 @@ class ProfileModels:
 
         # Timed runs
         run_times = []
-        for _ in tqdm(range(num_runs), desc=onnx_file):
+        for _ in TQDM(range(num_runs), desc=onnx_file):
             start_time = time.time()
             sess.run([output_name], {input_name: input_data})
             run_times.append((time.time() - start_time) * 1000)  # Convert to milliseconds
diff --git a/ultralytics/utils/callbacks/clearml.py b/ultralytics/utils/callbacks/clearml.py
index 48e91ece..dfb22039 100644
--- a/ultralytics/utils/callbacks/clearml.py
+++ b/ultralytics/utils/callbacks/clearml.py
@@ -9,6 +9,7 @@ try:
     from clearml import Task
     from clearml.binding.frameworks.pytorch_bind import PatchPyTorchModelIO
     from clearml.binding.matplotlib_bind import PatchedMatplotlib
+
     assert hasattr(clearml, '__version__')  # verify package is not directory
 
 except (ImportError, AssertionError):
diff --git a/ultralytics/utils/callbacks/mlflow.py b/ultralytics/utils/callbacks/mlflow.py
index 424c931d..8d4501b3 100644
--- a/ultralytics/utils/callbacks/mlflow.py
+++ b/ultralytics/utils/callbacks/mlflow.py
@@ -6,6 +6,7 @@ try:
     assert not TESTS_RUNNING  # do not log pytest
     assert SETTINGS['mlflow'] is True  # verify integration is enabled
     import mlflow
+
     assert hasattr(mlflow, '__version__')  # verify package is not directory
 
     import os
diff --git a/ultralytics/utils/downloads.py b/ultralytics/utils/downloads.py
index c62095c2..6e310bf1 100644
--- a/ultralytics/utils/downloads.py
+++ b/ultralytics/utils/downloads.py
@@ -11,9 +11,8 @@ from urllib import parse, request
 
 import requests
 import torch
-from tqdm import tqdm
 
-from ultralytics.utils import LOGGER, TQDM_BAR_FORMAT, checks, clean_url, emojis, is_online, url2file
+from ultralytics.utils import LOGGER, TQDM, checks, clean_url, emojis, is_online, url2file
 
 # Define Ultralytics GitHub assets maintained at https://github.com/ultralytics/assets
 GITHUB_ASSETS_REPO = 'ultralytics/assets'
@@ -101,11 +100,7 @@ def zip_directory(directory, compress=True, exclude=('.DS_Store', '__MACOSX'), p
     zip_file = directory.with_suffix('.zip')
     compression = ZIP_DEFLATED if compress else ZIP_STORED
     with ZipFile(zip_file, 'w', compression) as f:
-        for file in tqdm(files_to_zip,
-                         desc=f'Zipping {directory} to {zip_file}...',
-                         unit='file',
-                         disable=not progress,
-                         bar_format=TQDM_BAR_FORMAT):
+        for file in TQDM(files_to_zip, desc=f'Zipping {directory} to {zip_file}...', unit='file', disable=not progress):
             f.write(file, file.relative_to(directory))
 
     return zip_file  # return path to zip file
@@ -163,11 +158,7 @@ def unzip_file(file, path=None, exclude=('.DS_Store', '__MACOSX'), exist_ok=Fals
             LOGGER.warning(f'WARNING ⚠️ Skipping {file} unzip as destination directory {path} is not empty.')
             return path
 
-        for f in tqdm(files,
-                      desc=f'Unzipping {file} to {Path(path).resolve()}...',
-                      unit='file',
-                      disable=not progress,
-                      bar_format=TQDM_BAR_FORMAT):
+        for f in TQDM(files, desc=f'Unzipping {file} to {Path(path).resolve()}...', unit='file', disable=not progress):
             zipObj.extract(f, path=extract_path)
 
     return path  # return unzip dir
@@ -297,13 +288,12 @@ def safe_download(url,
                     if method == 'torch':
                         torch.hub.download_url_to_file(url, f, progress=progress)
                     else:
-                        with request.urlopen(url) as response, tqdm(total=int(response.getheader('Content-Length', 0)),
+                        with request.urlopen(url) as response, TQDM(total=int(response.getheader('Content-Length', 0)),
                                                                     desc=desc,
                                                                     disable=not progress,
                                                                     unit='B',
                                                                     unit_scale=True,
-                                                                    unit_divisor=1024,
-                                                                    bar_format=TQDM_BAR_FORMAT) as pbar:
+                                                                    unit_divisor=1024) as pbar:
                             with open(f, 'wb') as f_opened:
                                 for data in response:
                                     f_opened.write(data)