Repository: huggingface/transformers
Pull request: Add support for torch device objects in device validator

# What does this PR do?

Cc @zucchini-nlp 

Changed files:
filename: src/transformers/processing_utils.py
patch: @@ -76,6 +76,8 @@
 
 
 if is_torch_available():
+    import torch
+
     from .modeling_utils import PreTrainedAudioTokenizerBase
 
 if is_vision_available():
@@ -267,7 +269,7 @@ class methods and docstrings.
     do_center_crop: Optional[bool]
     data_format: Optional[Union[str, ChannelDimension]]
     input_data_format: Optional[Union[str, ChannelDimension]]
-    device: Annotated[Optional[str], device_validator()]
+    device: Annotated[Optional[Union[str, "torch.device"]], device_validator()]
     return_tensors: Annotated[Optional[Union[str, TensorType]], tensor_type_validator()]
     disable_grouping: Optional[bool]
     image_seq_length: Optional[int]
@@ -341,7 +343,7 @@ class VideosKwargs(TypedDict, total=False):
     crop_size: Annotated[Optional[Union[int, list[int], tuple[int, ...], dict[str, int]]], image_size_validator()]
     data_format: Optional[Union[str, ChannelDimension]]
     input_data_format: Optional[Union[str, ChannelDimension]]
-    device: Annotated[Optional[str], device_validator()]
+    device: Annotated[Optional[Union[str, "torch.device"]], device_validator()]
     do_sample_frames: Optional[bool]
     video_metadata: Annotated[Optional[VideoMetadataType], video_metadata_validator()]
     fps: Annotated[Optional[Union[int, float]], positive_any_number()]

filename: src/transformers/utils/type_validators.py
patch: @@ -4,12 +4,15 @@
 from ..tokenization_utils_base import PaddingStrategy, TruncationStrategy
 from ..video_utils import VideoMetadataType
 from .generic import TensorType
-from .import_utils import is_vision_available
+from .import_utils import is_torch_available, is_vision_available
 
 
 if is_vision_available():
     from ..image_utils import PILImageResampling
 
+if is_torch_available():
+    import torch
+
 
 def positive_any_number(value: int | float | None = None):
     if value is not None and (not isinstance(value, (int, float)) or not value >= 0):
@@ -53,6 +56,12 @@ def device_validator(value: str | int | None = None):
     possible_names = ["cpu", "cuda", "xla", "xpu", "mps", "meta"]
     if value is None:
         pass
+    elif is_torch_available() and isinstance(value, torch.device):
+        device_str = str(value)
+        if device_str.split(":")[0] not in possible_names:
+            raise ValueError(
+                f"If device is a torch.device, the value must be one of {possible_names} but got device={value}"
+            )
     elif isinstance(value, int) and value < 0:
         raise ValueError(
             f"If device is an integer, the value must be a strictly positive integer but got device={value}"
@@ -61,7 +70,7 @@ def device_validator(value: str | int | None = None):
         raise ValueError(f"If device is an string, the value must be one of {possible_names} but got device={value}")
     elif not isinstance(value, (int, str)):
         raise ValueError(
-            f"Device must be either an integer device ID or a string (e.g., 'cpu', 'cuda:0'), but got device={value}"
+            f"Device must be either an integer device ID, a string (e.g., 'cpu', 'cuda:0'), or a torch.device object, but got device={value}"
         )