diff --git a/python/infinicore/nn/functional/__init__.py b/python/infinicore/nn/functional/__init__.py index a28128a1d..cbe3d3196 100644 --- a/python/infinicore/nn/functional/__init__.py +++ b/python/infinicore/nn/functional/__init__.py @@ -37,6 +37,7 @@ from .triplet_margin_with_distance_loss import triplet_margin_with_distance_loss from .unfold import unfold from .upsample_bilinear import upsample_bilinear +from .upsample_nearest import upsample_nearest __all__ = [ "adaptive_max_pool1d", diff --git a/python/infinicore/nn/functional/interpolate.py b/python/infinicore/nn/functional/interpolate.py index 739e4de36..cc2486a23 100644 --- a/python/infinicore/nn/functional/interpolate.py +++ b/python/infinicore/nn/functional/interpolate.py @@ -85,6 +85,13 @@ def interpolate( "Per-dimension scale_factor is not supported; pass a scalar (or equal values)." ) + if mode == "nearest" and spatial_ndim == 1: + from .upsample_nearest import upsample_nearest + + if size_list: + return upsample_nearest(input, size=size_list[0]) + return upsample_nearest(input, scale_factor=scale_list[0]) + align_i = 0 if align_corners is None else int(bool(align_corners)) return Tensor( diff --git a/python/infinicore/ops/logical_and.py b/python/infinicore/ops/logical_and.py index 0aa17c1ef..4853f3b2d 100644 --- a/python/infinicore/ops/logical_and.py +++ b/python/infinicore/ops/logical_and.py @@ -5,9 +5,27 @@ def logical_and(input: Tensor, other: Tensor, *, out=None) -> Tensor: r"""Computes the element-wise logical AND of the given input tensors.""" - if input.device.type not in ("cpu"): + if input.device.type != "cpu": assert infinicore.use_ntops - return infinicore.ntops.torch.logical_and(input, other, out=out) + lhs = infinicore.empty(input.shape, dtype=infinicore.bool, device=input.device) + rhs = infinicore.empty(other.shape, dtype=infinicore.bool, device=other.device) + input_zero = infinicore.zeros( + input.shape, dtype=input.dtype, device=input.device + ) + other_zero = infinicore.zeros( + other.shape, dtype=other.dtype, device=other.device + ) + + infinicore.ntops.torch.ne(input, input_zero, out=lhs) + infinicore.ntops.torch.ne(other, other_zero, out=rhs) + + if out is None: + out = infinicore.empty( + input.shape, dtype=infinicore.bool, device=input.device + ) + + infinicore.ntops.torch.bitwise_and(lhs, rhs, out=out) + return out if out is None: return Tensor(_infinicore.logical_and(input._underlying, other._underlying)) diff --git a/python/infinicore/ops/logical_not.py b/python/infinicore/ops/logical_not.py index 04168fe0f..d6b3a4dd0 100644 --- a/python/infinicore/ops/logical_not.py +++ b/python/infinicore/ops/logical_not.py @@ -5,10 +5,22 @@ def logical_not(input: Tensor, *, out=None) -> Tensor: r"""Computes the element-wise logical NOT of the given input tensors.""" - # 1. 非CPU平台调用 ntops 实现 - if input.device.type not in ("cpu"): + if input.device.type != "cpu": assert infinicore.use_ntops - return infinicore.ntops.torch.logical_not(input, out=out) + input_zero = infinicore.zeros( + input.shape, dtype=input.dtype, device=input.device + ) + result = infinicore.empty( + input.shape, dtype=infinicore.bool, device=input.device + ) + + infinicore.ntops.torch.eq(input, input_zero, out=result) + + if out is None: + return result + + infinicore.ntops.torch.bitwise_and(result, result, out=out) + return out # 2. 如果没有提供 out,创建一个新的 Tensor 并返回 if out is None: diff --git a/test/infinicore/ops/fmod.py b/test/infinicore/ops/fmod.py index 8543e0f5b..d885be6fa 100644 --- a/test/infinicore/ops/fmod.py +++ b/test/infinicore/ops/fmod.py @@ -39,7 +39,11 @@ def parse_test_cases(): tol = _TOLERANCE_MAP[dtype] a_spec = TensorSpec.from_tensor(in_shape, in_strides, dtype) b_spec = TensorSpec.from_tensor( - in_shape if other_shape is None else other_shape, None, dtype + in_shape if other_shape is None else other_shape, + None, + dtype, + scale=0.9, + bias=0.1, ) cases.append( diff --git a/test/infinicore/ops/index_copy.py b/test/infinicore/ops/index_copy.py index f228f82b9..a8a769661 100644 --- a/test/infinicore/ops/index_copy.py +++ b/test/infinicore/ops/index_copy.py @@ -37,13 +37,13 @@ def parse_test_cases(): # index for index_copy should be 1-D with length equal to source.size(dim) index_len = src_shape[dim] + unique_index = torch.randperm(target_shape[dim])[:index_len].to(torch.int64) index_spec = TensorSpec.from_tensor( (index_len,), None, infinicore.int64, - init_mode=TensorInitializer.RANDINT, - low=0, - high=target_shape[dim], + init_mode=TensorInitializer.MANUAL, + set_tensor=unique_index, ) src_spec = TensorSpec.from_tensor(src_shape, None, infinicore.float32) @@ -90,7 +90,7 @@ def torch_operator(self, *args, **kwargs): return torch.index_copy(*args, **kwargs) def infinicore_operator(self, *args, **kwargs): - return infinicore.index_copy(*args, **kwargs) + return infinicore.index_copy(*args, **kwargs) def main(): diff --git a/test/infinicore/ops/logdet.py b/test/infinicore/ops/logdet.py index bebddd79a..771fa1f1d 100644 --- a/test/infinicore/ops/logdet.py +++ b/test/infinicore/ops/logdet.py @@ -6,6 +6,7 @@ import infinicore import torch from framework import BaseOperatorTest, TensorSpec, TestCase, GenericTestRunner +from framework.tensor import TensorInitializer # Test cases format: (matrix_shape, strides_or_None) # logdet(input) — returns (sign, logabsdet) in PyTorch @@ -28,12 +29,47 @@ _TENSOR_DTYPES = [infinicore.float32] +def _stable_matrix_spec(shape, strides, dtype): + rows, cols = shape + if rows != cols: + raise ValueError("logdet test matrices must be square") + + matrix = torch.full(shape, 0.01, dtype=torch.float32) + matrix += torch.eye(rows, dtype=torch.float32) * (rows + 1.0) + + if strides is None: + return TensorSpec.from_tensor( + shape, + None, + dtype, + init_mode=TensorInitializer.MANUAL, + set_tensor=matrix, + ) + + storage_size = 1 + for size, stride in zip(shape, strides): + storage_size += (size - 1) * abs(stride) + + storage = torch.zeros((storage_size,), dtype=torch.float32) + for i in range(rows): + for j in range(cols): + storage[i * strides[0] + j * strides[1]] = matrix[i, j] + + return TensorSpec.from_tensor( + shape, + strides, + dtype, + init_mode=TensorInitializer.MANUAL, + set_tensor=storage, + ) + + def parse_test_cases(): test_cases = [] for shape, strides in _TEST_CASES_DATA: for dtype in _TENSOR_DTYPES: tol = _TOLERANCE_MAP.get(dtype, {"atol": 1e-5, "rtol": 1e-4}) - spec = TensorSpec.from_tensor(shape, strides, dtype) + spec = _stable_matrix_spec(shape, strides, dtype) test_cases.append( TestCase(