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. spring boot 拦截异常 统一处理

    spring boot 默认情况下会映射到 /error 进行异常处理,提示不友好,需要自定义异常处理,提供友好展示 1.自定义异常类(spring 对于 RuntimeException 异常才会进 ...

  2. python 匿名函数&内置函数

    匿名函数:为了解决那些功能很简单的需求而设计的一句话函数怎么定义匿名函数: cal = lambda x : x*x # cal是函数名,lambda是定义匿名函数的关键字 冒号前面的额x是参数即函数 ...

  3. 使用spring-session共享springmvc项目的session

    一.说在前面 spring mvc项目,使用nginx,tomcat部署. 之前没做session共享,而nginx采用sticky模块进行分发. 但发现有时不能正确地指向同一台服务器,从而导致ses ...

  4. 微信小程序商城开源项目,Weixin-App-Shop 1.0 版本正式发布!!!

    微信小程序商城开源项目,Weixin-App-Shop 1.0 版本正式发布 Weixin-App-Shop 是捷微团队开发的微信小程序商城开源项目,涵盖了微信商城的全部功能,能够快速发布简单易用的小 ...

  5. list<T>升序、降序

    List<test> list = new List<test> (); var result = list.OrderByDescending(p => p.we).T ...

  6. 最长公共前缀(python) leetcode答案

    直接上代码: def longestCommonPrefix(strs): """ :type strs: List[str] :rtype: str "&qu ...

  7. c#电子印章制作管理系统

    产品名称:电子印章制作管理系统 版  本  号:v0.0.0.1产品说明:本产品采用位图绘制方式,主要针对OA.ERP.金融等行业取代实物印章的一款产品,本产品有以下特点1.制作方便,容易操作2.规格 ...

  8. c++ 使用模板按类型统计stl多维容器中元素的数量

    struct ItemCounter{template<typename T1, typename T2, typename = typename std::enable_if<!std: ...

  9. ceph-deploy部署过程

    [root@ceph-1 my_cluster]# ceph-deploy --overwrite-conf osd create ceph-1 --data data_vg1/data_lv1 -- ...

  10. python 并发编程 锁 / 信号量 / 事件 / 队列(进程间通信(IPC)) /生产者消费者模式

    (1)锁:进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 虽然使用加锁的形式实现了 ...