From f6db58dd372cb18b818ef4e5ddbe316f5955929e Mon Sep 17 00:00:00 2001 From: henrytsui000 Date: Mon, 24 Nov 2025 16:49:03 -0500 Subject: [PATCH 1/5] [Fix] typo of quiet (from quite) --- .github/workflows/deploy.yaml | 2 +- README.md | 2 +- docs/HOWTO.md | 2 +- yolo/lazy.py | 2 +- yolo/utils/logging_utils.py | 14 +++++++------- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 07348d68..24f52c0e 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -61,7 +61,7 @@ jobs: run: | python yolo/lazy.py task=inference use_wandb=False python yolo/lazy.py task=inference use_wandb=False model=v7 - python yolo/lazy.py task=inference use_wandb=False +quite=True + python yolo/lazy.py task=inference use_wandb=False +quiet=True python yolo/lazy.py task=inference use_wandb=False name=AnyNameYouWant python yolo/lazy.py task=inference use_wandb=False image_size=\[480,640] python yolo/lazy.py task=inference use_wandb=False task.nms.min_confidence=0.1 diff --git a/README.md b/README.md index 21689331..b3685577 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ python yolo/lazy.py task=inference \ # default is inference task.nms.min_confidence=0.1 \ # nms config task.fast_inference=onnx \ # onnx, trt, deploy task.data.source=data/toy/images/train \ # file, dir, webcam - +quite=True \ # Quite Output + +quiet=True \ # Quiet Output yolo task.data.source={Any Source} # if pip installed yolo task=inference task.data.source={Any} ``` diff --git a/docs/HOWTO.md b/docs/HOWTO.md index 2707b2e9..f2895176 100644 --- a/docs/HOWTO.md +++ b/docs/HOWTO.md @@ -17,7 +17,7 @@ python yolo/lazy.py task=validation dataset=toy name=validation # Inference python yolo/lazy.py task=inference python yolo/lazy.py task=inference device=cpu -python yolo/lazy.py task=inference +quite=True +python yolo/lazy.py task=inference +quiet=True python yolo/lazy.py task=inference name=AnyNameYouWant python yolo/lazy.py task=inference image_size=\[480,640] python yolo/lazy.py task=inference task.nms.min_confidence=0.1 diff --git a/yolo/lazy.py b/yolo/lazy.py index fb8fe2e2..35474619 100644 --- a/yolo/lazy.py +++ b/yolo/lazy.py @@ -26,7 +26,7 @@ def main(cfg: Config): gradient_clip_val=10, gradient_clip_algorithm="norm", deterministic=True, - enable_progress_bar=not getattr(cfg, "quite", False), + enable_progress_bar=not getattr(cfg, "quiet", False), default_root_dir=save_path, ) diff --git a/yolo/utils/logging_utils.py b/yolo/utils/logging_utils.py index 672a052a..28970be4 100644 --- a/yolo/utils/logging_utils.py +++ b/yolo/utils/logging_utils.py @@ -238,7 +238,7 @@ def on_validation_batch_end(self, trainer: Trainer, pl_module, outputs, batch, b logger.log_image("Prediction", images, step=step, boxes=[log_bbox(pred_boxes)]) -def setup_logger(logger_name, quite=False): +def setup_logger(logger_name, quiet=False): class EmojiFormatter(logging.Formatter): def format(self, record, emoji=":high_voltage:"): return f"{emoji} {super().format(record)}" @@ -249,7 +249,7 @@ def format(self, record, emoji=":high_voltage:"): if rich_logger: rich_logger.handlers.clear() rich_logger.addHandler(rich_handler) - if quite: + if quiet: rich_logger.setLevel(logging.ERROR) coco_logger = logging.getLogger("faster_coco_eval.core.cocoeval") @@ -257,9 +257,9 @@ def format(self, record, emoji=":high_voltage:"): def setup(cfg: Config): - quite = hasattr(cfg, "quite") - setup_logger("lightning.fabric", quite=quite) - setup_logger("lightning.pytorch", quite=quite) + quiet = hasattr(cfg, "quiet") + setup_logger("lightning.fabric", quiet=quiet) + setup_logger("lightning.pytorch", quiet=quiet) def custom_wandb_log(string="", level=int, newline=True, repeat=True, prefix=True, silent=False): if silent: @@ -275,7 +275,7 @@ def custom_wandb_log(string="", level=int, newline=True, repeat=True, prefix=Tru if hasattr(cfg.task, "ema") and cfg.task.ema.enable: progress.append(EMA(cfg.task.ema.decay)) - if quite: + if quiet: logger.setLevel(logging.ERROR) return progress, loggers, save_path @@ -336,7 +336,7 @@ def validate_log_directory(cfg: Config, exp_name: str) -> Path: ) save_path.mkdir(parents=True, exist_ok=True) - if not getattr(cfg, "quite", False): + if not getattr(cfg, "quiet", False): logger.info(f"📄 Created log folder: [blue b u]{save_path}[/]") logger.addHandler(FileHandler(save_path / "output.log")) return save_path From 8741d7f87355ce979e00312f4fb4e0bffc97d641 Mon Sep 17 00:00:00 2001 From: henrytsui000 Date: Tue, 30 Dec 2025 01:43:34 -0500 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=90=9B=20[Add]=20Gradient=20acc=20for?= =?UTF-8?q?=20stable=20single=20gpu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yolo/config/config.py | 1 + yolo/config/task/train.yaml | 1 + yolo/utils/logging_utils.py | 8 ++++--- yolo/utils/model_utils.py | 44 ++++++++++++++++++++++++++++++++++++- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/yolo/config/config.py b/yolo/config/config.py index 313e4354..2fad2fc8 100644 --- a/yolo/config/config.py +++ b/yolo/config/config.py @@ -60,6 +60,7 @@ class DataConfig: data_augment: Dict[str, int] source: Optional[Union[str, int]] dynamic_shape: Optional[bool] + equivalent_batch_size: Optional[int] = 64 @dataclass diff --git a/yolo/config/task/train.yaml b/yolo/config/task/train.yaml index 5e16f22a..769eaf66 100644 --- a/yolo/config/task/train.yaml +++ b/yolo/config/task/train.yaml @@ -7,6 +7,7 @@ epoch: 500 data: batch_size: 16 + equivalent_batch_size: 64 image_size: ${image_size} cpu_num: ${cpu_num} shuffle: True diff --git a/yolo/utils/logging_utils.py b/yolo/utils/logging_utils.py index 672a052a..943c3bca 100644 --- a/yolo/utils/logging_utils.py +++ b/yolo/utils/logging_utils.py @@ -38,7 +38,7 @@ from yolo.config.config import Config, YOLOLayer from yolo.model.yolo import YOLO from yolo.utils.logger import logger -from yolo.utils.model_utils import EMA +from yolo.utils.model_utils import EMA, GradientAccumulation from yolo.utils.solver_utils import make_ap_table @@ -68,7 +68,6 @@ def _init_progress(self, trainer: "Trainer") -> None: self._reset_progress_bar_ids() reconfigure(**self._console_kwargs) self._console = Console() - self._console.clear_live() self.progress = YOLOCustomProgress( *self.configure_columns(trainer), auto_refresh=False, @@ -105,7 +104,7 @@ def on_train_batch_end(self, trainer, pl_module, outputs, batch: Any, batch_idx: self._update(self.train_progress_bar_id, batch_idx + 1) self._update_metrics(trainer, pl_module) epoch_descript = "[cyan]Train [white]|" - batch_descript = "[green]Train [white]|" + batch_descript = "[green]Batch [white]|" metrics = self.get_metrics(trainer, pl_module) metrics.pop("v_num") for metrics_name, metrics_val in metrics.items(): @@ -273,6 +272,9 @@ def custom_wandb_log(string="", level=int, newline=True, repeat=True, prefix=Tru progress, loggers = [], [] + if cfg.task.task == "train" and hasattr(cfg.task.data, "equivalent_batch_size"): + progress.append(GradientAccumulation(data_cfg=cfg.task.data, scheduler_cfg=cfg.task.scheduler)) + if hasattr(cfg.task, "ema") and cfg.task.ema.enable: progress.append(EMA(cfg.task.ema.decay)) if quite: diff --git a/yolo/utils/model_utils.py b/yolo/utils/model_utils.py index 9d6c0ce5..15cc54f4 100644 --- a/yolo/utils/model_utils.py +++ b/yolo/utils/model_utils.py @@ -13,7 +13,13 @@ from torch.optim import Optimizer from torch.optim.lr_scheduler import LambdaLR, SequentialLR, _LRScheduler -from yolo.config.config import IDX_TO_ID, NMSConfig, OptimizerConfig, SchedulerConfig +from yolo.config.config import ( + IDX_TO_ID, + DataConfig, + NMSConfig, + OptimizerConfig, + SchedulerConfig, +) from yolo.model.yolo import YOLO from yolo.utils.bounding_box_utils import Anc2Box, Vec2Box, bbox_nms, transform_bbox from yolo.utils.logger import logger @@ -44,6 +50,7 @@ def __init__(self, decay: float = 0.9999, tau: float = 2000): self.decay = decay self.tau = tau self.step = 0 + self.batch_step_counter = 0 self.ema_state_dict = None def setup(self, trainer, pl_module, stage): @@ -53,18 +60,53 @@ def setup(self, trainer, pl_module, stage): param.requires_grad = False def on_validation_start(self, trainer: "Trainer", pl_module: "LightningModule"): + self.batch_step_counter = 0 if self.ema_state_dict is None: self.ema_state_dict = deepcopy(pl_module.model.state_dict()) pl_module.ema.load_state_dict(self.ema_state_dict) @no_grad() def on_train_batch_end(self, trainer: "Trainer", pl_module: "LightningModule", *args, **kwargs) -> None: + self.batch_step_counter += 1 + if self.batch_step_counter % trainer.accumulate_grad_batches: + return self.step += 1 decay_factor = self.decay * (1 - exp(-self.step / self.tau)) for key, param in pl_module.model.state_dict().items(): self.ema_state_dict[key] = lerp(param.detach(), self.ema_state_dict[key], decay_factor) +class GradientAccumulation(Callback): + def __init__(self, data_cfg: DataConfig, scheduler_cfg: SchedulerConfig): + super().__init__() + self.equivalent_batch_size = data_cfg.equivalent_batch_size + self.actual_batch_size = data_cfg.batch_size + self.warmup_epochs = getattr(scheduler_cfg.warmup, "epochs", 0) + self.current_batch = 0 + self.max_accumulation = 1 + self.warmup_batches = 0 + logger.info(":arrows_counterclockwise: Enable Gradient Accumulation") + + def setup(self, trainer: "Trainer", pl_module: "LightningModule", stage: str) -> None: + effective_batch_size = self.actual_batch_size * trainer.world_size + self.max_accumulation = max(1, round(self.equivalent_batch_size / effective_batch_size)) + batches_per_epoch = int(len(pl_module.train_loader) / trainer.world_size) + self.warmup_batches = int(self.warmup_epochs * batches_per_epoch) + + def on_train_epoch_start(self, trainer: "Trainer", pl_module: "LightningModule") -> None: + self.current_batch = trainer.global_step + + def on_train_batch_start(self, trainer: "Trainer", pl_module: "LightningModule", *args, **kwargs) -> None: + if self.current_batch < self.warmup_batches: + current_accumulation = round(lerp(1, self.max_accumulation, self.current_batch, self.warmup_batches)) + else: + current_accumulation = self.max_accumulation + trainer.accumulate_grad_batches = current_accumulation + + def on_train_batch_end(self, trainer: "Trainer", pl_module: "LightningModule", *args, **kwargs) -> None: + self.current_batch += 1 + + def create_optimizer(model: YOLO, optim_cfg: OptimizerConfig) -> Optimizer: """Create an optimizer for the given model parameters based on the configuration. From 3e7dd7d064ac7eb8286f35e70b185c3341cc2131 Mon Sep 17 00:00:00 2001 From: henrytsui000 Date: Tue, 30 Dec 2025 01:46:02 -0500 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=90=9B=20[Fix]=20for=20setting=20mult?= =?UTF-8?q?igpu,=20enable=20pick=20cuda=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yolo/config/config.py | 1 + yolo/config/general.yaml | 1 + yolo/lazy.py | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/yolo/config/config.py b/yolo/config/config.py index 2fad2fc8..c4128ac1 100644 --- a/yolo/config/config.py +++ b/yolo/config/config.py @@ -145,6 +145,7 @@ class Config: model: ModelConfig name: str + accelerator: Optional[str] device: Union[str, int, List[int]] cpu_num: int diff --git a/yolo/config/general.yaml b/yolo/config/general.yaml index c3380a79..324d00f9 100644 --- a/yolo/config/general.yaml +++ b/yolo/config/general.yaml @@ -1,3 +1,4 @@ +accelerator: auto device: 0 cpu_num: 16 diff --git a/yolo/lazy.py b/yolo/lazy.py index fb8fe2e2..c7266481 100644 --- a/yolo/lazy.py +++ b/yolo/lazy.py @@ -17,10 +17,12 @@ def main(cfg: Config): callbacks, loggers, save_path = setup(cfg) trainer = Trainer( - accelerator="auto", + accelerator=getattr(cfg, "accelerator", "auto"), + devices=cfg.device, max_epochs=getattr(cfg.task, "epoch", None), precision="16-mixed", callbacks=callbacks, + sync_batchnorm=True, logger=loggers, log_every_n_steps=1, gradient_clip_val=10, From 99edaaf92ef979091e1a834d03dff1e759a9d360 Mon Sep 17 00:00:00 2001 From: henrytsui000 Date: Tue, 30 Dec 2025 02:27:07 -0500 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=92=9A=20[Fix]=20bug=20for=20pytest?= =?UTF-8?q?=20for=20inference?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/conftest.py | 1 + tests/test_utils/test_bounding_box_utils.py | 2 +- yolo/config/general.yaml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 540d0074..3be303bc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -68,6 +68,7 @@ def model_v7(inference_v7_cfg: Config, device) -> YOLO: @pytest.fixture(scope="session") def solver(train_cfg: Config) -> Trainer: train_cfg.use_wandb = False + del train_cfg.task.data.equivalent_batch_size callbacks, loggers, save_path = setup(train_cfg) trainer = Trainer( accelerator="auto", diff --git a/tests/test_utils/test_bounding_box_utils.py b/tests/test_utils/test_bounding_box_utils.py index 434f6e9f..f5d2f0e6 100644 --- a/tests/test_utils/test_bounding_box_utils.py +++ b/tests/test_utils/test_bounding_box_utils.py @@ -118,7 +118,7 @@ def test_vec2box_autoanchor(): with initialize(config_path="../../yolo/config", version_base=None): cfg: Config = compose(config_name="config", overrides=["model=v9-m"]) device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - model = create_model(cfg.model, weight_path=None).to(device) + model = create_model(cfg.model, weight_path=None) vec2box = Vec2Box(model, cfg.model.anchor, cfg.image_size, device) assert vec2box.strides == [8, 16, 32] diff --git a/yolo/config/general.yaml b/yolo/config/general.yaml index 324d00f9..a4bda88d 100644 --- a/yolo/config/general.yaml +++ b/yolo/config/general.yaml @@ -1,5 +1,5 @@ accelerator: auto -device: 0 +device: auto cpu_num: 16 image_size: [640, 640] From e0d47ad7aa95ac78ae3c687a900a22e5b4414595 Mon Sep 17 00:00:00 2001 From: henrytsui000 Date: Tue, 30 Dec 2025 02:29:37 -0500 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=93=9D=20[Update]=20Docs,=20remove=20?= =?UTF-8?q?broken=20badge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b3685577..ef458561 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,10 @@ [![Documentation Status](https://readthedocs.org/projects/yolo-docs/badge/?version=latest)](https://yolo-docs.readthedocs.io/en/latest/?badge=latest) ![GitHub License](https://img.shields.io/github/license/WongKinYiu/YOLO) -![WIP](https://img.shields.io/badge/status-WIP-orange) [![Developer Mode Build & Test](https://github.com/WongKinYiu/YOLO/actions/workflows/develop.yaml/badge.svg)](https://github.com/WongKinYiu/YOLO/actions/workflows/develop.yaml) [![Deploy Mode Validation & Inference](https://github.com/WongKinYiu/YOLO/actions/workflows/deploy.yaml/badge.svg)](https://github.com/WongKinYiu/YOLO/actions/workflows/deploy.yaml) -[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/yolov9-learning-what-you-want-to-learn-using/real-time-object-detection-on-coco)](https://paperswithcode.com/sota/real-time-object-detection-on-coco) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)]() [![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-green)](https://huggingface.co/spaces/henry000/YOLO)