Skip to content

Commit d6278fe

Browse files
committed
Dynamic worker cap based on GPU VRAM instead of hard limit, bump to 0.4.1
Calculates max safe workers from actual GPU memory: CUDA context (~400MB) + model weights + JIT trace + batch inference per worker. Falls back to CPU core count / 2 on non-CUDA systems. Also prints VRAM size at startup.
1 parent 53fb4ce commit d6278fe

4 files changed

Lines changed: 49 additions & 9 deletions

File tree

backgroundremover/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
A library to remove background from videos and images
55
"""
66

7-
__version__ = "0.4.0"
7+
__version__ = "0.4.1"
88
__author__ = 'Johnathan Nader'
99
__credits__ = 'BackgroundRemoverAI.com'

backgroundremover/bg.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
try:
2828
if torch.cuda.is_available():
2929
DEVICE = torch.device('cuda:0')
30-
print(f"Device: CUDA ({torch.cuda.get_device_name(0)})")
30+
_gpu_name = torch.cuda.get_device_name(0)
31+
_gpu_mem = torch.cuda.get_device_properties(0).total_memory
32+
print(f"Device: CUDA ({_gpu_name}, {_gpu_mem // (1024**2)}MB VRAM)")
3133
elif torch.backends.mps.is_available():
3234
DEVICE = torch.device('mps')
3335
print("Device: MPS (Apple Silicon GPU)")
@@ -38,6 +40,44 @@
3840
print(f"Device: CPU (Setting CUDA or MPS failed: {e})")
3941
DEVICE = torch.device('cpu')
4042

43+
44+
def max_workers(model_name="u2net", gpu_batchsize=2):
45+
"""Estimate max safe worker processes based on available GPU/system memory.
46+
47+
Each worker spawns a separate process that loads its own copy of the model
48+
plus a CUDA context. This estimates how many can fit in VRAM.
49+
"""
50+
if torch.cuda.is_available():
51+
try:
52+
total_mem = torch.cuda.get_device_properties(0).total_memory
53+
except Exception:
54+
return 1
55+
56+
# Per-worker VRAM estimate:
57+
# CUDA context per process: ~400MB
58+
# Model weights (float32): ~175MB (u2net/human_seg), ~5MB (u2netp)
59+
# JIT traced copy: same as model weights
60+
# Batch inference tensors: ~30MB per frame in batch
61+
if model_name == "u2netp":
62+
model_bytes = 5 * 1024 * 1024
63+
else:
64+
model_bytes = 175 * 1024 * 1024
65+
66+
per_worker = (
67+
400 * 1024 * 1024 # CUDA context overhead
68+
+ model_bytes * 2 # model + JIT trace
69+
+ gpu_batchsize * 30 * 1024 * 1024 # inference tensors
70+
)
71+
72+
# Reserve 512MB for OS/driver/display
73+
usable = total_mem - 512 * 1024 * 1024
74+
calculated = max(1, int(usable // per_worker))
75+
return calculated
76+
77+
# CPU/MPS: limit by CPU cores (inference is compute-bound)
78+
cpu_count = os.cpu_count() or 2
79+
return max(1, cpu_count // 2)
80+
4181
class Net(torch.nn.Module):
4282
def __init__(self, model_name):
4383
super(Net, self).__init__()

backgroundremover/cmd/cli.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
from distutils.util import strtobool
44
from .. import utilities
5-
from ..bg import remove
5+
from ..bg import remove, max_workers
66

77

88
def main():
@@ -248,11 +248,11 @@ def main():
248248
print("Example: backgroundremover -i video.mp4 -tgwb -bi background.png -o output.gif")
249249
exit(1)
250250

251-
# Cap worker count to prevent hangs and resource exhaustion (see issue #181)
252-
if args.workernodes > 4:
253-
print(f"Warning: Requested {args.workernodes} workers, capping at 4. Higher values cause hangs and GPU memory exhaustion.")
254-
print("Use -wn 1 through -wn 4 for best results.")
255-
args.workernodes = 4
251+
# Dynamically cap worker count based on available GPU memory (see issue #181)
252+
safe_max = max_workers(model_name=args.model, gpu_batchsize=args.gpubatchsize)
253+
if args.workernodes > safe_max:
254+
print(f"Warning: Requested {args.workernodes} workers, capping at {safe_max} based on available memory.")
255+
args.workernodes = safe_max
256256

257257
# Parse background color if provided
258258
background_color = None

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
setup(
1313
name="backgroundremover",
14-
version="0.4.0",
14+
version="0.4.1",
1515
description="Background remover from image and video using AI",
1616
long_description=long_description,
1717
long_description_content_type="text/markdown",

0 commit comments

Comments
 (0)