Fix overriding Fast Image/Video Processors instance attributes affect other instances (#39363)
* fix and add tests * nit
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
|
from copy import deepcopy
|
||||||
from functools import lru_cache, partial
|
from functools import lru_cache, partial
|
||||||
from typing import Any, Optional, TypedDict, Union
|
from typing import Any, Optional, TypedDict, Union
|
||||||
|
|
||||||
@@ -229,7 +230,7 @@ class BaseImageProcessorFast(BaseImageProcessor):
|
|||||||
if kwarg is not None:
|
if kwarg is not None:
|
||||||
setattr(self, key, kwarg)
|
setattr(self, key, kwarg)
|
||||||
else:
|
else:
|
||||||
setattr(self, key, getattr(self, key, None))
|
setattr(self, key, deepcopy(getattr(self, key, None)))
|
||||||
|
|
||||||
# get valid kwargs names
|
# get valid kwargs names
|
||||||
self._valid_kwargs_names = list(self.valid_kwargs.__annotations__.keys())
|
self._valid_kwargs_names = list(self.valid_kwargs.__annotations__.keys())
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import copy
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
|
from copy import deepcopy
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -202,7 +202,7 @@ class BaseVideoProcessor(BaseImageProcessorFast):
|
|||||||
if kwargs.get(key) is not None:
|
if kwargs.get(key) is not None:
|
||||||
setattr(self, key, kwargs[key])
|
setattr(self, key, kwargs[key])
|
||||||
else:
|
else:
|
||||||
setattr(self, key, getattr(self, key, None))
|
setattr(self, key, deepcopy(getattr(self, key, None)))
|
||||||
|
|
||||||
def __call__(self, videos, **kwargs) -> BatchFeature:
|
def __call__(self, videos, **kwargs) -> BatchFeature:
|
||||||
return self.preprocess(videos, **kwargs)
|
return self.preprocess(videos, **kwargs)
|
||||||
@@ -774,7 +774,7 @@ class BaseVideoProcessor(BaseImageProcessorFast):
|
|||||||
Returns:
|
Returns:
|
||||||
`dict[str, Any]`: Dictionary of all the attributes that make up this video processor instance.
|
`dict[str, Any]`: Dictionary of all the attributes that make up this video processor instance.
|
||||||
"""
|
"""
|
||||||
output = copy.deepcopy(self.__dict__)
|
output = deepcopy(self.__dict__)
|
||||||
output.pop("model_valid_processing_keys", None)
|
output.pop("model_valid_processing_keys", None)
|
||||||
output.pop("_valid_kwargs_names", None)
|
output.pop("_valid_kwargs_names", None)
|
||||||
output["video_processor_type"] = self.__class__.__name__
|
output["video_processor_type"] = self.__class__.__name__
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import pathlib
|
|||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import requests
|
import requests
|
||||||
@@ -559,6 +560,43 @@ class ImageProcessingTestMixin:
|
|||||||
if not is_tested:
|
if not is_tested:
|
||||||
self.skipTest(reason="No validation found for `preprocess` method")
|
self.skipTest(reason="No validation found for `preprocess` method")
|
||||||
|
|
||||||
|
def test_override_instance_attributes_does_not_affect_other_instances(self):
|
||||||
|
if self.fast_image_processing_class is None:
|
||||||
|
self.skipTest(
|
||||||
|
"Only testing fast image processor, as most slow processors break this test and are to be deprecated"
|
||||||
|
)
|
||||||
|
|
||||||
|
image_processing_class = self.fast_image_processing_class
|
||||||
|
image_processor_1 = image_processing_class()
|
||||||
|
image_processor_2 = image_processing_class()
|
||||||
|
if not (hasattr(image_processor_1, "size") and isinstance(image_processor_1.size, dict)) or not (
|
||||||
|
hasattr(image_processor_1, "image_mean") and isinstance(image_processor_1.image_mean, list)
|
||||||
|
):
|
||||||
|
self.skipTest(
|
||||||
|
reason="Skipping test as the image processor does not have dict size or list image_mean attributes"
|
||||||
|
)
|
||||||
|
|
||||||
|
original_size_2 = deepcopy(image_processor_2.size)
|
||||||
|
for key in image_processor_1.size:
|
||||||
|
image_processor_1.size[key] = -1
|
||||||
|
modified_copied_size_1 = deepcopy(image_processor_1.size)
|
||||||
|
|
||||||
|
original_image_mean_2 = deepcopy(image_processor_2.image_mean)
|
||||||
|
image_processor_1.image_mean[0] = -1
|
||||||
|
modified_copied_image_mean_1 = deepcopy(image_processor_1.image_mean)
|
||||||
|
|
||||||
|
# check that the original attributes of the second instance are not affected
|
||||||
|
self.assertEqual(image_processor_2.size, original_size_2)
|
||||||
|
self.assertEqual(image_processor_2.image_mean, original_image_mean_2)
|
||||||
|
|
||||||
|
for key in image_processor_2.size:
|
||||||
|
image_processor_2.size[key] = -2
|
||||||
|
image_processor_2.image_mean[0] = -2
|
||||||
|
|
||||||
|
# check that the modified attributes of the first instance are not affected by the second instance
|
||||||
|
self.assertEqual(image_processor_1.size, modified_copied_size_1)
|
||||||
|
self.assertEqual(image_processor_1.image_mean, modified_copied_image_mean_1)
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_accelerator
|
@require_torch_accelerator
|
||||||
@require_vision
|
@require_vision
|
||||||
@@ -575,7 +613,6 @@ class ImageProcessingTestMixin:
|
|||||||
|
|
||||||
image_processor = torch.compile(image_processor, mode="reduce-overhead")
|
image_processor = torch.compile(image_processor, mode="reduce-overhead")
|
||||||
output_compiled = image_processor(input_image, device=torch_device, return_tensors="pt")
|
output_compiled = image_processor(input_image, device=torch_device, return_tensors="pt")
|
||||||
print(output_eager.pixel_values.dtype, output_compiled.pixel_values.dtype)
|
|
||||||
self._assert_slow_fast_tensors_equivalence(
|
self._assert_slow_fast_tensors_equivalence(
|
||||||
output_eager.pixel_values, output_compiled.pixel_values, atol=1e-4, rtol=1e-4, mean_atol=1e-5
|
output_eager.pixel_values, output_compiled.pixel_values, atol=1e-4, rtol=1e-4, mean_atol=1e-5
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from packaging import version
|
from packaging import version
|
||||||
@@ -448,3 +449,40 @@ class VideoProcessingTestMixin:
|
|||||||
|
|
||||||
if not is_tested:
|
if not is_tested:
|
||||||
self.skipTest(reason="No validation found for `preprocess` method")
|
self.skipTest(reason="No validation found for `preprocess` method")
|
||||||
|
|
||||||
|
def test_override_instance_attributes_does_not_affect_other_instances(self):
|
||||||
|
if self.fast_video_processing_class is None:
|
||||||
|
self.skipTest(
|
||||||
|
"Only testing fast video processor, as most slow processors break this test and are to be deprecated"
|
||||||
|
)
|
||||||
|
|
||||||
|
video_processing_class = self.fast_video_processing_class
|
||||||
|
video_processor_1 = video_processing_class()
|
||||||
|
video_processor_2 = video_processing_class()
|
||||||
|
if not (hasattr(video_processor_1, "size") and isinstance(video_processor_1.size, dict)) or not (
|
||||||
|
hasattr(video_processor_1, "image_mean") and isinstance(video_processor_1.image_mean, list)
|
||||||
|
):
|
||||||
|
self.skipTest(
|
||||||
|
reason="Skipping test as the image processor does not have dict size or list image_mean attributes"
|
||||||
|
)
|
||||||
|
|
||||||
|
original_size_2 = deepcopy(video_processor_2.size)
|
||||||
|
for key in video_processor_1.size:
|
||||||
|
video_processor_1.size[key] = -1
|
||||||
|
modified_copied_size_1 = deepcopy(video_processor_1.size)
|
||||||
|
|
||||||
|
original_image_mean_2 = deepcopy(video_processor_2.image_mean)
|
||||||
|
video_processor_1.image_mean[0] = -1
|
||||||
|
modified_copied_image_mean_1 = deepcopy(video_processor_1.image_mean)
|
||||||
|
|
||||||
|
# check that the original attributes of the second instance are not affected
|
||||||
|
self.assertEqual(video_processor_2.size, original_size_2)
|
||||||
|
self.assertEqual(video_processor_2.image_mean, original_image_mean_2)
|
||||||
|
|
||||||
|
for key in video_processor_2.size:
|
||||||
|
video_processor_2.size[key] = -2
|
||||||
|
video_processor_2.image_mean[0] = -2
|
||||||
|
|
||||||
|
# check that the modified attributes of the first instance are not affected by the second instance
|
||||||
|
self.assertEqual(video_processor_1.size, modified_copied_size_1)
|
||||||
|
self.assertEqual(video_processor_1.image_mean, modified_copied_image_mean_1)
|
||||||
|
|||||||
Reference in New Issue
Block a user