[ASR] predictions during training by Conformer-CTC seems not improve.
State: closed | Pull request: no
Labels: name: bug

**Describe the bug**
Hi,
I would like to use Conformer-CTC to train a Mandarin ASR model but even reach the 29th epoch, the predictions seem not to improve.
Meanwhile, another one uses QuartzNet15x5 looks good.
Is there something I have not noticed, please?

**Parts of prediction results**
```
Epoch 29: 100%|████████████████▉| 4198/4202 [21:52<00:01,  3.20it/s, loss=99.1, v_num=7-38][NeMo I 2022-11-25 03:17:08 wer:984] 
    dation DataLoader 0:  99%|██████████████████████████▊| 444/448 [00:55<00:00,  8.04it/s]
[NeMo I 2022-11-25 03:17:08 wer:985] reference:由於 身體 並 沒 有 處 於 最 佳 狀態
[NeMo I 2022-11-25 03:17:08 wer:986] predicted:但  道
Epoch 29: 100%|████████████████▉| 4199/4202 [21:52<00:00,  3.20it/s, loss=99.1, v_num=7-38][NeMo I 2022-11-25 03:17:08 wer:984] 
    dation DataLoader 0:  99%|██████████████████████████▊| 445/448 [00:55<00:00,  8.04it/s]
[NeMo I 2022-11-25 03:17:08 wer:985] reference:但 近日 身體 檢查 終於 還是 敵 不過 病魔 折磨
[NeMo I 2022-11-25 03:17:08 wer:986] predicted:中 元
Epoch 29: 100%|████████████████▉| 4200/4202 [21:53<00:00,  3.20it/s, loss=99.1, v_num=7-38][NeMo I 2022-11-25 03:17:09 wer:984] 
    dation DataLoader 0: 100%|██████████████████████████▉| 446/448 [00:55<00:00,  8.05it/s]
[NeMo I 2022-11-25 03:17:09 wer:985] reference:遠赴 廣西 連續 搗毀 兩 個 電信 詐騙 犯罪 團夥
[NeMo I 2022-11-25 03:17:09 wer:986] predicted:中 元
Epoch 29: 100%|████████████████▉| 4201/4202 [21:53<00:00,  3.20it/s, loss=99.1, v_num=7-38][NeMo I 2022-11-25 03:17:09 wer:984] 
    dation DataLoader 0: 100%|██████████████████████████▉| 447/448 [00:55<00:00,  8.04it/s]
[NeMo I 2022-11-25 03:17:09 wer:985] reference:自己 不 能 總 在 孩子 面前 打 遊戲 刷 微 博 微信
[NeMo I 2022-11-25 03:17:09 wer:986] predicted:中 元
```
**Steps/Code to reproduce bug**

`CUDA_VISIBLE_DEVICES=0,1 python speech_to_text_ctc.py`

**conformer_ctc_char.yaml**
```
# It contains the default values for training a Conformer-CTC ASR model, large size (~120M) with CTC loss and char-based vocabulary.
# Char-based encoding may give lower accuracy than sub-word encoding (conformer_ctc_bpe.yaml).

# You may find more detail on Conformer-CTC at `examples/asr/conf/conformer/conformer_ctc_bpe.yaml`

name: "Conformer-CTC-Char-Aishell-30ep-lr2.0"

model:
  sample_rate: 16000
  labels:  [" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
            "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "'"]
  log_prediction: true # enables logging sample predictions in the output during training
  ctc_reduction: 'mean_batch'
  skip_nan_grad: false

  train_ds:
    manifest_filepath: ???
    labels: ${model.labels}
    sample_rate: ${model.sample_rate}
    batch_size: 16 # you may increase batch_size if your memory allows
    shuffle: true
    num_workers: 8
    pin_memory: true
    trim_silence: false
    max_duration: 16.7 # it is set for LibriSpeech, you may need to update it for your dataset
    min_duration: 0.1
    # tarred datasets
    is_tarred: false
    tarred_audio_filepaths: null
    shuffle_n: 2048
    # bucketing params
    bucketing_strategy: "synced_randomized"
    bucketing_batch_size: null

  validation_ds:
    manifest_filepath: ???
    labels: ${model.labels}
    sample_rate: ${model.sample_rate}
    batch_size: 16 # you may increase batch_size if your memory allows
    shuffle: false
    num_workers: 8
    pin_memory: true

  test_ds:
    manifest_filepath: null
    labels: ${model.labels}
    sample_rate: ${model.sample_rate}
    batch_size: 16 # you may increase batch_size if your memory allows
    shuffle: false
    num_workers: 8
    pin_memory: true

  preprocessor:
    _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor
    sample_rate: ${model.sample_rate}
    normalize: "per_feature"
    window_size: 0.025
    window_stride: 0.01
    window: "hann"
    features: 80
    n_fft: 512
    log: true
    frame_splicing: 1
    dither: 0.00001
    pad_to: 0
    pad_value: 0.0

  spec_augment:
    _target_: nemo.collections.asr.modules.SpectrogramAugmentation
    freq_masks: 2 # set to zero to disable it
    # you may use lower time_masks for smaller models to have a faster convergence
    time_masks: 10 # set to zero to disable it
    freq_width: 27
    time_width: 0.05

  encoder:
    _target_: nemo.collections.asr.modules.ConformerEncoder
    feat_in: ${model.preprocessor.features}
    feat_out: -1 # you may set it if you need different output size other than the default d_model
    n_layers: 16
    d_model: 256

    # Sub-sampling params
    subsampling: striding # vggnet, striding, stacking or stacking_norm, dw_striding
    subsampling_factor: 4 # must be power of 2 for striding and vggnet
    subsampling_conv_channels: -1 # set to -1 to make it equal to the d_model
    causal_downsampling: false

    # Feed forward module's params
    ff_expansion_factor: 4

    # Multi-headed Attention Module's params
    self_attention_model: rel_pos # rel_pos or abs_pos
    n_heads: 8 # may need to be lower for smaller d_models
    # [left, right] specifies the number of steps to be seen from left and right of each step in self-attention
    att_context_size: [-1, -1] # -1 means unlimited context
    att_context_style: regular # regular or chunked_limited
    xscaling: true # scales up the input embeddings by sqrt(d_model)
    untie_biases: true # unties the biases of the TransformerXL layers
    pos_emb_max_len: 5000

    # Convolution module's params
    conv_kernel_size: 31
    conv_norm_type: 'batch_norm' # batch_norm or layer_norm or groupnormN (N specifies the number of groups)
    # conv_context_size can be"causal" or a list of two integers while conv_context_size[0]+conv_context_size[1]+1==conv_kernel_size
    # null means [(kernel_size-1)//2, (kernel_size-1)//2], and 'causal' means [(kernel_size-1), 0]
    conv_context_size: null

    ### regularization
    dropout: 0.1 # The dropout used in most of the Conformer Modules
    dropout_pre_encoder: 0.1 # The dropout used before the encoder
    dropout_emb: 0.0 # The dropout used for embeddings
    dropout_att: 0.1 # The dropout for multi-headed attention modules

  decoder:
    _target_: nemo.collections.asr.modules.ConvASRDecoder
    feat_in: null
    num_classes: -1
    vocabulary: ${model.labels}

  optim:
    name: adamw
    lr: 3 #0.01 很慢
    # optimizer arguments
    betas: [0.9, 0.98]
    # less necessity for weight_decay as we already have large augmentations with SpecAug
    # you may need weight_decay for large models, stable AMP training, small datasets, or when lower augmentations are used
    # weight decay of 0.0 with lr of 2.0 also works fine
    weight_decay: 1e-3

    # scheduler setup
    sched:
      name: NoamAnnealing
      d_model: ${model.encoder.d_model}
      # scheduler config override
      warmup_steps: 10000
      warmup_ratio: null
      min_lr: 1e-6

trainer:
  devices: 2 # number of GPUs, -1 would use all available GPUs
  num_nodes: 1
  max_epochs: 30
  max_steps: -1 # computed at runtime if not set
  val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations
  accelerator: gpu
  strategy: ddp
  accumulate_grad_batches: 1
  gradient_clip_val: 0.0
  precision: 32 # Should be set to 16 for O1 and O2 to enable the AMP.
  log_every_n_steps: 10  # Interval of logging.
  enable_progress_bar: True
  resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc.
  num_sanity_val_steps: 0 # number of steps to perform validation steps for sanity check the validation process before starting the training, setting to 0 disables it
  check_val_every_n_epoch: 1 # number of evaluations on validation every n epochs
  sync_batchnorm: true
  enable_checkpointing: False  # Provided by exp_manager
  logger: false  # Provided by exp_manager
  benchmark: false # needs to be false for models with variable-length speech input as it slows down training


exp_manager:
  exp_dir: ../exp
  name: ${name}
  create_tensorboard_logger: true
  create_checkpoint_callback: true
  checkpoint_callback_params:
    # in case of multiple validation sets, first one is used
    monitor: "val_wer"
    mode: "min"
    save_top_k: 5
    always_save_nemo: True # saves the checkpoints as nemo files instead of PTL checkpoints

  # you need to set these two to True to continue the training
  resume_if_exists: false
  resume_ignore_no_checkpoint: false

  # You may use this section to create a W&B logger
  create_wandb_logger: false
  wandb_logger_kwargs:
    name: null
    project: null
```
**speech_to_text_ctc.py**
```

from curses import use_default_colors
import pytorch_lightning as pl
from omegaconf import OmegaConf

from nemo.collections.asr.models import EncDecCTCModel
from nemo.core.config import hydra_runner
from nemo.utils import logging
from nemo.utils.exp_manager import exp_manager
use_cer = True
log_prediction = True
manifest_path = "/home/face/NeMo/examples/asr/"
train_manifest = f"{manifest_path}train_manifest.json"
dev_manifest = f"{manifest_path}dev_manifest.json"
test_manifest = f"{manifest_path}test_manifest.json"

charset = []
#將 vocab.txt 讀入 list 中，使其能寫入 config 的 labels
with open(f"{manifest_path}Aishell_vocab/train_dev.txt ", "r") as vocab_read:
    
    for char in vocab_read.read():
        charset.append(char) #EX: ['余', '耍', '汞', '圳']
    # print(charset)
    # print(len(charset))


@hydra_runner(config_path="../conf/conformer", config_name="conformer_ctc_char")
def main(cfg):
    cfg.model.labels = charset
    cfg.model.train_ds.manifest_filepath = train_manifest
    cfg.model.validation_ds.manifest_filepath = dev_manifest
    cfg.model.test_ds.manifest_filepath = test_manifest

    logging.info(f'Hydra config: {OmegaConf.to_yaml(cfg)}')

    trainer = pl.Trainer(**cfg.trainer)
    exp_manager(trainer, cfg.get("exp_manager", None))
    asr_model = EncDecCTCModel(cfg=cfg.model, trainer=trainer)
    asr_model._wer.use_cer = use_cer
    asr_model._wer.log_prediction = log_prediction

    # Initialize the weights of the model from another model, if provided via config
    asr_model.maybe_init_from_pretrained_checkpoint(cfg)

    trainer.fit(asr_model)

    if hasattr(cfg.model, 'test_ds') and cfg.model.test_ds.manifest_filepath is not None:
        if asr_model.prepare_test(trainer):
            trainer.test(asr_model)


if __name__ == '__main__':
    main()  # noqa pylint: disable=no-value-for-parameter
```


**Environment overview (please complete the following information)**

 - Environment location: Bare-metal
 - Method of NeMo install: From source


**Environment details**

-nemo-tookit
1.12.0
- OS version 
Linux version 4.15.0-142-generic (buildd@lgw01-amd64-039) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)) #146~16.04.1-Ubuntu SMP Tue Apr 13 09:27:15 UTC 2021
- PyTorch version
1.13.0
- Python version
3.8
**Additional context**

Add any other context about the problem here.
GPU: NVIDIA GeForce 2080TI