I am currently trying to port a soccer model to Pyro. It looks about right on my end but was hoping anyone had some insight on any possible traps.
#hyperpriors home = pymc.Normal('home', 0, .0001, value=0) tau_att = pymc.Gamma('tau_att', .1, .1, value=10) tau_def = pymc.Gamma('tau_def', .1, .1, value=10) intercept = pymc.Normal('intercept', 0, .0001, value=0) #team-specific parameters atts_star = pymc.Normal("atts_star", mu=0, tau=tau_att, size=num_teams, value=att_starting_points.values) defs_star = pymc.Normal("defs_star", mu=0, tau=tau_def, size=num_teams, value=def_starting_points.values) # trick to code the sum to zero contraint @pymc.deterministic def atts(atts_star=atts_star): atts = atts_star.copy() atts = atts - np.mean(atts_star) return atts @pymc.deterministic def defs(defs_star=defs_star): defs = defs_star.copy() defs = defs - np.mean(defs_star) return defs @pymc.deterministic def home_theta(home_team=home_team, away_team=away_team, home=home, atts=atts, defs=defs, intercept=intercept): return np.exp(intercept + home + atts[home_team] + defs[away_team]) @pymc.deterministic def away_theta(home_team=home_team, away_team=away_team, home=home, atts=atts, defs=defs, intercept=intercept): return np.exp(intercept + atts[away_team] + defs[home_team]) home_goals = pymc.Poisson('home_goals', mu=home_theta, value=observed_home_goals, observed=True) away_goals = pymc.Poisson('away_goals', mu=away_theta, value=observed_away_goals, observed=True)
The above is the PYMC3 variant.
I believe ported over to Pyro this is the following.
def hierarchical_football(home_team, away_team, home_obs_goals, away_obs_goals, num_teams): home = pyro.sample("home", dist.Normal(0, .0001)) intercept = pyro.sample("intercept", dist.Normal(0, .0001)) tau_att = pyro.sample( "tau_att", dist.Gamma(.1, .1) ) tau_def = pyro.sample( "tau_def", dist.Gamma(.1, .1) ) with pyro.plate("plate_i", num_teams): atts_star = pyro.sample("atts_star", dist.Normal(0.0, tau_att)) defs_star = pyro.sample("defs_star", dist.Normal(0.0, tau_def)) atts = pyro.deterministic("atts", atts_star - atts_star.mean() ) defs = pyro.deterministic("defs", defs_star - defs_star.mean() ) home_theta = pyro.deterministic("home_theta", torch.exp(intercept + home + atts[home_team] + defs[away_team]) ) away_theta = pyro.deterministic("away_theta", torch.exp(intercept + atts[away_team] + defs[home_team]) ) home_goals = pyro.sample('home_goals', dist.Poisson(home_theta), obs=home_obs_goals ) away_goals = pyro.sample('away_goals', dist.Poisson(away_theta), obs=away_obs_goals ) return home_goals, away_goals
Does the above make sense as far as a port?
One of the open end defects is I couldnt figure out how to set initial starting values in Pyro.