Skip to content

Commit 40333b9

Browse files
committed
Merge pull request #1512 from dwf/hantek_nan2
Rebase of #1486
2 parents 8bd3cc2 + e990818 commit 40333b9

File tree

2 files changed

+87
-3
lines changed

2 files changed

+87
-3
lines changed

pylearn2/devtools/nan_guard.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import logging
1212
from theano.compile import Mode
1313
import theano
14+
import theano.tensor as T
15+
import theano.sandbox.cuda as cuda
1416
import numpy as np
1517
from pylearn2.models.dbm import flatten
1618
from pylearn2.utils import contains_nan, contains_inf
@@ -36,6 +38,23 @@ class NanGuardMode(Mode):
3638
If True, raise an error when a value greater than 1e10 is encountered.
3739
"""
3840
def __init__(self, nan_is_error, inf_is_error, big_is_error=True):
41+
if cuda.cuda_available:
42+
self.guard_input = cuda.fvector('nan_guard')
43+
if nan_is_error or inf_is_error:
44+
self.gpumin = theano.function(
45+
[self.guard_input], T.min(self.guard_input),
46+
mode='FAST_RUN'
47+
)
48+
if inf_is_error:
49+
self.gpumax = theano.function(
50+
[self.guard_input], T.max(self.guard_input),
51+
mode='FAST_RUN'
52+
)
53+
if big_is_error:
54+
self.gpuabsmax = theano.function(
55+
[self.guard_input], T.max(T.abs_(self.guard_input)),
56+
mode='FAST_RUN'
57+
)
3958
def do_check_on(var, nd, f, is_input):
4059
"""
4160
Checks `var` for NaNs / Infs. If detected, raises an exception
@@ -56,15 +75,31 @@ def do_check_on(var, nd, f, is_input):
5675
"""
5776
error = False
5877
if nan_is_error:
59-
if contains_nan(var):
78+
err = False
79+
if cuda.cuda_available and isinstance(var, cuda.CudaNdarray):
80+
err = np.isnan(self.gpumin(var.reshape(var.size)))
81+
else:
82+
err = contains_nan(var)
83+
if err:
6084
logger.error('NaN detected')
6185
error = True
6286
if inf_is_error:
63-
if contains_inf(var):
87+
err = False
88+
if cuda.cuda_available and isinstance(var, cuda.CudaNdarray):
89+
err = (np.isinf(self.gpumin(var.reshape(var.size))) or \
90+
np.isinf(self.gpumax(var.reshape(var.size))))
91+
else:
92+
err = contains_inf(var)
93+
if err:
6494
logger.error('Inf detected')
6595
error = True
6696
if big_is_error:
67-
if np.abs(var).max() > 1e10:
97+
err = False
98+
if cuda.cuda_available and isinstance(var, cuda.CudaNdarray):
99+
err = (self.gpuabsmax(var.reshape(var.size)) > 1e10)
100+
else:
101+
err = (np.abs(var).max() > 1e10)
102+
if err:
68103
logger.error('Big value detected')
69104
error = True
70105
if error:
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
This test is for testing the NanGuardMode.
3+
"""
4+
from pylearn2.devtools.nan_guard import NanGuardMode
5+
import numpy
6+
import theano
7+
import theano.tensor as T
8+
9+
10+
def test_NanGuardMode():
11+
"""
12+
Tests if NanGuardMode is working by feeding in numpy.inf and numpy.nans
13+
intentionally. A working implementation should be able to capture all
14+
the abnormalties.
15+
"""
16+
x = T.matrix()
17+
w = theano.shared(numpy.random.randn(5, 7).astype(theano.config.floatX))
18+
y = T.dot(x, w)
19+
20+
fun = theano.function(
21+
[x], y,
22+
mode=NanGuardMode(nan_is_error=True, inf_is_error=True)
23+
)
24+
a = numpy.random.randn(3, 5).astype(theano.config.floatX)
25+
infa = numpy.tile(
26+
(numpy.asarray(100.) ** 1000000).astype(theano.config.floatX), (3, 5))
27+
nana = numpy.tile(
28+
numpy.asarray(numpy.nan).astype(theano.config.floatX), (3, 5))
29+
biga = numpy.tile(
30+
numpy.asarray(1e20).astype(theano.config.floatX), (3, 5))
31+
32+
work = [False, False, False]
33+
34+
fun(a) # normal values
35+
try:
36+
fun(infa) # INFs
37+
except AssertionError:
38+
work[0] = True
39+
try:
40+
fun(nana) # NANs
41+
except AssertionError:
42+
work[1] = True
43+
try:
44+
fun(biga) # big values
45+
except AssertionError:
46+
work[2] = True
47+
48+
if not (work[0] and work[1] and work[2]):
49+
raise AssertionError("NanGuardMode not working.")

0 commit comments

Comments
 (0)