158 lines
5.5 KiB
Python
158 lines
5.5 KiB
Python
# coding: utf-8
|
|
import logging
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
import torch
|
|
|
|
from ray.experimental.channel.serialization_context import _SerializationContext
|
|
from ray.experimental.util.types import Device
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"scalar_and_dtype",
|
|
[
|
|
# Basic tests
|
|
(1.23456, torch.float16),
|
|
(1.23456, torch.bfloat16),
|
|
(1.23456, torch.float32),
|
|
(1.23456, torch.float64),
|
|
(123, torch.int8),
|
|
(123, torch.int16),
|
|
(123456, torch.int32),
|
|
(123456, torch.int64),
|
|
(123, torch.uint8),
|
|
(123, torch.uint16),
|
|
(123456, torch.uint32),
|
|
(123456, torch.uint64),
|
|
(True, torch.bool),
|
|
# Boundary values tests - integers
|
|
(127, torch.int8), # INT8_MAX
|
|
(-128, torch.int8), # INT8_MIN
|
|
(32767, torch.int16), # INT16_MAX
|
|
(-32768, torch.int16), # INT16_MIN
|
|
(2147483647, torch.int32), # INT32_MAX
|
|
(-2147483648, torch.int32), # INT32_MIN
|
|
(9223372036854775807, torch.int64), # INT64_MAX
|
|
(-9223372036854775808, torch.int64), # INT64_MIN
|
|
# Boundary values tests - unsigned integers
|
|
(255, torch.uint8), # UINT8_MAX
|
|
(0, torch.uint8), # UINT8_MIN
|
|
(65535, torch.uint16), # UINT16_MAX
|
|
(0, torch.uint16), # UINT16_MIN
|
|
(4294967295, torch.uint32), # UINT32_MAX
|
|
(0, torch.uint32), # UINT32_MIN
|
|
(18446744073709551615, torch.uint64), # UINT64_MAX
|
|
(0, torch.uint64), # UINT64_MIN
|
|
# Floating point special values
|
|
(float("inf"), torch.float32),
|
|
(float("-inf"), torch.float32),
|
|
(float("nan"), torch.float32),
|
|
(float("inf"), torch.float64),
|
|
(float("-inf"), torch.float64),
|
|
(float("nan"), torch.float64),
|
|
# Float precision tests
|
|
(1.2345678901234567, torch.float32), # Beyond float32 precision
|
|
(1.2345678901234567, torch.float64), # Within float64 precision
|
|
(1e-45, torch.float32), # Near float32 smallest positive normal
|
|
(
|
|
2.2250738585072014e-308,
|
|
torch.float64,
|
|
), # Near float64 smallest positive normal
|
|
],
|
|
)
|
|
def test_scalar_tensor(scalar_and_dtype):
|
|
scalar, dtype = scalar_and_dtype
|
|
context = _SerializationContext()
|
|
scalar_tensor = torch.tensor(scalar, dtype=dtype)
|
|
np_array, tensor_dtype, tensor_device_type = context.serialize_to_numpy_or_scalar(
|
|
scalar_tensor
|
|
)
|
|
assert tensor_dtype == dtype
|
|
deserialized_tensor = context.deserialize_from_numpy_or_scalar(
|
|
np_array, dtype, tensor_device_type, Device.CPU
|
|
)
|
|
|
|
# Special handling for NaN values
|
|
if torch.is_floating_point(scalar_tensor) and torch.isnan(scalar_tensor):
|
|
assert torch.isnan(deserialized_tensor)
|
|
else:
|
|
assert (deserialized_tensor == scalar_tensor).all()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"tensor_shape_and_dtype",
|
|
[
|
|
((10, 10), torch.float16),
|
|
((10, 10), torch.bfloat16),
|
|
((10, 10, 10), torch.float32),
|
|
((10, 10, 10, 10), torch.float64),
|
|
((10, 10), torch.int8),
|
|
((10, 10), torch.int16),
|
|
((10, 10), torch.int32),
|
|
((10, 10), torch.int64),
|
|
((10, 10), torch.uint8),
|
|
((10, 10), torch.uint16),
|
|
((10, 10), torch.uint32),
|
|
((10, 10), torch.uint64),
|
|
],
|
|
)
|
|
def test_non_scalar_tensor(tensor_shape_and_dtype):
|
|
tensor_shape, dtype = tensor_shape_and_dtype
|
|
context = _SerializationContext()
|
|
|
|
# Create tensor based on dtype with varying values
|
|
if dtype in [torch.float16, torch.bfloat16, torch.float32, torch.float64]:
|
|
# For floating point types, use randn
|
|
tensor = torch.randn(*tensor_shape).to(dtype)
|
|
else:
|
|
# For integer types, create varying values within appropriate ranges
|
|
total_elements = torch.prod(torch.tensor(tensor_shape)).item()
|
|
|
|
if dtype == torch.uint8:
|
|
# Range: 0 to 255
|
|
values = torch.arange(0, min(total_elements, 256), dtype=torch.int32) % 256
|
|
elif dtype == torch.uint16:
|
|
# Range: 0 to 65535
|
|
values = (
|
|
torch.arange(0, min(total_elements, 65536), dtype=torch.int32) % 65536
|
|
)
|
|
elif dtype == torch.int8:
|
|
# Range: -128 to 127
|
|
values = (
|
|
torch.arange(0, min(total_elements, 256), dtype=torch.int32) % 256
|
|
) - 128
|
|
elif dtype == torch.int16:
|
|
# Range: -32768 to 32767
|
|
values = (
|
|
torch.arange(0, min(total_elements, 65536), dtype=torch.int32) % 65536
|
|
) - 32768
|
|
elif dtype == torch.int32:
|
|
# Use a smaller range to avoid overflow
|
|
values = torch.arange(0, total_elements, dtype=torch.int32) % 10000 - 5000
|
|
else: # int64
|
|
# Use a smaller range to avoid overflow
|
|
values = torch.arange(0, total_elements, dtype=torch.int64) % 10000 - 5000
|
|
|
|
# Reshape the values to match the target shape
|
|
tensor = values.reshape(tensor_shape).to(dtype)
|
|
|
|
np_array, tensor_dtype, tensor_device_type = context.serialize_to_numpy_or_scalar(
|
|
tensor
|
|
)
|
|
deserialized_tensor = context.deserialize_from_numpy_or_scalar(
|
|
np_array, tensor_dtype, tensor_device_type, Device.CPU
|
|
)
|
|
|
|
assert (tensor == deserialized_tensor).all()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if os.environ.get("PARALLEL_CI"):
|
|
sys.exit(pytest.main(["-n", "auto", "--boxed", "-vs", __file__]))
|
|
else:
|
|
sys.exit(pytest.main(["-sv", __file__]))
|