def test_pymc3_convert_dists(): """Just a basic check that all PyMC3 RVs will convert to and from Theano RVs.""" tt.config.compute_test_value = "ignore" theano.config.cxx = "" with pm.Model() as model: norm_rv = pm.Normal("norm_rv", 0.0, 1.0, observed=1.0) mvnorm_rv = pm.MvNormal("mvnorm_rv", np.r_[0.0], np.c_[1.0], shape=1, observed=np.r_[1.0]) cauchy_rv = pm.Cauchy("cauchy_rv", 0.0, 1.0, observed=1.0) halfcauchy_rv = pm.HalfCauchy("halfcauchy_rv", 1.0, observed=1.0) uniform_rv = pm.Uniform("uniform_rv", observed=1.0) gamma_rv = pm.Gamma("gamma_rv", 1.0, 1.0, observed=1.0) invgamma_rv = pm.InverseGamma("invgamma_rv", 1.0, 1.0, observed=1.0) exp_rv = pm.Exponential("exp_rv", 1.0, observed=1.0) halfnormal_rv = pm.HalfNormal("halfnormal_rv", 1.0, observed=1.0) beta_rv = pm.Beta("beta_rv", 2.0, 2.0, observed=1.0) binomial_rv = pm.Binomial("binomial_rv", 10, 0.5, observed=5) dirichlet_rv = pm.Dirichlet("dirichlet_rv", np.r_[0.1, 0.1], observed=np.r_[0.1, 0.1]) poisson_rv = pm.Poisson("poisson_rv", 10, observed=5) bernoulli_rv = pm.Bernoulli("bernoulli_rv", 0.5, observed=0) betabinomial_rv = pm.BetaBinomial("betabinomial_rv", 0.1, 0.1, 10, observed=5) categorical_rv = pm.Categorical("categorical_rv", np.r_[0.5, 0.5], observed=1) multinomial_rv = pm.Multinomial("multinomial_rv", 5, np.r_[0.5, 0.5], observed=np.r_[2]) # Convert to a Theano `FunctionGraph` fgraph = model_graph(model) rvs_by_name = { n.owner.inputs[1].name: n.owner.inputs[1] for n in fgraph.outputs } pymc_rv_names = {n.name for n in model.observed_RVs} assert all( isinstance(rvs_by_name[n].owner.op, RandomVariable) for n in pymc_rv_names) # Now, convert back to a PyMC3 model pymc_model = graph_model(fgraph) new_pymc_rv_names = {n.name for n in pymc_model.observed_RVs} pymc_rv_names == new_pymc_rv_names
def test_pymc_broadcastable(): """Test PyMC3 to Theano conversion amid array broadcasting.""" tt.config.compute_test_value = 'ignore' mu_X = tt.vector('mu_X') sd_X = tt.vector('sd_X') mu_Y = tt.vector('mu_Y') sd_Y = tt.vector('sd_Y') mu_X.tag.test_value = np.array([0.], dtype=tt.config.floatX) sd_X.tag.test_value = np.array([1.], dtype=tt.config.floatX) mu_Y.tag.test_value = np.array([1.], dtype=tt.config.floatX) sd_Y.tag.test_value = np.array([0.5], dtype=tt.config.floatX) with pm.Model() as model: X_rv = pm.Normal('X_rv', mu_X, sd=sd_X, shape=(1, )) Y_rv = pm.Normal('Y_rv', mu_Y, sd=sd_Y, shape=(1, )) Z_rv = pm.Normal('Z_rv', X_rv + Y_rv, sd=sd_X + sd_Y, shape=(1, ), observed=[10.]) with pytest.warns(UserWarning): fgraph = model_graph(model) Z_rv_tt = canonicalize(fgraph, return_graph=False) # This will break comparison if we don't reuse it rng = Z_rv_tt.owner.inputs[1].owner.inputs[-1] mu_X_ = mt.vector('mu_X') sd_X_ = mt.vector('sd_X') mu_Y_ = mt.vector('mu_Y') sd_Y_ = mt.vector('sd_Y') tt.config.compute_test_value = 'ignore' X_rv_ = mt.NormalRV(mu_X_, sd_X_, (1, ), rng, name='X_rv') X_rv_ = mt.addbroadcast(X_rv_, 0) Y_rv_ = mt.NormalRV(mu_Y_, sd_Y_, (1, ), rng, name='Y_rv') Y_rv_ = mt.addbroadcast(Y_rv_, 0) Z_rv_ = mt.NormalRV(mt.add(X_rv_, Y_rv_), mt.add(sd_X_, sd_Y_), (1, ), rng, name='Z_rv') obs_ = mt(Z_rv.observations) Z_rv_obs_ = mt.observed(obs_, Z_rv_) Z_rv_meta = canonicalize(Z_rv_obs_.reify(), return_graph=False) assert mt(Z_rv_tt) == mt(Z_rv_meta)
def test_pymc_convert_dists(): """Just a basic check that all PyMC3 RVs will convert to and from Theano RVs.""" tt.config.compute_test_value = 'ignore' theano.config.cxx = '' with pm.Model() as model: norm_rv = pm.Normal('norm_rv', 0.0, 1.0, observed=1.0) mvnorm_rv = pm.MvNormal('mvnorm_rv', np.r_[0.0], np.c_[1.0], shape=1, observed=np.r_[1.0]) cauchy_rv = pm.Cauchy('cauchy_rv', 0.0, 1.0, observed=1.0) halfcauchy_rv = pm.HalfCauchy('halfcauchy_rv', 1.0, observed=1.0) uniform_rv = pm.Uniform('uniform_rv', observed=1.0) gamma_rv = pm.Gamma('gamma_rv', 1.0, 1.0, observed=1.0) invgamma_rv = pm.InverseGamma('invgamma_rv', 1.0, 1.0, observed=1.0) exp_rv = pm.Exponential('exp_rv', 1.0, observed=1.0) # Convert to a Theano `FunctionGraph` fgraph = model_graph(model) rvs_by_name = { n.owner.inputs[1].name: n.owner.inputs[1] for n in fgraph.outputs } pymc_rv_names = {n.name for n in model.observed_RVs} assert all( isinstance(rvs_by_name[n].owner.op, RandomVariable) for n in pymc_rv_names) # Now, convert back to a PyMC3 model pymc_model = graph_model(fgraph) new_pymc_rv_names = {n.name for n in pymc_model.observed_RVs} pymc_rv_names == new_pymc_rv_names
def test_pymc_normal_model(): """Conduct a more in-depth test of PyMC3/Theano conversions for a specific model.""" tt.config.compute_test_value = 'ignore' mu_X = tt.dscalar('mu_X') sd_X = tt.dscalar('sd_X') mu_Y = tt.dscalar('mu_Y') mu_X.tag.test_value = np.array(0., dtype=tt.config.floatX) sd_X.tag.test_value = np.array(1., dtype=tt.config.floatX) mu_Y.tag.test_value = np.array(1., dtype=tt.config.floatX) # We need something that uses transforms... with pm.Model() as model: X_rv = pm.Normal('X_rv', mu_X, sd=sd_X) S_rv = pm.HalfCauchy('S_rv', beta=np.array(0.5, dtype=tt.config.floatX)) Y_rv = pm.Normal('Y_rv', X_rv * S_rv, sd=S_rv) Z_rv = pm.Normal('Z_rv', X_rv + Y_rv, sd=sd_X, observed=10.) fgraph = model_graph(model, output_vars=[Z_rv]) Z_rv_tt = canonicalize(fgraph, return_graph=False) # This will break comparison if we don't reuse it rng = Z_rv_tt.owner.inputs[1].owner.inputs[-1] mu_X_ = mt.dscalar('mu_X') sd_X_ = mt.dscalar('sd_X') tt.config.compute_test_value = 'ignore' X_rv_ = mt.NormalRV(mu_X_, sd_X_, None, rng, name='X_rv') S_rv_ = mt.HalfCauchyRV(np.array(0., dtype=tt.config.floatX), np.array(0.5, dtype=tt.config.floatX), None, rng, name='S_rv') Y_rv_ = mt.NormalRV(mt.mul(X_rv_, S_rv_), S_rv_, None, rng, name='Y_rv') Z_rv_ = mt.NormalRV(mt.add(X_rv_, Y_rv_), sd_X, None, rng, name='Z_rv') obs_ = mt(Z_rv.observations) Z_rv_obs_ = mt.observed(obs_, Z_rv_) Z_rv_meta = mt(canonicalize(Z_rv_obs_.reify(), return_graph=False)) assert mt(Z_rv_tt) == Z_rv_meta # Now, let's try that with multiple outputs. fgraph.disown() fgraph = model_graph(model, output_vars=[Y_rv, Z_rv]) assert len(fgraph.variables) == 25 Y_new_rv = walk(Y_rv, fgraph.memo) S_new_rv = walk(S_rv, fgraph.memo) X_new_rv = walk(X_rv, fgraph.memo) Z_new_rv = walk(Z_rv, fgraph.memo) # Make sure our new vars are actually in the graph and where # they should be. assert Y_new_rv == fgraph.outputs[0] assert Z_new_rv == fgraph.outputs[1] assert X_new_rv in fgraph.variables assert S_new_rv in fgraph.variables assert isinstance(Z_new_rv.owner.op, Observed) # Let's only look at the variables involved in the `Z_rv` subgraph. Z_vars = theano.gof.graph.variables(theano.gof.graph.inputs([Z_new_rv]), [Z_new_rv]) # Let's filter for only the `RandomVariables` with names. Z_vars_count = Counter([ n.name for n in Z_vars if n.name and n.owner and isinstance(n.owner.op, RandomVariable) ]) # Each new RV should be present and only occur once. assert Y_new_rv.name in Z_vars_count.keys() assert X_new_rv.name in Z_vars_count.keys() assert Z_new_rv.owner.inputs[1].name in Z_vars_count.keys() assert all(v == 1 for v in Z_vars_count.values())