diff --git a/bgfilter/segmentation.py b/bgfilter/segmentation.py index 5792dcd..dc54240 100644 --- a/bgfilter/segmentation.py +++ b/bgfilter/segmentation.py @@ -37,13 +37,16 @@ class BiRefNetSegmenter: ) from exc self.torch = torch + self.device = self._resolve_device(settings.device) + # fp16 only pays off on CUDA; CPU lacks native fp16 kernels (~100x slower), + # so the dtype follows the device. The fp16 checkpoint upcasts on CPU. + self.dtype = torch.float16 if self.device.type == "cuda" else torch.float32 self.model = AutoModelForImageSegmentation.from_pretrained( resolve_model_source(settings.model_name), trust_remote_code=True, - torch_dtype=torch.float16, # checkpoint ships fp16; run it as-is, inputs cast to match + dtype=self.dtype, ) self.model.eval() - self.device = self._resolve_device(settings.device) self.model.to(self.device) size = settings.input_size @@ -65,7 +68,7 @@ class BiRefNetSegmenter: def mask(self, rgb: np.ndarray) -> np.ndarray: """Return a soft foreground mask, float32 0..1, at the input resolution.""" image = Image.fromarray(rgb.astype(np.uint8), mode="RGB") - tensor = self.transform(image).unsqueeze(0).to(self.device, dtype=self.torch.float16) + tensor = self.transform(image).unsqueeze(0).to(self.device, dtype=self.dtype) with self.torch.inference_mode(): pred = self.model(tensor)[-1].sigmoid() pred = pred[0, 0].detach().float().cpu().numpy() diff --git a/bgfilter/vitmatte_infer.py b/bgfilter/vitmatte_infer.py index 3d5f953..48a5004 100644 --- a/bgfilter/vitmatte_infer.py +++ b/bgfilter/vitmatte_infer.py @@ -19,10 +19,13 @@ class ViTMatteRunner: ) from exc self.torch = torch + self.device = self._resolve_device(settings.device) + # fp16 only pays off on CUDA (tensor cores); CPU has no native fp16 conv/gemm + # kernels and degrades ~100x, so the dtype follows the device, never a param. + self.dtype = torch.float16 if self.device.type == "cuda" else torch.float32 source = resolve_model_source(settings.model_name) self.processor = VitMatteImageProcessor.from_pretrained(source) - self.model = VitMatteForImageMatting.from_pretrained(source, torch_dtype=torch.float16) - self.device = self._resolve_device(settings.device) + self.model = VitMatteForImageMatting.from_pretrained(source, dtype=self.dtype) self.model.to(self.device) self.model.eval() @@ -38,7 +41,7 @@ class ViTMatteRunner: trimap_image = Image.fromarray(trimap.astype(np.uint8), mode="L") inputs = self.processor(images=image, trimaps=trimap_image, return_tensors="pt") inputs = { - key: value.to(self.device, dtype=self.torch.float16) + key: value.to(self.device, dtype=self.dtype) if value.is_floating_point() else value.to(self.device) for key, value in inputs.items()