简单transformer运用

通俗易懂解读: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 会计算:
      • “苹果”和其他元素(香蕉、橙子)的相关性。
      • “香蕉”和其他元素的相关性,依此类推。
    • 计算步骤
      1. 将输入序列(每个元素是一个向量)映射为 Query(Q)、Key(K)、Value(V)三个向量。
      2. 计算注意力分数: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。
      3. 输出一个加权后的向量,表示当前元素对整个序列的关注结果。
(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)。

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 训练模型
  • 步骤
    1. 准备数据:加载梅尔频谱图,划分训练/验证集,用 DataLoader 批次加载。
    2. 定义模型:使用 nn.TransformerEncoderLayer,设置 d_model、nhead 等参数。
    3. 前向传播:通过 Self-Attention 处理序列,池化后输出分类结果。
    4. 训练:设置优化器、学习率调度器,循环计算损失、更新参数。
    5. 调整参数:修改 d_model、nhead、num_layers 等,优化性能。
  • Self-Attention 的作用:捕捉序列中帧与帧之间的关系,比如语音中不同时间点的关联。
  • 训练技巧
    • 使用 Warmup 学习率调度(代码中已实现)。
    • 定期验证,保存最佳模型。
    • 调整参数时,观察验证集准确率,避免过拟合。

7. 动手实践

如果你想自己训练一个类似模型,可以用以下步骤:

  1. 环境准备
    • 安装 PyTorch:pip install torch
    • 下载数据集(代码中的链接已失效,可用其他语音数据集如 LibriSpeech 替代)。
  2. 修改代码
    • 调整 d_model=128、nhead=4、num_layers=3,观察效果。
    • 实现 Conformer(参考 https://arxiv.org/abs/2005.08100)。
  3. 训练
    • 运行 main 函数,设置 total_steps=70000,观察验证准确率。
  4. 推理
    • 用训练好的模型预测测试集,生成提交文件

逐行讲解 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)优化性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/83388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

redis的哨兵模式和Redis cluster

目录 一. redis的主从复制 二. 哨兵模式 2.1 定义 2.2 作用 2.3 配置实例 三. Redis cluster 3.1 定义 3.2 作用 3.3 配置实例 1. 新建集群文件目录 2. 准备可执行文件到每个文件夹 3. 开启群集功能 4. 启动redis节点 5. 查看是否启动成功 6. 启动集群 7. 测试…

简述八大排序(Sort)

1.插入排序 1.1直接插入排序 给定一组数据,若数据只有一个肯定是有序的,我们将无序数据一个个插入到已有序的数据中。用i遍历无序数据,j遍历有序数据,找到合适插入位置,用tmp存放目标插入数据,将其与j对应…

xcode 编译运行错误 Sandbox: rsync(29343) deny(1) file-write-create

解决方法 方法一:修改Targets -> Build Settings 中 ENABLE_USER_SCRIPT_SANDBOXING 设置 NO 方法二:项目使用cocoaPods进行三方管理 且 使用了 use_frameworks,把 use_frameworks 注释掉,然后重新自行pod install

linux系统中防火墙的操作

防火墙 开放ssh端口 sudo ufw allow 22/tcp # 允许 SSH 连接 sudo ufw enable开放防火墙端口 sudo ufw allow 80/tcp # HTTP sudo ufw allow 443/tcp # HTTPS(如果需要) sudo ufw enable查看挡墙防火墙设置 sudo ufw status删除其中一条防火墙规…

[特殊字符] 超强 Web React版 PDF 阅读器!支持分页、缩放、旋转、全屏、懒加载、缩略图!

在现代 Web 项目中,PDF 浏览是一个常见需求:从政务公文到合同协议,PDF 文件无处不在。但很多方案要么体验不佳,要么集成复杂。今天,我给大家带来一个开箱即用、功能全面的 PDF 预览组件 —— [PDFView](https://www.np…

设计模式——策略设计模式(行为型)

摘要 策略设计模式是一种行为型设计模式,它定义了一系列算法并将每个算法封装起来,使它们可以相互替换。该模式让算法的变化独立于使用算法的客户,从而使得算法可以灵活地切换和扩展。其主要角色包括策略接口、具体策略类和环境类。策略模式…

DeepSeek-R1-0528,官方的端午节特别献礼

DeepSeek:端午安康!刻在国人骨子里的浪漫 2025 年 05 月 28 日 | DeepSeek 端午特别献礼 当粽叶飘香时,DeepSeek 悄然带来一份节日惊喜 版本号 DeepSeek-R1-0528 正式上线 官方赋予它的灵魂是: 思考更深 推理更强 用户通过官网…

mac安装brew时macos无法信任ruby的解决方法

背景 在使用如下脚本安装brew时,遇到安装ruby,macos不信任外部软件,在安全性点击信任仍然无法安装。 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"如何解决 本地安装好符…

2025音频传输模块全球选购指南:高品质音频体验的品牌之选

随着无线技术的迅猛发展,音频传输模块(Audio Transmission Module)已成为高品质音频体验的关键技术之一。它们广泛应用于智能家居、无线耳机、会议系统、广播设备以及专业音频领域。面对市场上多样化的产品,如何选择适合自己需求的…

解析楼宇自控系统:分布式结构的核心特点与优势展现

在建筑智能化发展的进程中,楼宇自控系统作为实现建筑高效运行与管理的关键,其系统结构的选择至关重要。传统的集中式楼宇自控系统在面对日益复杂的建筑环境和多样化的管理需求时,逐渐暴露出诸多弊端,如可靠性低、扩展性差、响应速…

Spring Boot对一些技术框架进行了统一版本号管理

这个说法是 正确的。 Spring Boot 对许多常用依赖进行了版本管理,因此在项目中引入这些依赖时,通常不需要指定版本号。 Spring Boot 依赖版本管理 🛠️ spring-boot-starter-parent:当你的项目在 pom.xml (Maven 项目) 中继承自…

关于MySQL的索引

一、索引 1、索引概述 1.1、介绍 索引( index )是帮助 MySQL 高效获取数据的数据结构 ( 有序 ) 。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据&…

微服务常用日志追踪方案:Sleuth + Zipkin + ELK

在微服务架构中,一个用户请求往往需要经过多个服务的协同处理。为了有效追踪请求的完整调用链路,需要一套完整的日志追踪方案。Sleuth Zipkin ELK 组合提供了完整的解决方案 Sleuth:生成和传播追踪IDZipkin:收集、存储和可视化…

R语言基础| 创建数据集

在R语言中,有多种数据类型,用以存储和处理数据。每种数据类型都有其特定的用途和操作函数,使得R语言在处理各种数据分析任务时非常灵活和强大: 向量(Vector): 向量是R语言中最基本的数据类型,它…

nssctf第二题[SWPUCTF 2021 新生赛]简简单单的逻辑

这是题目&#xff0c;下载后得到一个python文件,打开 解读代码&#xff1a; for i in range(len(list)):key (list[i]>>4)((list[i] & 0xf)<<4)result str(hex(ord(flag[i])^key))[2:].zfill(2)list[i]>>4&#xff1a;从列表中取数字同时高4位向右位…

mysql(十五)

目录 子查询 1.准备工作 2--创建表格 3--插入数据 2.where 子查询单列单个数据 格式 查询 3.where 子查询单列多个数据(in) 格式 查询 使用子查询 4.from 多行多数据 格式 查询 子查询 将select的查询的返回结果 当成另外一个selet语句的内容去使用。 子查询放在()里面 注意…

【HarmonyOS 5】鸿蒙Taro跨端框架

‌Taro跨端框架‌ 支持React语法开发鸿蒙应用&#xff0c;架构分为三层&#xff1a; ArkVM层运行业务代码和React核心TaroElement树处理节点创建和属性绑定TaroRenderNode虚拟节点树与上屏节点一一对应 import { Component } from tarojs/taro export default class MyCompon…

华为OD机试真题——会议接待 /代表团坐车(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享》 华为OD机试真题《会议…

C语言---动态内存管理、柔性数组

一、malloc和free 1、变长数组 变长数组是指数组的大小可以通过变量来指定。 在c99以及之后的标准中&#xff1a; #include<stdio.h> int main() { int n0; scanf("%d",&n); } 2、malloc和free 这个函数向内存申请一块连续可用的空间&#xff0c;并返…

WEBSTORM前端 —— 第3章:移动 Web —— 第4节:移动适配-VM

目录 一、适配方案 二、VM布局 ​编辑 三、vh布局 四、案例—酷我音乐 一、适配方案 二、VM布局 三、vh布局 四、案例—酷我音乐