|
9 | 9 | from label_studio_ml.utils import InMemoryLRUDictCache |
10 | 10 | from label_studio_sdk._extensions.label_studio_tools.core.utils.io import get_local_path |
11 | 11 |
|
| 12 | +# Monkey-patch torch.as_tensor to handle numpy 2.x compatibility |
| 13 | +_original_as_tensor = torch.as_tensor |
| 14 | +def _patched_as_tensor(data, dtype=None, device=None): |
| 15 | + """Patched version of torch.as_tensor that handles numpy 2.x compatibility""" |
| 16 | + if isinstance(data, np.ndarray): |
| 17 | + # For numpy 2.x compatibility, ensure arrays are properly converted |
| 18 | + if dtype is None and data.dtype == np.uint8: |
| 19 | + # Explicitly convert uint8 arrays |
| 20 | + return _original_as_tensor(data.copy(), dtype=torch.uint8, device=device) |
| 21 | + elif dtype is not None: |
| 22 | + # If dtype is specified, ensure the array is compatible |
| 23 | + if data.dtype == np.float32 and dtype == torch.int: |
| 24 | + # Convert float32 to int properly |
| 25 | + return _original_as_tensor(data.astype(np.int32), dtype=dtype, device=device) |
| 26 | + return _original_as_tensor(data, dtype=dtype, device=device) |
| 27 | +torch.as_tensor = _patched_as_tensor |
| 28 | + |
| 29 | +# Also patch tensor.numpy() to handle numpy 2.x compatibility |
| 30 | +_original_tensor_numpy = torch.Tensor.numpy |
| 31 | +def _patched_tensor_numpy(self, *args, **kwargs): |
| 32 | + """Patched version of tensor.numpy() that handles numpy 2.x compatibility""" |
| 33 | + try: |
| 34 | + return _original_tensor_numpy(self, *args, **kwargs) |
| 35 | + except RuntimeError as e: |
| 36 | + if "Numpy is not available" in str(e): |
| 37 | + # Fallback: manually convert tensor to numpy array |
| 38 | + # This is a workaround for numpy 2.x compatibility issues |
| 39 | + arr = self.detach().cpu().contiguous() |
| 40 | + # Convert to list first, then to numpy array |
| 41 | + if arr.dim() == 0: |
| 42 | + return np.array(arr.item()) |
| 43 | + else: |
| 44 | + # Map torch dtypes to numpy dtypes |
| 45 | + dtype_map = { |
| 46 | + torch.float32: np.float32, |
| 47 | + torch.float64: np.float64, |
| 48 | + torch.int32: np.int32, |
| 49 | + torch.int64: np.int64, |
| 50 | + torch.uint8: np.uint8, |
| 51 | + torch.bool: np.bool_, |
| 52 | + } |
| 53 | + np_dtype = dtype_map.get(arr.dtype, None) |
| 54 | + return np.array(arr.tolist(), dtype=np_dtype) |
| 55 | + raise |
| 56 | +torch.Tensor.numpy = _patched_tensor_numpy |
| 57 | + |
12 | 58 | logger = logging.getLogger(__name__) |
13 | 59 | _MODELS_DIR = pathlib.Path(__file__).parent / "models" |
14 | 60 |
|
@@ -91,6 +137,8 @@ def set_image(self, img_path, calculate_embeddings=True, task=None): |
91 | 137 | ) |
92 | 138 | image = cv2.imread(image_path) |
93 | 139 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) |
| 140 | + # Ensure image is contiguous and properly typed for numpy 2.x compatibility |
| 141 | + image = np.ascontiguousarray(image, dtype=np.uint8) |
94 | 142 | self.predictor.set_image(image) |
95 | 143 | payload = {'image_shape': image.shape[:2]} |
96 | 144 | logger.debug(f'Finished set_image({img_path}) in `IN_MEM_CACHE`: image shape {image.shape[:2]}') |
|
0 commit comments