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. 关于XML的小思考

    最近一段时间又接触了XML语言,现在看来它是一种可扩展标记语言,它的格式是标签语言,例如<>****<>此类,它在动态编译中有重要的作用,举个例子,一个班级里有37个人,到学期 ...

  2. 分布式 基本理论 CAP 2

    关于P P, 即 Partition字面意思是网络分区,其实 包括了 各种网络问题, 我们要把它理解 一个 广义的 分区问题. P 涉及到了 时间, 这么说吧, 出现了分区, 那就是节点之间 “长久的 ...

  3. mybatis学习 -每天一记(驼峰命名匹配)

    在mybatis 中,数据库表有一个与之对应的实体类.类属性的命名是驼峰命名的,所以在mybatis中要开启驼峰匹配, 在spring boot 的项目中,至需要在yml文件中配置 即可. 当然也有其 ...

  4. EF_简单的增删改查

    EF分为三种code_first,model_first,dabase_first这三种模式,网上的例子有好多,但是用了之后感觉实际中都不是这么用的,此处记录写下来日后用的着了可以快速应用,记录如下: ...

  5. myeclipse2017+ssm+tomcat8+jdk1.8

    练习上手ssm项目 工具:myeclipse2017,spring4,jdk1.8,tomcat8 搭建链接:https://www.cnblogs.com/cuglkb/p/6734666.html ...

  6. MySql:SELECT 语句(四)通配符的使用

    1. LIKE 操作符 要在搜索子句中使用通配符,必须要使用 LIKE 操作符. 1)百分号通配符 最常用的通配符是百分号(%). % 表示任何字符出现的任意次数.但是 NULL 除外.可以匹配 0 ...

  7. SHA-256算法和区块链原理初探

    组内技术分享的内容,目前网上相关资料很多,但读起来都不太合自己的习惯,于是自己整理并编写一篇简洁并便于(自己)理解和分享的文章. 因为之前对密码学没有专门研究,自己的体会或理解会特别标注为" ...

  8. sklearn中的SVM

    scikit-learn中SVM的算法库分为两类,一类是分类的算法库,包括SVC, NuSVC,和LinearSVC 3个类.另一类是回归算法库,包括SVR, NuSVR,和LinearSVR 3个类 ...

  9. keepliave

    keepalived的主要功能 1. healthcheck:           检查后端节点是否正常工作           如果发现后端节点异常,就将该异常节点从调度规则中删除:        ...

  10. python day05笔记总结

    2019.4.2 S21 day05笔记总结 一.昨日内容回顾与补充 1.extend(列表独有功能) 循环添加到一个列表中 a.有列表users = ['张三',‘李四]   people = [' ...