Porting from PyMC3 ( Hierarchical Bayesian Model ) Football

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.

http://danielweitzenfeld.github.io/passtheroc/blog/2014/10/28/bayes-premier-league/

#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.

see this example for init_to_value usage

Hey, if you’re still working on this, I ported the same model in pymc, pyro, numpyro and others – here. It samples well