提交 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
class TensorConstantSignature(tuple):
"""
A Signature object for comparing TensorConstant instances.
r"""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):
_, d = self
return hash_from_ndarray(d)
def _get_sum(self):
@property
def sum(self):
"""Compute sum of non NaN / Inf values in the array."""
try:
return self._sum
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.
if isinstance(self._sum, np.memmap):
self._sum = np.asarray(self._sum).item()
if self.has_nan and self.no_nan.mask.all():
# In this case the sum is not properly computed by numpy.
self._sum = 0
if np.isinf(self._sum) or np.isnan(self._sum):
# NaN may happen when there are both -inf and +inf values.
if self.has_nan:
......@@ -956,25 +972,22 @@ class TensorConstantSignature(tuple):
self._sum = np.ma.masked_array(self[1], mask).sum()
# At this point there should be no more NaN.
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:
return self._no_nan
except AttributeError:
nan_mask = np.isnan(self[1])
if nan_mask.any():
self._no_nan = np.ma.masked_array(self[1], nan_mask)
self.has_nan = True
else:
self._no_nan = self[1]
self.has_nan = False
nans = np.isnan(self[1])
self._no_nan = np.ma.masked_array(self[1], nans)
self.has_nan = np.any(nans)
return self._no_nan
no_nan = property(_get_no_nan)
def get_unique_value(x: TensorVariable) -> Optional[Number]:
"""Return the unique value of a tensor, if there is one"""
......
......@@ -90,7 +90,7 @@ from aesara.tensor.basic import (
)
from aesara.tensor.elemwise import DimShuffle
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.shape import Reshape, Shape, Shape_i, shape_padright, specify_shape
from aesara.tensor.type import (
......@@ -1116,46 +1116,6 @@ class TestCast:
# 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():
# This was raised by a user in https://github.com/Theano/Theano/issues/2975
assert tm._allclose(-0.311023883434, -0.311022856884)
......
from copy import copy
import numpy as np
import pytest
from numpy.testing import assert_equal, assert_string_equal
import aesara
import tests.unittest_tools as utt
from aesara.compile.mode import get_default_mode
from aesara.graph.basic import Constant, equal_computations
from aesara.tensor import get_vector_length
from aesara.tensor.basic import constant
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.type import (
TensorType,
......@@ -19,6 +22,7 @@ from aesara.tensor.type import (
iscalar,
ivector,
matrix,
scalar,
tensor3,
)
from aesara.tensor.type_other import MakeSlice
......@@ -30,6 +34,9 @@ from aesara.tensor.var import (
)
pytestmark = pytest.mark.filterwarnings("error")
@pytest.mark.parametrize(
"fct, value",
[
......@@ -264,3 +271,54 @@ def test_dense_types():
x = constant(1)
assert not isinstance(x, DenseTensorVariable)
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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论