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. QMap迭代器

    QMap<int, QString> intToStr; intToStr[] = "test" for (auto iter = intToStr.begin(); ...

  2. Mac 端配置 Lua 环境

    一.设计目的 Lua 是一种轻量级的脚本语言,其目的是为了嵌入到程序中,从而为程序提供灵活的扩展和定制功能. 二.特性 轻量级:编译后仅仅 100 余K,可以很方便的嵌入到程序中. 可扩展:Lua 提 ...

  3. vue每次修改刷新当前子组件

    刚入门vue,发现很多坑,对很多框架兼容性不太友好,比如layui等 每次删除相关信息,更新相关信息,不会主动刷新当前页面内容,只能手动刷新 第一步,我们在跟组件理由设置一个参数,用来判断是否需要刷新 ...

  4. JVM内存模型和面试题解析

    一.JVM运行时区域 其中, 线程私有的:程序计数器,虚拟机栈,本地方法栈 线程共享的:堆,方法区,直接内存 1 程序计数器 程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示 ...

  5. json与csv的基础用与法

    json库是处理json格式的python标准库 有两个过程: 编码(encoding):将python数据类型转换为json格式的过程 解码(decoding):从json格式中解析数据得到的pyt ...

  6. C++并发编程学习笔记

    // //  main.cpp //  test1 // //  Created by sofard on 2018/12/27. //  Copyright © 2018年 dapshen. All ...

  7. Python-基础函数与常用模块考核

    第二模块考核(2019/ 03/ 03) ### 第一模块内容1.请写出 “路飞学城alex” 分别用utf - 8和gbk编码所占的位数(口述) ➜ ~ python3 >>> b ...

  8. easyui-textbox多行文本中输入内容,有回车操作时将文本拼接<br/>

    <input class="easyui-textbox" name="versionText" id="versionText" d ...

  9. ArcGIS 批量修改数据名称-arcgis案例实习教程

    ArcGIS 批量修改数据名称-arcgis案例实习教程 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 功能:批量修改数据/文件名称 使用方法: 输入:文件夹(或者 ...

  10. css预处理器:Sass LASS Stylus

    语法 Sass h1 { color: #0982C1; } h1 color: #0982c1 LESS h1 { color: #0982C1; } Stylus /* style.styl */ ...