Skip to content

Commit 83b91d8

Browse files
Theano-PyMC compatibility updates (#4218)
* Changes for renamed scan_module in Theano * Use direct import for OpFromGraph * Remove direct use of Theano's old tests package * Replace uses of old _get_test_value * Update and pin theano-pymc version to 1.0.11 * Fix Theano type determination for generator observations * Fix dtype in test_expand_packed_triangular * Remove old test value exception compatibility code Co-authored-by: Brandon T. Willard <[email protected]>
1 parent 0b07970 commit 83b91d8

10 files changed

+39
-28
lines changed

environment-dev.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ channels:
55
dependencies:
66
- python=3.6
77
- arviz>=0.9
8-
- theano-pymc>=1.0.5
8+
- theano-pymc==1.0.11
99
- numpy>=1.13
1010
- scipy>=0.18
1111
- pandas >=0.18

pymc3/distributions/dist_math.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
import theano
2626
from theano.scalar import UnaryScalarOp, upgrade_to_float_no_complex
2727
from theano.tensor.slinalg import Cholesky
28-
from theano.scan_module import until
28+
from theano.compile.builders import OpFromGraph
29+
from theano.scan import until
2930
from theano import scan
3031
from .shape_utils import to_tuple
3132

@@ -257,7 +258,7 @@ def dlogp(inputs, gradients):
257258

258259
return [-0.5 * g_cov * g_logp, -g_delta * g_logp]
259260

260-
return theano.OpFromGraph([cov, delta], [logp], grad_overrides=dlogp, inline=True)
261+
return OpFromGraph([cov, delta], [logp], grad_overrides=dlogp, inline=True)
261262

262263

263264
class SplineWrapper(theano.Op):

pymc3/distributions/multivariate.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from scipy import stats, linalg
2525

2626
from theano.gof.op import get_test_value
27+
from theano.gof.utils import TestValueError
2728
from theano.tensor.nlinalg import det, matrix_inverse, trace, eigh
2829
from theano.tensor.slinalg import Cholesky
2930
import pymc3 as pm
@@ -38,12 +39,6 @@
3839
from .shape_utils import to_tuple
3940
from ..math import kron_dot, kron_diag, kron_solve_lower, kronecker
4041

41-
# TODO: Remove this once the theano-pymc dependency is above 1.0.9
42-
try:
43-
from theano.gof.utils import TestValueError
44-
except ImportError:
45-
TestValueError = AttributeError
46-
4742

4843
__all__ = [
4944
"MvNormal",

pymc3/model.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,11 @@ def init_value(self):
16751675

16761676

16771677
def pandas_to_array(data):
1678+
"""Convert a Pandas object to a NumPy array.
1679+
1680+
XXX: When `data` is a generator, this will return a Theano tensor!
1681+
1682+
"""
16781683
if hasattr(data, "values"): # pandas
16791684
if data.isnull().any().any(): # missing values
16801685
ret = np.ma.MaskedArray(data.values, data.isnull().values)
@@ -1776,7 +1781,10 @@ def __init__(
17761781

17771782
if type is None:
17781783
data = pandas_to_array(data)
1779-
type = TensorType(distribution.dtype, data.shape)
1784+
if isinstance(data, theano.gof.graph.Variable):
1785+
type = data.type
1786+
else:
1787+
type = TensorType(distribution.dtype, data.shape)
17801788

17811789
self.observations = data
17821790

pymc3/ode/ode.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import scipy
1818
import theano
1919
import theano.tensor as tt
20+
from theano.gof.op import get_test_value
2021
from ..ode import utils
2122
from ..exceptions import ShapeError, DtypeError
2223

@@ -163,7 +164,7 @@ def __call__(self, y0, theta, return_sens=False, **kwargs):
163164
if theano.config.compute_test_value != "off":
164165
# compute test values from input test values
165166
test_states, test_sens = self._simulate(
166-
y0=self._get_test_value(y0), theta=self._get_test_value(theta)
167+
y0=get_test_value(y0), theta=get_test_value(theta)
167168
)
168169

169170
# check types of simulation result

pymc3/tests/helpers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from theano.sandbox.rng_mrg import MRG_RandomStreams
1919
from ..theanof import set_tt_rng, tt_rng
2020
import theano
21+
from theano.gradient import verify_grad as tt_verify_grad
2122

2223

2324
class SeededTest:
@@ -106,3 +107,9 @@ def select_by_precision(float64, float32):
106107
@contextlib.contextmanager
107108
def not_raises():
108109
yield
110+
111+
112+
def verify_grad(op, pt, n_tests=2, rng=None, *args, **kwargs):
113+
if rng is None:
114+
rng = nr.RandomState(411342)
115+
tt_verify_grad(op, pt, n_tests, rng, *args, **kwargs)

pymc3/tests/test_dist_math.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import numpy.testing as npt
1717
import theano.tensor as tt
1818
import theano
19-
import theano.tests.unittest_tools as utt
2019
import pymc3 as pm
2120
from scipy import stats, interpolate
2221
import pytest
@@ -32,6 +31,7 @@
3231
i0e,
3332
clipped_beta_rvs,
3433
)
34+
from .helpers import verify_grad
3535

3636

3737
def test_bound():
@@ -175,10 +175,10 @@ def func(chol_vec, delta):
175175
chol_vec_val = floatX(np.array([0.5, 1.0, -0.1]))
176176

177177
delta_val = floatX(np.random.randn(1, 2))
178-
utt.verify_grad(func, [chol_vec_val, delta_val])
178+
verify_grad(func, [chol_vec_val, delta_val])
179179

180180
delta_val = floatX(np.random.randn(5, 2))
181-
utt.verify_grad(func, [chol_vec_val, delta_val])
181+
verify_grad(func, [chol_vec_val, delta_val])
182182

183183
@pytest.mark.skip(reason="Fix in theano not released yet: Theano#5908")
184184
@theano.configparser.change_flags(compute_test_value="ignore")
@@ -205,7 +205,7 @@ def test_grad(self):
205205
x = np.linspace(0, 1, 100)
206206
y = x * x
207207
spline = SplineWrapper(interpolate.InterpolatedUnivariateSpline(x, y, k=1))
208-
utt.verify_grad(spline, [0.5])
208+
verify_grad(spline, [0.5])
209209

210210
@theano.configparser.change_flags(compute_test_value="ignore")
211211
def test_hessian(self):
@@ -221,10 +221,10 @@ def test_hessian(self):
221221
class TestI0e:
222222
@theano.configparser.change_flags(compute_test_value="ignore")
223223
def test_grad(self):
224-
utt.verify_grad(i0e, [0.5])
225-
utt.verify_grad(i0e, [-2.0])
226-
utt.verify_grad(i0e, [[0.5, -2.0]])
227-
utt.verify_grad(i0e, [[[0.5, -2.0]]])
224+
verify_grad(i0e, [0.5])
225+
verify_grad(i0e, [-2.0])
226+
verify_grad(i0e, [[0.5, -2.0]])
227+
verify_grad(i0e, [[[0.5, -2.0]]])
228228

229229

230230
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "float128"])

pymc3/tests/test_math.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import numpy.testing as npt
1717
import theano
1818
import theano.tensor as tt
19-
from theano.tests import unittest_tools as utt
2019
from pymc3.math import (
2120
LogDet,
2221
logdet,
@@ -31,7 +30,7 @@
3130
kron_dot,
3231
kron_solve_lower,
3332
)
34-
from .helpers import SeededTest
33+
from .helpers import SeededTest, verify_grad
3534
import pytest
3635
from pymc3.theanof import floatX
3736

@@ -153,7 +152,7 @@ def test_log1mexp():
153152
class TestLogDet(SeededTest):
154153
def setup_method(self):
155154
super().setup_method()
156-
utt.seed_rng()
155+
np.random.seed(899853)
157156
self.op_class = LogDet
158157
self.op = logdet
159158

@@ -166,10 +165,10 @@ def validate(self, input_mat):
166165
numpy_out = np.sum(np.log(np.abs(svd_diag)))
167166

168167
# Compare the result computed to the expected value.
169-
utt.assert_allclose(numpy_out, out)
168+
np.allclose(numpy_out, out)
170169

171170
# Test gradient:
172-
utt.verify_grad(self.op, [input_mat])
171+
verify_grad(self.op, [input_mat])
173172

174173
@pytest.mark.skipif(
175174
theano.config.device in ["cuda", "gpu"],
@@ -186,7 +185,7 @@ def test_basic(self):
186185
def test_expand_packed_triangular():
187186
with pytest.raises(ValueError):
188187
x = tt.matrix("x")
189-
x.tag.test_value = np.array([[1.0]])
188+
x.tag.test_value = np.array([[1.0]], dtype=theano.config.floatX)
190189
expand_packed_triangular(5, x)
191190
N = 5
192191
packed = tt.vector("packed")

pymc3/tests/test_variational_inference.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ def test_remove_scan_op():
750750
inference = ADVI()
751751
buff = io.StringIO()
752752
inference.run_profiling(n=10).summary(buff)
753-
assert "theano.scan_module.scan_op.Scan" not in buff.getvalue()
753+
assert "theano.scan.op.Scan" not in buff.getvalue()
754754
buff.close()
755755

756756

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
arviz>=0.9.0
2-
theano-pymc>=1.0.5
2+
theano-pymc==1.0.11
33
numpy>=1.13.0
44
scipy>=0.18.1
55
pandas>=0.18.0
@@ -8,5 +8,5 @@ fastprogress>=0.2.0
88
h5py>=2.7.0
99
typing-extensions>=3.7.4
1010
dataclasses; python_version < '3.7'
11-
contextvars; python_version < '3.7'
11+
contextvars; python_version < '3.7'
1212
dill

0 commit comments

Comments
 (0)