From c58f32e146799cb96a48b4aee4f9ca5b221237a6 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:01:47 -0300 Subject: [PATCH 01/30] fix:Update NCCL environment variable and improve AMP usage in training loop --- doclayout_yolo/engine/trainer.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/doclayout_yolo/engine/trainer.py b/doclayout_yolo/engine/trainer.py index 7541d5f..ab85e61 100644 --- a/doclayout_yolo/engine/trainer.py +++ b/doclayout_yolo/engine/trainer.py @@ -226,7 +226,7 @@ def _setup_ddp(self, world_size): torch.cuda.set_device(RANK) self.device = torch.device("cuda", RANK) # LOGGER.info(f'DDP info: RANK {RANK}, WORLD_SIZE {world_size}, DEVICE {self.device}') - os.environ["NCCL_BLOCKING_WAIT"] = "1" # set to enforce timeout + os.environ["TORCH_NCCL_BLOCKING_WAIT"] = "1" # set to enforce timeout dist.init_process_group( backend="nccl" if dist.is_nccl_available() else "gloo", timeout=timedelta(seconds=32400), # 3 hours @@ -377,14 +377,16 @@ def _do_train(self, world_size=1): x["momentum"] = np.interp(ni, xi, [self.args.warmup_momentum, self.args.momentum]) # Forward - with torch.cuda.amp.autocast(self.amp): - batch = self.preprocess_batch(batch) - self.loss, self.loss_items = self.model(batch) - if RANK != -1: - self.loss *= world_size - self.tloss = ( - (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items - ) + if self.amp: + #with torch.cuda.amp.autocast(self.amp): + with torch.amp.autocast(device_type='cuda', dtype=torch.float16): #https://pytorch.org/docs/stable/amp.html# + batch = self.preprocess_batch(batch) + self.loss, self.loss_items = self.model(batch) + if RANK != -1: + self.loss *= world_size + self.tloss = ( + (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items + ) # Backward self.scaler.scale(self.loss).backward() From fbffec78eb09c32162ea175996a9f85b17024c29 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:02:41 -0300 Subject: [PATCH 02/30] fix: Add conditional batch normalization to dilated convolution in DilatedBlock --- doclayout_yolo/nn/modules/g2l_crm.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doclayout_yolo/nn/modules/g2l_crm.py b/doclayout_yolo/nn/modules/g2l_crm.py index 62466b1..deccfeb 100644 --- a/doclayout_yolo/nn/modules/g2l_crm.py +++ b/doclayout_yolo/nn/modules/g2l_crm.py @@ -33,10 +33,16 @@ def __init__(self, c, dilation, k, fuse="sum", shortcut=True): def dilated_conv(self, x, dilation): act = self.dcv.act - bn = self.dcv.bn weight = self.dcv.conv.weight padding = dilation * (self.k//2) - return act(bn(F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation))) + + if hasattr(self.dcv, "bn") and self.dcv.bn is not None: + bn = self.dcv.bn + x = bn(F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation)) + else: + x = F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation) + + return act(x) def forward(self, x): """'forward()' applies the YOLO FPN to input data.""" From ebc4c45ce145aff2a0051cb49dfd5a9c12d620b9 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:02:56 -0300 Subject: [PATCH 03/30] fix: Update autocast usage in check_train_batch_size function for improved compatibility --- doclayout_yolo/utils/autobatch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doclayout_yolo/utils/autobatch.py b/doclayout_yolo/utils/autobatch.py index 998c803..c11895f 100644 --- a/doclayout_yolo/utils/autobatch.py +++ b/doclayout_yolo/utils/autobatch.py @@ -22,8 +22,8 @@ def check_train_batch_size(model, imgsz=640, amp=True): Returns: (int): Optimal batch size computed using the autobatch() function. """ - - with torch.cuda.amp.autocast(amp): + with torch.amp.autocast("cuda", amp): + #with torch.cuda.amp.autocast(amp): return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size From f24bc62e9f7c166352627660311ffe4d6e9ca9b3 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:03:06 -0300 Subject: [PATCH 04/30] fix: Update autocast usage in check_amp function for improved compatibility with PyTorch --- doclayout_yolo/utils/checks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doclayout_yolo/utils/checks.py b/doclayout_yolo/utils/checks.py index e378281..bccfd4e 100644 --- a/doclayout_yolo/utils/checks.py +++ b/doclayout_yolo/utils/checks.py @@ -638,7 +638,8 @@ def check_amp(model): def amp_allclose(m, im): """All close FP32 vs AMP results.""" a = m(im, device=device, verbose=False)[0].boxes.data # FP32 inference - with torch.cuda.amp.autocast(True): + with torch.amp.autocast("cuda", True): + #with torch.cuda.amp.autocast(True): b = m(im, device=device, verbose=False)[0].boxes.data # AMP inference del m return a.shape == b.shape and torch.allclose(a, b.float(), atol=0.5) # close to 0.5 absolute tolerance From 48106f50acc31f350add62c570a574cd23ad8846 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:03:14 -0300 Subject: [PATCH 05/30] fix: Update autocast usage in VarifocalLoss for improved compatibility with PyTorch --- doclayout_yolo/utils/loss.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doclayout_yolo/utils/loss.py b/doclayout_yolo/utils/loss.py index 2c65ebf..33e6b10 100644 --- a/doclayout_yolo/utils/loss.py +++ b/doclayout_yolo/utils/loss.py @@ -30,7 +30,8 @@ def __init__(self): def forward(pred_score, gt_score, label, alpha=0.75, gamma=2.0): """Computes varfocal loss.""" weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label - with torch.cuda.amp.autocast(enabled=False): + with torch.amp.autocast("cuda", enabled=False): + #with torch.cuda.amp.autocast(enabled=False): loss = ( (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), reduction="none") * weight) .mean(1) From 1ec3dae35882bd4e8ba476e608375bdf9fb0a451 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:03:26 -0300 Subject: [PATCH 06/30] fix: Add FP16 conversion function for model optimization in torch_utils --- doclayout_yolo/utils/torch_utils.py | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/doclayout_yolo/utils/torch_utils.py b/doclayout_yolo/utils/torch_utils.py index a59ff0a..07852d2 100644 --- a/doclayout_yolo/utils/torch_utils.py +++ b/doclayout_yolo/utils/torch_utils.py @@ -462,7 +462,23 @@ def update_attr(self, model, include=(), exclude=("process_group", "reducer")): if self.enabled: copy_attr(self.ema, model, include, exclude) - +def convert_to_fp16(model): + """Convert model to FP16 (half) precision. + + Args: + model (nn.Module): PyTorch model to convert to FP16. + + Returns: + (nn.Module): FP16 model. + """ + for layer in model.modules(): + if not isinstance(layer, (nn.BatchNorm2d, nn.SyncBatchNorm)): + try : + layer.half() + except Exception as e: + LOGGER.warning(f"Failed to convert layer {layer} to FP16. {e}") + return model + def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "") -> None: """ Strip optimizer from 'f' to finalize training, optionally save as 's'. @@ -483,21 +499,22 @@ def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "") -> None: strip_optimizer(f) ``` """ - x = torch.load(f, map_location=torch.device("cpu")) + x = torch.load(f, map_location=torch.device("cpu"), weights_only=False) # load checkpoint if "model" not in x: LOGGER.info(f"Skipping {f}, not a valid Ultralytics model.") return - - if hasattr(x["model"], "args"): - x["model"].args = dict(x["model"].args) # convert from IterableSimpleNamespace to dict + model = x["model"] + if hasattr(model, "args"): + model.args = dict(model.args) # convert from IterableSimpleNamespace to dict args = {**DEFAULT_CFG_DICT, **x["train_args"]} if "train_args" in x else None # combine args if x.get("ema"): - x["model"] = x["ema"] # replace model with ema - for k in "optimizer", "best_fitness", "ema", "updates": # keys + model = x["ema"] # replace model with ema + for k in ["optimizer", "best_fitness", "ema", "updates"]: # keys x[k] = None x["epoch"] = -1 - x["model"].half() # to FP16 - for p in x["model"].parameters(): + model = convert_to_fp16(model) + + for p in model.parameters(): p.requires_grad = False x["train_args"] = {k: v for k, v in args.items() if k in DEFAULT_CFG_KEYS} # strip non-default keys # x['model'].args = x['train_args'] From e13be8bc83206102c174e673a7eae345585c519c Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:06:43 -0300 Subject: [PATCH 07/30] fix: Update environment variable for NCCL blocking wait and adjust autocast usage in trainer --- doclayout_yolo/engine/trainer.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/doclayout_yolo/engine/trainer.py b/doclayout_yolo/engine/trainer.py index ab85e61..7541d5f 100644 --- a/doclayout_yolo/engine/trainer.py +++ b/doclayout_yolo/engine/trainer.py @@ -226,7 +226,7 @@ def _setup_ddp(self, world_size): torch.cuda.set_device(RANK) self.device = torch.device("cuda", RANK) # LOGGER.info(f'DDP info: RANK {RANK}, WORLD_SIZE {world_size}, DEVICE {self.device}') - os.environ["TORCH_NCCL_BLOCKING_WAIT"] = "1" # set to enforce timeout + os.environ["NCCL_BLOCKING_WAIT"] = "1" # set to enforce timeout dist.init_process_group( backend="nccl" if dist.is_nccl_available() else "gloo", timeout=timedelta(seconds=32400), # 3 hours @@ -377,16 +377,14 @@ def _do_train(self, world_size=1): x["momentum"] = np.interp(ni, xi, [self.args.warmup_momentum, self.args.momentum]) # Forward - if self.amp: - #with torch.cuda.amp.autocast(self.amp): - with torch.amp.autocast(device_type='cuda', dtype=torch.float16): #https://pytorch.org/docs/stable/amp.html# - batch = self.preprocess_batch(batch) - self.loss, self.loss_items = self.model(batch) - if RANK != -1: - self.loss *= world_size - self.tloss = ( - (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items - ) + with torch.cuda.amp.autocast(self.amp): + batch = self.preprocess_batch(batch) + self.loss, self.loss_items = self.model(batch) + if RANK != -1: + self.loss *= world_size + self.tloss = ( + (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items + ) # Backward self.scaler.scale(self.loss).backward() From 0d6735c3999bd3970749011a756cbeb4947c60df Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:06:49 -0300 Subject: [PATCH 08/30] fix: Simplify dilated convolution by always applying batch normalization --- doclayout_yolo/nn/modules/g2l_crm.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/doclayout_yolo/nn/modules/g2l_crm.py b/doclayout_yolo/nn/modules/g2l_crm.py index deccfeb..62466b1 100644 --- a/doclayout_yolo/nn/modules/g2l_crm.py +++ b/doclayout_yolo/nn/modules/g2l_crm.py @@ -33,16 +33,10 @@ def __init__(self, c, dilation, k, fuse="sum", shortcut=True): def dilated_conv(self, x, dilation): act = self.dcv.act + bn = self.dcv.bn weight = self.dcv.conv.weight padding = dilation * (self.k//2) - - if hasattr(self.dcv, "bn") and self.dcv.bn is not None: - bn = self.dcv.bn - x = bn(F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation)) - else: - x = F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation) - - return act(x) + return act(bn(F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation))) def forward(self, x): """'forward()' applies the YOLO FPN to input data.""" From 899d4f08ed9c173cd110079e8027dc86b9335924 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:06:54 -0300 Subject: [PATCH 09/30] fix: Update autocast usage in check_train_batch_size for improved compatibility with PyTorch --- doclayout_yolo/utils/autobatch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doclayout_yolo/utils/autobatch.py b/doclayout_yolo/utils/autobatch.py index c11895f..998c803 100644 --- a/doclayout_yolo/utils/autobatch.py +++ b/doclayout_yolo/utils/autobatch.py @@ -22,8 +22,8 @@ def check_train_batch_size(model, imgsz=640, amp=True): Returns: (int): Optimal batch size computed using the autobatch() function. """ - with torch.amp.autocast("cuda", amp): - #with torch.cuda.amp.autocast(amp): + + with torch.cuda.amp.autocast(amp): return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size From e98471ab7b1bdf7bcac64d4febeafb1b83fd3806 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:06:59 -0300 Subject: [PATCH 10/30] fix: Update autocast usage in check_amp function for improved compatibility with PyTorch --- doclayout_yolo/utils/checks.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doclayout_yolo/utils/checks.py b/doclayout_yolo/utils/checks.py index bccfd4e..e378281 100644 --- a/doclayout_yolo/utils/checks.py +++ b/doclayout_yolo/utils/checks.py @@ -638,8 +638,7 @@ def check_amp(model): def amp_allclose(m, im): """All close FP32 vs AMP results.""" a = m(im, device=device, verbose=False)[0].boxes.data # FP32 inference - with torch.amp.autocast("cuda", True): - #with torch.cuda.amp.autocast(True): + with torch.cuda.amp.autocast(True): b = m(im, device=device, verbose=False)[0].boxes.data # AMP inference del m return a.shape == b.shape and torch.allclose(a, b.float(), atol=0.5) # close to 0.5 absolute tolerance From 01334b63d7319b2267dcde9b439555df5cd360de Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:07:05 -0300 Subject: [PATCH 11/30] fix: Update autocast usage in VarifocalLoss to improve compatibility with PyTorch --- doclayout_yolo/utils/loss.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doclayout_yolo/utils/loss.py b/doclayout_yolo/utils/loss.py index 33e6b10..2c65ebf 100644 --- a/doclayout_yolo/utils/loss.py +++ b/doclayout_yolo/utils/loss.py @@ -30,8 +30,7 @@ def __init__(self): def forward(pred_score, gt_score, label, alpha=0.75, gamma=2.0): """Computes varfocal loss.""" weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label - with torch.amp.autocast("cuda", enabled=False): - #with torch.cuda.amp.autocast(enabled=False): + with torch.cuda.amp.autocast(enabled=False): loss = ( (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), reduction="none") * weight) .mean(1) From fcf431f6dcbc499cfef1718241eab01116307827 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:07:14 -0300 Subject: [PATCH 12/30] refactor: Remove convert_to_fp16 function and streamline model handling in strip_optimizer --- doclayout_yolo/utils/torch_utils.py | 34 +++++++---------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/doclayout_yolo/utils/torch_utils.py b/doclayout_yolo/utils/torch_utils.py index 07852d2..dca780a 100644 --- a/doclayout_yolo/utils/torch_utils.py +++ b/doclayout_yolo/utils/torch_utils.py @@ -462,23 +462,6 @@ def update_attr(self, model, include=(), exclude=("process_group", "reducer")): if self.enabled: copy_attr(self.ema, model, include, exclude) -def convert_to_fp16(model): - """Convert model to FP16 (half) precision. - - Args: - model (nn.Module): PyTorch model to convert to FP16. - - Returns: - (nn.Module): FP16 model. - """ - for layer in model.modules(): - if not isinstance(layer, (nn.BatchNorm2d, nn.SyncBatchNorm)): - try : - layer.half() - except Exception as e: - LOGGER.warning(f"Failed to convert layer {layer} to FP16. {e}") - return model - def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "") -> None: """ Strip optimizer from 'f' to finalize training, optionally save as 's'. @@ -499,22 +482,21 @@ def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "") -> None: strip_optimizer(f) ``` """ - x = torch.load(f, map_location=torch.device("cpu"), weights_only=False) # load checkpoint + x = torch.load(f, map_location=torch.device("cpu")) if "model" not in x: LOGGER.info(f"Skipping {f}, not a valid Ultralytics model.") return - model = x["model"] - if hasattr(model, "args"): - model.args = dict(model.args) # convert from IterableSimpleNamespace to dict + + if hasattr(x["model"], "args"): + x["model"].args = dict(x["model"].args) # convert from IterableSimpleNamespace to dict args = {**DEFAULT_CFG_DICT, **x["train_args"]} if "train_args" in x else None # combine args if x.get("ema"): - model = x["ema"] # replace model with ema - for k in ["optimizer", "best_fitness", "ema", "updates"]: # keys + x["model"] = x["ema"] # replace model with ema + for k in "optimizer", "best_fitness", "ema", "updates": # keys x[k] = None x["epoch"] = -1 - model = convert_to_fp16(model) - - for p in model.parameters(): + x["model"].half() # to FP16 + for p in x["model"].parameters(): p.requires_grad = False x["train_args"] = {k: v for k, v in args.items() if k in DEFAULT_CFG_KEYS} # strip non-default keys # x['model'].args = x['train_args'] From 5bcbb159a4a2a6ea7c9afed9dcd89076b45275ed Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:39:54 -0300 Subject: [PATCH 13/30] fix: Update environment variable for NCCL blocking wait and improve autocast usage in training loop --- doclayout_yolo/engine/trainer.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/doclayout_yolo/engine/trainer.py b/doclayout_yolo/engine/trainer.py index 7541d5f..c65e1c8 100644 --- a/doclayout_yolo/engine/trainer.py +++ b/doclayout_yolo/engine/trainer.py @@ -226,7 +226,7 @@ def _setup_ddp(self, world_size): torch.cuda.set_device(RANK) self.device = torch.device("cuda", RANK) # LOGGER.info(f'DDP info: RANK {RANK}, WORLD_SIZE {world_size}, DEVICE {self.device}') - os.environ["NCCL_BLOCKING_WAIT"] = "1" # set to enforce timeout + os.environ["TORCH_NCCL_BLOCKING_WAIT"] = "1" # set to enforce timeout dist.init_process_group( backend="nccl" if dist.is_nccl_available() else "gloo", timeout=timedelta(seconds=32400), # 3 hours @@ -377,14 +377,16 @@ def _do_train(self, world_size=1): x["momentum"] = np.interp(ni, xi, [self.args.warmup_momentum, self.args.momentum]) # Forward - with torch.cuda.amp.autocast(self.amp): - batch = self.preprocess_batch(batch) - self.loss, self.loss_items = self.model(batch) - if RANK != -1: - self.loss *= world_size - self.tloss = ( - (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items - ) + if self.amp: + with torch.amp.autocast(device_type="cuda", dtype=torch.float16): #https://pytorch.org/docs/stable/amp.html# + #with torch.cuda.amp.autocast(self.amp): + batch = self.preprocess_batch(batch) + self.loss, self.loss_items = self.model(batch) + if RANK != -1: + self.loss *= world_size + self.tloss = ( + (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items + ) # Backward self.scaler.scale(self.loss).backward() From 2d491457425b475947927ce8f254cf3247ba4660 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:40:12 -0300 Subject: [PATCH 14/30] fix: Enhance dilated_conv method to conditionally apply batch normalization before activation --- doclayout_yolo/nn/modules/g2l_crm.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doclayout_yolo/nn/modules/g2l_crm.py b/doclayout_yolo/nn/modules/g2l_crm.py index 62466b1..b44cd1a 100644 --- a/doclayout_yolo/nn/modules/g2l_crm.py +++ b/doclayout_yolo/nn/modules/g2l_crm.py @@ -33,10 +33,15 @@ def __init__(self, c, dilation, k, fuse="sum", shortcut=True): def dilated_conv(self, x, dilation): act = self.dcv.act - bn = self.dcv.bn weight = self.dcv.conv.weight padding = dilation * (self.k//2) - return act(bn(F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation))) + if hasattr(self.dcv, "bn") and self.dcv.bn is not None: + bn = self.dcv.bn + x = bn(F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation)) + else: + x = F.conv2d(x, weight, stride=1, padding=padding, dilation=dilation) + + return act(x) # Apply activation function def forward(self, x): """'forward()' applies the YOLO FPN to input data.""" From 615db3963286de0b172baad976ad390d5d54f5eb Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:41:03 -0300 Subject: [PATCH 15/30] fix: Update autocast usage in check_train_batch_size for improved compatibility with PyTorch --- doclayout_yolo/utils/autobatch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doclayout_yolo/utils/autobatch.py b/doclayout_yolo/utils/autobatch.py index 998c803..c11895f 100644 --- a/doclayout_yolo/utils/autobatch.py +++ b/doclayout_yolo/utils/autobatch.py @@ -22,8 +22,8 @@ def check_train_batch_size(model, imgsz=640, amp=True): Returns: (int): Optimal batch size computed using the autobatch() function. """ - - with torch.cuda.amp.autocast(amp): + with torch.amp.autocast("cuda", amp): + #with torch.cuda.amp.autocast(amp): return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size From e7e1479ae3b4163b0b0cd3489c06e2edd2dba1e8 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:41:23 -0300 Subject: [PATCH 16/30] fix: Update autocast usage in check_amp function for improved compatibility with PyTorch --- doclayout_yolo/utils/checks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doclayout_yolo/utils/checks.py b/doclayout_yolo/utils/checks.py index e378281..bccfd4e 100644 --- a/doclayout_yolo/utils/checks.py +++ b/doclayout_yolo/utils/checks.py @@ -638,7 +638,8 @@ def check_amp(model): def amp_allclose(m, im): """All close FP32 vs AMP results.""" a = m(im, device=device, verbose=False)[0].boxes.data # FP32 inference - with torch.cuda.amp.autocast(True): + with torch.amp.autocast("cuda", True): + #with torch.cuda.amp.autocast(True): b = m(im, device=device, verbose=False)[0].boxes.data # AMP inference del m return a.shape == b.shape and torch.allclose(a, b.float(), atol=0.5) # close to 0.5 absolute tolerance From 909ef27a94428565fd25aa89a1de9b8357ec8585 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:41:38 -0300 Subject: [PATCH 17/30] fix: Update autocast usage in VarifocalLoss to align with PyTorch best practices --- doclayout_yolo/utils/loss.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doclayout_yolo/utils/loss.py b/doclayout_yolo/utils/loss.py index 2c65ebf..33e6b10 100644 --- a/doclayout_yolo/utils/loss.py +++ b/doclayout_yolo/utils/loss.py @@ -30,7 +30,8 @@ def __init__(self): def forward(pred_score, gt_score, label, alpha=0.75, gamma=2.0): """Computes varfocal loss.""" weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label - with torch.cuda.amp.autocast(enabled=False): + with torch.amp.autocast("cuda", enabled=False): + #with torch.cuda.amp.autocast(enabled=False): loss = ( (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), reduction="none") * weight) .mean(1) From 88eaaa68754a8165b6a79d5b1022f3183ddace0b Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 09:43:51 -0300 Subject: [PATCH 18/30] fix: Add convert_to_fp16 function for model half precision conversion --- doclayout_yolo/utils/torch_utils.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/doclayout_yolo/utils/torch_utils.py b/doclayout_yolo/utils/torch_utils.py index dca780a..5e073f4 100644 --- a/doclayout_yolo/utils/torch_utils.py +++ b/doclayout_yolo/utils/torch_utils.py @@ -462,6 +462,16 @@ def update_attr(self, model, include=(), exclude=("process_group", "reducer")): if self.enabled: copy_attr(self.ema, model, include, exclude) +def convert_to_fp16(model): + """Convert model to FP16 (half precision) and return original device.""" + for layers in model.modules(): + if isinstance(layers, (nn.BatchNorm2d, nn.BatchNorm1d, nn.SyncBatchNorm)): + try: + layers.half() + except Exception: + LOGGER.warning(f"Warning: layer {layers} not supported for FP16 conversion") + return model + def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "") -> None: """ Strip optimizer from 'f' to finalize training, optionally save as 's'. @@ -487,16 +497,18 @@ def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "") -> None: LOGGER.info(f"Skipping {f}, not a valid Ultralytics model.") return - if hasattr(x["model"], "args"): - x["model"].args = dict(x["model"].args) # convert from IterableSimpleNamespace to dict + model = x["model"] + if hasattr(model, "args"): + model.args = dict(model.args) # convert from IterableSimpleNamespace to dict args = {**DEFAULT_CFG_DICT, **x["train_args"]} if "train_args" in x else None # combine args if x.get("ema"): - x["model"] = x["ema"] # replace model with ema - for k in "optimizer", "best_fitness", "ema", "updates": # keys + model = x["ema"] # replace model with ema + for k in ["optimizer", "best_fitness", "ema", "updates"]: # keys x[k] = None x["epoch"] = -1 - x["model"].half() # to FP16 - for p in x["model"].parameters(): + model = convert_to_fp16(model) # to FP16 + #x["model"].half() # to FP16 + for p in model.parameters(): p.requires_grad = False x["train_args"] = {k: v for k, v in args.items() if k in DEFAULT_CFG_KEYS} # strip non-default keys # x['model'].args = x['train_args'] From 015f105af780fae5eaa2876f4b382cf3421a3b3b Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Mon, 24 Mar 2025 10:15:58 -0300 Subject: [PATCH 19/30] feat: Add Dockerfile for environment setup with CUDA 11.8 and Python 3.9 --- Dockerfile | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..da18fbc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +# Change the version of cuda and cudnn according to user cuda and cudnn version +FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 + +ENV DEBIAN_FRONTEND=noninteractive +ENV HOME=/root + +# Install libraries and dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + software-properties-common \ + ffmpeg \ + libsm6 \ + libxext6 \ + git \ + curl \ + unzip \ + wget \ + tar \ + build-essential \ + libopenmpi-dev \ + pkg-config \ + cmake \ + libpoppler-cpp-dev \ + poppler-utils \ + && add-apt-repository ppa:deadsnakes/ppa \ + && apt-get update \ + && apt-get install -y --no-install-recommends python3.9 python3.9-distutils python3.9-dev python3-pip \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN pip install --upgrade setuptools + +# Update Python symlink to point to Python 3.9 +RUN ln -sf /usr/bin/python3.9 /usr/bin/python \ + && ln -sf /usr/bin/python3.9 /usr/bin/python3 +RUN pip install huggingface-hub + +#if repository is local +COPY ./DocLayout-YOLO ${HOME}/DocLayout-YOLO +WORKDIR ${HOME}/DocLayout-YOLO +RUN pip install -e . + +# if want to use pip install from https://pypi.org/project/doclayout-yolo/ +#RUN pip install doclayout-yolo + +WORKDIR ${HOME} + +CMD [ "bash" ] \ No newline at end of file From d0ad89fcce2f187ef6161c9fdd33b383fb71453d Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Thu, 27 Mar 2025 16:50:49 -0300 Subject: [PATCH 20/30] fix: Update Dockerfile to authorize reading and writing to the home directory --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index da18fbc..33466ab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,5 +43,7 @@ RUN pip install -e . #RUN pip install doclayout-yolo WORKDIR ${HOME} +#authorize reading and writing to the home directory +RUN chmod -R 777 ${HOME} CMD [ "bash" ] \ No newline at end of file From 916c7b2ab4b9bb0d915dc44b5865800c51ac17f3 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Thu, 27 Mar 2025 16:51:03 -0300 Subject: [PATCH 21/30] fix: Refactor autocast usage in BaseTrainer for improved compatibility with PyTorch --- doclayout_yolo/engine/trainer.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/doclayout_yolo/engine/trainer.py b/doclayout_yolo/engine/trainer.py index c65e1c8..b3ba156 100644 --- a/doclayout_yolo/engine/trainer.py +++ b/doclayout_yolo/engine/trainer.py @@ -19,6 +19,7 @@ import torch from torch import distributed as dist from torch import nn, optim +import torch.amp from doclayout_yolo.cfg import get_cfg, get_save_dir from doclayout_yolo.data.utils import check_cls_dataset, check_det_dataset @@ -377,16 +378,14 @@ def _do_train(self, world_size=1): x["momentum"] = np.interp(ni, xi, [self.args.warmup_momentum, self.args.momentum]) # Forward - if self.amp: - with torch.amp.autocast(device_type="cuda", dtype=torch.float16): #https://pytorch.org/docs/stable/amp.html# - #with torch.cuda.amp.autocast(self.amp): - batch = self.preprocess_batch(batch) - self.loss, self.loss_items = self.model(batch) - if RANK != -1: - self.loss *= world_size - self.tloss = ( - (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items - ) + with torch.amp.autocast(device_type="cuda", enabled=self.amp): #https://pytorch.org/docs/stable/amp.html# + batch = self.preprocess_batch(batch) + self.loss, self.loss_items = self.model(batch) + if RANK != -1: + self.loss *= world_size + self.tloss = ( + (self.tloss * i + self.loss_items) / (i + 1) if self.tloss is not None else self.loss_items + ) # Backward self.scaler.scale(self.loss).backward() From 7314f9a1f8e198196cdd611d7cf278cf01219b56 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Thu, 27 Mar 2025 16:51:14 -0300 Subject: [PATCH 22/30] fix: Update autocast usage in check_train_batch_size for improved clarity and compatibility --- doclayout_yolo/utils/autobatch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doclayout_yolo/utils/autobatch.py b/doclayout_yolo/utils/autobatch.py index c11895f..14b13b4 100644 --- a/doclayout_yolo/utils/autobatch.py +++ b/doclayout_yolo/utils/autobatch.py @@ -5,6 +5,7 @@ import numpy as np import torch +import torch.amp from doclayout_yolo.utils import DEFAULT_CFG, LOGGER, colorstr from doclayout_yolo.utils.torch_utils import profile @@ -22,8 +23,7 @@ def check_train_batch_size(model, imgsz=640, amp=True): Returns: (int): Optimal batch size computed using the autobatch() function. """ - with torch.amp.autocast("cuda", amp): - #with torch.cuda.amp.autocast(amp): + with torch.amp.autocast(device_type="cuda", enabled=amp): return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size From 6b95b99f888386bbbf8c99d876b6a644af735d9c Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Thu, 27 Mar 2025 16:51:31 -0300 Subject: [PATCH 23/30] fix: Update autocast usage in check_amp for improved clarity and compatibility with PyTorch --- doclayout_yolo/utils/checks.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doclayout_yolo/utils/checks.py b/doclayout_yolo/utils/checks.py index bccfd4e..c7d8383 100644 --- a/doclayout_yolo/utils/checks.py +++ b/doclayout_yolo/utils/checks.py @@ -13,11 +13,11 @@ from importlib import metadata from pathlib import Path from typing import Optional - import cv2 import numpy as np import requests import torch +import torch.amp from matplotlib import font_manager from doclayout_yolo.utils import ( @@ -638,8 +638,7 @@ def check_amp(model): def amp_allclose(m, im): """All close FP32 vs AMP results.""" a = m(im, device=device, verbose=False)[0].boxes.data # FP32 inference - with torch.amp.autocast("cuda", True): - #with torch.cuda.amp.autocast(True): + with torch.amp.autocast(device_type="cuda", enabled=True): b = m(im, device=device, verbose=False)[0].boxes.data # AMP inference del m return a.shape == b.shape and torch.allclose(a, b.float(), atol=0.5) # close to 0.5 absolute tolerance From 74ba0b29cb14e6ae3d5ca8177e6564fe5241c71a Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Thu, 27 Mar 2025 16:51:39 -0300 Subject: [PATCH 24/30] fix: Update autocast usage in VarifocalLoss for improved clarity and compatibility with PyTorch --- doclayout_yolo/utils/loss.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doclayout_yolo/utils/loss.py b/doclayout_yolo/utils/loss.py index 33e6b10..262d119 100644 --- a/doclayout_yolo/utils/loss.py +++ b/doclayout_yolo/utils/loss.py @@ -1,6 +1,7 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license import torch +import torch.amp import torch.nn as nn import torch.nn.functional as F @@ -30,8 +31,7 @@ def __init__(self): def forward(pred_score, gt_score, label, alpha=0.75, gamma=2.0): """Computes varfocal loss.""" weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label - with torch.amp.autocast("cuda", enabled=False): - #with torch.cuda.amp.autocast(enabled=False): + with torch.amp.autocast(device_type="cuda", enabled=False): loss = ( (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), reduction="none") * weight) .mean(1) From 7ba2a65061c2b19d74297c1cd9a67f0d262aaa17 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Thu, 27 Mar 2025 17:38:03 -0300 Subject: [PATCH 25/30] fix: Update Dockerfile to copy entire project directory for improved build context --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 33466ab..ba63c53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,7 @@ RUN ln -sf /usr/bin/python3.9 /usr/bin/python \ RUN pip install huggingface-hub #if repository is local -COPY ./DocLayout-YOLO ${HOME}/DocLayout-YOLO +COPY . ${HOME}/DocLayout-YOLO WORKDIR ${HOME}/DocLayout-YOLO RUN pip install -e . From caa205aa2e10682becfa6d3467123dd98eb314ef Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Fri, 28 Mar 2025 09:21:17 -0300 Subject: [PATCH 26/30] fix: Update torch.load to include weights_only parameter for improved model loading --- doclayout_yolo/utils/torch_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doclayout_yolo/utils/torch_utils.py b/doclayout_yolo/utils/torch_utils.py index 5e073f4..51e25ef 100644 --- a/doclayout_yolo/utils/torch_utils.py +++ b/doclayout_yolo/utils/torch_utils.py @@ -492,7 +492,7 @@ def strip_optimizer(f: Union[str, Path] = "best.pt", s: str = "") -> None: strip_optimizer(f) ``` """ - x = torch.load(f, map_location=torch.device("cpu")) + x = torch.load(f, map_location=torch.device("cpu"), weights_only=False) if "model" not in x: LOGGER.info(f"Skipping {f}, not a valid Ultralytics model.") return From 6e7d25a9d7d8725860d2eb68eed2e4a0a1e5c61c Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Fri, 28 Mar 2025 09:34:28 -0300 Subject: [PATCH 27/30] fix: Update Dockerfile to change HOME environment variable and streamline Python installation --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index ba63c53..bc6610e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 ENV DEBIAN_FRONTEND=noninteractive -ENV HOME=/root +ENV HOME=/DocLayout-YOLO-World # Install libraries and dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -31,8 +31,8 @@ RUN pip install --upgrade setuptools # Update Python symlink to point to Python 3.9 RUN ln -sf /usr/bin/python3.9 /usr/bin/python \ - && ln -sf /usr/bin/python3.9 /usr/bin/python3 -RUN pip install huggingface-hub + && ln -sf /usr/bin/python3.9 /usr/bin/python3 \ + && pip install huggingface-hub #if repository is local COPY . ${HOME}/DocLayout-YOLO From b40901aa39dac476b7addc27759a6bd5f93b4671 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Fri, 11 Apr 2025 11:31:32 -0300 Subject: [PATCH 28/30] fix: Remove the HOME environment variable and streamline the Docker file by simplifying the COPY and WORKDIR instructions. Enable the use of requirements file to install only the necessary library instead of the biblio. --- Dockerfile | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index bc6610e..2875d11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,6 @@ FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 ENV DEBIAN_FRONTEND=noninteractive -ENV HOME=/DocLayout-YOLO-World # Install libraries and dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -17,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ tar \ build-essential \ libopenmpi-dev \ + libcairo2-dev \ pkg-config \ cmake \ libpoppler-cpp-dev \ @@ -34,16 +34,8 @@ RUN ln -sf /usr/bin/python3.9 /usr/bin/python \ && ln -sf /usr/bin/python3.9 /usr/bin/python3 \ && pip install huggingface-hub -#if repository is local -COPY . ${HOME}/DocLayout-YOLO -WORKDIR ${HOME}/DocLayout-YOLO -RUN pip install -e . +COPY requirements.txt . -# if want to use pip install from https://pypi.org/project/doclayout-yolo/ -#RUN pip install doclayout-yolo - -WORKDIR ${HOME} -#authorize reading and writing to the home directory -RUN chmod -R 777 ${HOME} +RUN pip install -r requirements.txt CMD [ "bash" ] \ No newline at end of file From dcf77f91b71b47e7999e18cd831408814305dd24 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Fri, 11 Apr 2025 11:32:22 -0300 Subject: [PATCH 29/30] feat: Add requirements.txt for dependency management --- requirements.txt | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4e0b700 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,83 @@ +albucore==0.0.23 +albumentations==2.0.5 +annotated-types==0.7.0 +blinker==1.4 +certifi==2025.1.31 +charset-normalizer==3.4.1 +contourpy==1.3.0 +cryptography==3.4.8 +cycler==0.12.1 +dbus-python==1.2.18 +distro==1.7.0 +eval_type_backport==0.2.2 +filelock==3.18.0 +fonttools==4.56.0 +fsspec==2025.3.0 +httplib2==0.20.2 +huggingface-hub==0.29.3 +idna==3.10 +importlib-metadata==4.6.4 +importlib_resources==6.5.2 +jeepney==0.7.1 +Jinja2==3.1.6 +keyring==23.5.0 +kiwisolver==1.4.7 +launchpadlib==1.10.16 +lazr.restfulclient==0.14.4 +lazr.uri==1.0.6 +MarkupSafe==3.0.2 +matplotlib==3.9.4 +more-itertools==8.10.0 +mpmath==1.3.0 +networkx==3.2.1 +numpy==2.0.2 +nvidia-cublas-cu12==12.4.5.8 +nvidia-cuda-cupti-cu12==12.4.127 +nvidia-cuda-nvrtc-cu12==12.4.127 +nvidia-cuda-runtime-cu12==12.4.127 +nvidia-cudnn-cu12==9.1.0.70 +nvidia-cufft-cu12==11.2.1.3 +nvidia-curand-cu12==10.3.5.147 +nvidia-cusolver-cu12==11.6.1.9 +nvidia-cusparse-cu12==12.3.1.170 +nvidia-cusparselt-cu12==0.6.2 +nvidia-nccl-cu12==2.21.5 +nvidia-nvjitlink-cu12==12.4.127 +nvidia-nvtx-cu12==12.4.127 +oauthlib==3.2.0 +opencv-python==4.11.0.86 +opencv-python-headless==4.11.0.86 +packaging==24.2 +pandas==2.2.3 +pillow==11.1.0 +psutil==7.0.0 +py-cpuinfo==9.0.0 +pydantic==2.11.0 +pydantic_core==2.33.0 +PyGObject==3.42.1 +PyJWT==2.3.0 +pyparsing==2.4.7 +python-apt==2.4.0+ubuntu4 +python-dateutil==2.9.0.post0 +pytz==2025.2 +PyYAML==6.0.2 +requests==2.32.3 +scipy==1.13.1 +seaborn==0.13.2 +SecretStorage==3.3.1 +simsimd==6.2.1 +six==1.16.0 +stringzilla==3.12.3 +sympy==1.13.1 +thop==0.1.1.post2209072238 +torch==2.6.0 +torchvision==0.21.0 +tqdm==4.67.1 +triton==3.2.0 +typing-inspection==0.4.0 +typing_extensions==4.13.0 +tzdata==2025.2 +urllib3==2.3.0 +#pycairo +wadllib==1.3.6 +zipp==3.21.0 \ No newline at end of file From 7e35688a12918a65cc2c408015d2b52138ed3aa2 Mon Sep 17 00:00:00 2001 From: Geo99pro Date: Fri, 11 Apr 2025 11:32:22 -0300 Subject: [PATCH 30/30] feat: Add requirements.txt for dependency management --- requirements.txt | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4e0b700 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,83 @@ +albucore==0.0.23 +albumentations==2.0.5 +annotated-types==0.7.0 +blinker==1.4 +certifi==2025.1.31 +charset-normalizer==3.4.1 +contourpy==1.3.0 +cryptography==3.4.8 +cycler==0.12.1 +dbus-python==1.2.18 +distro==1.7.0 +eval_type_backport==0.2.2 +filelock==3.18.0 +fonttools==4.56.0 +fsspec==2025.3.0 +httplib2==0.20.2 +huggingface-hub==0.29.3 +idna==3.10 +importlib-metadata==4.6.4 +importlib_resources==6.5.2 +jeepney==0.7.1 +Jinja2==3.1.6 +keyring==23.5.0 +kiwisolver==1.4.7 +launchpadlib==1.10.16 +lazr.restfulclient==0.14.4 +lazr.uri==1.0.6 +MarkupSafe==3.0.2 +matplotlib==3.9.4 +more-itertools==8.10.0 +mpmath==1.3.0 +networkx==3.2.1 +numpy==2.0.2 +nvidia-cublas-cu12==12.4.5.8 +nvidia-cuda-cupti-cu12==12.4.127 +nvidia-cuda-nvrtc-cu12==12.4.127 +nvidia-cuda-runtime-cu12==12.4.127 +nvidia-cudnn-cu12==9.1.0.70 +nvidia-cufft-cu12==11.2.1.3 +nvidia-curand-cu12==10.3.5.147 +nvidia-cusolver-cu12==11.6.1.9 +nvidia-cusparse-cu12==12.3.1.170 +nvidia-cusparselt-cu12==0.6.2 +nvidia-nccl-cu12==2.21.5 +nvidia-nvjitlink-cu12==12.4.127 +nvidia-nvtx-cu12==12.4.127 +oauthlib==3.2.0 +opencv-python==4.11.0.86 +opencv-python-headless==4.11.0.86 +packaging==24.2 +pandas==2.2.3 +pillow==11.1.0 +psutil==7.0.0 +py-cpuinfo==9.0.0 +pydantic==2.11.0 +pydantic_core==2.33.0 +PyGObject==3.42.1 +PyJWT==2.3.0 +pyparsing==2.4.7 +python-apt==2.4.0+ubuntu4 +python-dateutil==2.9.0.post0 +pytz==2025.2 +PyYAML==6.0.2 +requests==2.32.3 +scipy==1.13.1 +seaborn==0.13.2 +SecretStorage==3.3.1 +simsimd==6.2.1 +six==1.16.0 +stringzilla==3.12.3 +sympy==1.13.1 +thop==0.1.1.post2209072238 +torch==2.6.0 +torchvision==0.21.0 +tqdm==4.67.1 +triton==3.2.0 +typing-inspection==0.4.0 +typing_extensions==4.13.0 +tzdata==2025.2 +urllib3==2.3.0 +#pycairo +wadllib==1.3.6 +zipp==3.21.0 \ No newline at end of file