asimfayaz commited on
Commit
39d16fa
·
1 Parent(s): 38f7a30

Fix daemon process multiprocessing by using spawn method

Browse files

- Set multiprocessing start method to 'spawn' at module level
- This allows multiprocessing to work in daemon environments like HuggingFace Spaces
- Fixes 'daemonic processes are not allowed to have children' error
- Maintains process isolation for OpenMP safety and crash protection
- Restores proper background removal with alpha matting support

Files changed (1) hide show
  1. hy3dshape/hy3dshape/rembg.py +19 -24
hy3dshape/hy3dshape/rembg.py CHANGED
@@ -24,6 +24,13 @@ os.environ["PYTHONFAULTHANDLER"] = "1" # Better error reporting
24
  os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid Intel MKL errors
25
  os.environ["OMP_THREAD_LIMIT"] = "1" # Limit total number of OpenMP threads
26
 
 
 
 
 
 
 
 
27
  from PIL import Image
28
  from rembg import remove, new_session
29
 
@@ -71,21 +78,11 @@ def _remove_bg_in_process(image_bytes, use_alpha_matting=True):
71
 
72
  class BackgroundRemover():
73
  def __init__(self):
74
- # Set multiprocessing start method to 'spawn' to avoid OpenMP fork issues
75
- # Only set if not already set
76
- current_method = multiprocessing.get_start_method(allow_none=True)
77
- if current_method != 'spawn':
78
- try:
79
- multiprocessing.set_start_method('spawn', force=True)
80
- print(f"Set multiprocessing start method to 'spawn' (was: {current_method})")
81
- except RuntimeError as e:
82
- # If already set and not 'spawn', we'll have to work with what we have
83
- print(f"Warning: Could not set multiprocessing start method to 'spawn': {e}")
84
- print(f"Current method: {multiprocessing.get_start_method()}")
85
-
86
- # We don't initialize the session here anymore as it will be created in the subprocess
87
- self.session = None
88
- self.max_retries = 2 # Maximum number of retries for background removal
89
 
90
  def __call__(self, image: Image.Image):
91
  if not isinstance(image, Image.Image):
@@ -105,25 +102,22 @@ class BackgroundRemover():
105
  if image.mode != 'RGBA':
106
  image = image.convert('RGBA')
107
 
 
 
108
  # Convert image to bytes for passing to subprocess
109
  img_bytes = io.BytesIO()
110
  image.save(img_bytes, format='PNG')
111
  img_bytes = img_bytes.getvalue()
112
 
113
- # Create a process context
114
- try:
115
- ctx = multiprocessing.get_context('spawn')
116
- except RuntimeError:
117
- # Fallback to default context if spawn is not available
118
- ctx = multiprocessing
119
-
120
  # Try with alpha matting first (high quality)
 
121
  for attempt in range(self.max_retries):
122
  try:
123
- with ctx.Pool(processes=1) as pool:
124
  result = pool.apply(_remove_bg_in_process, args=(img_bytes, True))
125
 
126
  if result is not None:
 
127
  return Image.open(io.BytesIO(result))
128
  break # Exit retry loop if we got a result (even if None)
129
  except Exception as e:
@@ -135,10 +129,11 @@ class BackgroundRemover():
135
  print("Alpha matting failed, falling back to standard background removal")
136
  for attempt in range(self.max_retries):
137
  try:
138
- with ctx.Pool(processes=1) as pool:
139
  result = pool.apply(_remove_bg_in_process, args=(img_bytes, False))
140
 
141
  if result is not None:
 
142
  return Image.open(io.BytesIO(result))
143
  break # Exit retry loop if we got a result (even if None)
144
  except Exception as e:
 
24
  os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid Intel MKL errors
25
  os.environ["OMP_THREAD_LIMIT"] = "1" # Limit total number of OpenMP threads
26
 
27
+ # Fix daemon process multiprocessing by using spawn instead of fork
28
+ try:
29
+ multiprocessing.set_start_method('spawn', force=True)
30
+ print("Set multiprocessing start method to 'spawn' for daemon compatibility")
31
+ except RuntimeError as e:
32
+ print(f"Could not set multiprocessing start method: {e}")
33
+
34
  from PIL import Image
35
  from rembg import remove, new_session
36
 
 
78
 
79
  class BackgroundRemover():
80
  def __init__(self):
81
+ # Initialize background remover with multiprocessing using spawn method
82
+ # OpenMP conflicts are handled by environment variables and process isolation
83
+ print("Initializing BackgroundRemover with multiprocessing (spawn method)")
84
+ self.session = None # Session will be created in subprocess
85
+ self.max_retries = 2
 
 
 
 
 
 
 
 
 
 
86
 
87
  def __call__(self, image: Image.Image):
88
  if not isinstance(image, Image.Image):
 
102
  if image.mode != 'RGBA':
103
  image = image.convert('RGBA')
104
 
105
+ print("Starting background removal with multiprocessing (spawn method)...")
106
+
107
  # Convert image to bytes for passing to subprocess
108
  img_bytes = io.BytesIO()
109
  image.save(img_bytes, format='PNG')
110
  img_bytes = img_bytes.getvalue()
111
 
 
 
 
 
 
 
 
112
  # Try with alpha matting first (high quality)
113
+ print("Attempting alpha matting background removal...")
114
  for attempt in range(self.max_retries):
115
  try:
116
+ with multiprocessing.Pool(processes=1) as pool:
117
  result = pool.apply(_remove_bg_in_process, args=(img_bytes, True))
118
 
119
  if result is not None:
120
+ print("Alpha matting successful")
121
  return Image.open(io.BytesIO(result))
122
  break # Exit retry loop if we got a result (even if None)
123
  except Exception as e:
 
129
  print("Alpha matting failed, falling back to standard background removal")
130
  for attempt in range(self.max_retries):
131
  try:
132
+ with multiprocessing.Pool(processes=1) as pool:
133
  result = pool.apply(_remove_bg_in_process, args=(img_bytes, False))
134
 
135
  if result is not None:
136
+ print("Standard background removal successful")
137
  return Image.open(io.BytesIO(result))
138
  break # Exit retry loop if we got a result (even if None)
139
  except Exception as e: