非因果卷积/因果卷积

因果卷积:

因果卷积可以用上图直观表示。即对于上一层t时刻的值,只依赖于下一层t时刻及其之前的值。和传统的卷积神经网络的不同之处在于,因果卷积不能看到未来的数据,它是单向的结构,不是双向的。也就是说只有有了前面的因才有后面的果,是一种严格的时间约束模型,因此被成为因果卷积。

上面的图片可以详细的解释因果卷积,但是问题就来,如果我要考虑很久之前的变量x,那么卷积层数就必须增加(自行体会)。。。卷积层数的增加就带来:梯度消失,训练复杂,拟合效果不好的问题,为了决绝这个问题,出现了扩展卷积(dilated)

(1) 流式推理中的卷积要求

  • 无未来信息依赖:卷积核只能访问当前及之前的输入,不允许访问未来输入。
  • 因果卷积(Causal Convolution):通过调整卷积核的 Padding,使卷积操作仅依赖历史时间步的数据。

(2) Padding 设计

  • 普通卷积的 Padding:在非流式模型中,通常使用 SAME Padding(如 TensorFlow 或 PyTorch 的对称填充),填充方式使得输入和输出长度一致。这会导致卷积核访问未来时间步数据,无法实现流式推理。
  • 因果卷积的 Padding
    • 对卷积核进行不对称填充(如只在输入前侧填充),使得卷积操作仅依赖于当前及之前的时间步。
    • 具体填充量 = 卷积核大小 – 1,例如 3×1 卷积核的填充量是 2。
import torch
import torch.nn as nn
from torch.autograd import Variable

__CUDA__ = torch.cuda.is_available()

class CausalConv1d(nn.Module):
    """
    A causal 1D convolution.
    """
    def __init__(self, kernel_size, in_channels, out_channels, dilation):
        super(CausalConv1d, self).__init__(self)
        
        # attributes:
        self.kernel_size = kernel_size
        self.in_channels = in_channels
        self.dilation = dilation
        
        # modules:
        self.conv1d = torch.nn.Conv1d(in_channels, out_channels,
                                      kernel_size, stride=1,
                                      padding=padding = (kernel_size-1) * dilation,
                                      dilation=dilation)

    def forward(self, seq):
        """
        Note that Conv1d expects (batch, in_channels, in_length).
        We assume that seq ~ (len(seq), batch, in_channels), so we'll reshape it first.
        """
        seq_ = seq.permute(1,2,0)
        conv1d_out = self.conv1d(seq_).permute(2,0,1)
        # remove k-1 values from the end:
        return conv1d_out[0:-(self.kernel_size-1)]

扩展因果卷积:【空洞因果卷积 Dilated causal Conv】

对于因果卷积,存在的一个问题是需要很多层或者很大的filter来增加卷积的感受野。扩大卷积(dilated convolution)是通过跳过部分输入来使filter可以应用于大于filter本身长度的区域。等同于通过增加零来从原始filter中生成更大的filter。

dilated的好处是不做pooling损失信息的情况下,加大了感受野,让每个卷积输出都包含较大范围的信息。在图像需要全局信息或者语音文本需要较长的sequence信息依赖的问题中,都能很好的应用dilated conv,比如图像分割、语音合成WaveNet、机器翻译ByteNet中.

Normalization 层的选择与调整

Normalization 是流式推理中另一个关键挑战。普通的批归一化(Batch Normalization, BN)需要计算全局统计量(如均值和方差),这在流式推理中是不可能实现的。

(1) Batch Normalization 的问题

  • 需要整个批次的数据来计算统计量,无法在单步流式推理中实现。
  • 通常在训练阶段使用 batch statistics,在推理阶段使用 running statistics

(2) 解决方法

Layer Normalization (LN)

  • 不依赖于批次,而是对每个样本的特征维度进行归一化,非常适合流式推理。

Instance Normalization (IN)

  • 类似于 Layer Normalization,但操作在每个样本的空间维度上进行归一化。

Group Normalization (GN)

  • 介于 Batch 和 Layer Normalization 之间,将特征划分为组,并在组内进行归一化。

Online Normalization(自回归统计)

  • 通过滑动窗口或指数移动平均(EMA)计算局部统计量,仅依赖过去的信息。
  • 这种方法特别适合流式推理,但实现较为复杂。

实践中的流式推理设置

结合以上两点,具体实现流式模型时需要注意以下步骤:

  1. 卷积层
    • 替换普通卷积为因果卷积。
    • 如果使用扩张卷积(Dilated Convolution),需要保证所有层的 Padding 符合因果逻辑。
  2. 归一化层
    • 替换 BatchNormLayerNorm
    • 在需要时,引入自回归统计机制。
  3. 框架支持
    • 确保模型在流式输入中可以逐步更新输入窗口(如时间序列切片)。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注