重要

您正在檢視 NeMo 2.0 文件。此版本為 API 和新的函式庫 NeMo Run 引入了重大變更。我們目前正在將所有功能從 NeMo 1.0 移植到 2.0。如需先前版本或 2.0 中尚未提供的功能的相關文件,請參閱 NeMo 24.07 文件

NeMo ASR 配置檔案#

本節說明 NeMo 配置檔案設定,該設定特定於 ASR 集合中的模型。如需關於如何設定與執行實驗(所有 NeMo 模型通用,例如實驗管理器和 PyTorch Lightning 訓練器參數)的一般資訊,請參閱 NeMo 模型 章節。

NeMo ASR 配置檔案的模型章節通常需要關於正在使用的資料集、音訊檔案的預處理器、正在執行的任何增強的參數以及模型架構規格的資訊。本頁的章節更詳細地涵蓋了這些內容。

所有 NeMo ASR 腳本的範例配置檔案都可以在 examples 的 config 目錄 中找到。

資料集配置#

訓練、驗證和測試參數分別使用配置檔案中的 train_dsvalidation_dstest_ds 章節指定。根據任務,可能會有一些引數指定音訊檔案的取樣率、資料集的詞彙表(用於字元預測)、是否對資料集進行洗牌等等。您也可以決定將 manifest_filepath 等欄位留白,以便在執行時透過命令列指定。

實驗中使用的 Dataset 類別接受的任何初始化參數都可以在配置檔案中設定。請參閱 API 的 Datasets 章節,以取得 Dataset 及其各自參數的清單。

ASR 訓練和驗證配置範例應如下所示

# Specified at the beginning of the config file
labels: &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", "'"]

model:
  train_ds:
    manifest_filepath: ???
    sample_rate: 16000
    labels: *labels   # Uses the labels above
    batch_size: 32
    trim_silence: True
    max_duration: 16.7
    shuffle: True
    num_workers: 8
    pin_memory: true
    # tarred datasets
    is_tarred: false # If set to true, uses the tarred version of the Dataset
    tarred_audio_filepaths: null     # Not used if is_tarred is false
    shuffle_n: 2048                  # Not used if is_tarred is false
    # bucketing params
    bucketing_strategy: "synced_randomized"
    bucketing_batch_size: null
    bucketing_weights: null

  validation_ds:
    manifest_filepath: ???
    sample_rate: 16000
    labels: *labels   # Uses the labels above
    batch_size: 32
    shuffle: False    # No need to shuffle the validation data
    num_workers: 8
    pin_memory: true

有兩種方法可以在多個 manifest 上進行測試/驗證

  • manifest_filepath 欄位中指定清單。結果將針對每個 manifest 報告,第一個 manifest 將用於整體損失/WER(如果您希望變更該 manifest,請指定 val_dl_idx)。在這種情況下,所有 manifest 將共用配置參數。

  • 使用 ds_item 鍵並將配置物件清單傳遞給它。這允許您為驗證使用不同配置的資料集,例如

model:
  validation_ds:
    ds_item:
    - name: dataset1
      manifest_filepath: ???
      # Config parameters for dataset1
      ...
    - name: dataset2
      manifest_filepath: ???
      # Config parameters for dataset2
      ...

預設情況下,資料載入器會在模型實例化時設定。但是,可以透過在配置中設定 defer_setup,將資料載入器設定延遲到模型的 setup() 方法。

例如,可以如下方式延遲訓練資料設定

model:
  train_ds:
    # Configure training data as usual
    ...
    # Defer train dataloader setup from `__init__` to `setup`
    defer_setup: true

預處理器配置#

如果您正在為實驗載入音訊檔案,您可能希望使用預處理器將原始音訊訊號轉換為特徵(例如 mel-頻譜圖或 MFCC)。配置的 preprocessor 章節透過 _target_ 欄位指定要使用的音訊預處理器,以及該預處理器的任何初始化參數。

指定預處理器的範例如下

model:
  ...
  preprocessor:
    # _target_ is the audio preprocessor module you want to use
    _target_: nemo.collections.asr.modules.AudioToMelSpectrogramPreprocessor
    normalize: "per_feature"
    window_size: 0.02
    ...
    # Other parameters for the preprocessor

請參閱 音訊預處理器 API 章節,以取得預處理器選項、預期引數和預設值。

增強配置#

NeMo ASR 有一些即時頻譜圖增強選項,可以使用 spec_augment 章節在配置檔案中指定。

例如,CutoutSpecAugment 的選項可透過 SpectrogramAugmentation 模組取得。

以下範例設定了 Cutout(透過 rect_* 參數)和 SpecAugment(透過 freq_*time_* 參數)。

model:
  ...
  spec_augment:
    _target_: nemo.collections.asr.modules.SpectrogramAugmentation
    # Cutout parameters
    rect_masks: 5   # Number of rectangles to cut from any given spectrogram
    rect_freq: 50   # Max cut of size 50 along the frequency dimension
    rect_time: 120  # Max cut of size 120 along the time dimension
    # SpecAugment parameters
    freq_masks: 2   # Cut two frequency bands
    freq_width: 15  # ... of width 15 at maximum
    time_masks: 5    # Cut out 10 time bands
    time_width: 25  # ... of width 25 at maximum

您可以使用 Cutout、頻率/時間 SpecAugment 或兩者都不使用的任何組合。

使用 NeMo ASR,您還可以新增增強管線,這些管線可用於模擬添加到通道中音訊的各種雜訊。管線中的增強器應用於資料層中讀取的音訊資料。線上增強器可以使用 train_ds 中的 augmentor 章節在配置檔案中指定。以下範例新增了一個增強管線,該管線首先以 0.5 的機率和 -50 dB 到 -10 dB 之間隨機選擇的等級向音訊樣本新增白雜訊,然後將結果樣本傳遞到從為配置檔案中 impulse 增強提供的 manifest 檔案中隨機選擇的房間脈衝響應。

model:
  ...
  train_ds:
  ...
      augmentor:
          white_noise:
              prob: 0.5
              min_level: -50
              max_level: -10
          impulse:
              prob: 0.3
              manifest_path: /path/to/impulse_manifest.json

請參閱 音訊增強器 API 章節以取得更多詳細資訊。

分詞器配置#

某些模型利用外部分詞器進行子詞編碼,而不是明確定義其詞彙表。

對於此類模型,tokenizer 章節會新增到模型配置中。ASR 模型目前支援兩種自訂分詞器

  • Google Sentencepiece 分詞器(配置中的分詞器類型為 bpe

  • HuggingFace WordPiece 分詞器(配置中的分詞器類型為 wpe

  • 聚合分詞器(配置中的分詞器類型為 agg,請參閱下文)

為了建置自訂分詞器,請參閱 ASR 教學目錄中提供的 ASR_with_Subword_Tokenization 筆記本。

以下範例設定了使用者在路徑中指定的 SentencePiece Tokenizer

model:
  ...
  tokenizer:
    dir: "<path to the directory that contains the custom tokenizer files>"
    type: "bpe"  # can be "bpe" or "wpe"

聚合 (agg) 分詞器功能可以組合分詞器以訓練多語言模型。配置檔案如下所示

model:
  ...
  tokenizer:
    type: "agg"  # aggregate tokenizer
    langs:
      en:
        dir: "<path to the directory that contains the tokenizer files>"
        type: "bpe"  # can be "bpe" or "wpe"
      es:
        dir: "<path to the directory that contains the tokenizer files>"
        type: "bpe"  # can be "bpe" or "wpe"

在上述配置檔案中,每種語言都與其自己的預先訓練的分詞器相關聯,這些分詞器會按照分詞器的列出順序分配一個 token ID 範圍。為了訓練多語言模型,需要填寫 manifest 檔案中的 lang 欄位,以允許將每個樣本路由到正確的分詞器。在推論時,路由根據推斷的 token ID 範圍完成。

對於使用子詞分詞的模型,我們與字元分詞模型共用解碼器模組 (ConvASRDecoder)。所有參數都是共用的,但對於使用子詞編碼的模型,設定配置時存在細微差異。對於此類模型,分詞器用於在自動建構模型時填寫遺失的資訊。

例如,對應於子詞分詞模型的解碼器配置應如下所示

model:
  ...
  decoder:
    _target_: nemo.collections.asr.modules.ConvASRDecoder
    feat_in: *enc_final
    num_classes: -1  # filled with vocabulary size from tokenizer at runtime
    vocabulary: []  # filled with vocabulary from tokenizer at runtime

即時程式碼切換#

Nemo 支援在訓練/驗證/測試期間即時建立程式碼切換的合成語句。這允許您建立支援語句內程式碼切換的 ASR 模型。如果您在磁碟上有 Nemo 格式化的音訊資料(JSON manifest 或 tarred 音訊資料),您可以透過向 train_dsvalidation_dstest_ds 新增一些額外參數,輕鬆地將任意數量的這些音訊來源混合在一起。

請注意,這允許您將任何種類的音訊來源混合在一起,以建立從所有來源取樣的合成語句。最常見的用例是將不同語言混合在一起以建立多語言程式碼切換模型,但您也可以將來自相同語言(或語系)的不同音訊來源混合在一起,以建立雜訊穩健資料,或混合來自同一語言的快速和慢速語音。

對於多語言程式碼切換模型,如果混合不同語言,我們建議對您的分詞器使用 AggTokenizer。

以下範例展示了如何將 3 種不同的語言:英語 (en)、德語 (de) 和日語 (ja) 新增到 train_ds 模型區塊,但是您可以將類似的邏輯新增到您的 validation_dstest_ds 區塊,以用於即時程式碼切換驗證和測試資料。此範例將 3 種語言混合在一起,但您可以使用任意多種語言。但是,請注意,您新增的語言越多,您的 min_durationmax_duration 就需要設定得越高,以確保所有語言都取樣到每個合成語句中,並且設定這些超參數越高,在訓練和評估期間每個小批次將使用更多的 VRAM。

model:
  train_ds:
    manifest_filepath: [/path/to/EN/tarred_manifest.json, /path/to/DE/tarred_manifest.json, /path/to/JA/tarred_manifest.json]
    tarred_audio_filepaths: ['/path/to/EN/tars/audio__OP_0..511_CL_.tar', '/path/to/DE/tars/audio__OP_0..1023_CL_.tar', '/path/to/JA/tars/audio__OP_0..2047_CL_.tar']
    is_code_switched: true
    is_tarred: true
    shuffle: true
      code_switched:              # add this block for code-switching
        min_duration: 12          # the minimum number of seconds for each synthetic code-switched utterance
        max_duration: 20          # the maximum number of seconds for each synthetic code-switched utterance
        min_monolingual: 0.3      # the minimum percentage of utterances which will be pure monolingual (0.3 = 30%)
        probs: [0.25, 0.5, 0.25]  # the probability to sample each language (matches order of `language` above) if not provided, assumes uniform distribution
        force_monochannel: true   # if your source data is multi-channel, then setting this to True will force the synthetic utterances to be mono-channel
        sampling_scales: 0.75     # allows you to down/up sample individual languages. Can set this as an array for individual languages, or a scalar for all languages
        seed: 123                 # add a seed for replicability in future runs (highly useful for `validation_ds` and `test_ds`)

模型架構配置#

每個配置檔案都應描述用於實驗的模型架構。NeMo ASR 集合中的模型需要 encoder 章節和 decoder 章節,其中 _target_ 欄位指定每個章節要使用的模組。

以下是模型章節中大多數 ASR 模型共用的參數清單

參數

資料類型

描述

支援的值

log_prediction

bool

是否應在每個步驟的輸出中列印隨機樣本及其預測的文字稿。

ctc_reduction

字串

指定 CTC 損失的縮減類型。預設為 mean_batch,這將在對每個樣本的長度取平均值後,對批次取平均值。

nonemean_batch meansum

以下章節更詳細地介紹了每個模型架構的特定配置。

如需關於 ASR 模型的更多資訊,請參閱 模型 章節。

Jasper 和 QuartzNet#

JasperQuartzNet 模型非常相似,因此它們配置中的元件也非常相似。

兩種架構都將 ConvASREncoder 用於 encoder,參數在下表中詳細說明。編碼器參數包括關於 Jasper/QuartzNet [BxR] 編碼器架構的詳細資訊,包括要使用的區塊數量 (B)、重複每個子區塊的次數 (R) 以及每個區塊的卷積參數。

區塊數量 Bjasper 下方的清單元素數量減去一個序言和兩個結語區塊來決定。子區塊數量 R 由設定 repeat 參數來決定。

若要使用 QuartzNet(它使用更緊湊的時間通道可分離卷積)而不是 Jasper,請將 separable: true 新增到架構中除最後一個區塊之外的所有區塊。

變更參數名稱 jasper

參數

資料類型

描述

支援的值

feat_in

int

輸入特徵的數量。應等於預處理器參數中的 features

activation

字串

要在編碼器中使用的激活函數。

hardtanhreluseluswish

conv_mask

bool

是否在編碼器中使用遮罩卷積。預設為 true

jasper

一個區塊清單,用於指定您的編碼器架構。此清單中的每個條目代表架構中的一個區塊,並包含該區塊的參數,包括卷積參數、dropout 以及區塊重複的次數。請參閱 JasperQuartzNet 論文,以取得關於特定模型配置的詳細資訊。

QuartzNet 15x5(15 個區塊,每個子區塊重複 5 次)編碼器配置應如下例所示

# Specified at the beginning of the file for convenience
n_mels: &n_mels 64    # Used for both the preprocessor and encoder as number of input features
repeat: &repeat 5     # R=5
dropout: &dropout 0.0
separable: &separable true  # Set to true for QN. Set to false for Jasper.

model:
  ...
  encoder:
    _target_: nemo.collections.asr.modules.ConvASREncoder
    feat_in: *n_mels  # Should match "features" in the preprocessor.
    activation: relu
    conv_mask: true

    jasper:   # This field name should be "jasper" for both types of models.

    # Prologue block
    - dilation: [1]
      dropout: *dropout
      filters: 256
      kernel: [33]
      repeat: 1   # Prologue block is not repeated.
      residual: false
      separable: *separable
      stride: [2]

    # Block 1
    - dilation: [1]
      dropout: *dropout
      filters: 256
      kernel: [33]
      repeat: *repeat
      residual: true
      separable: *separable
      stride: [1]

    ... # Entries for blocks 2~14

    # Block 15
    - dilation: [1]
      dropout: *dropout
      filters: 512
      kernel: [75]
      repeat: *repeat
      residual: true
      separable: *separable
      stride: [1]

    # Two epilogue blocks
    - dilation: [2]
      dropout: *dropout
      filters: 512
      kernel: [87]
      repeat: 1   # Epilogue blocks are not repeated
      residual: false
      separable: *separable
      stride: [1]

    - dilation: [1]
      dropout: *dropout
      filters: &enc_filters 1024
      kernel: [1]
      repeat: 1   # Epilogue blocks are not repeated
      residual: false
      stride: [1]

Jasper 和 QuartzNet 都使用 ConvASRDecoder 作為解碼器。解碼器參數在下表中詳細說明。

參數

資料類型

描述

支援的值

feat_in

int

解碼器的輸入特徵數量。應等於編碼器最後一個區塊中的濾波器數量。

vocabulary

清單

模型的有效輸出字元清單。例如,對於英文資料集,這可以是所有小寫字母、空格和撇號的清單。

num_classes

int

輸出類別的數量,即 vocabulary 的長度。

例如,對應於上述編碼器的解碼器配置應如下所示

model:
  ...
  decoder:
    _target_: nemo.collections.asr.modules.ConvASRDecoder
    feat_in: *enc_filters
    vocabulary: *labels
    num_classes: 28   # Length of the vocabulary list

Citrinet#

CitrinetQuartzNet 模型非常相似,因此它們配置中的元件也非常相似。與 QuartzNet 相比,Citrinet 利用 Squeeze and Excitation 以及子詞分詞。根據資料集,我們使用不同的分詞器。對於 Librispeech,我們使用 HuggingFace WordPiece 分詞器,對於所有其他資料集,我們使用 Google Sentencepiece 分詞器 - 通常是 unigram 分詞器類型。

兩種架構都將 ConvASREncoder 用於 encoder,參數如上所述。編碼器參數包括關於 Citrinet-C 編碼器架構的詳細資訊,包括每個通道使用的濾波器數量 (C)。Citrinet-C 配置是 Citrinet-21x5xC 的簡寫符號,使得 B = 21R = 5 是預設值,通常不應變更。

若要使用 Citrinet 而不是 QuartzNet,請參閱在 examples/asr/conf/citrinet 目錄中找到的 citrinet_512.yaml 配置。Citrinet 主要由與 JasperQuartzNet 相同的 JasperBlock 組成。

雖然 Citrinet 和 QuartzNet 的配置相似,但我們注意到以下用於 Citrinet 的其他標誌。請參閱 JasperBlock 文件,以了解這些引數的含義。

參數

資料類型

描述

支援的值

se

bool

是否應用 squeeze-and-excitation 機制。

truefalse

se_context_size

int

SE 上下文大小。-1 表示全域上下文。

-1+ve int

stride_last

bool

最後一個重複區塊或所有重複區塊的步幅。

truefalse

residual_mode

字串

要建構的殘差分支類型。可以是逐點殘差加法或逐點步幅殘差注意力

"add""stride_add"

Citrinet-512 配置應如下所示

model:
  ...
  # Specify some defaults across the entire model
  model_defaults:
    repeat: 5
    dropout: 0.1
    separable: true
    se: true
    se_context_size: -1
  ...
  encoder:
    _target_: nemo.collections.asr.modules.ConvASREncoder
    feat_in: *n_mels  # Should match "features" in the preprocessor.
    activation: relu
    conv_mask: true

    jasper:   # This field name should be "jasper" for the JasperBlock (which constructs Citrinet).

    # Prologue block
    - filters: 512
      repeat: 1
      kernel: [5]
      stride: [1]
      dilation: [1]
      dropout: 0.0
      residual: false
      separable: ${model.model_defaults.separable}
      se: ${model.model_defaults.se}
      se_context_size: ${model.model_defaults.se_context_size}

    # Block 1
    - filters: 512
      repeat: ${model.model_defaults.repeat}
      kernel: [11]
      stride: [2]
      dilation: [1]
      dropout: ${model.model_defaults.dropout}
      residual: true
      separable: ${model.model_defaults.separable}
      se: ${model.model_defaults.se}
      se_context_size: ${model.model_defaults.se_context_size}
      stride_last: true
      residual_mode: "stride_add"

    ... # Entries for blocks 2~21

    # Block 22
    - filters: 512
      repeat: ${model.model_defaults.repeat}
      kernel: [39]
      stride: [1]
      dilation: [1]
      dropout: ${model.model_defaults.dropout}
      residual: true
      separable: ${model.model_defaults.separable}
      se: ${model.model_defaults.se}
      se_context_size: ${model.model_defaults.se_context_size}

    # Epilogue block

    - filters: &enc_final 640
      repeat: 1
      kernel: [41]
      stride: [1]
      dilation: [1]
      dropout: 0.0
      residual: false
      separable: ${model.model_defaults.separable}
      se: ${model.model_defaults.se}
      se_context_size: ${model.model_defaults.se_context_size}

如上所述,Citrinet 使用 ConvASRDecoder 作為解碼器層,類似於 QuartzNet。只需稍微變更配置,因為 Citrinet 使用子詞分詞。

注意

以下資訊與實作其編碼器作為 ConvASREncoder 並使用 SqueezeExcite 機制的所有上述模型相關。

可以修改 ConvASREncoder 網路中的 SqueezeExcite 區塊,以在模型實例化後(甚至在模型訓練後)使用不同的上下文視窗,以便使用有限的上下文評估模型。這可以使用 change_conv_asr_se_context_window() 來達成

# Here, model can be any model that has a `ConvASREncoder` as its encoder, and utilized `SqueezeExcite` blocks
# `context_window` : It is an integer representing the number of timeframes (each corresponding to some window stride).
# `update_config` : Bool flag which determines whether the config of the model should be updated to reflect the new context window.

# Here, we specify that 128 timeframes of 0.01s stride should be the context window
# This is equivalent to 128 * 0.01s context window for `SqueezeExcite`
model.change_conv_asr_se_context_window(context_window=128, update_config=True)

Conformer-CTC#

Conformer-CTC 模型的配置檔案分別在 <NeMo_git_root>/examples/asr/conf/conformer/conformer_ctc_char.yaml<NeMo_git_root>/examples/asr/conf/conformer/conformer_ctc_bpe.yaml 包含基於字元的編碼和子詞編碼。Conformer-CTC 配置的某些元件包括以下資料集

  • train_dsvalidation_dstest_ds

  • 最佳化器 (optim)

  • 增強 (spec_augment)

  • 解碼器

  • 訓練器

  • exp_manager

這些資料集與其他 ASR 模型(例如 QuartzNet)相似。如果您想使用子詞編碼而不是基於字元的編碼,則應有一個分詞器章節,您可以在其中指定分詞器。

編碼器章節包含關於 Conformer-CTC 編碼器架構的詳細資訊。您可以在配置檔案和 nemo.collections.asr.modules.ConformerEncoder 中找到更多資訊。

Squeezeformer-CTC#

Squeezeformer-CTC 模型的配置檔案分別在 <NeMo_git_root>/examples/asr/conf/squeezeformer/squeezeformer_ctc_char.yaml<NeMo_git_root>/examples/asr/conf/squeezeformer/squeezeformer_ctc_bpe.yaml 包含基於字元的編碼和子詞編碼。Squeezeformer-CTC 配置的元件與 Conformer 配置 - QuartzNet 相似。

編碼器章節包含關於 Squeezeformer-CTC 編碼器架構的詳細資訊。您可以在配置檔案和 nemo.collections.asr.modules.SqueezeformerEncoder 中找到更多資訊。

ContextNet#

請參閱 ContextNet 的模型頁面,以取得關於此模型的更多資訊。

Conformer-Transducer#

請參閱 Conformer-Transducer 的模型頁面,以取得關於此模型的更多資訊。

LSTM-Transducer 和 LSTM-CTC#

LSTM-Transducer 和 LSTM-CTC 模型的配置檔案可以在 <NeMo_git_root>/examples/asr/conf/lstm/lstm_transducer_bpe.yaml<NeMo_git_root>/examples/asr/conf/lstm/lstm_ctc_bpe.yaml 中找到。大多數配置與其他 ctc 或 transducer 模型相似。主要區別在於編碼器部分。編碼器章節包含關於基於 RNN 的編碼器架構的詳細資訊。您可以在配置檔案和 nemo.collections.asr.modules.RNNEncoder 中找到更多資訊。

InterCTC 配置#

所有基於 CTC 的模型也支援 InterCTC 損失。若要使用它,您需要指定 2 個參數,如下例所示

model:
   # ...
   interctc:
     loss_weights: [0.3]
     apply_at_layers: [8]

這可以用於重現論文中的預設設定(假設總層數為 18)。您也可以指定來自不同層的多個 CTC 損失,例如,若要從第 3 層和第 8 層取得 2 個損失,權重分別為 0.1 和 0.3,請指定

model:
   # ...
   interctc:
     loss_weights: [0.1, 0.3]
     apply_at_layers: [3, 8]

請注意,最終層 CTC 損失權重會自動計算,以將所有權重正規化為 1(在上述範例中為 0.6)。

隨機深度配置#

隨機深度 是用於正規化 ASR 模型訓練的有用技術。目前僅支援 nemo.collections.asr.modules.ConformerEncoder。若要使用它,請在編碼器配置檔案中指定以下參數,以重現論文中的預設設定

model:
   # ...
   encoder:
     # ...
     stochastic_depth_drop_prob: 0.3
     stochastic_depth_mode: linear  # linear or uniform
     stochastic_depth_start_layer: 1

請參閱 ConformerEncoder 的文件 以取得更多詳細資訊。請注意,隨機深度支援 CTC 和 Transducer 模型變體(或任何其他使用 conformer 作為編碼器的模型/損失類型)。

Transducer 配置#

所有基於 CTC 的 ASR 模型配置都可以修改為支援 Transducer 損失訓練。下面,我們討論啟用 Transducer 訓練的配置中所需的修改。所有修改都在 model 配置中進行。

模型預設值#

它是模型配置的子章節,表示整個模型共用的預設值,表示為 model.model_defaults

transducer 模型主要有三个组成部分, 它们是:

  • enc_hidden:Encoder 网络最后一层的隐藏层维度。

  • pred_hidden:Prediction 网络最后一层的隐藏层维度。

  • joint_hidden:Joint 网络中间层的隐藏层维度。

可以通过使用 OmegaConf 插值在配置中访问这些值,如下所示:

model:
  ...
  model_defaults:
    enc_hidden: 256
    pred_hidden: 256
    joint_hidden: 256
  ...
  decoder:
    ...
    prednet:
      pred_hidden: ${model.model_defaults.pred_hidden}

声学 Encoder 模型#

transducer 模型由三个模型组合而成。其中一个模型是声学(encoder)模型。我们应该能够将任何 CTC 声学模型配置直接放入 transducer 配置的这一部分。

唯一需要满足的条件是:声学模型的最后一层必须具有在 ``model_defaults.enc_hidden`` 中定义的隐藏层维度

Decoder / Prediction 模型#

Prediction 模型通常是一个自回归的、因果模型,它消耗文本标记并返回嵌入,这些嵌入将由 Joint 模型使用。基于 LSTM 的 Prediction 网络的基本配置可以在 decoder 部分的 ContextNet 或其他 Transducer 架构中找到。有关更多信息,请参阅 ASR 教程部分的 Intro to Transducers 教程。

此配置可以复制粘贴到任何自定义 transducer 模型中,无需修改。

让我们讨论一些重要的参数

  • blank_as_pad:在普通的 transducer 模型中,嵌入矩阵不识别 Transducer Blank 标记(类似于 CTC Blank)。但是,这会导致自回归循环更加复杂且效率较低。相反,默认情况下设置的此标志会将 Transducer Blank 标记添加到嵌入矩阵中 - 并将其用作填充值(零张量)。这使得推理更有效率,而不会损害训练。有关更多信息,请参阅 ASR 教程部分的 Intro to Transducers 教程。

  • prednet.pred_hidden:LSTM 的隐藏层维度和 Prediction 网络的输出维度。

decoder:
  _target_: nemo.collections.asr.modules.RNNTDecoder
  normalization_mode: null
  random_state_sampling: false
  blank_as_pad: true

  prednet:
    pred_hidden: ${model.model_defaults.pred_hidden}
    pred_rnn_layers: 1
    t_max: null
    dropout: 0.0

Joint 模型#

Joint 模型是一个简单的前馈多层感知器网络。此 MLP 接受声学模型和 Prediction 模型的输出,并计算整个词汇空间上的联合概率分布。Joint 网络的基本配置可以在 joint 部分的 ContextNet 或其他 Transducer 架构中找到。有关更多信息,请参阅 ASR 教程部分的 Intro to Transducers 教程。

此配置可以复制粘贴到任何自定义 transducer 模型中,无需修改。

Joint 模型配置有几个基本组件,我们将在下面讨论

  • log_softmax:由于在如此大的张量上计算 softmax 的成本很高,因此 RNNT 损失的 Numba CUDA 实现将在调用时隐式计算 log softmax(因此其输入应为 logits)。CPU 版本的损失不会遇到此类内存问题,因此它需要对数概率。由于 CPU-GPU 的行为不同,None 值将根据输入张量是在 CPU 还是 GPU 设备上自动切换行为。

  • preserve_memory:此标志将在计算 Joint 张量时在某些关键部分调用 torch.cuda.empty_cache()。虽然此操作可能允许我们保留一些内存,但 empty_cache() 操作非常慢,并且会使训练速度降低一个或多个数量级。它可供使用,但不建议使用。

  • fuse_loss_wer:此标志执行“批处理拆分”,然后执行“融合损失 + 指标”计算。这将在下一个训练 Transducer 模型的教程中详细讨论。

  • fused_batch_size:当上述标志设置为 True 时,模型将具有两个不同的“批处理大小”。在三个数据加载器配置 (model.*_ds.batch_size) 中提供的批处理大小现在将是 Acoustic model 批处理大小,而 fused_batch_size 将是 Prediction modelJoint modeltransducer loss 模块和 decoding 模块的批处理大小。

  • jointnet.joint_hidden:joint 网络的隐藏中间维度。

joint:
  _target_: nemo.collections.asr.modules.RNNTJoint
  log_softmax: null  # sets it according to cpu/gpu device

  # fused mode
  fuse_loss_wer: false
  fused_batch_size: 16

  jointnet:
    joint_hidden: ${model.model_defaults.joint_hidden}
    activation: "relu"
    dropout: 0.0

Sampled Softmax Joint 模型#

在某些情况下,transducer 模型会使用大型词汇表 - 例如,对于具有大量语言的多语言模型。在这种情况下,我们需要考虑训练 Transducer 网络的内存成本,这不允许使用大型词汇表。

对于这种情况,可以改用 SampledRNNTJoint 模块而不是通常的 RNNTJoint 模块,以便使用词汇表的采样子集而不是完整的词汇表文件来计算损失。

它只添加一个额外的参数

  • n_samples:指定要从词汇空间中采样的最小标记数,不包括 RNNT 空白标记。如果给定值大于整个词汇表大小,则将使用完整的词汇表。

所需的唯一配置差异是用 nemo.collections.asr.modules.SampledRNNTJoint 替换 nemo.collections.asr.modules.RNNTJoint

joint:
  _target_: nemo.collections.asr.modules.SampledRNNTJoint
  n_samples: 500
  ...  # All other arguments from RNNTJoint can be used after this.

批处理拆分/融合批处理步骤的效果#

以下信息解释了为什么内存是训练 Transducer 模型时的一个问题,以及 NeMo 如何通过其融合批处理步骤解决此问题。可以阅读该材料以获得深入的理解,否则可以跳过。您也可以在“ASR_with_Transducers”教程中按照这些步骤操作。

深入探讨 Transducer Joint 的内存成本

Transducers 的重要限制之一是计算 Joint 模块的巨大内存成本。Joint 模块由两个步骤组成。

  1. 将声学和转录特征维度投影到一些标准隐藏维度(由 model.model_defaults.joint_hidden 指定)

  2. 将此中间隐藏维度投影到最终词汇空间以获得转录。

以下面的示例为例。

BS=32;T(在 2 倍步幅后)= 800,U(使用字符编码)= 400-450 个标记,词汇表大小 V = 28(26 个字母字符、空格和撇号)。让 Joint 模型的隐藏维度为 640(大多数 Google Transducer 论文都使用 640 的隐藏维度)。

  • \(Memory \, (Hidden, \, gb) = 32 \times 800 \times 450 \times 640 \times 4 = 29.49\) 千兆字节(每个浮点数 4 个字节)。

  • \(Memory \, (Joint, \, gb) = 32 \times 800 \times 450 \times 28 \times 4 = 1.290\) 千兆字节(每个浮点数 4 个字节)

注意:这仅适用于前向传播!我们需要将此内存加倍以存储梯度!这么多内存也仅适用于 单独的 Joint 模型。Prediction 模型以及大型声学模型本身及其梯度需要更多内存!

即使使用混合精度,也大约需要 30 GB 的 GPU RAM,仅用于网络的一部分 + 其梯度。

融合批处理步骤的效果#

根本问题是,当 [T x U] 大小时,联合张量的大小会增加。内存成本的这种增长是由于多种原因造成的 - 要么是模型构建(下采样),要么是数据集预处理的选择(字符标记化与子词标记化)。

NeMo 可以控制的另一个维度是批处理。由于我们批处理样本的方式,小样本和大样本都被集中到一个批处理中。因此,即使单个样本并非都与该批处理中 T 和 U 的最大长度一样长,但在构造此类样本批处理时,为了计算效率,它仍将消耗大量内存。

因此,与往常一样 - 用计算速度换取内存节省

融合操作如下

  1. 在单个通道中转发整个声学模型。(此处使用全局批处理大小用于声学模型 - 在 model.*_ds.batch_size 中找到)

  2. fused_batch_size 拆分声学模型的 logits,并循环遍历这些子批次。

  3. 为 Prediction 模型构造相同 fused_batch_size 的子批次。现在目标序列长度为 \(U_{sub-batch} < U\)

  4. 将此 \(U_{sub-batch}\) 与来自声学模型的子批次(具有 \(T_{sub-batch} < T)\))一起馈送到 Joint 模型中。请记住,我们只需要在此处切掉一部分声学模型,因为我们有来自声学模型的完整样本批次 \((B, T, D)\)

  5. 执行步骤 (3) 和 (4) 会产生 \(T_{sub-batch}\)\(U_{sub-batch}\)。执行子批次联合步骤 - 中间内存成本为 \((B, T_{sub-batch}, U_{sub-batch}, V)\)

  6. 计算子批次的损失并保存在列表中,以便稍后连接。

  7. 使用上述 Joint 张量和子批次的真实标签计算子批次指标(例如字符/单词错误率)。保留分数以便稍后在整个批次中取平均值。

  8. 删除子批次联合矩阵 \((B, T_{sub-batch}, U_{sub-batch}, V)\)。现在只有来自 .backward() 的梯度保留在计算图中。

  9. 重复步骤 (3) - (8),直到消耗完所有子批次。

  10. 清理步骤。计算完整批次 WER 并记录。连接损失列表并传递给 PTL 以计算等效于原始(完整批次)Joint 步骤的值。删除子批处理所需的辅助对象。

Transducer 解码#

使用 CTC 训练的模型可以通过对其解码器的输出执行常规 argmax 来简单地转录文本。对于基于 transducer 的模型,三个网络必须以同步方式运行,以便转录声学特征。Transducer 解码步骤的基本配置可以在 decoding 部分的 ContextNet 或其他 Transducer 架构中找到。有关更多信息,请参阅 ASR 教程部分的 Intro to Transducers 教程。

此配置可以复制粘贴到任何自定义 transducer 模型中,无需修改。

顶层最重要的组件是 strategy。它可以采用多个值之一

  • greedy:这是样本级贪婪解码。它通常非常慢,因为批处理中的每个样本都将独立解码。对于出版物,应将此方法与批处理大小为 1 一起使用以获得精确的结果。

  • greedy_batch:这是通用默认值,应几乎与 greedy 解码分数匹配(如果声学特征不受批处理模式下的特征混合影响)。即使对于小批处理大小,此策略也比 greedy 快得多。

  • beam:使用 Prediction 模型的隐式语言模型运行波束搜索。它通常会很慢,并且可能需要调整波束大小才能获得更好的转录。

  • tsd:时间同步解码。请参阅论文:用于 RNN Transducer 的对齐长度同步解码,了解有关已实施算法的详细信息。时间同步解码 (TSD) 执行时间按因子 T * max_symmetric_expansions 增长。对于较长的序列,T 较大,因此波束可能需要很长时间才能获得良好的结果。TSD 也需要更多内存才能执行。

  • alsd:对齐长度同步解码。请参阅论文:用于 RNN Transducer 的对齐长度同步解码,了解有关已实施算法的详细信息。对齐长度同步解码 (ALSD) 执行时间比 TSD 快,增长因子为 T + U_max,其中 U_max 是执行期间预期的最大目标长度。通常,T + U_max < T * max_symmetric_expansions。但是,ALSD 波束是非唯一的。因此,需要使用更大的波束大小才能实现与 TSD 相同的(或接近相同的)解码准确度。对于给定的解码准确度,可以通过 ALSD 比 TSD 获得更快的解码速度。

  • maes:修改后的自适应扩展搜索解码。请参阅论文 通过自适应扩展搜索加速 RNN Transducer 推理。修改后的自适应同步解码 (mAES) 执行时间是根据每个时间步所需的扩展(对于标记)数量自适应的。扩展数量通常可以限制为 1 或 2,在大多数情况下 2 就足够了。这种波束搜索技术可能会获得更高的 WER,同时牺牲一些评估时间。

decoding:
  strategy: "greedy_batch"

  # preserve decoding alignments
  preserve_alignments: false

  # Overrides the fused batch size after training.
  # Setting it to -1 will process whole batch at once when combined with `greedy_batch` decoding strategy
  fused_batch_size: Optional[int] = -1

  # greedy strategy config
  greedy:
    max_symbols: 10

  # beam strategy config
  beam:
    beam_size: 2
    score_norm: true
    softmax_temperature: 1.0  # scale the logits by some temperature prior to softmax
    tsd_max_sym_exp: 10  # for Time Synchronous Decoding, int > 0
    alsd_max_target_len: 5.0  # for Alignment-Length Synchronous Decoding, float > 1.0
    maes_num_steps: 2  # for modified Adaptive Expansion Search, int > 0
    maes_prefix_alpha: 1  # for modified Adaptive Expansion Search, int > 0
    maes_expansion_beta: 2  # for modified Adaptive Expansion Search, int >= 0
    maes_expansion_gamma: 2.3  # for modified Adaptive Expansion Search, float >= 0

Transducer 损失#

此部分配置 Transducer 损失本身的类型以及可能的子部分。默认情况下,将使用 Transducer 损失的优化实现,该实现依赖于 Numba 进行 CUDA 加速。Transducer 损失部分的基本配置可以在 loss 部分的 ContextNet 或其他 Transducer 架构中找到。有关更多信息,请参阅 ASR 教程部分的 Intro to Transducers 教程。

此配置可以复制粘贴到任何自定义 transducer 模型中,无需修改。

损失配置基于解析器模式,可以按如下方式使用

  1. loss_namedefault 通常是一个不错的选择。将选择可用的已解析损失之一,并匹配通过显式 {loss_name}_kwargs 子配置传递的子配置中的 kwargs。

  2. {loss_name}_kwargs:此子配置传递给上面的已解析损失,可用于配置已解析损失。

loss:
  loss_name: "default"
  warprnnt_numba_kwargs:
    fastemit_lambda: 0.0

FastEmit 正则化#

默认的基于 Numba 的 WarpRNNT 损失支持 FastEmit 正则化。最近提出的正则化方法 - FastEmit:具有序列级发射正则化的低延迟流式 ASR 允许我们近乎直接地控制 transducer 模型的延迟。

有关 fastemit_lambda 的结果和建议,请参阅上述论文。

混合 ASR-TTS 模型配置#

混合 ASR-TTS 模型 由三个部分组成

  • ASR 模型 (EncDecCTCModelBPEEncDecRNNTBPEModelEncDecHybridRNNTCTCBPEModel)

  • TTS 梅尔频谱图生成器(目前仅支持 FastPitch 模型)

  • 增强器模型(可选)

此外,该配置允许指定 纯文本数据集

配置的主要部分

  • ASR 模型
    • asr_model_path:ASR 模型检查点 (.nemo) 文件的路径,仅加载一次,然后 ASR 模型的配置存储在 asr_model 字段中

    • asr_model_type:仅在从头开始训练时才需要。rnnt_bpe 对应于 EncDecRNNTBPEModelctc_bpe 对应于 EncDecCTCModelBPEhybrid_rnnt_ctc_bpe 对应于 EncDecHybridRNNTCTCBPEModel

    • asr_model_fuse_bn:融合预训练 ASR 模型中的 BatchNorm,可以提高微调场景中的质量

  • TTS 模型
    • tts_model_path:预训练 TTS 模型检查点 (.nemo) 文件的路径,仅加载一次,然后模型的配置存储在 tts_model 字段中

  • 增强器模型
    • enhancer_model_path:增强器模型的可选路径。仅加载一次,配置存储在 enhancer_model 字段中

  • train_ds
    • text_data:与纯文本数据相关的属性
      • manifest_filepath纯文本数据集 清单的路径(或路径)

      • speakers_filepath:包含多说话人 TTS 模型的说话人 ID 的文本文件的路径(或路径)(说话人在训练期间随机采样)

      • min_wordsmax_words:用于按字数过滤纯文本清单的参数

      • tokenizer_workers:用于初始标记化的工作进程数(加载数据时)。建议值为 num_CPUs / num_GPUs

    • asr_tts_sampling_techniqueasr_tts_sampling_temperatureasr_tts_sampling_probabilities:纯文本和音频文本数据的采样参数(如果两者都指定)。对应于 ConcatDatasetsampling_techniquesampling_temperaturesampling_probabilities 参数。

    • 所有其他组件与传统的 ASR 模型类似

  • validation_dstest_ds 对应于底层 ASR 模型

model:
  sample_rate: 16000

  # asr model
  asr_model_path: ???
  asr_model: null
  asr_model_type: null  # rnnt_bpe, ctc_bpe or hybrid_rnnt_ctc_bpe; needed only if instantiating from config, otherwise type is auto inferred
  asr_model_fuse_bn: false  # only ConformerEncoder supported now, use false for other models

  # tts model
  tts_model_path: ???
  tts_model: null

  # enhancer model
  enhancer_model_path: null
  enhancer_model: null

  train_ds:
    text_data:
      manifest_filepath: ???
      speakers_filepath: ???
      min_words: 1
      max_words: 45  # 45 - recommended value, ~16.7 sec for LibriSpeech
      tokenizer_workers: 1
    asr_tts_sampling_technique: round-robin  # random, round-robin, temperature
    asr_tts_sampling_temperature: null
    asr_tts_sampling_probabilities: null  # [0.5,0.5] – ASR,TTS
    manifest_filepath: ???
    batch_size: 16 # you may increase batch_size if your memory allows
    # other params

使用纯文本数据进行微调#

要使用纯文本数据微调现有的 ASR 模型,请使用 <NeMo_git_root>/examples/asr/asr_with_tts/speech_to_text_bpe_with_text_finetune.py 脚本和相应的配置 <NeMo_git_root>/examples/asr/conf/asr_tts/hybrid_asr_tts.yaml

请指定所有必需模型(ASR、TTS 和增强器检查点)的路径,以及 train_ds.text_data.manifest_filepathtrain_ds.text_data.speakers_filepath

python speech_to_text_bpe_with_text_finetune.py \
    model.asr_model_path=<path to ASR model> \
    model.tts_model_path=<path to compatible TTS model> \
    model.enhancer_model_path=<optional path to enhancer model> \
    model.asr_model_fuse_bn=<true recommended if ConformerEncoder with BatchNorm, false otherwise> \
    model.train_ds.manifest_filepath=<path to manifest with audio-text pairs or null> \
    model.train_ds.text_data.manifest_filepath=<path(s) to manifest with train text> \
    model.train_ds.text_data.speakers_filepath=<path(s) to speakers list> \
    model.train_ds.text_data.tokenizer_workers=4 \
    model.validation_ds.manifest_filepath=<path to validation manifest> \
    model.train_ds.batch_size=<batch_size>

从头开始训练#

要使用纯文本数据从头开始训练 ASR 模型,请使用 <NeMo_git_root>/examples/asr/asr_with_tts/speech_to_text_bpe_with_text.py 脚本和传统的 ASR 模型配置,例如 <NeMo_git_root>/examples/asr/conf/conformer/conformer_ctc_bpe.yaml<NeMo_git_root>/examples/asr/conf/conformer/conformer_transducer_bpe.yaml

请指定 ASR 模型类型、TTS 模型和(可选)增强器的路径,以及与纯文本数据相关的字段。对这些选项使用 +++ 标记,因为这些选项在原始 ASR 模型配置中不存在。

python speech_to_text_bpe_with_text.py \
    ++asr_model_type=<rnnt_bpe or ctc_bpe> \
    ++tts_model_path=<path to compatible tts model> \
    ++enhancer_model_path=<optional path to enhancer model> \
    ++model.train_ds.text_data.manifest_filepath=<path(s) to manifests with train text> \
    ++model.train_ds.text_data.speakers_filepath=<path(s) to speakers list> \
    ++model.train_ds.text_data.min_words=1 \
    ++model.train_ds.text_data.max_words=45 \
    ++model.train_ds.text_data.tokenizer_workers=4

微调配置#

所有 ASR 脚本都支持通过将预训练权重从检查点部分/完全加载到当前实例化的模型中来轻松进行微调。请注意,当前实例化的模型应具有与预训练检查点匹配的参数(以便权重可以正确加载)。为了直接微调预先存在的检查点,请按照教程 ASR 语言微调进行操作。

模型可以通过两种方式进行微调:* 仅更新或保留当前分词器 * 更新模型架构和分词器

通过更新或保留当前分词器进行微调#

在这种情况下,模型架构不会更新。模型通过两种方式使用预训练权重进行初始化

  1. 提供 NeMo 模型的路径(通过 init_from_nemo_model

  2. 提供预训练 NeMo 模型的名称(将通过云下载)(通过 init_from_pretrained_model

然后,用户可以使用现有的分词器或使用新的词汇表更新分词器。当用户不想更新模型架构但想使用新的词汇表更新分词器时,这很有用。

相同的脚本也可用于微调 CTC、RNNT 或混合模型。

<NeMo_repo>/examples/asr/speech_to_text_finetune.py 脚本通过以下参数支持这种类型的微调

python examples/asr/speech_to_text_finetune.py \
    --config-path=<path to dir of configs> \
    --config-name=<name of config without .yaml>) \
    model.train_ds.manifest_filepath="<path to manifest file>" \
    model.validation_ds.manifest_filepath="<path to manifest file>" \
    model.tokenizer.update_tokenizer=<True/False> \ # True to update tokenizer, False to retain existing tokenizer
    model.tokenizer.dir=<path to tokenizer dir> \ # Path to tokenizer dir when update_tokenizer=True
    model.tokenizer.type=<tokenizer type> \ # tokenizer type when update_tokenizer=True
    trainer.devices=-1 \
    trainer.accelerator='gpu' \
    trainer.max_epochs=50 \
    +init_from_nemo_model="<path to .nemo model file>" (or +init_from_pretrained_model="<name of pretrained checkpoint>")

有关更多详细信息,请参阅 <NeMo_repo>/examples/asr/conf/asr_finetune/speech_to_text_finetune.yaml。

使用 HuggingFace 数据集微调 ASR 模型#

用户可以使用 HuggingFace 数据集来微调 NeMo ASR 模型。以下配置文件可用于此目的:<NeMo_repo>/examples/asr/conf/asr_finetune/speech_to_text_hf_finetune.yaml

如前所述,用户可以根据自己的要求更新分词器或使用现有的分词器。如果用户想从 HuggingFace 数据集创建新的分词器,他们可以使用以下脚本:<NeMo_repo>/scripts/tokenizers/get_hf_text_data.py

通过更改模型架构和分词器进行微调#

如果用户也想更新模型架构,他们可以使用以下脚本

为了提供预训练模型,用户可以通过多种方式提供预训练权重 -

  1. 提供 NeMo 模型的路径(通过 init_from_nemo_model

  2. 提供预训练 NeMo 模型的名称(将通过云下载)(通过 init_from_pretrained_model

  3. 提供 Pytorch Lightning 检查点文件的路径(通过 init_from_ptl_ckpt

examples/asr/ 目录中有多个 ASR 子任务,您可以替换下面的 <subtask> 标记。

python examples/asr/<subtask>/script_to_<script_name>.py \
    --config-path=<path to dir of configs> \
    --config-name=<name of config without .yaml>) \
    model.train_ds.manifest_filepath="<path to manifest file>" \
    model.validation_ds.manifest_filepath="<path to manifest file>" \
    trainer.devices=-1 \
    trainer.accelerator='gpu' \
    trainer.max_epochs=50 \
    +init_from_nemo_model="<path to .nemo model file>" # (or +init_from_pretrained_model, +init_from_ptl_ckpt )

要重新初始化模型的一部分,使其与预训练模型不同,用户可以通过配置提及它们

init_from_nemo_model: "<path to .nemo model file>"
    asr_model:
        include: ["preprocessor","encoder"]
        exclude: ["decoder"]

微调执行流程图#

在准备您自己的训练或微调脚本时,请遵循执行流程图顺序以获得正确的推理。

根据模型类型,可能需要执行额外的步骤 -