CNN经过一些简单的调整就可以成为序列建模和预测的强大工具
尽管卷积神经网络(CNNs)通常与图像分类任务相关,但经过适当的修改,它已被证明是进行序列建模和预测的有价值的工具。在本文中,我们将详细探讨时域卷积网络(TCN)所包含的基本构建块,以及它们如何结合在一起创建一个强大的预测模型。使用我们的开源Darts TCN实现,我们展示了只用几行代码就可以在真实数据集上实现准确预测。
以下对时间卷积网络的描述基于以下论文:https://arxiv.org/pdf/1803.01271.pdf。本文引用用(*)表示。
动机
到目前为止,深度学习背景下的序列建模主题主要与递归神经网络架构(如LSTM和GRU)有关。S. Bai等人(*)认为,这种思维方式已经过时,在对序列数据进行建模时,应该将卷积网络作为主要候选者之一加以考虑。他们能够表明,在许多任务中,卷积网络可以取得比RNNs更好的性能,同时避免了递归模型的常见缺陷,如梯度爆炸/消失问题或缺乏内存保留。此外,使用卷积网络而不是递归网络可以提高性能,因为它允许并行计算输出。他们提出的架构称为时间卷积网络(TCN),将在下面的部分中进行解释。为了便于理解TCN体系结构及其Darts实现,本文将尽可能使用与库中看到的相同的模型参数名称。
基本模型
概述
TCN是时域卷积网络(Temporal Convolutional Network)的简称,它由具有相同输入和输出长度的扩张的、因果的1D卷积层组成。下面几节将详细介绍这些术语的实际含义。
一维卷积网络
一维卷积网络以一个三维张量作为输入,也输出一个三维张量。我们的TCN实现的输入张量具有形状(batch_size、input_length、input_size),输出张量具有形状(batch_size、input_length、output_size)。由于TCN中的每一层都有相同的输入和输出长度,所以只有输入和输出张量的第三维是不同的。在单变量情况下,input_size和output_size都等于1。在更一般的多变量情况下,input_size和output_size可能不同,因为我们可能不希望预测输入序列的每个组件。
单个1D卷积层接收一个shape的输入张量(batch_size, input_length, nr_input_channels)并输出一个shape张量(batch_size, input_length, nr_output_channels)。为了了解单个层如何将其输入转换为输出,让我们看一下批处理的一个元素(对批处理中的每个元素都进行相同的处理)。让我们从最简单的例子开始,其中nr_input_channels和nr_output_channels都等于1。在这种情况下,我们看到的是一维输入和输出张量。下图显示了输出张量的一个元素是如何计算的。
我们可以看到,要计算输出的一个元素,我们需要查看输入的一系列长度为kernel_size的连续元素。在上面的例子中,我们选择了一个3的kernel_size。为了得到输出,我们取输入的子序列和相同长度的已学习权值的核向量的点积。输出的下一个元素,相同的应用程序,但kernel_size-sized窗口的输入序列是由一个元素转移到正确的(对于本预测模型,stride 总是设置为1)。请注意,相同的一组内核权重将被用来计算每输出一个卷积层。下图显示了两个连续的输出元素及其各自的输入子序列。
为了使可视化更简单,与核向量的点积不再显示,而是对每个具有相同核权重的输出元素发生。
为了确保输出序列与输入序列具有相同的长度,将应用一些零填充。这意味着在输入张量的开始或结束处添加额外的零值项,以确保输出具有所需的长度。后面的部分将详细解释如何做到这一点。
现在让我们看看有多个输入通道的情况,即nr_input_channels大于1。在本例中,上述过程对每个单独的输入通道都重复,但每次都使用不同的内核。这将导致nr_input_channels中间输出向量和kernel_size * nr_input_channels的一些内核权重。然后将所有中间输出向量相加,得到最终输出向量。在某种意义上,这相当于与一个形状的输入张量(input_size, nr_input_channels)和一个形状的内核张量(kernel_size, nr_input_channels)进行2D卷积,如下图所示。它仍然是一维的因为窗口只沿着一个轴移动,但是我们在每一步都有一个二维卷积因为我们使用的是一个二维核矩阵。
对于本例,我们选择nr_input_channels等于2。现在,我们使用nr_input_channels by kernel_size内核矩阵沿着nr_input_channels宽系列长度input_length来代替在一维输入序列上滑动的核向量。
如果nr_input_channels和nr_output_channels都大于1,那么对每个具有不同内核矩阵的输出通道重复上述过程。然后将输出向量堆叠在一起,得到一个形状的输出张量(input_length, nr_output_channels)。本例中的内核权重数等于kernel_sizenr_input_channelsnr_output_channels。
nr_input_channels和nr_output_channels这两个变量取决于该层在网络中的位置。第一层是nr_input_channels = input_size,最后一层是nr_output_channels = output_size。所有其他层将使用由num_filters提供的中间通道号。
因果卷积
对于因果关系,对于{0,…,input_length - 1}中的每一个i,输出序列的第i个元素可能只依赖于索引为{0,…,i}的输入序列中的元素。换句话说,输出序列中的元素只能依赖于输入序列中在它之前的元素。如前所述,为了确保一个输出张量与输入张量具有相同的长度,我们需要进行零填充。如果我们只在输入张量的左侧填充零,那么就可以保证因果卷积。要理解这一点,请考虑最右边的输出元素。假设输入序列的右边没有填充,它所依赖的最后一个元素就是输入的最后一个元素。现在考虑输出序列中倒数第二个输出元素。与最后一个输出元素相比,它的内核窗口向左移动了1,这意味着它在输入序列中最右边的依赖项是输入序列中倒数第二个元素。根据归纳,对于输出序列中的每个元素,其在输入序列中的最新依赖项与其本身具有相同的索引。下图展示了一个input_length为4,kernel_size为3的示例。
我们可以看到,在两个条目的左填充为零的情况下,我们可以获得相同的输出长度,同时遵守因果关系规则。事实上,在没有扩展的情况下,维持输入长度所需的零填充条目的数量总是等于kernel_size - 1。
扩张
预测模型的一种理想质量是输出中特定条目的值取决于输入中所有先前的条目,即索引小于或等于其自身的所有条目。当接受野(指影响输出的特定条目的原始输入的一组条目)的大小为input_length时,就可以实现这一点。我们也称其为“完整的历史记录”。正如我们以前看到的,一个传统的卷积层在输出中创建一个依赖于输入的kernel_size项的条目,这些条目的索引小于或等于它自己。例如,如果我们的kernel_size为3,那么输出中的第5个元素将依赖于输入中的元素3、4和5。当我们将多个层叠加在一起时,这个范围就会扩大。在下面的图中我们可以看到,通过kernel_size 3叠加两层,我们得到的接受野大小为5。
一般而言,具有n层且kernel_size为k的一维卷积网络的接收场r为
为了知道需要多少层才能完全覆盖,我们可以将接受野大小设为input_length l,然后求解层数n(非整数值需要进行四舍五入):
这意味着,kernel_size固定,完整的历史覆盖所需的层数是线性的输入长度的张量,这将导致网络变得非常深非常快,导致模型与大量的参数,需要更长的时间来训练。此外,大量的层已被证明会导致与损失函数梯度相关的退化问题。在保持层数相对较小的情况下,增加感受野大小的一种方法是向卷积网络引入膨胀概念。
卷积层上下文中的膨胀是指输入序列的元素之间的距离,该元素用于计算输出序列的一个条目。因此,传统的卷积层可以看作是dilated为1的扩散层,因为1个输出值的输入元素是相邻的。下图显示了一个dilated为2的扩散层的示例,其input_length为4,kernel_size为3。
与dilated-1扩散的情况相比,该层的接收场沿5而不是3的长度扩展。更普遍地,具有内核大小k的d扩散层的接收场沿1 + d的长度扩展。*(k-1)。如果d是固定的,那么仍然需要输入张量的长度为线性的数字才能实现完全的接收场覆盖(我们只是减小了常数)。
这个问题可以通过在层中向上移动时d的值呈指数增加来解决。为此,我们选择一个常数dilation_base整数b,它将使我们根据其下的层数i来计算特定层的膨胀d,即d = b ** i。下图显示了一个网络,其中input_length为10,kernel_size为3,dilation_base为2,这将导致3个膨胀的卷积层完全覆盖。