Convolutional LSTM Network: A Machine LearningApproach for Precipitation Nowcasting

这篇文章主要是了解方法.

原始文档: https://www.yuque.com/lart/papers/nvx1re

这篇文章主要提出了一种改进的卷积实现的LSTM结构. 从而更好的利用时空特征.

LSTM大致历史回顾

原始LSTM

圆圈是CEC, 里面是一条y = x的直线表示该神经元的激活函数是线性的,自连接的权重为1.

+ Forget Gate

+ Peehole

简化版示意图:

这里提到了参考文献2提出的一种改进LSTM结构, 较之前的LSTM的改进主要是添加了Peehole(窥视孔), 将细胞单元连接到了输入门, 遗忘门, 输出门上. 该文章中提到的FC-LSTM实际上就是这样的一类LSTM结构. 它的计算方法是:

其中的小圆圈表示哈达吗乘积, 也就是元素间的乘积运算. 可以看出来, 这里在输入门, 遗忘门, 输出门的输入上, 都考虑了细胞状态c_{t-1}, 与原始的LSTM不同

+ Convolution

本文的想法就是使用了卷及操作来代替矩阵乘法的操作.

虽然FC-LSTM层已被证明对处理时间相关性很有效, 但它对空间数据的处理, 包含太多冗余. FC-LSTM在处理时空数据时的主要缺点是它在输入到状态和状态到状态转换中使用全连接,其中没有空间信息被编码.

这里提出了FC-LSTM的扩展,它**在输入到状态和状态到状态转换中都具有卷积结构. **通过堆叠多个ConvLSTM层并形成编码预测结构,可以建立更一般的时空序列预测模型。

文章的设计的一个显着特点是所有输入X1, ..., Xt, 细胞输出C1, ..., Ct, 隐藏状态H1, ..., Ht, 和ConvLSTM的几个门it, ft, ot是都是3维张量, 它们的最后两个维度是空间维度(行和列).

这里的对应的公式如下:

如果将状态视为移动对象的隐藏表示,具有大转换核的ConvLSTM应该能够捕获更快的运动,而具有较小核的ConvLSTM能够捕获较慢的运动。此外, 前面FC-LSTM公式表示的输入, 细胞输出和隐藏状态, 也可以被视为3维张量. 只是它们最后两个维度为1. 在这个意义上, FC-LSTM实际上是ConvLSTM的一个特例, 其中所有特征都"站"在一个单元格上.

  • 为了确保状态具有与输入相同的行数和相同的列数,在应用卷积运算之前需要padding。这里边界点上隐藏状态的填充可以被视为使用外部世界的状态进行计算
  • 通常,在第一个输入到来之前,将LSTM的所有状态初始化为零,这对应于对于未来的“完全无知”

类似地,如果对隐藏状态执行零填充(在本文中使用),实际上将外部世界的状态设置为零并且假设没有关于外部的预知。通过填充状态,可以区别对待边界点,这在许多情况下是有帮助的。例如,假设观察的系统是被墙围绕的移动球。虽然看不到这些墙,但们可以通过一次又一次地发现球在它们上面弹跳来推断它们的存在,如果边界点具有与内点相同的状态转移动力学(the same state transition dynamics),则很难做到这一点。

编解码结构

与FC-LSTM一样,ConvLSTM也可以作为更复杂结构的构建块。对于我们的时空序列预测问题,我们使用图3所示的结构,它包括两个网络,一个编码网络和一个预测网络。预测网络的初始状态和单元输出是从编码网络的最后状态复制的。两个网络都是通过堆叠多个ConvLSTM层形成的。

由于我们的预测目标与输入具有相同的维度,我们将预测网络中的所有状态连接起来并将它们馈送到1x1卷积层以生成最终预测。

代码启发

这里代码的实现, 让我学习到了对于LSTM处理图片类的数据的时候, (时空)计算的特殊之处. 时间步 和不同 ConvLSTMCell 的堆叠之间, 有关联有分离. 同一时间步内, 会存在多个Cell的堆叠计算, 而只输入一次原始数据, 并且, 每一个Cell的输出都会作为下一时间步的输入, 同时, 在下一时间步里, 原始输入还是一样的. 整体时间步展开, 构成了一个网格状的结构. 关键的一点是, 每个时间步对应的Cell的卷积权重是一致的. 因为使用的是相同的卷积层.

        self._all_layers = []
for i in range(self.num_layers):
name = 'cell{}'.format(i)
cell = ConvLSTMCell(self.input_channels[i],
self.hidden_channels[i],
self.kernel_size,
self.bias)
# 设定 self.cell{i} = cell 很好的方法, 值得借鉴, 后期添加属性
setattr(self, name, cell)
self._all_layers.append(cell)

大致手绘了一下时间步为5, 每个时间步有5个Cell的展开结构:

代码参考

import torch
import torch.nn as nn class ConvLSTMCell(nn.Module):
def __init__(self, input_channels, hidden_channels, kernel_size, bias=True):
super(ConvLSTMCell, self).__init__() assert hidden_channels % 2 == 0 self.input_channels = input_channels
self.hidden_channels = hidden_channels
self.bias = bias
self.kernel_size = kernel_size
self.num_features = 4 # N=(W?F+2P)/S+1
self.padding = int((kernel_size - 1) / 2) self.Wxi = nn.Conv2d(self.input_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=True)
self.Whi = nn.Conv2d(self.hidden_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=False) self.Wxf = nn.Conv2d(self.input_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=True)
self.Whf = nn.Conv2d(self.hidden_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=False) self.Wxc = nn.Conv2d(self.input_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=True)
self.Whc = nn.Conv2d(self.hidden_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=False) self.Wxo = nn.Conv2d(self.input_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=True)
self.Who = nn.Conv2d(self.hidden_channels, self.hidden_channels,
self.kernel_size, 1, self.padding, bias=False) self.Wci = None
self.Wcf = None
self.Wco = None def forward(self, x, h, c):
ci = torch.sigmoid(self.Wxi(x) + self.Whi(h) + c * self.Wci)
cf = torch.sigmoid(self.Wxf(x) + self.Whf(h) + c * self.Wcf)
cc = cf * c + ci * torch.tanh(self.Wxc(x) + self.Whc(h))
co = torch.sigmoid(self.Wxo(x) + self.Who(h) + cc * self.Wco)
ch = co * torch.tanh(cc)
return ch, cc def init_hidden(self, batch_size, hidden, shape):
self.Wci = torch.zeros(1, hidden, shape[0], shape[1]).cuda()
self.Wcf = torch.zeros(1, hidden, shape[0], shape[1]).cuda()
self.Wco = torch.zeros(1, hidden, shape[0], shape[1]).cuda()
return torch.zeros(batch_size, hidden, shape[0], shape[1]).cuda(), \
torch.zeros(batch_size, hidden, shape[0], shape[1]).cuda() class ConvLSTM(nn.Module):
# input_channels corresponds to the first input feature map
# hidden state is a list of succeeding lstm layers.
def __init__(self,
input_channels,
hidden_channels,
kernel_size,
step=2,
effective_step=[1],
bias=True):
"""
:param input_channels: 输入通道数
:param hidden_channels: 隐藏通道数, 是个列表, 可以表示这个ConvLSTM内部每一层结构
:param kernel_size: 卷积实现对应的核尺寸
:param step: 该ConvLSTM自身总的循环次数
:param effective_step: 输出中将要使用的步数(不一定全用)
:param bias: 各个门的偏置项
"""
super(ConvLSTM, self).__init__() self.input_channels = [input_channels] + hidden_channels
self.hidden_channels = hidden_channels
self.kernel_size = kernel_size
self.num_layers = len(hidden_channels)
self.step = step
self.bias = bias
self.effective_step = effective_step self._all_layers = []
for i in range(self.num_layers):
name = 'cell{}'.format(i)
cell = ConvLSTMCell(self.input_channels[i],
self.hidden_channels[i],
self.kernel_size,
self.bias)
# 设定 self.cell{i} = cell 很好的方法, 值得借鉴, 后期添加属性
setattr(self, name, cell)
self._all_layers.append(cell) def forward(self, input):
internal_state = []
outputs = []
for step in range(self.step):
"""
每个时间步里都要进行对原始输入`input`的多个ConvLSTMCell的的级联处理.
而第一个时间步里, 设定各个ConvLSTMCell所有的初始h与c都是0.
各个ConvLSTMCell的输出h和c都是下一个时间步下对应的ConvLSTMCell的输入用的h和c,
各个ConvLSTMCell的输入都是同一时间步下上一个ConvLSTMCell的输出的h(作为input项)
和自身对应的h和c.
"""
x = input # 对每种隐藏状态尺寸来进行叠加
for i in range(self.num_layers):
# all cells are initialized in the first step
name = f'cell{i}' # 初始化各个ConvLSTM的门里的Peehole权重为0
if step == 0:
bsize, _, height, width = x.size() # getattr获得了对应的self.cell{i}的值, 也就是对应的层
(h, c) = getattr(self, name).init_hidden(
batch_size=bsize,
hidden=self.hidden_channels[i],
shape=(height, width)
)
# 第一步里的h和c都是0
internal_state.append((h, c)) # do forward
(h, c) = internal_state[i]
x, new_c = getattr(self, name)(x, h, c)
# update new h&c
internal_state[i] = (x, new_c)
# only record effective steps
if step in self.effective_step:
outputs.append(x) return outputs, (x, new_c)

使用方法:

if __name__ == '__main__':
# gradient check
convlstm = ConvLSTM(input_channels=512,
hidden_channels=[128, 64, 64, 32, 32],
kernel_size=3,
step=2, # 这里最后会判定有效的步的输出, 要判定是否step in eff_steps, 所以得保证step可能在列表中
effective_step=[1]).cuda()
loss_fn = torch.nn.MSELoss() input = torch.randn(1, 512, 64, 32).cuda()
target = torch.randn(1, 32, 64, 32, requires_grad=True, dtype=torch.float64).cuda() output, (x, new_c) = convlstm(input)
print(output[0].size())
output = output[0].double()
res = torch.autograd.gradcheck(loss_fn,
(output, target),
eps=1e-6,
raise_exception=True)
print(res) # 输出
# torch.Size([1, 32, 64, 32])
# True

参考文章

  1. Generating Sequences With Recurrent Neural Networks
  2. 关于Peehole的改进的提出: https://www.researchgate.net/publication/2562741_Long_Short-Term_Memory_in_Recurrent_Neural_Networks?enrichId=rgreq-8d9f795da6b29cae037bf9e0cb943d7a-XXX&enrichSource=Y292ZXJQYWdlOzI1NjI3NDE7QVM6MzcxMDEwMjU2ODE4MTc2QDE0NjU0NjcxNDYwMjU%3D&el=1_x_3&_esc=publicationCoverPdf
  3. https://blog.csdn.net/xmdxcsj/article/details/52526843
  4. https://blog.csdn.net/shincling/article/details/49362161
  5. https://blog.csdn.net/sinat_26917383/article/details/71817742
  6. 文中代码来自: https://github.com/automan000/Convolution_LSTM_PyTorch

Convolutional LSTM Network: A Machine LearningApproach for Precipitation Nowcasting的更多相关文章

  1. 论文翻译:2019_TCNN: Temporal convolutional neural network for real-time speech enhancement in the time domain

    论文地址:TCNN:时域卷积神经网络用于实时语音增强 论文代码:https://github.com/LXP-Never/TCNN(非官方复现) 引用格式:Pandey A, Wang D L. TC ...

  2. 1 - ImageNet Classification with Deep Convolutional Neural Network (阅读翻译)

    ImageNet Classification with Deep Convolutional Neural Network 利用深度卷积神经网络进行ImageNet分类 Abstract We tr ...

  3. 论文翻译:2020_FLGCNN: A novel fully convolutional neural network for end-to-end monaural speech enhancement with utterance-based objective functions

    论文地址:FLGCNN:一种新颖的全卷积神经网络,用于基于话语的目标函数的端到端单耳语音增强 论文代码:https://github.com/LXP-Never/FLGCCRN(非官方复现) 引用格式 ...

  4. 论文阅读(Weilin Huang——【TIP2016】Text-Attentional Convolutional Neural Network for Scene Text Detection)

    Weilin Huang--[TIP2015]Text-Attentional Convolutional Neural Network for Scene Text Detection) 目录 作者 ...

  5. [notes] ImageNet Classification with Deep Convolutional Neual Network

    Paper: ImageNet Classification with Deep Convolutional Neual Network Achievements: The model address ...

  6. 卷积神经网络(Convolutional Neural Network,CNN)

    全连接神经网络(Fully connected neural network)处理图像最大的问题在于全连接层的参数太多.参数增多除了导致计算速度减慢,还很容易导致过拟合问题.所以需要一个更合理的神经网 ...

  7. Convolutional Neural Network in TensorFlow

    翻译自Build a Convolutional Neural Network using Estimators TensorFlow的layer模块提供了一个轻松构建神经网络的高端API,它提供了创 ...

  8. 论文阅读(Weilin Huang——【arXiv2016】Accurate Text Localization in Natural Image with Cascaded Convolutional Text Network)

    Weilin Huang——[arXiv2016]Accurate Text Localization in Natural Image with Cascaded Convolutional Tex ...

  9. 卷积神经网络(Convolutional Neural Network, CNN)简析

    目录 1 神经网络 2 卷积神经网络 2.1 局部感知 2.2 参数共享 2.3 多卷积核 2.4 Down-pooling 2.5 多层卷积 3 ImageNet-2010网络结构 4 DeepID ...

随机推荐

  1. 性能测试Jmeter压测ZooKeeper-自定义java请求

     要想通过自定义java请求来压测ZooKeeper,那么我们就需要做两件事情,第一我们需要知道java如何操作ZooKeeper,第二就是怎么能将我们写的jar包让jmeter识别,首先我们先来干第 ...

  2. How does the compilation and linking process work?

    The compilation of a C++ program involves three steps: Preprocessing: the preprocessor takes a C++ s ...

  3. springboot+VUE(一)

    https://segmentfault.com/blog/wangjihong 安装nodejs与NPM 下载nodejs的LTL版本,并安装 https://nodejs.org/en/ 执行no ...

  4. Oracle的SQL优化思路

    个人总结SQL脚本优化,大体如下: (1)选择最有效率的表名顺序(只在基于规则的优化器中有效): ORACLE解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表dir ...

  5. IntelliJ IDEA 集成 SVN

    在idea中使用subversion提交代码需要使用SVN SVN下载官网:https://tortoisesvn.net/downloads.html 可以根据自己电脑下载相应的版本,如果安装了的需 ...

  6. redis基本数据结构

    redis5中数据类型

  7. springboot学习随笔(三):Controller参数映射

    接上章内容,我们看看浏览器参数如何映射到我们的Controller层 我们新建UserController和User实 User.java package com.example.main; impo ...

  8. dojo里添加目录树

    其实循环生成目录树这个方法不仅仅局限于在使用dojo的情况下,只要明白了其中的原理,在任何一种语言下都能动态循环生成. 1. 数据结构 在这里先说明一下数据结构,我这里循环生成目录树的数据结构是像这样 ...

  9. window django-https 证书

    1.openssl 下载 http://slproweb.com/products/Win32OpenSSL.html 根据你的系统来选择不同的版本下载安装,选带light的比较小. 2.安装后添加环 ...

  10. Linux 总线、设备、驱动模型 与 设备树

    1.总线.设备.驱动模型 本着高内聚.低耦合的原则,Linux 把设备驱动模型分为了总线.设备和驱动三个实体,这三个实体在内核里的职责分别如下: 设备和驱动向总线进行注册,总线负责把设备和对应的驱动绑 ...