通俗易懂解讀:hw04.py 文件內容與 Transformer 的應用
這個文件是一個 Python 腳本(hw04.py),用于完成 NTU 2021 Spring 機器學習課程的 HW4 作業任務:揚聲器分類(Speaker Classification)。它主要通過 Transformer 模型(尤其是自注意力機制,Self-Attention)來實現分類,并提供了訓練和推理代碼。以下我會詳細講解文件的結構,重點教你如何使用 Transformer 和 Self-Attention,并讓你明白如何訓練模型、調整參數。
1. 文件概述
- 任務:從語音特征(梅爾頻譜圖,mel-spectrogram)中分類揚聲器(600 個類別)。
- 數據集:Voxceleb2 數據集的子集,包含 600 個揚聲器的音頻特征。
- 目標:
- 學習使用 Transformer 模型(Simple 級別)。
- 調整 Transformer 參數(Medium 級別)。
- 構建 Conformer(Hard 級別,代碼中未實現)。
- 進一步實現 Self-Attention Pooling 和 Additive Margin Softmax(Boss 級別,代碼中未實現)。
- 代碼結構:
- 數據準備:解壓數據、加載數據集、定義 DataLoader。
- 模型定義:使用 TransformerEncoderLayer 實現分類器。
- 訓練:實現訓練循環、學習率調度和驗證。
- 推理:加載模型,預測測試集揚聲器并生成提交文件。
2. Transformer 和 Self-Attention 的原理與應用
先簡單講解 Transformer 和 Self-Attention 的原理,然后結合代碼看它們如何被使用。
(1) Transformer 和 Self-Attention 原理
- Transformer:
- 由 Google 在 2017 年論文《Attention is All You Need》提出,是一種基于注意力機制的模型,取代了傳統的 RNN。
- 核心組件:自注意力(Self-Attention) 和 前饋神經網絡(Feedforward Network)。
- 優點:能并行處理序列(不像 RNN 逐個處理),捕捉長距離依賴。
- Self-Attention:
- 是一種注意力機制,讓模型在處理序列中的每個元素時,關注整個序列的其他元素。
- 比如處理“[蘋果, 香蕉, 橙子]”時,Self-Attention 會計算:
- “蘋果”和其他元素(香蕉、橙子)的相關性。
- “香蕉”和其他元素的相關性,依此類推。
- 計算步驟:
- 將輸入序列(每個元素是一個向量)映射為 Query(Q)、Key(K)、Value(V)三個向量。
- 計算注意力分數:Attention(Q,K,V)=softmax(QKTdk)V \text{Attention}(Q, K, V) = \text{softmax}(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)=softmax(dk??QKT?)V。
- 輸出一個加權后的向量,表示當前元素對整個序列的關注結果。
(2) 代碼中的 Transformer 和 Self-Attention
- 模型定義(Classifier 類):
python
收起自動換行運行
復制class Classifier(nn.Module): def __init__(self, d_model=80, n_spks=600, dropout=0.1): super().__init__() self.prenet = nn.Linear(40, d_model) self.encoder_layer = nn.TransformerEncoderLayer( d_model=d_model, dim_feedforward=256, nhead=2 ) self.pred_layer = nn.Sequential( nn.Linear(d_model, d_model), nn.ReLU(), nn.Linear(d_model, n_spks), )
- self.prenet:將輸入特征(梅爾頻譜圖,維度為 40)投影到 d_model=80 的維度,為 Transformer 處理做準備。
- self.encoder_layer:使用 PyTorch 的 nn.TransformerEncoderLayer,這是一個標準的 Transformer 編碼層,包含:
- Self-Attention:通過 nhead=2 設置多頭注意力(Multi-Head Attention),將 d_model 均分為 2 頭,每頭處理 d_model/nhead=40 維度。
- Feedforward Network:通過 dim_feedforward=256 設置前饋網絡的隱藏層維度。
- 默認使用 dropout(0.1)和 ReLU 激活函數。
- 代碼中注釋掉了一個 nn.TransformerEncoder,原本應該是堆疊多個 TransformerEncoderLayer(比如 num_layers=2),但當前只用了一層。
- 前向傳播(forward 方法):
python
收起自動換行運行
復制def forward(self, mels): out = self.prenet(mels) # (batch size, length, 40) -> (batch size, length, d_model) out = out.permute(1, 0, 2) # (batch size, length, d_model) -> (length, batch size, d_model) out = self.encoder_layer(out) # Transformer 編碼 out = out.transpose(0, 1) # (length, batch size, d_model) -> (batch size, length, d_model) stats = out.mean(dim=1) # 平均池化:(batch size, d_model) out = self.pred_layer(stats) # (batch size, n_spks) return out
- Self-Attention 的作用:
- 輸入 mels 是梅爾頻譜圖,形狀為 (batch size, length, 40),表示一個 batch 的音頻特征。
- 經過 self.prenet,維度變成 (batch size, length, d_model)。
- out = out.permute(1, 0, 2) 調整維度為 (length, batch size, d_model),因為 TransformerEncoderLayer 期望輸入是 (sequence length, batch size, d_model)。
- self.encoder_layer(out) 執行 Self-Attention 和 Feedforward 操作:
- Self-Attention 計算每個時間步(幀)對其他所有幀的關注權重。
- Feedforward 對每個幀獨立應用前饋網絡。
- 最后通過平均池化(out.mean(dim=1))將序列維度壓縮,得到每個樣本的特征向量 (batch size, d_model),再通過 self.pred_layer 輸出分類結果 (batch size, n_spks)。
- Self-Attention 的作用:
3. 如何使用 Transformer
通過這個代碼,我教你如何在 PyTorch 中使用 Transformer 來完成一個分類任務。
(1) 定義 Transformer 模型
- 使用 nn.TransformerEncoderLayer 構建基本層:
python
收起自動換行運行
復制self.encoder_layer = nn.TransformerEncoderLayer( d_model=d_model, # 輸入和輸出的特征維度 nhead=2, # 多頭注意力的頭數,d_model 必須能被 nhead 整除 dim_feedforward=256, # 前饋網絡的隱藏層維度 dropout=0.1 # dropout 比例 )
- 如果需要堆疊多層,可以用 nn.TransformerEncoder:
python
收起自動換行運行
復制
(代碼中注釋掉了這部分,當前只用了一層。)self.encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=2)
(2) 輸入數據準備
- Transformer 需要輸入形狀為 (sequence length, batch size, d_model):
- 代碼中通過 out.permute(1, 0, 2) 調整維度。
- 輸入的 mels 是 (batch size, length, 40),先通過 self.prenet 投影到 d_model=80,再調整維度。
(3) 前向傳播
- 直接調用 self.encoder_layer(out),PyTorch 會自動處理 Self-Attention 和 Feedforward。
- 輸出需要根據任務調整:
- 這里是分類任務,所以用平均池化(out.mean(dim=1))壓縮序列維度,然后通過全連接層輸出分類結果。
(4) 應用場景
- Transformer 適合處理序列數據(如語音、文本)。
- Self-Attention 讓模型能捕捉序列中任意兩個位置之間的關系,比如語音中不同幀之間的關聯。
4. 如何訓練模型
訓練一個模型需要準備數據、定義模型、設置優化器和學習率調度器,然后進入訓練循環。以下是代碼中的訓練過程解析。
(1) 數據準備
- 數據集(myDataset 類):
- 加載梅爾頻譜圖(torch.load),隨機截取 segment_len=128 幀。
- 標簽是揚聲器 ID(從 mapping.json 中獲取)。
- DataLoader(get_dataloader 函數):
- 按 90%(訓練)/10%(驗證)劃分數據集。
- 使用 collate_batch 函數填充批次數據,確保長度一致(填充值為 -20,表示極小的對數值)。
(2) 模型和優化器
- 模型:model = Classifier(n_spks=speaker_num).to(device),初始化 Classifier。
- 損失函數:criterion = nn.CrossEntropyLoss(),用于多分類任務。
- 優化器:optimizer = AdamW(model.parameters(), lr=1e-3),使用 AdamW 優化器,初始學習率 1e-3。
- 學習率調度器(get_cosine_schedule_with_warmup):
- 包含 Warmup 階段(前 1000 步,學習率從 0 線性增加到 1e-3)。
- 之后按余弦衰減(Cosine Decay)降低學習率。
(3) 訓練循環(main 函數)
- 訓練步驟:
python
收起自動換行運行
復制for step in range(total_steps): batch = next(train_iterator) loss, accuracy = model_fn(batch, model, criterion, device) loss.backward() optimizer.step() scheduler.step() optimizer.zero_grad()
- 每步從 train_loader 獲取一個批次。
- 計算損失和準確率(model_fn)。
- 反向傳播、優化器更新參數、調度器調整學習率、清空梯度。
- 驗證:
- 每 2000 步(valid_steps)驗證一次,計算驗證集準確率。
- 保存最佳模型(best_accuracy)。
- 保存模型:每 10,000 步(save_steps)保存最佳模型到 model.ckpt。
(4) 推理(main 函數,推理部分)
- 加載訓練好的模型,預測測試集揚聲器,生成 output.csv(格式:Id, Category)。
5. 如何調整 Transformer 參數
調整 Transformer 參數是 HW4 的 Medium 級別任務。以下是代碼中可以調整的部分,以及調整的意義。
(1) 調整參數的地方
- 在 Classifier 的 __init__ 中:
python
收起自動換行運行
復制self.encoder_layer = nn.TransformerEncoderLayer( d_model=d_model, dim_feedforward=256, nhead=2 )
- d_model=80:特征維度,增加會提升模型容量,但計算量更大。
- nhead=2:多頭注意力頭數,d_model 必須能被整除(當前 80/2=40)。
- dim_feedforward=256:前饋網絡隱藏層維度,增加會增強模型表達能力。
- 堆疊多層(當前注釋掉了):
python
收起自動換行運行
復制self.encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=2)
- num_layers=2:增加層數會讓模型更深,能捕捉更復雜的模式,但可能過擬合。
(2) 調整建議
- 增大 d_model:比如從 80 增加到 128,增強模型容量,但需要確保 nhead 能整除(比如 nhead=4)。
- 增加 nhead:比如從 2 增加到 4,允許多頭注意力捕捉更多不同類型的依賴關系。
- 調整 dim_feedforward:比如從 256 增加到 512,增強前饋網絡的能力。
- 增加層數:取消注釋 self.encoder,設置 num_layers=3,讓模型更深。
- 調整 dropout:默認 0.1,可以嘗試 0.2 或 0.05,防止過擬合。
- 效果:文檔中提到(HW04.pdf 第13頁),調整參數后公共基準從 0.82523(Simple)提升到 0.90547(Medium)。
(3) 注意事項
- 增加參數會增加計算量,可能需要更大的 batch size 或更長的訓練時間。
- 過大的模型可能過擬合,需要調整學習率或增加 dropout。
6. 總結:如何使用 Transformer 訓練模型
- 步驟:
- 準備數據:加載梅爾頻譜圖,劃分訓練/驗證集,用 DataLoader 批次加載。
- 定義模型:使用 nn.TransformerEncoderLayer,設置 d_model、nhead 等參數。
- 前向傳播:通過 Self-Attention 處理序列,池化后輸出分類結果。
- 訓練:設置優化器、學習率調度器,循環計算損失、更新參數。
- 調整參數:修改 d_model、nhead、num_layers 等,優化性能。
- Self-Attention 的作用:捕捉序列中幀與幀之間的關系,比如語音中不同時間點的關聯。
- 訓練技巧:
- 使用 Warmup 學習率調度(代碼中已實現)。
- 定期驗證,保存最佳模型。
- 調整參數時,觀察驗證集準確率,避免過擬合。
7. 動手實踐
如果你想自己訓練一個類似模型,可以用以下步驟:
- 環境準備:
- 安裝 PyTorch:pip install torch
- 下載數據集(代碼中的鏈接已失效,可用其他語音數據集如 LibriSpeech 替代)。
- 修改代碼:
- 調整 d_model=128、nhead=4、num_layers=3,觀察效果。
- 實現 Conformer(參考 https://arxiv.org/abs/2005.08100)。
- 訓練:
- 運行 main 函數,設置 total_steps=70000,觀察驗證準確率。
- 推理:
- 用訓練好的模型預測測試集,生成提交文件
逐行講解 Conformer 代碼實現
由于你之前沒有接觸過 Conformer,我會從零開始詳細講解之前提供的 ConformerBlock 和 ConformerConvModule 的代碼實現,逐行分析其功能、原理和實現細節。Conformer 是 Transformer 的變種,專為語音任務設計,結合了全局建模(Self-Attention)和局部建模(卷積)的優勢。以下代碼來自之前修改的 hw04.py,我們會重點聚焦 Conformer 的實現部分。
1. Conformer 代碼實現
以下是 ConformerConvModule 和 ConformerBlock 的完整代碼,我會逐行解釋其作用。
import torch
import torch.nn as nn
import torch.nn.functional as F# 卷積模塊,用于捕捉局部特征
class ConformerConvModule(nn.Module):def __init__(self, d_model=80, kernel_size=31, dropout=0.1):super().__init__()# Pointwise Convolution 1self.pointwise_conv1 = nn.Conv1d(d_model, d_model * 2, kernel_size=1, stride=1, padding=0, bias=True)self.glu = nn.GLU(dim=1) # Gated Linear Unit# Depthwise Convolutionself.depthwise_conv = nn.Conv1d(d_model,d_model,kernel_size=kernel_size,stride=1,padding=(kernel_size - 1) // 2,groups=d_model, # Depthwisebias=True)self.bn = nn.BatchNorm1d(d_model)self.swish = nn.Swish()# Pointwise Convolution 2self.pointwise_conv2 = nn.Conv1d(d_model, d_model, kernel_size=1, stride=1, padding=0, bias=True)self.dropout = nn.Dropout(dropout)def forward(self, x):# x: (batch, length, d_model) -> (batch, d_model, length) for convx = x.transpose(1, 2)# Pointwise Conv 1 + GLUx = self.pointwise_conv1(x)x = self.glu(x)# Depthwise Conv + BN + Swishx = self.depthwise_conv(x)x = self.bn(x)x = self.swish(x)# Pointwise Conv 2x = self.pointwise_conv2(x)x = self.dropout(x)# Back to (batch, length, d_model)x = x.transpose(1, 2)return x# Conformer 塊,包含 FFN、Self-Attention 和卷積模塊
class ConformerBlock(nn.Module):def __init__(self, d_model=80, nhead=2, dim_feedforward=256, dropout=0.1, kernel_size=31):super().__init__()# Feed-Forward Module (half-step)self.ffn1 = nn.Sequential(nn.LayerNorm(d_model),nn.Linear(d_model, dim_feedforward),nn.Swish(),nn.Dropout(dropout),nn.Linear(dim_feedforward, d_model))# Multi-Head Self-Attentionself.self_attention = nn.MultiheadAttention(d_model, nhead, dropout=dropout)self.norm1 = nn.LayerNorm(d_model)self.dropout1 = nn.Dropout(dropout)# Convolution Moduleself.conv_module = ConformerConvModule(d_model, kernel_size, dropout)self.norm2 = nn.LayerNorm(d_model)self.dropout2 = nn.Dropout(dropout)# Feed-Forward Module (half-step)self.ffn2 = nn.Sequential(nn.LayerNorm(d_model),nn.Linear(d_model, dim_feedforward),nn.Swish(),nn.Dropout(dropout),nn.Linear(dim_feedforward, d_model))self.norm3 = nn.LayerNorm(d_model)self.dropout3 = nn.Dropout(dropout)def forward(self, x):# x: (length, batch, d_model)# FFN 1 (half-step)x = x + 0.5 * self.dropout1(self.ffn1(x))# Multi-Head Self-Attentionattn_output, _ = self.self_attention(x, x, x)x = self.norm1(x + self.dropout1(attn_output))# Convolution Modulex = self.norm2(x + self.dropout2(self.conv_module(x)))# FFN 2 (half-step)x = self.norm3(x + self.dropout3(self.ffn2(x)))return x
2. 逐行講解 ConformerConvModule
(1) 初始化方法 __init__
python
收起自動換行運行
復制
class ConformerConvModule(nn.Module): def __init__(self, d_model=80, kernel_size=31, dropout=0.1):
- class ConformerConvModule(nn.Module):定義一個卷積模塊,繼承 PyTorch 的 nn.Module 類,所有神經網絡模塊都需要繼承這個類。
- d_model=80:輸入和輸出的特征維度(類似 Transformer 的隱藏維度)。
- kernel_size=31:卷積核大小,決定了捕捉局部特征的范圍(越大,感受野越大)。
- dropout=0.1:Dropout 比例,防止過擬合。
python
收起自動換行運行
復制
super().__init__()
- 調用父類 nn.Module 的初始化方法,確保正確初始化模塊。
python
收起自動換行運行
復制
self.pointwise_conv1 = nn.Conv1d(d_model, d_model * 2, kernel_size=1, stride=1, padding=0, bias=True)
- nn.Conv1d:一維卷積,適用于序列數據(如語音的梅爾頻譜圖)。
- d_model:輸入通道數(特征維度)。
- d_model * 2:輸出通道數,升維到兩倍,用于后續 GLU(Gated Linear Unit)操作。
- kernel_size=1:點卷積(Pointwise Convolution),只對每個時間步獨立操作,不涉及鄰域。
- stride=1:步幅為 1,不改變序列長度。
- padding=0:無填充,因為 kernel_size=1 不需要填充。
- bias=True:包含偏置參數。
python
收起自動換行運行
復制
self.glu = nn.GLU(dim=1) # Gated Linear Unit
- nn.GLU:Gated Linear Unit,一種門控機制。
- dim=1:在通道維度上操作(因為輸入是 (batch, channel, length))。
- GLU 的作用:將 d_model * 2 的通道分成兩部分,一部分作為值,另一部分通過 sigmoid 激活作為門控,輸出 d_model 個通道。公式為: GLU(x)=x1?σ(x2)\text{GLU}(x) = x_1 \cdot \sigma(x_2)GLU(x)=x1??σ(x2?) 其中 x1 x_1 x1? 和 x2 x_2 x2? 是通道拆分的兩部分。
python
收起自動換行運行
復制
self.depthwise_conv = nn.Conv1d( d_model, d_model, kernel_size=kernel_size, stride=1, padding=(kernel_size - 1) // 2, groups=d_model, # Depthwise bias=True )
- nn.Conv1d:定義深度可分離卷積(Depthwise Convolution)。
- d_model:輸入和輸出通道數保持一致。
- kernel_size=31:卷積核大小,捕捉局部特征。
- stride=1:步幅為 1。
- padding=(kernel_size - 1) // 2:自動計算填充,確保輸出長度不變(例如 kernel_size=31 時,padding=15)。
- groups=d_model:深度卷積,每個輸入通道獨立卷積,減少參數量。
- bias=True:包含偏置。
python
收起自動換行運行
復制
self.bn = nn.BatchNorm1d(d_model)
- nn.BatchNorm1d:一維批歸一化,作用于通道維度。
- 歸一化每個通道的特征,加速訓練,穩定梯度。
python
收起自動換行運行
復制
self.swish = nn.Swish()
- nn.Swish:激活函數,公式為 Swish(x)=x?σ(x) \text{Swish}(x) = x \cdot \sigma(x) Swish(x)=x?σ(x),比 ReLU 更平滑。
python
收起自動換行運行
復制
self.pointwise_conv2 = nn.Conv1d(d_model, d_model, kernel_size=1, stride=1, padding=0, bias=True)
- 第二個點卷積,將特征降維回 d_model。
python
收起自動換行運行
復制
self.dropout = nn.Dropout(dropout)
- Dropout 層,隨機丟棄部分神經元,防止過擬合。
(2) 前向傳播方法 forward
python
收起自動換行運行
復制
def forward(self, x):
- 定義前向傳播,輸入 x 是 (batch, length, d_model) 的張量。
python
收起自動換行運行
復制
x = x.transpose(1, 2)
- transpose(1, 2):將 (batch, length, d_model) 轉換為 (batch, d_model, length),因為 nn.Conv1d 期望輸入是 (batch, channel, length)。
python
收起自動換行運行
復制
x = self.pointwise_conv1(x)
- 應用第一個點卷積,將通道數從 d_model 升到 d_model * 2。
python
收起自動換行運行
復制
x = self.glu(x)
- 應用 GLU,將通道數降回 d_model,并通過門控機制選擇性保留信息。
python
收起自動換行運行
復制
x = self.depthwise_conv(x)
- 應用深度卷積,捕捉局部特征(kernel_size=31 覆蓋 31 個時間步)。
python
收起自動換行運行
復制
x = self.bn(x)
- 應用批歸一化,穩定特征分布。
python
收起自動換行運行
復制
x = self.swish(x)
- 應用 Swish 激活,增加非線性。
python
收起自動換行運行
復制
x = self.pointwise_conv2(x)
- 應用第二個點卷積,進一步處理特征,保持維度為 (batch, d_model, length)。
python
收起自動換行運行
復制
x = self.dropout(x)
- 應用 Dropout,防止過擬合。
python
收起自動換行運行
復制
x = x.transpose(1, 2)
- 將維度轉回 (batch, length, d_model),與輸入一致。
python
收起自動換行運行
復制
return x
- 返回處理后的張量。
3. 逐行講解 ConformerBlock
(1) 初始化方法 __init__
python
收起自動換行運行
復制
class ConformerBlock(nn.Module): def __init__(self, d_model=80, nhead=2, dim_feedforward=256, dropout=0.1, kernel_size=31):
- 定義 Conformer 塊,參數與 ConformerConvModule 類似。
- nhead=2:多頭注意力的頭數。
- dim_feedforward=256:前饋網絡的隱藏層維度。
python
收起自動換行運行
復制
super().__init__()
python
收起自動換行運行
復制
self.ffn1 = nn.Sequential( nn.LayerNorm(d_model), nn.Linear(d_model, dim_feedforward), nn.Swish(), nn.Dropout(dropout), nn.Linear(dim_feedforward, d_model) )
- 定義第一個前饋模塊(FFN1)。
- nn.LayerNorm(d_model):層歸一化,歸一化每個時間步的特征。
- nn.Linear(d_model, dim_feedforward):將維度從 d_model 擴展到 dim_feedforward。
- nn.Swish():Swish 激活。
- nn.Dropout(dropout):Dropout。
- nn.Linear(dim_feedforward, d_model):降維回 d_model。
python
收起自動換行運行
復制
self.self_attention = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
- nn.MultiheadAttention:多頭自注意力。
- d_model:輸入維度。
- nhead=2:頭數,每頭處理 d_model/nhead=40 維度。
- dropout=dropout:注意力中的 Dropout。
python
收起自動換行運行
復制
self.norm1 = nn.LayerNorm(d_model) self.dropout1 = nn.Dropout(dropout)
- norm1 和 dropout1:用于自注意力后的歸一化和 Dropout。
python
收起自動換行運行
復制
self.conv_module = ConformerConvModule(d_model, kernel_size, dropout)
- 調用 ConformerConvModule,處理局部特征。
python
收起自動換行運行
復制
self.norm2 = nn.LayerNorm(d_model) self.dropout2 = nn.Dropout(dropout)
- norm2 和 dropout2:卷積模塊后的歸一化和 Dropout。
python
收起自動換行運行
復制
self.ffn2 = nn.Sequential( nn.LayerNorm(d_model), nn.Linear(d_model, dim_feedforward), nn.Swish(), nn.Dropout(dropout), nn.Linear(dim_feedforward, d_model) )
- 定義第二個前饋模塊(FFN2),結構與 FFN1 相同。
python
收起自動換行運行
復制
self.norm3 = nn.LayerNorm(d_model) self.dropout3 = nn.Dropout(dropout)
- norm3 和 dropout3:FFN2 后的歸一化和 Dropout。
(2) 前向傳播方法 forward
python
收起自動換行運行
復制
def forward(self, x):
- 輸入 x 是 (length, batch, d_model),符合 Transformer 的輸入格式。
python
收起自動換行運行
復制
x = x + 0.5 * self.dropout1(self.ffn1(x))
- 應用 FFN1,半步前饋(系數 0.5 是 Conformer 的設計)。
- self.ffn1(x):通過 FFN1 處理。
- self.dropout1(...):應用 Dropout。
- x + 0.5 * ...:殘差連接,穩定訓練。
python
收起自動換行運行
復制
attn_output, _ = self.self_attention(x, x, x)
- 應用多頭自注意力。
- self.self_attention(x, x, x):輸入 Query、Key、Value 均為 x,計算自注意力。
- attn_output:注意力輸出,形狀仍為 (length, batch, d_model)。
- _:忽略注意力權重。
python
收起自動換行運行
復制
x = self.norm1(x + self.dropout1(attn_output))
- x + self.dropout1(attn_output):殘差連接。
- self.norm1(...):層歸一化。
python
收起自動換行運行
復制
x = self.norm2(x + self.dropout2(self.conv_module(x)))
- 應用卷積模塊。
- self.conv_module(x):通過 ConformerConvModule 處理。
- self.dropout2(...):Dropout。
- x + ...:殘差連接。
- self.norm2(...):層歸一化。
python
收起自動換行運行
復制
x = self.norm3(x + self.dropout3(self.ffn2(x)))
- 應用 FFN2,與 FFN1 類似。
python
收起自動換行運行
復制
return x
- 返回處理后的張量,形狀不變。
4. 總結與使用
- ConformerConvModule:通過卷積捕捉局部特征,適合語音任務中的短時相關性。
- ConformerBlock:結合 FFN、Self-Attention 和卷積,平衡全局和局部建模。
- 如何使用:
- 在 Classifier 中替換 TransformerEncoderLayer 為 ConformerBlock。
- 堆疊多層:self.encoder = nn.Sequential(*[ConformerBlock(...) for _ in range(2)])。
- 調整參數(如 d_model、kernel_size)優化性能。