wavenet::detail::Layer::Process applies layer1x1_post_film only inside the GatingMode::BLENDED branch. Under GatingMode::NONE and GatingMode::GATED the layer runs layer1x1 and never applies the FiLM.
The trainer applies it whenever layer1x1 is active, independent of gating (nam/models/wavenet/_layer_array.py):
layer_output = post_activation
if self._layer1x1 is not None:
layer_output = self._layer1x1(layer_output)
if self._layer1x1_post_film is not None:
layer_output = self._layer1x1_post_film(layer_output, ...)
So a model trained with layer1x1_post_film active and non-blended gating renders differently in the runtime than it does in training. It fails silently: the config parser accepts it (it only checks that layer1x1_post_film.active implies layer1x1.active), the FiLM is constructed, and set_weights_ still consumes its weights — so the rest of the blob is read correctly and nothing is misaligned. The modulation is simply skipped.
test_layer1x1_post_film_active() nominally covers this case (it uses GatingMode::NONE) but asserts only that the output is finite, and its FiLM weights make the modulation an identity, so it cannot catch it.
Found while building end-to-end parity fixtures against the trainer with every FiLM site active under GatingMode::NONE. PR follows.
wavenet::detail::Layer::Process applies layer1x1_post_film only inside the GatingMode::BLENDED branch. Under GatingMode::NONE and GatingMode::GATED the layer runs layer1x1 and never applies the FiLM.
The trainer applies it whenever layer1x1 is active, independent of gating (nam/models/wavenet/_layer_array.py):
So a model trained with layer1x1_post_film active and non-blended gating renders differently in the runtime than it does in training. It fails silently: the config parser accepts it (it only checks that layer1x1_post_film.active implies layer1x1.active), the FiLM is constructed, and set_weights_ still consumes its weights — so the rest of the blob is read correctly and nothing is misaligned. The modulation is simply skipped.
test_layer1x1_post_film_active() nominally covers this case (it uses GatingMode::NONE) but asserts only that the output is finite, and its FiLM weights make the modulation an identity, so it cannot catch it.
Found while building end-to-end parity fixtures against the trainer with every FiLM site active under GatingMode::NONE. PR follows.