提交 880015b4 authored 作者: Brandon T. Willard's avatar Brandon T. Willard 提交者: Brandon T. Willard

Remove warnings from TensorConstantSignature

上级 f16f8559
...@@ -877,10 +877,18 @@ TensorType.variable_type = TensorVariable ...@@ -877,10 +877,18 @@ TensorType.variable_type = TensorVariable
class TensorConstantSignature(tuple): class TensorConstantSignature(tuple):
""" r"""A signature object for comparing `TensorConstant` instances.
A Signature object for comparing TensorConstant instances.
An instance is a pair with the type ``(Type, ndarray)``.
TODO FIXME: Subclassing `tuple` is unnecessary, and it appears to be
preventing the use of a much more convenient `__init__` that removes the
need for all these lazy computations and their safety checks.
Also, why do we even need this signature stuff? We could simply implement
good `Constant.__eq__` and `Constant.__hash__` implementations.
An instance is a pair: (Type instance, ndarray). We could also produce plain `tuple`\s with hashable values.
""" """
...@@ -929,19 +937,27 @@ class TensorConstantSignature(tuple): ...@@ -929,19 +937,27 @@ class TensorConstantSignature(tuple):
_, d = self _, d = self
return hash_from_ndarray(d) return hash_from_ndarray(d)
def _get_sum(self): @property
def sum(self):
"""Compute sum of non NaN / Inf values in the array.""" """Compute sum of non NaN / Inf values in the array."""
try: try:
return self._sum return self._sum
except AttributeError: except AttributeError:
self._sum = self.no_nan.sum()
# The following 2 lines are needede as in Python 3.3 with NumPy # Prevent warnings when there are `inf`s and `-inf`s present
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
self._sum = self.no_nan.sum()
# The following 2 lines are needed as in Python 3.3 with NumPy
# 1.7.1, numpy.ndarray and numpy.memmap aren't hashable. # 1.7.1, numpy.ndarray and numpy.memmap aren't hashable.
if isinstance(self._sum, np.memmap): if isinstance(self._sum, np.memmap):
self._sum = np.asarray(self._sum).item() self._sum = np.asarray(self._sum).item()
if self.has_nan and self.no_nan.mask.all(): if self.has_nan and self.no_nan.mask.all():
# In this case the sum is not properly computed by numpy. # In this case the sum is not properly computed by numpy.
self._sum = 0 self._sum = 0
if np.isinf(self._sum) or np.isnan(self._sum): if np.isinf(self._sum) or np.isnan(self._sum):
# NaN may happen when there are both -inf and +inf values. # NaN may happen when there are both -inf and +inf values.
if self.has_nan: if self.has_nan:
...@@ -956,25 +972,22 @@ class TensorConstantSignature(tuple): ...@@ -956,25 +972,22 @@ class TensorConstantSignature(tuple):
self._sum = np.ma.masked_array(self[1], mask).sum() self._sum = np.ma.masked_array(self[1], mask).sum()
# At this point there should be no more NaN. # At this point there should be no more NaN.
assert not np.isnan(self._sum) assert not np.isnan(self._sum)
return self._sum
sum = property(_get_sum) if isinstance(self._sum, np.ma.core.MaskedConstant):
self._sum = 0
return self._sum
def _get_no_nan(self): @property
def no_nan(self):
try: try:
return self._no_nan return self._no_nan
except AttributeError: except AttributeError:
nan_mask = np.isnan(self[1]) nans = np.isnan(self[1])
if nan_mask.any(): self._no_nan = np.ma.masked_array(self[1], nans)
self._no_nan = np.ma.masked_array(self[1], nan_mask) self.has_nan = np.any(nans)
self.has_nan = True
else:
self._no_nan = self[1]
self.has_nan = False
return self._no_nan return self._no_nan
no_nan = property(_get_no_nan)
def get_unique_value(x: TensorVariable) -> Optional[Number]: def get_unique_value(x: TensorVariable) -> Optional[Number]:
"""Return the unique value of a tensor, if there is one""" """Return the unique value of a tensor, if there is one"""
......
...@@ -90,7 +90,7 @@ from aesara.tensor.basic import ( ...@@ -90,7 +90,7 @@ from aesara.tensor.basic import (
) )
from aesara.tensor.elemwise import DimShuffle from aesara.tensor.elemwise import DimShuffle
from aesara.tensor.exceptions import NotScalarConstantError from aesara.tensor.exceptions import NotScalarConstantError
from aesara.tensor.math import dense_dot, eq from aesara.tensor.math import dense_dot
from aesara.tensor.math import sum as at_sum from aesara.tensor.math import sum as at_sum
from aesara.tensor.shape import Reshape, Shape, Shape_i, shape_padright, specify_shape from aesara.tensor.shape import Reshape, Shape, Shape_i, shape_padright, specify_shape
from aesara.tensor.type import ( from aesara.tensor.type import (
...@@ -1116,46 +1116,6 @@ class TestCast: ...@@ -1116,46 +1116,6 @@ class TestCast:
# gradient numerically # gradient numerically
def test_nan_inf_constant_signature():
# Test that the signature of a constant tensor containing NaN and Inf
# values is correct.
test_constants = [
[np.nan, np.inf, 0, 1],
[np.nan, np.inf, -np.inf, 1],
[0, np.inf, -np.inf, 1],
[0, 3, -np.inf, 1],
[0, 3, np.inf, 1],
[np.nan, 3, 4, 1],
[0, 3, 4, 1],
np.nan,
np.inf,
-np.inf,
0,
1,
]
n = len(test_constants)
# We verify that signatures of two rows i, j in the matrix above are
# equal if and only if i == j.
for i in range(n):
for j in range(n):
x = constant(test_constants[i])
y = constant(test_constants[j])
assert (x.signature() == y.signature()) == (i == j)
# Also test that nan !=0 and nan != nan.
x = scalar()
mode = get_default_mode()
if isinstance(mode, aesara.compile.debugmode.DebugMode):
# Disable the check preventing usage of NaN / Inf values.
# We first do a copy of the mode to avoid side effects on other tests.
mode = copy(mode)
mode.check_isfinite = False
f = aesara.function([x], eq(x, np.nan), mode=mode)
assert f(0) == 0
assert f(np.nan) == 0
def test_basic_allclose(): def test_basic_allclose():
# This was raised by a user in https://github.com/Theano/Theano/issues/2975 # This was raised by a user in https://github.com/Theano/Theano/issues/2975
assert tm._allclose(-0.311023883434, -0.311022856884) assert tm._allclose(-0.311023883434, -0.311022856884)
......
from copy import copy
import numpy as np import numpy as np
import pytest import pytest
from numpy.testing import assert_equal, assert_string_equal from numpy.testing import assert_equal, assert_string_equal
import aesara import aesara
import tests.unittest_tools as utt import tests.unittest_tools as utt
from aesara.compile.mode import get_default_mode
from aesara.graph.basic import Constant, equal_computations from aesara.graph.basic import Constant, equal_computations
from aesara.tensor import get_vector_length from aesara.tensor import get_vector_length
from aesara.tensor.basic import constant from aesara.tensor.basic import constant
from aesara.tensor.elemwise import DimShuffle from aesara.tensor.elemwise import DimShuffle
from aesara.tensor.math import dot from aesara.tensor.math import dot, eq
from aesara.tensor.subtensor import AdvancedSubtensor, Subtensor from aesara.tensor.subtensor import AdvancedSubtensor, Subtensor
from aesara.tensor.type import ( from aesara.tensor.type import (
TensorType, TensorType,
...@@ -19,6 +22,7 @@ from aesara.tensor.type import ( ...@@ -19,6 +22,7 @@ from aesara.tensor.type import (
iscalar, iscalar,
ivector, ivector,
matrix, matrix,
scalar,
tensor3, tensor3,
) )
from aesara.tensor.type_other import MakeSlice from aesara.tensor.type_other import MakeSlice
...@@ -30,6 +34,9 @@ from aesara.tensor.var import ( ...@@ -30,6 +34,9 @@ from aesara.tensor.var import (
) )
pytestmark = pytest.mark.filterwarnings("error")
@pytest.mark.parametrize( @pytest.mark.parametrize(
"fct, value", "fct, value",
[ [
...@@ -264,3 +271,54 @@ def test_dense_types(): ...@@ -264,3 +271,54 @@ def test_dense_types():
x = constant(1) x = constant(1)
assert not isinstance(x, DenseTensorVariable) assert not isinstance(x, DenseTensorVariable)
assert isinstance(x, DenseTensorConstant) assert isinstance(x, DenseTensorConstant)
class TestTensorConstantSignature:
vals = [
[np.nan, np.inf, 0, 1],
[np.nan, np.inf, -np.inf, 1],
[0, np.inf, -np.inf, 1],
[0, 3, -np.inf, 1],
[0, 3, np.inf, 1],
[np.nan, 3, 4, 1],
[0, 3, 4, 1],
np.nan,
np.inf,
-np.inf,
0,
1,
]
@pytest.mark.parametrize("val_1", vals)
@pytest.mark.parametrize("val_2", vals)
def test_nan_inf_constant_signature(self, val_1, val_2):
# Test that the signature of a constant tensor containing NaN and Inf
# values is correct.
# We verify that signatures of two rows i, j in the matrix above are
# equal if and only if i == j.
x = constant(val_1)
y = constant(val_2)
assert (x.signature() == y.signature()) == (val_1 is val_2)
def test_nan_nan(self):
# Also test that nan !=0 and nan != nan.
x = scalar()
mode = get_default_mode()
if isinstance(mode, aesara.compile.debugmode.DebugMode):
# Disable the check preventing usage of NaN / Inf values.
# We first do a copy of the mode to avoid side effects on other tests.
mode = copy(mode)
mode.check_isfinite = False
f = aesara.function([x], eq(x, np.nan), mode=mode)
assert f(0) == 0
assert f(np.nan) == 0
def test_empty_hash(self):
x = constant(np.array([], dtype=np.int64))
y = constant(np.array([], dtype=np.int64))
x_sig = x.signature()
y_sig = y.signature()
assert hash(x_sig) == hash(y_sig)
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论