Hi Lasse,
the minimum simulator code is very helpful, now I can simulate a desired output with the TwoLevelGenerativeModel().
With 4 participants in a batch and the 4 observations each participant, the output looks like this with batch_size = 2:
{'sim_data': array([[[[1.29470631, 1. , 0. ],
[2.78270631, 1. , 0. ],
[3.39770631, 1. , 0. ],
[6.39470631, 0. , 0. ]],
[[1.68407352, 1. , 1. ],
[1.85707352, 1. , 1. ],
[1.11507352, 0. , 1. ],
[2.77207352, 0. , 1. ]],
[[1.36106071, 1. , 2. ],
[2.99906071, 1. , 2. ],
[4.23206071, 1. , 2. ],
[4.13506071, 0. , 2. ]],
[[0.87416584, 1. , 3. ],
[0.78516584, 1. , 3. ],
[1.36316584, 0. , 3. ],
[0.67516584, 0. , 3. ]]],
[[[1.54510175, 0. , 0. ],
[4.51710175, 1. , 0. ],
[1.68410175, 0. , 0. ],
[0.81410175, 0. , 0. ]],
[[2.34517544, 0. , 1. ],
[1.99617544, 0. , 1. ],
[0.82817544, 0. , 1. ],
[1.50817544, 1. , 1. ]],
[[1.30738178, 1. , 2. ],
[2.85238178, 1. , 2. ],
[1.80738178, 0. , 2. ],
[1.57038178, 0. , 2. ]],
[[0.57009528, 0. , 3. ],
[3.31809528, 0. , 3. ],
[0.51009528, 0. , 3. ],
[0.69309528, 0. , 3. ]]]]),
'hyper_prior_draws': array([[ 1.41857089, -0.93169315, 3.31628374, 0.45483618, 0.20133162,
0.44102315, 0.69175527, 0.79266394, 0.0595174 , 0.10295194],
[ 0.60878216, -1.39706776, 2.78171975, 0.47483292, 0.39313015,
0.11375621, 0.16225779, 0.7928784 , 0.03337419, 0.13652142]]),
'local_prior_draws': array([[[ 0.82724444, 0.40367882, 4.02537849, 0.35320437,
0.13170631],
[ 0.90479767, -0.68222203, 2.49417105, 0.41947897,
0.12407352],
[ 0.88580755, 0.05465446, 3.15031844, 0.54067406,
0.16306071],
[ 0.9926855 , -0.18758255, 2.97067231, 0.41571828,
0.16816584]],
[[ 0.58973456, -1.01946977, 2.24953471, 0.39817652,
0.24910175],
[ 0.55350562, -1.36531887, 1.57962135, 0.41177689,
0.62417544],
[ 0.58416283, -1.30227951, 3.34284877, 0.49790414,
0.52538178],
[ 0.56352598, -1.26160684, 2.31466931, 0.43792337,
0.16509528]]]),
'shared_prior_draws': None,
'sim_batchable_context': [array([[0, 0, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]]),
array([[0, 0, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1],
[0, 0, 1, 1]])],
'sim_non_batchable_context': array([4, 4, 4, 4]),
'prior_batchable_context': None,
'prior_non_batchable_context': None}
I set the summary and the inference network as follows:
summary_net = bf.summary_networks.HierarchicalNetwork([
bf.networks.DeepSet(),
bf.networks.DeepSet(summary_dim=64)
])
inference_net = bf.networks.InvertibleNetwork(
num_params=15,
coupling_settings={"dense_args": dict(kernel_regularizer=None), "dropout": False},
name="ddm_inference",
)
then, I tried to set up a configurator that organize the output of TwoLevelGenerativeModel as in https://github.com/stefanradev93/BayesFlow/blob/master/examples/LCA_Model_Posterior_Estimation.ipynb.
from tensorflow.keras.utils import to_categorical
def configurator(forward_dict):
"""Configure the output of the GenerativeModel for a BayesFlow setup."""
# Prepare placeholder dict
out_dict = {}
# Extract simulated response times
data = forward_dict["sim_data"]
# Convert list of condition indicators to a 2D array and add a
# trailing dimension of 1, so shape becomes (batch_size, num_obs, 1)
# We need this in order to easily concatenate the context with the data
context = np.array(forward_dict["sim_batchable_context"])[..., None]
# One-hot encoding of integer choices
categorical_resp = to_categorical(data[:, :, :, 1], num_classes=2)
# Concatenate rt, resp, context
out_dict["summary_conditions"] = np.c_[data[:, :, :, :3], categorical_resp, context].astype(np.float32)
# Make inference network aware of varying numbers of trials
# We create a vector of shape (batch_size, 1) by repeating the sqrt(num_obs)
vec_num_obs = forward_dict["sim_non_batchable_context"] * np.ones((data.shape[0], 1))
out_dict["direct_conditions"] = np.sqrt(vec_num_obs).astype(np.float32)
# Get data generating parameters
out_dict["local_parameters"] = forward_dict["local_prior_draws"].astype(np.float32)
# Get data generating parameters
out_dict["hyper_parameters"] = forward_dict["hyper_prior_draws"].astype(np.float32)
return out_dict
This configurator returns a dictionary like this. In the “summary_conditions”, the columns are:
- Reaction Time,
- Response,
- Subject Index,
4, 5: One-hot encoding for two conditions:
{'summary_conditions': array([[[[ 2.6474695 , 1. , 0. , 0. ,
1. , 0. ],
[ 3.3264694 , 1. , 0. , 0. ,
1. , 0. ],
[ 7.2974696 , 0. , 0. , 1. ,
0. , 1. ],
[ 3.8964696 , 1. , 0. , 0. ,
1. , 1. ]],
[[ 1.9811877 , 1. , 1. , 0. ,
1. , 0. ],
[ 1.8581877 , 1. , 1. , 0. ,
1. , 0. ],
[ 2.4871876 , 1. , 1. , 0. ,
1. , 1. ],
[ 2.5161877 , 1. , 1. , 0. ,
1. , 1. ]],
[[-0.03797305, 1. , 2. , 0. ,
1. , 0. ],
[-0.03797305, 1. , 2. , 0. ,
1. , 0. ],
[-0.03797305, 1. , 2. , 0. ,
1. , 1. ],
[-0.03797305, 1. , 2. , 0. ,
1. , 1. ]],
[[ 1.405282 , 1. , 3. , 0. ,
1. , 0. ],
[ 2.2722821 , 1. , 3. , 0. ,
1. , 0. ],
[ 1.968282 , 0. , 3. , 1. ,
0. , 1. ],
[ 1.265282 , 0. , 3. , 1. ,
0. , 1. ]]],
[[[ 1.8850831 , 1. , 0. , 0. ,
1. , 0. ],
[ 1.4160831 , 1. , 0. , 0. ,
1. , 0. ],
[ 1.3750831 , 1. , 0. , 0. ,
1. , 1. ],
[ 0.7910831 , 1. , 0. , 0. ,
1. , 1. ]],
[[ 2.1057036 , 1. , 1. , 0. ,
1. , 0. ],
[ 1.2727035 , 1. , 1. , 0. ,
1. , 0. ],
[ 4.5987034 , 1. , 1. , 0. ,
1. , 1. ],
[ 2.9247036 , 0. , 1. , 1. ,
0. , 1. ]],
[[ 1.2369583 , 1. , 2. , 0. ,
1. , 0. ],
[ 1.2579583 , 1. , 2. , 0. ,
1. , 0. ],
[ 1.6269583 , 0. , 2. , 1. ,
0. , 1. ],
[ 2.2309582 , 0. , 2. , 1. ,
0. , 1. ]],
[[ 0.87938637, 0. , 3. , 1. ,
0. , 0. ],
[ 1.9493864 , 1. , 3. , 0. ,
1. , 0. ],
[ 1.1853864 , 1. , 3. , 0. ,
1. , 1. ],
[ 2.1333864 , 0. , 3. , 1. ,
0. , 1. ]]]], dtype=float32),
'direct_conditions': array([[2., 2., 2., 2.],
[2., 2., 2., 2.]], dtype=float32),
'local_parameters': array([[[ 0.9636896 , 0.04489963, 4.8279986 , 0.40029538,
0.2964695 ],
[ 0.8681931 , 1.1129119 , 5.250871 , 0.41632465,
0.3461877 ],
[ 1.0855117 , -2.1465156 , 2.145133 , 1.4483211 ,
-0.03797305],
[ 0.9783554 , -1.4380984 , 2.4775946 , 0.5278079 ,
0.51528203]],
[[ 1.309698 , 1.1134202 , 2.546568 , 0.42023334,
0.35108307],
[ 1.0092192 , -0.3970489 , 3.036948 , 0.43358582,
0.46970353],
[ 0.9460304 , -0.23147029, 2.9617784 , 0.43887368,
0.42495826],
[ 1.2671711 , -0.43410122, 2.7386088 , 0.42810172,
0.47738636]]], dtype=float32),
'hyper_parameters': array([[ 0.9527935 , -1.1164383 , 3.3564892 , 0.27710044, 0.2009128 ,
0.09594686, 1.336043 , 1.1092404 , 0.52335066, 0.3671519 ],
[ 1.2016746 , -0.7607997 , 3.1105556 , 0.42581084, 0.43157616,
0.14350495, 1.0815748 , 0.2312061 , 0.01252569, 0.08018385]],
dtype=float32)}
However, I got the following error message while passing all the info to the Trainer():
INFO:root:Performing a consistency check with provided components...
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\trainers.py:1314, in Trainer._check_consistency(self)
1313 logger.info("Performing a consistency check with provided components...")
-> 1314 _ = self.amortizer.compute_loss(self.configurator(self.generative_model(_n_sim)))
1315 logger.info("Done.")
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\amortizers.py:209, in AmortizedPosterior.compute_loss(self, input_dict, **kwargs)
208 # Get amortizer outputs
--> 209 net_out, sum_out = self(input_dict, return_summary=True, **kwargs)
210 z, log_det_J = net_out
File ~\AppData\Roaming\Python\Python311\site-packages\keras\src\utils\traceback_utils.py:70, in filter_traceback.<locals>.error_handler(*args, **kwargs)
68 # To get the full stack trace, call:
69 # `tf.debugging.disable_traceback_filtering()`
---> 70 raise e.with_traceback(filtered_tb) from None
71 finally:
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\amortizers.py:181, in AmortizedPosterior.call(self, input_dict, return_summary, **kwargs)
180 # Compute output of inference net
--> 181 net_out = self.inference_net(input_dict[DEFAULT_KEYS["parameters"]], full_cond, **kwargs)
183 # Return summary outputs or not, depending on parameter
KeyError: "Exception encountered when calling layer 'hierarchical_ddm_amortizer' (type AmortizedPosterior).\n\nparameters\n\nCall arguments received by layer 'hierarchical_ddm_amortizer' (type AmortizedPosterior):\n • input_dict={'summary_conditions': 'tf.Tensor(shape=(2, 4, 4, 6), dtype=float32)', 'direct_conditions': 'tf.Tensor(shape=(2, 4), dtype=float32)', 'local_parameters': 'tf.Tensor(shape=(2, 4, 5), dtype=float32)', 'hyper_parameters': 'tf.Tensor(shape=(2, 10), dtype=float32)'}\n • return_summary=True\n • kwargs={'training': 'None'}"
During handling of the above exception, another exception occurred:
ConfigurationError Traceback (most recent call last)
Cell In[345], line 1
----> 1 trainer = bf.trainers.Trainer(
2 generative_model=model, amortizer=amortizer, configurator=configurator)
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\trainers.py:220, in Trainer.__init__(self, amortizer, generative_model, configurator, checkpoint_path, max_to_keep, default_lr, skip_checks, memory, **kwargs)
218 # Perform a sanity check with provided components
219 if not skip_checks:
--> 220 self._check_consistency()
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\trainers.py:1317, in Trainer._check_consistency(self)
1315 logger.info("Done.")
1316 except Exception as err:
-> 1317 raise ConfigurationError(
1318 "Could not carry out computations of generative_model ->"
1319 + f"configurator -> amortizer -> loss! Error trace:\n {err}"
1320 )
ConfigurationError: Could not carry out computations of generative_model ->configurator -> amortizer -> loss! Error trace:
"Exception encountered when calling layer 'hierarchical_ddm_amortizer' (type AmortizedPosterior).\n\nparameters\n\nCall arguments received by layer 'hierarchical_ddm_amortizer' (type AmortizedPosterior):\n • input_dict={'summary_conditions': 'tf.Tensor(shape=(2, 4, 4, 6), dtype=float32)', 'direct_conditions': 'tf.Tensor(shape=(2, 4), dtype=float32)', 'local_parameters': 'tf.Tensor(shape=(2, 4, 5), dtype=float32)', 'hyper_parameters': 'tf.Tensor(shape=(2, 10), dtype=float32)'}\n • return_summary=True\n • kwargs={'training': 'None'}"
I first changed the key “local_parameters” in the configurator to “parameters”, and then got some other errors:
INFO:root:Performing a consistency check with provided components...
---------------------------------------------------------------------------
InvalidArgumentError Traceback (most recent call last)
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\trainers.py:1314, in Trainer._check_consistency(self)
1313 logger.info("Performing a consistency check with provided components...")
-> 1314 _ = self.amortizer.compute_loss(self.configurator(self.generative_model(_n_sim)))
1315 logger.info("Done.")
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\amortizers.py:209, in AmortizedPosterior.compute_loss(self, input_dict, **kwargs)
208 # Get amortizer outputs
--> 209 net_out, sum_out = self(input_dict, return_summary=True, **kwargs)
210 z, log_det_J = net_out
File ~\AppData\Roaming\Python\Python311\site-packages\keras\src\utils\traceback_utils.py:70, in filter_traceback.<locals>.error_handler(*args, **kwargs)
68 # To get the full stack trace, call:
69 # `tf.debugging.disable_traceback_filtering()`
---> 70 raise e.with_traceback(filtered_tb) from None
71 finally:
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\amortizers.py:181, in AmortizedPosterior.call(self, input_dict, return_summary, **kwargs)
180 # Compute output of inference net
--> 181 net_out = self.inference_net(input_dict[DEFAULT_KEYS["parameters"]], full_cond, **kwargs)
183 # Return summary outputs or not, depending on parameter
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\inference_networks.py:178, in InvertibleNetwork.call(self, targets, condition, inverse, **kwargs)
177 return self.inverse(targets, condition, **kwargs)
--> 178 return self.forward(targets, condition, **kwargs)
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\inference_networks.py:215, in InvertibleNetwork.forward(self, targets, condition, **kwargs)
214 for layer in self.coupling_layers:
--> 215 z, log_det_J = layer(z, condition, **kwargs)
216 log_det_Js.append(log_det_J)
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\coupling_networks.py:612, in CouplingLayer.call(self, target_or_z, condition, inverse, **kwargs)
611 if not inverse:
--> 612 return self.forward(target_or_z, condition, **kwargs)
613 return self.inverse(target_or_z, condition, **kwargs)
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\coupling_networks.py:637, in CouplingLayer.forward(self, target, condition, **kwargs)
636 if self.act_norm is not None:
--> 637 target, log_det_J_act = self.act_norm(target)
638 log_det_Js += log_det_J_act
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\helper_networks.py:369, in ActNorm.call(self, target, inverse)
368 if not inverse:
--> 369 return self._forward(target)
370 else:
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\helper_networks.py:376, in ActNorm._forward(self, target)
374 """Performs a forward pass through the layer."""
--> 376 z = self.scale * target + self.bias
377 ldj = tf.math.reduce_sum(tf.math.log(tf.math.abs(self.scale)), axis=-1)
InvalidArgumentError: Exception encountered when calling layer 'act_norm_42' (type ActNorm).
{{function_node __wrapped__Mul_device_/job:localhost/replica:0/task:0/device:CPU:0}} Incompatible shapes: [15] vs. [2,4,5] [Op:Mul] name:
Call arguments received by layer 'act_norm_42' (type ActNorm):
• target=tf.Tensor(shape=(2, 4, 5), dtype=float32)
• inverse=False
During handling of the above exception, another exception occurred:
ConfigurationError Traceback (most recent call last)
Cell In[347], line 1
----> 1 trainer = bf.trainers.Trainer(
2 generative_model=model, amortizer=amortizer, configurator=configurator)
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\trainers.py:220, in Trainer.__init__(self, amortizer, generative_model, configurator, checkpoint_path, max_to_keep, default_lr, skip_checks, memory, **kwargs)
218 # Perform a sanity check with provided components
219 if not skip_checks:
--> 220 self._check_consistency()
File ~\AppData\Roaming\Python\Python311\site-packages\bayesflow\trainers.py:1317, in Trainer._check_consistency(self)
1315 logger.info("Done.")
1316 except Exception as err:
-> 1317 raise ConfigurationError(
1318 "Could not carry out computations of generative_model ->"
1319 + f"configurator -> amortizer -> loss! Error trace:\n {err}"
1320 )
ConfigurationError: Could not carry out computations of generative_model ->configurator -> amortizer -> loss! Error trace:
Exception encountered when calling layer 'act_norm_42' (type ActNorm).
{{function_node __wrapped__Mul_device_/job:localhost/replica:0/task:0/device:CPU:0}} Incompatible shapes: [15] vs. [2,4,5] [Op:Mul] name:
Call arguments received by layer 'act_norm_42' (type ActNorm):
• target=tf.Tensor(shape=(2, 4, 5), dtype=float32)
• inverse=False
Could you give me some advice on the configurator, and possibly on the summary and inference network if there is any problem about them?
I don’t know how to organize the data so that it make sense to the Trainer() function, and a piece of example code of a configurator for hierarchical data could be very helful!
Thanks a lot for your time!!
Best,
Yufei