Belle II Software light-2601-hyperion
model.py
1#!/usr/bin/env python3
2
3
10
11import keras
12
13
14@keras.saving.register_keras_serializable(package="MyLayers")
15class MyConcatenate(keras.layers.Layer):
16 """Concatenate the 3D input tensors and their 2D masks along the axis=1 dimension."""
17
18 def call(self, inputs):
19 '''
20 Expect the input to be list of 3D tensors
21 '''
22 return keras.ops.concatenate(inputs, axis=1)
23
24 def compute_mask(self, inputs, mask=None):
25 '''
26 Expect the mask to be list of 2D mask tensors
27 '''
28 if mask is None:
29 return None
30 return keras.ops.concatenate(mask, axis=1)
31
32 def get_config(self):
33 '''
34 Keras needs this
35 '''
36 return super().get_config()
37
38
39def create_mlp(hidden_units, dropout_rate, activation, normalization_layer, name=None):
40 mlp_layers = []
41 for units in hidden_units:
42 mlp_layers.append(normalization_layer())
43 mlp_layers.append(keras.layers.Dense(units, activation=activation))
44 mlp_layers.append(keras.layers.Dropout(dropout_rate))
45
46 return keras.Sequential(mlp_layers, name=name)
47
48
49def get_tflat_model(parameters, number_of_features):
50 """
51 Configure tflat model from parameters
52 """
53 clip_value = parameters.get("clip_value")
54 mask_value = parameters.get("mask_value")
55 num_trk = parameters.get("num_trk")
56 num_trk_features = parameters.get("num_trk_features")
57 num_ecl = parameters.get("num_ecl")
58 num_ecl_features = parameters.get("num_ecl_features")
59 num_roe = parameters.get("num_roe")
60 num_roe_features = parameters.get("num_roe_features")
61 num_transformer_blocks = parameters.get("num_transformer_blocks")
62 num_heads = parameters.get("num_heads")
63 embedding_dims = parameters.get("embedding_dims")
64 mlp_hidden_units_factors = parameters.get("mlp_hidden_units_factors")
65 dropout_rate = parameters.get("dropout_rate")
66
67 # Compute start columns for tracks, ecl clusters and rest of event
68 trk_start = 0
69 ecl_start = num_trk*num_trk_features
70 roe_start = ecl_start + num_ecl*num_ecl_features
71
72 # Create model inputs
73 inputs = keras.layers.Input((number_of_features,))
74
75 # Replace NaN's by a special number
76 raw_features = keras.ops.nan_to_num(inputs, nan=mask_value)
77
78 # Clip features to mitigate outliers
79 raw_features = keras.ops.clip(raw_features, x_min=-clip_value, x_max=clip_value)
80
81 # Preprocess the track features
82
83 # Get the track features
84 raw_trk_features = raw_features[:, trk_start:trk_start+num_trk*num_trk_features]
85
86 # 3D tensor with axes for samples, tracks and features
87 reshaped_trk_features = keras.layers.Reshape((num_trk, num_trk_features))(raw_trk_features)
88
89 # Create a keras mask for padded tracks
90 masked_trk_features = keras.layers.Masking(mask_value=mask_value)(reshaped_trk_features)
91
92 # Normalize the input features
93 normed_trk_features = keras.layers.BatchNormalization()(masked_trk_features)
94
95 # Embed features in latent space with embedding_dims
96 encoded_trk_features = keras.layers.Dense(
97 units=embedding_dims,
98 activation=keras.activations.selu,
99 name="Embedding_trk_dense_1")(normed_trk_features)
100 encoded_trk_features = keras.layers.Dropout(dropout_rate, name="Embedding_trk_dropout_1")(encoded_trk_features)
101 encoded_trk_features = keras.layers.BatchNormalization(name="Embedding_trk_batchnorm")(encoded_trk_features)
102 encoded_trk_features = keras.layers.Dense(
103 units=embedding_dims,
104 activation=keras.activations.selu,
105 name="Embedding_trk_dense_2")(encoded_trk_features)
106 encoded_trk_features = keras.layers.Dropout(dropout_rate, name="Embedding_trk_dropout_2")(encoded_trk_features)
107
108 # Preprocess the ecl features
109
110 # Get the ecl features
111 raw_ecl_features = raw_features[:, ecl_start:ecl_start+num_ecl*num_ecl_features]
112
113 # 3D tensor with axes for samples, ecl candidates and features
114 reshaped_ecl_features = keras.layers.Reshape((num_ecl, num_ecl_features))(raw_ecl_features)
115
116 # Create a keras mask for padded ecl candidates
117 masked_ecl_features = keras.layers.Masking(mask_value=mask_value)(reshaped_ecl_features)
118
119 # Normalize the input features
120 normed_ecl_features = keras.layers.BatchNormalization()(masked_ecl_features)
121
122 # Embed features in latent space with embedding_dims
123 encoded_ecl_features = keras.layers.Dense(
124 units=embedding_dims,
125 activation=keras.activations.selu,
126 name="Embedding_ecl_dense_1")(normed_ecl_features)
127 encoded_ecl_features = keras.layers.Dropout(dropout_rate, name="Embedding_ecl_dropout_1")(encoded_ecl_features)
128 encoded_ecl_features = keras.layers.BatchNormalization(name="Embedding_ecl_batchnorm")(encoded_ecl_features)
129 encoded_ecl_features = keras.layers.Dense(
130 units=embedding_dims,
131 activation=keras.activations.selu,
132 name="Embedding_ecl_dense_2")(encoded_ecl_features)
133 encoded_ecl_features = keras.layers.Dropout(dropout_rate, name="Embedding_ecl_dropout_2")(encoded_ecl_features)
134
135 # Preprocess the rest of event features
136
137 # Get the roe features
138 raw_roe_features = raw_features[:, roe_start:roe_start+num_roe*num_roe_features]
139
140 # 3D tensor with axes for samples, roe's and features
141 reshaped_roe_features = keras.layers.Reshape((num_roe, num_roe_features))(raw_roe_features)
142
143 # Create a keras mask for padded roe
144 masked_roe_features = keras.layers.Masking(mask_value=mask_value)(reshaped_roe_features)
145
146 # Normalize the input features
147 normed_roe_features = keras.layers.BatchNormalization()(masked_roe_features)
148
149 # Embed features in latent space with embedding_dims
150 encoded_roe_features = keras.layers.Dense(
151 units=embedding_dims,
152 activation=keras.activations.selu,
153 name="Embedding_roe_dense_1")(normed_roe_features)
154 encoded_roe_features = keras.layers.Dropout(dropout_rate, name="Embedding_roe_dropout_1")(encoded_roe_features)
155 encoded_roe_features = keras.layers.BatchNormalization(name="Embedding_roe_batchnorm")(encoded_roe_features)
156 encoded_roe_features = keras.layers.Dense(
157 units=embedding_dims,
158 activation=keras.activations.selu,
159 name="Embedding_roe_dense_2")(encoded_roe_features)
160 encoded_roe_features = keras.layers.Dropout(dropout_rate, name="Embedding_roe_dropout_2")(encoded_roe_features)
161
162 # Concatenate all encoded features and their masks
163 encoded_features = MyConcatenate()([encoded_trk_features, encoded_ecl_features, encoded_roe_features])
164
165 # Create multiple layers of the Transformer block.
166 for block_idx in range(num_transformer_blocks):
167 # Create a multi-head attention layer.
168 attention_output = keras.layers.MultiHeadAttention(
169 num_heads=num_heads,
170 key_dim=embedding_dims,
171 dropout=dropout_rate,
172 name=f"multihead_attention_{block_idx}",
173 )(encoded_features, encoded_features)
174 # Skip connection 1.
175 x = keras.layers.Add(name=f"skip_connection1_{block_idx}")(
176 [attention_output, encoded_features]
177 )
178 # Layer normalization 1.
179 x = keras.layers.LayerNormalization(name=f"layer_norm1_{block_idx}", epsilon=1e-6)(x)
180 # Feedforward.
181 feedforward_output = keras.layers.Dense(units=3*embedding_dims, activation='relu',
182 name=f"feedforward_{block_idx}_dense_1")(x)
183 feedforward_output = keras.layers.Dense(units=embedding_dims, name=f"feedforward_{block_idx}_dense_2")(feedforward_output)
184 feedforward_output = keras.layers.Dropout(dropout_rate, name=f"feedforward_{block_idx}_dropout")(feedforward_output)
185 # Skip connection 2.
186 x = keras.layers.Add(name=f"skip_connection2_{block_idx}")([feedforward_output, x])
187 # Layer normalization 2.
188 encoded_features = keras.layers.LayerNormalization(
189 name=f"layer_norm2_{block_idx}", epsilon=1e-6
190 )(x)
191
192 # Pool the "contextualized" embeddings of the features.
193 features = keras.layers.GlobalAveragePooling1D()(encoded_features)
194
195 # Compute MLP hidden_units.
196 mlp_hidden_units = [
197 factor * features.shape[-1] for factor in mlp_hidden_units_factors
198 ]
199 # Create final MLP.
200 features = create_mlp(
201 hidden_units=mlp_hidden_units,
202 dropout_rate=dropout_rate,
203 activation=keras.activations.selu,
204 normalization_layer=keras.layers.BatchNormalization,
205 name="ClassifierMLP",
206 )(features)
207
208 # Add a sigmoid as a binary classifer.
209 outputs = keras.layers.Dense(units=1, activation="sigmoid", name="sigmoid")(features)
210 model = keras.Model(inputs=inputs, outputs=outputs)
211 return model
compute_mask(self, inputs, mask=None)
Definition model.py:24
call(self, inputs)
Definition model.py:18