TypeError in model with shape(16,8,2)

Hi,
I’m trying to model an experiment where participant have to rate the age of different avatar.
Data from the experiment has the shape (16,8,2). I’m encountering a type error using a bernouilli distribution with shape(1, 8, 1) I get the error :
TypeError: Cannot convert Type TensorType(int64, 3D) (of Variable is_troll_shared__) into Type TensorType(int64, (True, False, True)). You can try to manually convert is_troll_shared__ into a TensorType(int64, (True, False, True)).

import pymc3 as pm
import numpy as np

# A study on avatar perceived age. Participants have to rate the age of each avatar twice

# 16 avatars to rate
# 8 participants
# Each participant rate the same avatar twice (2)
num_avatar = 16
num_participant = 8
exposure_time = 2


age_obs_data = np.random.randint(0, 100, size=(num_avatar, num_participant, exposure_time)) # fake data

with pm.Model() as model3:
    # Age
    ## priors
    μ_avatars_age = pm.Uniform('μ_avatars_age', 0, 100, shape=(num_avatar, 1, 1))
    σ_avatars_age = pm.HalfCauchy('σ_avatars_age', 25, shape=(num_avatar, 1, 1))
    
    
    μ_participant_bias = pm.Normal('μ_participant_bias', 0, 10, shape=(1, num_participant, 1))
    
    # Troll detection: they rate the age of the avatar at random instead of trying to identify the true age
    μ_troll  = pm.Uniform('μ_troll', 0, 100)
    σ_troll = pm.Uniform('σ_troll', 0, 10)
    p_troll  = pm.Uniform('p_troll', 0, 1, shape=(1, num_participant, 1)) 
    is_troll = pm.Bernoulli('is_troll', p=p_troll, shape=(1, num_participant, 1))
    
    μ = pm.math.switch(is_troll > 0, μ_troll, μ_avatars_age + μ_participant_bias)
    σ = pm.math.switch(is_troll > 0, σ_troll, σ_avatars_age)
    
    obs_age = pm.Normal('obs_age', 
                        mu=μ_avatars_age + μ_participant_bias,
                        sd=σ_avatars_age,
                        shape=(num_avatar, num_participant, 1),
                        observed=age_obs_data,
                       )
    

    trace = pm.sample(draws=2000,)

Mixed effect model or hierarchical model is much easier to handle if you format your data into a long data table format. You can have a look at the doc eg http://docs.pymc.io/notebooks/GLM-hierarchical.html, @Jack_Caster’s repository https://github.com/JackCaster/GLM_with_PyMC3, my repository https://github.com/junpenglao/GLMM-in-Python as examples.

I’m observing a big drop in sampling performance using long form data, a factor of 10X.

Original code 150 it/s

import pymc3 as pm
import numpy as np

# A study on avatar perceived age. Participants have to rate the age of each avatar twice

# 16 avatars to rate
# 8 participants
# Each participant rate the same avatar twice (2)
num_avatar = 16
num_participant = 100
exposure_time = 2


age_obs_data = np.random.randint(0, 100, size=(num_avatar, num_participant, exposure_time)) # fake data

with pm.Model() as model1:
    # Age
    ## priors
    μ_avatars_age = pm.Uniform('μ_avatars_age', 0, 100, shape=(num_avatar, 1, 1))
    σ_avatars_age = pm.HalfCauchy('σ_avatars_age', 25, shape=(num_avatar, 1, 1))
    
    
    μ_participant_bias = pm.Normal('μ_participant_bias', 0, 10, shape=(1, num_participant, 1))
    
    
    obs_age = pm.Normal('obs_age', 
                        mu=μ_avatars_age + μ_participant_bias,
                        sd=σ_avatars_age,
                        shape=(num_avatar, num_participant, 1),
                        observed=age_obs_data,
                       )
    

    trace = pm.sample(draws=2000, cores=1)

long form code 20 it/s

import pymc3 as pm
import numpy as np
import pandas as pd
import patsy

# A study on avatar perceived age. Participants have to rate the age of each avatar twice

# 16 avatars to rate
# 8 participants
# Each participant rate the same avatar twice (2)
num_avatar = 16
num_participant = 100
exposure_time = 2


participant = np.repeat(np.arange(num_participant), num_avatar*exposure_time)
avatar = np.repeat(np.arange(num_avatar), num_participant*exposure_time)
data = np.random.randint(0, 100, size=(num_avatar*num_participant*exposure_time))


df = pd.DataFrame([participant, avatar, data], index=['participant', 'avatar', 'data']).T
df.participant = df.participant.astype('category')
df.avatar = df.avatar.astype('category')

participant_dm = np.asarray(patsy.dmatrix('0 + participant', data=df))
avatar_dm = np.asarray(patsy.dmatrix('0 + avatar', data=df))

with pm.Model() as model2:
    # Age
    ## priors
    μ_avatars_age = pm.math.dot(avatar_dm, pm.Uniform('μ_avatars_age', 0, 100, shape=num_avatar))
    σ_avatars_age = pm.math.dot(avatar_dm, pm.HalfCauchy('σ_avatars_age', 25, shape=num_avatar))
    
    μ_participant = pm.math.dot(participant_dm, pm.Normal('μ_participant', mu=0, sd=5, shape=num_participant))
        
    obs_age = pm.Normal('obs_age',
                        mu=μ_avatars_age + μ_participant,
                        sd=σ_avatars_age,
                        observed=df.data.values,
                        shape=len(df.data.values)
                       )
    
    trace = pm.sample(draws=2000, cores=1)

Is it normal or am I doing something wrong?