前言:传统的时序处理,普遍采用RNN做为基础网络模型,如其变体LSTM、GRU、BPTT等。但是在处理使用LSTM时时序的卷积神经网络


目录

  • 论文及代码链接
  • 一、论文解读
    • 1、 摘要
    • 2、引言(摘)
    • 3、时序卷积神经网络(Temporal Convolutional Networks)
      • 3.1 因果卷积(Causal Convolution)
      • 3.2 膨胀卷积(Dilated Convolution)
      • 3.3 残差连接(Residual Connections)
  • 二、源码解读
  • 三、总结分析
    • 1、优点
    • 2、缺点
  • 参考致谢

论文及代码链接

Paper:An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence Modeling
Code:Github:https://github.com/LOCUSLAB/tcn


一、论文解读

1、 摘要

   对于大多数deeplearning工作者,序列模型与RNN几乎是密不可分(这是因为RNN天生的循环自回归的结构是对时间序列的很好的表示)。然而,最新的一项研究表明,卷积结构在音频合成和机器翻译等tasks上效果可以优于递归神经网络。给定一个新的序列建模tasks或者是数据集,使用什么样的架构呢?论文对序列建模的通用卷积和递归结构进行了系统的评估。通过大量全面的标准tasks,对模型中进行评估,其中这些tasks通常用于递归网络的基准测试。论文研究表明,一个简单的卷积结构在不同的tasks和数据集上优于典型的递归神经网络,如LSTMs,同时卷积表现出更长的有效memory。论文的结论是序列建模和递归网络之间的共同联系应该重新考虑,卷积网络应该被认为是序列建模tasks的新的,自然的网路结构(natural starting point) 。

2、引言(摘)

  为了表示卷积网络,论文描述了一个通用的时间卷积网络(TCN)体系结构,它应用于所有的tasks。这种架构是由最近的研究进行了改进,特意保留了结构的简单性,结合了现代卷积架构的一些最佳实践经验。并与典型的递归体系结构(如LSTMs和GRUs)进行了比较。
  结果表明,TCNs在大量的序列建模任务中明显优于基线递归架构。这一点尤其值得注意,因为这些任务包括各种各样的基准,这些基准通常用于评估网络设计。这表明卷积结构最新在音频处理等应用中取得了成功,但并不局限于这些领域。
  为了进一步了解这些结论,作者深入分析了递归网络的记忆(memory)保持特性。结果表明,尽管递归结构理论上具有捕捉无限长时间的能力,但总的来说TCNs仍然表现出更长的记忆能力,TCNs更适用于长时间记忆的领域。
  总结:论文的研究是关于序列建模任务的卷积和递归结构的系统比较。结果表明,序列建模和递归网络之间的共同联系应该重新考虑。TCN体系结构不仅比LSTMs和GRUs等典型的递归网络更加精确,而且更加简单明了。因此,它可能是将深度网络应用于序列的更佳方法的起点(starting point)。

3、时序卷积神经网络(Temporal Convolutional Networks)

3.1 因果卷积(Causal Convolution)


  图片是是参考waveNet,可以用上图直观表示。 即对于上一层t时刻的值,只依赖于下一层t时刻及其之前的值。和传统的卷积神经网络的不同之处在于,因果卷积不能看到未来的数据,它是单向的结构,不是双向的。也就是说只有有了前面的因才有后面的果,是一种严格的时间约束模型,因此被成为因果卷积。但是问题就来,如果我要考虑很久之前的变量x,那么卷积层数就必须增加。卷积层数的增加就带来:梯度消失,训练复杂,拟合效果不好的问题,为了决绝这个问题,出现了扩展卷积(dilated)。

3.2 膨胀卷积(Dilated Convolution)


  对于因果卷积,存在的一个问题是需要很多层或者很大的filter来增加卷积的感受野。本文中,作者通过大小排列来的扩大卷积来增加感受野。扩大卷积(dilated convolution)是通过跳过部分输入来使filter可以应用于大于filter本身长度的区域。等同于通过增加零来从原始filter中生成更大的filter。d=1,2,4,8,16,…,膨胀系数为2的阶乘,膨胀卷积如上图所示。公式表达如下:F(s)=(x∗df)(s)=∑i=0k−1f(i)⋅xs−d⋅iF(s)=(x*_df)(s)=\sum^{k-1}_{i=0}f(i)\cdot x_{s-d\cdot i} F(s)=(x∗d​f)(s)=i=0∑k−1​f(i)⋅xs−d⋅i​

  论文采用的膨胀卷积为有"交叉"的一维卷积,膨胀系数d为1,2,4。

3.3 残差连接(Residual Connections)


我初次接触残差连接,是阅读何凯明大神的ResNet论文接触的,论文通过简单的残差连接,一定程度上消除了深度网络部分梯度消失和爆炸的影响。并且残差连接被证明是训练深层网络的有效方法,它使得网络可以以跨层的方式传递信息。论文构建了一个残差块,由于防止出现输入处理过程中出现维度变化,或者是为原始数据增加权重,增加训练参数。很多论文中都用到,例如CVPR2019的2s-GCN。如上图所示,一个残差块包含两层的卷积和非线性映射,在每层中还加入了WeightNorm和Dropout来正则化网络。

  总体来讲,TCN模型比较简,论文主要是将TCN的结构梳理了一下,感觉和wavenet很像,作者也说了参考了waveNet,加入了残差结构,并在很多的序列问题上进行了实验。实验效果如下:

二、源码解读

  论文给出了源代码,采用pytorch架构。由于是对TCN进行分析和总结,所以在不同的序列数据集上进行训练,证明了TCN结构的泛化能力。本小白将代码的主要结构简单的讲解,如有理解错误,希望大佬指正,不胜感激。
  以Mnist数据集为例mnist_pixel。作者将手写数字矩阵28x28矩阵,扩展成一维Sequence:1x784。batch_size=64,所以最后的序列结构为64x1x784。一张图片为1x784的序列矩阵,每一批次64张。论文代码简洁,清晰,有利于对TCN的深入了解。
TCN模型
剪枝,一维卷积后会出现多余的padding。

class Chomp1d(nn.Module):def __init__(self, chomp_size):super(Chomp1d, self).__init__()# 表示对继承自父类属性进行初始化self.chomp_size = chomp_sizedef forward(self, x):"""其实这就是一个裁剪的模块,裁剪多出来的paddingtensor.contiguous()会返回有连续内存的相同张量有些tensor并不是占用一整块内存,而是由不同的数据块组成tensor的view()操作依赖于内存是整块的,这时只需要执行contiguous()函数,就是把tensor变成在内存中连续分布的形式本函数主要是增加padding方式对卷积后的张量做切边而实现因果卷积"""return x[:, :, :-self.chomp_size].contiguous()

时序模块,两层一维卷积,两层Weight_Norm,两层Chomd1d,非线性激活函数为Relu,dropout为0.2。

class TemporalBlock(nn.Module):def __init__(self, n_inputs, n_outputs, kernel_size, stride, dilation, padding, dropout=0.2):"""相当于一个Residual block:param n_inputs: int, 输入通道数:param n_outputs: int, 输出通道数:param kernel_size: int, 卷积核尺寸:param stride: int, 步长,一般为1:param dilation: int, 膨胀系数:param padding: int, 填充系数:param dropout: float, dropout比率"""super(TemporalBlock, self).__init__()self.conv1 = weight_norm(nn.Conv1d(n_inputs, n_outputs, kernel_size,stride=stride, padding=padding, dilation=dilation))# 经过conv1,输出的size其实是(Batch, input_channel, seq_len + padding)self.chomp1 = Chomp1d(padding)  # 裁剪掉多出来的padding部分,维持输出时间步为seq_lenself.relu1 = nn.ReLU()self.dropout1 = nn.Dropout(dropout)self.conv2 = weight_norm(nn.Conv1d(n_outputs, n_outputs, kernel_size,stride=stride, padding=padding, dilation=dilation))self.chomp2 = Chomp1d(padding)  # 裁剪掉多出来的padding部分,维持输出时间步为seq_lenself.relu2 = nn.ReLU()self.dropout2 = nn.Dropout(dropout)self.net = nn.Sequential(self.conv1, self.chomp1, self.relu1, self.dropout1,self.conv2, self.chomp2, self.relu2, self.dropout2)self.downsample = nn.Conv1d(n_inputs, n_outputs, 1) if n_inputs != n_outputs else Noneself.relu = nn.ReLU()self.init_weights()def init_weights(self):"""参数初始化:return:"""self.conv1.weight.data.normal_(0, 0.01)self.conv2.weight.data.normal_(0, 0.01)if self.downsample is not None:self.downsample.weight.data.normal_(0, 0.01)def forward(self, x):""":param x: size of (Batch, input_channel, seq_len):return:"""out = self.net(x)res = x if self.downsample is None else self.downsample(x)return self.relu(out + res)

时序卷积模块,使用for循环对8层隐含层,每层25个节点进行构建。模型如下。其中*layer不是c中的指针,困惑了笔者一段时间,之后查看资料知道 * 表示迭代器拆分layers为一层层网络。

class TemporalConvNet(nn.Module):def __init__(self, num_inputs, num_channels, kernel_size=2, dropout=0.2):"""TCN,目前paper给出的TCN结构很好的支持每个时刻为一个数的情况,即sequence结构,对于每个时刻为一个向量这种一维结构,勉强可以把向量拆成若干该时刻的输入通道,对于每个时刻为一个矩阵或更高维图像的情况,就不太好办。:param num_inputs: int, 输入通道数:param num_channels: list,每层的hidden_channel数,例如[25,25,25,25]表示有4个隐层,每层hidden_channel数为25:param kernel_size: int, 卷积核尺寸:param dropout: float, drop_out比率"""super(TemporalConvNet, self).__init__()layers = []num_levels = len(num_channels)for i in range(num_levels):dilation_size = 2 ** i  # 膨胀系数:1,2,4,8……in_channels = num_inputs if i == 0 else num_channels[i - 1]  # 确定每一层的输入通道数,输入层通道为1,隐含层是25。out_channels = num_channels[i]  # 确定每一层的输出通道数layers += [TemporalBlock(in_channels, out_channels, kernel_size, stride=1, dilation=dilation_size,padding=(kernel_size - 1) * dilation_size, dropout=dropout)]self.network = nn.Sequential(*layers)   # *作用是将输入迭代器拆成一个个元素def forward(self, x):"""输入x的结构不同于RNN,一般RNN的size为(Batch, seq_len, channels)或者(seq_len, Batch, channels),这里把seq_len放在channels后面,把所有时间步的数据拼起来,当做Conv1d的输入尺寸,实现卷积跨时间步的操作,很巧妙的设计。:param x: size of (Batch, input_channel, seq_len):return: size of (Batch, output_channel, seq_len)"""return self.network(x)

TCN模块,创新点1D·FCN,最后采用softmax进行分类。

class TCN(nn.Module):def __init__(self, input_size, output_size, num_channels, kernel_size, dropout):super(TCN, self).__init__()self.tcn = TemporalConvNet(input_size, num_channels, kernel_size=kernel_size, dropout=dropout)self.linear = nn.Linear(num_channels[-1], output_size)def forward(self, inputs):"""Inputs have to have dimension (N, C_in, L_in)"""y1 = self.tcn(inputs)  # input should have dimension (N, C, L)o = self.linear(y1[:, :, -1])# 增加一个维度,1D·FCNreturn F.log_softmax(o, dim=1)

三、总结分析

通过网络图可知,TCN感受野可控,并且结构简单,速度更快。优缺点总结如下,感谢作者满腹的小不甘。

1、优点

(1)并行性。当给定一个句子时,TCN可以将句子并行的处理,而不需要像RNN那样顺序的处理。
(2)灵活的感受野。TCN的感受野的大小受层数、卷积核大小、扩张系数等决定。可以根据不同的任务不同的特性灵活定制。
(3)稳定的梯度。RNN经常存在梯度消失和梯度爆炸的问题,这主要是由不同时间段上共用参数导致的,和传统卷积神经网络一样,TCN不太存在梯度消失和爆炸问题。
(4)内存更低。RNN在使用时需要将每步的信息都保存下来,这会占据大量的内存,TCN在一层里面卷积核是共享的,内存使用更低。

2、缺点

(1)TCN 在迁移学习方面可能没有那么强的适应能力。这是因为在不同的领域,模型预测所需要的历史信息量可能是不同的。因此,在将一个模型从一个对记忆信息需求量少的问题迁移到一个需要更长记忆的问题上时,TCN 可能会表现得很差,因为其感受野不够大。
(2)论文中描述的TCN还是一种单向的结构,在语音识别和语音合成等任务上,纯单向的结构还是相当有用的。但是在文本中大多使用双向的结构,当然将TCN也很容易扩展成双向的结构,不使用因果卷积,使用传统的卷积结构即可。
(3)TCN毕竟是卷积神经网络的变种,虽然使用扩展卷积可以扩大感受野,但是仍然受到限制,相比于Transformer那种可以任意长度的相关信息都可以抓取到的特性还是差了点。TCN在文本中的应用还有待检验。

参考致谢

cv小白,学习借鉴,如有侵权,通知即删。如有出错,希望指正,不胜感激。
TCN时间卷积网络 - 剪水作花飞的文章 - 知乎
TCN-时间卷积网络-满腹的小不甘-CSDN
【NLP】因果卷积(causal)与扩展卷积(dilated)-阿木鸣
[1]:Bai S , Kolter J Z , Koltun V . An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence Modeling[J]. 2018.

TCN论文及代码解读总结相关推荐

  1. Memory-Associated Differential Learning论文及代码解读

    Memory-Associated Differential Learning论文及代码解读 论文来源: 论文PDF: Memory-Associated Differential Learning论 ...

  2. EGNet: Edge Guidance Network for Salient Object Detection 论文及代码解读

    EGNet: Edge Guidance Network for Salient Object Detection 论文及代码解读 注:本文原创作者为Jia-Xing Zhao, Jiang-Jian ...

  3. VGAE(Variational graph auto-encoders)论文及代码解读

    一,论文来源 论文pdf Variational graph auto-encoders 论文代码 github代码 二,论文解读 理论部分参考: Variational Graph Auto-Enc ...

  4. 一文详解单目VINS论文与代码解读目录

    本文旨在对前一阶段学习vins-mono开源框架的总结.结合暑假秋招之前报名的深蓝学院的<从零开始手写VIO>课程,本文从VIO原理以及开源代码分析两部分进行详细介绍.PS:提升代码能力最 ...

  5. LSS-lift splat shoot论文与代码解读

    目录 序言 论文 代码 总结 序言 最近开始学习多摄融合领域了,定义是输入为多个摄像机图像,获得多个视角的相机图像特征,通过相机内外参数进行特征映射到BEV视角,得到360°的视觉感知结果,今天分享的 ...

  6. Exploiting Shared Representations for Personalized Federated Learning 论文笔记+代码解读

    论文地址点这里 一. 介绍 联邦学习中由于各个客户端上数据异构问题,导致全局训练模型无法适应每一个客户端的要求.作者通过利用客户端之间的共同代表来解决这个问题.具体来说,将数据异构的联邦学习问题视为并 ...

  7. 融合transformer和对抗学习的多变量时间序列异常检测算法TranAD论文和代码解读...

    一.前言 今天的文章来自VLDB TranAD: Deep Transformer Networks for Anomaly Detection in Multivariate Time Series ...

  8. Selective Search for Object Recognition(IJCV 2013) 论文及代码解读

    这篇论文已经被很多人解读过啦,以下是传送门: Selective Search for Object Recognition Selective Search for Object Recogniti ...

  9. 【Pranet】论文及代码解读(ResNet部分)——jialiang nie

    1.ResNet结构简介 ResNet--残差神经网络最重要的一个思想在于对接收的数据进行卷积等一系列操作后(F(x)),再与自身的identity(x)进行相加(即F(x)+x),之后一起经过rel ...

最新文章

  1. python中的daemon守护进程实现方法
  2. loadrunner 调用java_LoadRunner调用Java程序—性能测试
  3. 防止SQL注入解决方案
  4. lnmp、lamp、lnmpa一键安装包
  5. 我的Go+语言初体验——【三、spx案例测试(附-视频)】
  6. oracle查询大小写敏感参数,让Oracle 大小写敏感 表名 字段名 对像名
  7. 程序发出的广播其他程序收不到_RabbitMQ 如何实现对同一个应用的多个节点进行广播...
  8. linux运行tdbshutdown,Converting Oracle Database from Linux to Windows using RMAN
  9. logstash关于date时间处理的几种方式总结
  10. html tab标签_如何用HTML写一个网页
  11. 工业企业数据库处理——2.匹配样本
  12. 【小项目】STM32环境监测 | MQ2可燃气体传感器+雨滴传感器+DHT11温湿度传感器+OLED屏幕
  13. 生信技能树课程记录笔记(四)20220527
  14. 经典算法详解(2):费氏数列
  15. 电源的环路补偿、功率级补偿、Vout的波形对应的响应速度-运放环路补偿
  16. 被谷歌出卖定位信息成“嫌疑犯”,花了大价钱才避免窦娥冤 | 一个自行车爱好者自述...
  17. win10装win7遇到的问题。
  18. 中南大学移动宽带连接路由器解决方案
  19. 使用html+css完成仿站操作要点
  20. AsyncHttpClient源码分析-基于Netty的连接池实现

热门文章

  1. css概述、选择器以及样式属性
  2. linux c 检测程序是否运行环境,Linux下用C语言判断程序是否已运行
  3. linux下c语言抓包,C语言实现抓包工具
  4. 打开oracle的sqlplus的方式
  5. Spring源码分析4 — spring bean创建和初始化
  6. 我找到了 4 个 Midjourney 的免费替代品,停止为 Midjourney 付费,有免费的 AI 替代品
  7. 拼图软件哪个好用?分享几款好用拼图工具
  8. 岭回归算法的原理和代码实战
  9. python画出roc曲线 auc计算逻辑_Python画ROC曲线和AUC值计算
  10. 微信支付JsApi 40163错误