李宏毅机器学习2021 HW4 学习记录

链接

transformer
提交地址

基础代码

自注意力机制网络结构

自注意力机制的网络结构如下:
来源论文
左侧为编码器,有六个相同的层组成,每层有两个子层;右侧为解码器,也由 N=6 个相同的层组成,每层包含三个子层。
编码器负责处理输入序列。它逐层转换输入数据,每一层都通过自注意力机制捕捉序列中不同位置间的关系。这样,编码器产生的最终输出包含了输入序列的全面表示,这些表示随后传递给解码器。
解码器负责生成输出序列。它逐层生成输出,同时利用编码器的输出来捕捉输入序列的相关信息。在序列生成过程中,解码器的自注意力层被修改以防止未来位置的信息泄露,确保每个位置的输出只依赖于之前的输出。
在训练过程中,首先将整个输入序列提供给编码器,编码器逐层处理序列并生成表示。然后,这些表示被传递给解码器。解码器根据编码器的输出以及到目前为止已生成的输出序列的信息,逐步生成输出序列
如果是分类任务,只用编码器就行

自注意力机制应用方法

torch.nn.TransformerEncoderLayer

编码器的最小单元(上面左图),一定需要定义

  • d_model: 输入张量特征数(required).
  • nhead: 多头自注意力机制的头数(required).
  • dim_feedforward:全连接层的维数 (default=2048).
  • dropout: the dropout value (default=0.1).
  • activation: 激活函数 relu or gelu (default=relu).
  self.encoder_layer = nn.TransformerEncoderLayer(
      d_model=d_model, dim_feedforward=256, nhead=2
    )

torch.nn.TransformerEncoder:

上一个的升级版本,可以不定义,它包含了N个transformer encoder layers

  • encoder_layer: 要用的layer(required).
  • num_layers :sub-encoder-layers的数目(required).
self.encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=2)

网络结构代码

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),
    )

  def forward(self, mels):
    """
    args:
      mels: (batch size, length, 40)
    return:
      out: (batch size, n_spks)
    """
    # out: (batch size, length, d_model)
    out = self.prenet(mels)  
    
    # out: (length, batch size, d_model)
    out = out.permute(1, 0, 2) 
    # 编码器期待 (length, batch size, d_model)格式的输入
  
    # out: (length, batch size, d_model)    
    out = self.encoder_layer(out)
    
    # out: (batch size, length, d_model)
    out = out.transpose(0, 1)
    
    # 沿着 length 维度的平均池化操作,所以后续的向量就少了一个维度
    stats = out.mean(dim=1)

    # out: (batch, n_spks)
    out = self.pred_layer(stats)
    return out

其余值得学习的东西

动态学习率及余弦退火算法

warm up

先采用这个算法,初期学习率是线性增长的

余弦退火算法

初期过后,学习率需要衰减
在这里插入图片描述
取了余弦函数中0~pi/2,实现学习率的衰减

代码
def get_cosine_schedule_with_warmup(
  optimizer: Optimizer,
  num_warmup_steps: int,
  num_training_steps: int,
  num_cycles: float = 0.5,
  last_epoch: int = -1,
):
  """
  用于调整学习率的函数,它创建了一个结合了warmup阶段和余弦退火调度的学习率调度器
  Args:
    num_warmup_steps:warm_up的步骤
    num_training_steps:训练的步骤
    num_cycles (defaults to 0.5):在余弦调度中的波形数量
    last_epoch (defaults to -1):The index of the last epoch when resuming training.
  """

  def lr_lambda(current_step):
    # Warmup:如果当前步数小于warmup步数,学习率线性增加
    if current_step < num_warmup_steps:
      return float(current_step) / float(max(1, num_warmup_steps))
    # decadence 衰减
    progress = float(current_step - num_warmup_steps) / float(
      max(1, num_training_steps - num_warmup_steps)
    )
    # (math.cos(math.pi * float(num_cycles) * 2.0 * progress)) 根据训练进度计算一个介于-1到1之间的值,然后调整到0到1之间,乘以0.5以使最大学习率减半
    return max(
      0.0, 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress))
    )

  # 需要一个传入一个lambda函数,学习率等于初始学习率乘该函数的返回值
  return LambdaLR(optimizer, lr_lambda, last_epoch)
调用
  optimizer = AdamW(model.parameters(), lr=1e-3)
  scheduler = get_cosine_schedule_with_warmup(optimizer, warmup_steps, total_steps)
  
   # Updata model
   # 学习率调度器 (scheduler) 负责根据预设的规则调整优化器 (optimizer) 中的学习率
   loss.backward()
   optimizer.step()
   scheduler.step()
   optimizer.zero_grad()

Medium

主要涉及到几个参数的调整
在这里插入图片描述
除此之外,可以多放几个自注意力层

self.encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=2)

最后应用的模型

import torch
import torch.nn as nn
import torch.nn.functional as F


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=512, nhead=1
    )
    self.encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=2)

    # 输出处理:将自注意力机制的输出转化为分类数量
    self.pred_layer = nn.Sequential(
      # nn.Linear(d_model, d_model),
      nn.Linear(d_model, n_spks),
    )

  def forward(self, mels):
    """
    args:
      mels: (batch size, length, 40)
    return:
      out: (batch size, n_spks)
    """
    # out: (batch size, length, d_model)
    out = self.prenet(mels)  
    # out: (length, batch size, d_model)
    out = out.permute(1, 0, 2)
    # The encoder layer expect features in the shape of (length, batch size, d_model).
    out = self.encoder(out)
    # out: (batch size, length, d_model)
    out = out.transpose(0, 1)
    # mean pooling
    stats = out.mean(dim=1)

    # out: (batch, n_spks)
    out = self.pred_layer(stats)
    return out

结果

在这里插入图片描述

后来把d_models改成224,得到了更好的结果
在这里插入图片描述

Hard

这里需要改变整个模型的结构,conformer

图示

网络的结构如下:
在这里插入图片描述
相比于之前使用的网络,其主要变化是 conformer blocks中增加了convolution module,它长下面这样:
在这里插入图片描述
当然,它给我们打包好了,知道怎么用就行

使用

首先要安装库

$ pip install conformer

然后直接用它里面的conformer block模块就可以了

import torch
import conformer
from conformer import Conformer

conformer = Conformer(
    dim = 512,           # 模型中每个层的输出特征数
    depth = 12,          # 模型中Conformer块的数量
    dim_head = 64,       # 自注意力机制中每个头的维度
    heads = 8,           # 头的数目
    ff_mult = 4,         # 前馈层中隐藏层大小相对于模型维度dim的倍数
    conv_expansion_factor = 2,   # 卷积层扩张因子,影响卷积层中间隐藏层的大小
    conv_kernel_size = 31,       # 卷积层的核大小
    attn_dropout = 0.,
    ff_dropout = 0.,
    conv_dropout = 0.,    # 自注意力层、前馈网络层和卷积层中的dropout率
)

x = torch.randn(1, 1024, 512)  # 对于上面的block块,期待的输入

conformer(x) # (1, 1024, 512)

效果不如之前

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值