# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import pytest import torch from nemo.collections.asr.modules.conformer_encoder import ConformerEncoder class TestStochasticDepth: """Testing stochastic depth functionality.""" def test_stochastic_depth_model_creation(self): """Testing basic model creation and the drop probs are correctly assigned.""" n_layers = 4 model = ConformerEncoder(feat_in=10, n_layers=n_layers, d_model=4, feat_out=8) # checking that by default SD is disabled assert model.layer_drop_probs == [0.0] * n_layers # linear mode for drop_prob in [0.3, 0.5, 0.9]: for start_layer in [1, 3]: model = ConformerEncoder( feat_in=10, n_layers=n_layers, d_model=4, feat_out=8, stochastic_depth_drop_prob=drop_prob, stochastic_depth_start_layer=start_layer, ) L = n_layers - start_layer assert model.layer_drop_probs == [0.0] * start_layer + [drop_prob * l / L for l in range(1, L + 1)] # uniform mode for drop_prob in [0.3, 0.5, 0.9]: model = ConformerEncoder( feat_in=10, n_layers=n_layers, d_model=4, feat_out=8, stochastic_depth_drop_prob=drop_prob, stochastic_depth_mode="uniform", stochastic_depth_start_layer=start_layer, ) L = n_layers - start_layer assert model.layer_drop_probs == [0.0] * start_layer + [drop_prob] * L # checking for errors for drop_prob in [-1.0, 1.0]: with pytest.raises(ValueError, match="stochastic_depth_drop_prob has to be in"): ConformerEncoder( feat_in=10, n_layers=n_layers, d_model=4, feat_out=8, stochastic_depth_drop_prob=drop_prob, stochastic_depth_mode="uniform", ) with pytest.raises(ValueError, match="stochastic_depth_mode has to be one of"): ConformerEncoder(feat_in=10, n_layers=n_layers, d_model=4, feat_out=8, stochastic_depth_mode="weird") for start_layer in [-1, 0, 5]: with pytest.raises(ValueError, match="stochastic_depth_start_layer has to be in"): ConformerEncoder( feat_in=10, n_layers=n_layers, d_model=4, feat_out=8, stochastic_depth_start_layer=start_layer, ) def test_stochastic_depth_forward(self): """Testing that forward works and we get randomness during training, but not during eval.""" random_input = torch.rand((1, 2, 2)) random_length = torch.tensor([2, 2], dtype=torch.int64) model = ConformerEncoder( feat_in=2, n_layers=3, d_model=4, feat_out=4, stochastic_depth_drop_prob=0.8, dropout=0.0, dropout_pre_encoder=0.0, dropout_emb=0.0, conv_norm_type="layer_norm", conv_kernel_size=3, ) model.train() outputs = [None] * 5 for i in range(5): outputs[i] = model(audio_signal=random_input, length=random_length)[0] # checking that not all outputs are the same num_diff = 0 for i in range(1, 5): if not torch.allclose(outputs[i], outputs[0]): num_diff += 1 assert num_diff > 0 model.eval() outputs = [None] * 5 for i in range(5): outputs[i] = model(audio_signal=random_input, length=random_length)[0] # checking that not all outputs are the same num_diff = 0 for i in range(1, 5): if not torch.allclose(outputs[i], outputs[0]): num_diff += 1 assert num_diff == 0