赞
踩
目录
本周我阅读了一篇题为《Convolutional LSTM Network: A Machine Learning Approach for Precipitation Nowcasting》的文献。该文献主要介绍了ConvLSTM结构,并将其应用于降水预测,取得了令人满意的结果。随后,我手动推导了一遍RNN的前向传播过程,以便更好地理解RNN的计算过程,并弄清了其中参数维度的变化。此外,我还学习了张量的基础知识,对张量有了初步的认识。
This week, I read a paper titled "Convolutional LSTM Network: A Machine Learning Approach for Precipitation Nowcasting." The paper primarily introduces the ConvLSTM structure and its application in precipitation forecasting, achieving satisfactory results. Afterwards, I manually derived the forward propagation process of an RNN to gain a better understanding of its computational process and to clarify the changes in parameter dimensions. Additionally, I also studied the fundamentals of tensors, which provided me with a preliminary understanding of tensors.
题目:Convolutional LSTM Network: A Machine Learning Approach for Precipitation Nowcasting
文章链接:https://arxiv.org/pdf/1506.04214.pdf
文章研究的主要内容是预测一个地区在短时间内的降雨强度,文章将降水临近预报定义为一个时空序列预测问题,输入以及预测目标都是时空序列,根据这些特点,然后提出了ConvLSTM,并且于FC-LSTM以及ROVER进行了比较,并得出了新提出的模型的表现要比现有最优算法的表现还要好的结果。
The main content of the paper is predicting rainfall intensity over a short period of time in a region. The study defines near-term precipitation forecasting as a spatio-temporal sequence prediction problem, where both the inputs and prediction targets are spatio-temporal sequences. Based on these characteristics, the paper proposes ConvLSTM and compares it with FC-LSTM and ROVER. The results show that the performance of the newly proposed model is better than that of the existing optimal algorithms.
FC-LSTM在处理时空数据方面的主要缺点是它在没有进行空间信息编码的输入到状态和状态到状态的转换中使用了完全连接,缺乏空间信息的提取;所以,文章设计了ConvLSTM:
三个输入,记忆单元、隐藏状态和输入X都由一维变为三维张量
使用Zero-padding来进行填充C和H,达到和X的行数和列数是一样的。作者也解释了Zero-padding的好处。
该过程的方程如下所示:
*表示卷积,⭕是hadamard积。公式其实就是把input-to-state, state-to-state 的正常乘积运算,用术语叫做hadamard乘积,改为卷积运算
本质上没有变化,做的事情基本上是将向量与权重的乘积,换成了卷积,这样能大大减少参数量。
现代的降水预报方法大致分为两类:
一、数值天气预报(NWP):指根据大气实况,在一定的初值和边界条件下,通过大型计算机作数值计算,求解描写天气演变过程的流体力学和热力学的方程组,预测未来一定时间段的大气运动状态和天气现象的方法。但是其对于即时预报需要十分复杂的过程;
二、雷达外推方法:主要是通过模型训练来预测云层的移动,可以充分的利用雷达回波图历史数据,有效的捕获时空相关性。但是由于流量估计步骤和雷达回波外推步骤是分开的,并且很难确定模型参数以提供良好的预测性能,从而限制了其发挥;
1、将2D图像转换为3D张量
降水临近预报的目标是利用先前观测到的雷达回波序列来预测当地地区(如香港、纽约或东京)的未来雷达地图的固定长度。在实际应用中,雷达地图通常每6-10分钟从天气雷达上获取一次,并在接下来的1-6小时内进行临近预报,即预测前方的6-60帧。降水预报实际上是时空预测问题。
每个正方形小格点代表11公里可以看做一个地区。p值为降雨量,也可以为雷达反射率,它和降雨量之间有关系可以转换。对于雷达回波图来说每一个图片的对应像素点通过一定的变换其实是可以直接得到这个点的一些物理量的,所以这个P实际作者想说的就是这个物理量的维度。
2、Encoding-forecasting
两个网络、一个编码网络和一个预测网络。类似于中,预测网络的初始状态和单元输出是从编码网络的最后一个状态复制出来的。这两个网络都是通过堆叠几个ConvLSTM层来形成的。由于我们的预测目标具有与输入相同的维数,所以我们将预测网络中的所有状态连接起来,并将它们送入 1 × 1 卷积层,以生成最终预测。
一、数据集
Moving-MNIST:数据集为图中 有两个数字的时空序列的移动。 大小为64乘以64, 整个序列为20,前十个为输入数据,后十个为预测数据。移动数字是从MNIST数据集中的500位数字的子集中随机选择的。起始位置和速度方向均匀随机选择,速度振幅随机选择。这个生成过程重复15000次,得到一个包含10000个训练序列、2000个验证序列和3000个测试序列的数据集。
二、评估指标
对比FC-LSTM以及不同架构ConvLSTM参数多少以及交叉熵的结果。
三、超参数的设定
所有的模型的均采用cross-entropy交叉熵作为损失函数,用的optimizer为RMSProp, 学习率为0.001并且有0.9的延迟率。
三、实验数据
对于ConvLSTM网络,本文将补丁大小设置为4×4,以便每个64×64帧用一个16×16×16张量表示。
ConvLSTM的三种变体:
1层网络包含一个有256个隐藏状态的ConvLSTM层,
2层网络有两个ConvLSTM层,每层有128个隐藏状态,3层网络在三个ConvLSTM层中分别有128、64和64个隐藏状态。
-5x5 ‘和’ -1x1 ‘表示相应的状态对状态内核大小,即5×5或1×1。“256”、“128”和“64”表示ConvLSTM层中隐藏状态的数量。’ (5x5) ‘和’ (9x9) '表示输入到状态的内核大小;
每个模型不管是多少层的,input-to-state的kernel size都为一致的,只有每层的state-to-state的kernel size在变,以及 hidden state的大小在变。
本文首次成功地将机器学习方法,特别是深度学习,应用到具有挑战性的降水临近预报问题上,本文将降水临近预报定义为一个时空序列预测问题,并提出了一个新的LSTM扩展,称为ConvLSTM来解决这一问题。ConvLSTM层不仅保留了FC-LSTM的优势,而且由于其固有的卷积结构,也适用于时空数据。通过将ConvLSTM纳入编码-预测结构,我们建立了一个端到端可训练的预报模型。
输入变量维度input_size为4,隐藏层隐藏节点hidden_size大小为4,RNN层数num_layer为1,批量大小即样本数量为2,输入序列长度seq_len长度为4。
- import torch
- from torch import nn
-
- torch.manual_seed(0) # 设置随机种子,随机函数生成的结果会相同
-
- input_size = 4 # 输入数据特征大小
- hidden_size = 3 # 隐藏层特征大小
- num_layers = 1 # RNN层数
-
- batch_size = 2 # 批次大小
- seq_len = 4 # 输入序列长度
input_one.shape:[batch_sieze,seq_len,input_size],即[2,4,4]
h_prev.shape:[batch.size,hidden_size],即[2,3]
nn.RNN中定义了batch_first=true,即把batch_size的大小放在第0维,则output_api.shape:[batch_size,seq_len,hidden_size],h_n_api.shape:[num_layer,batch_size,hidden_size]
本来h_prev是2维张量,现在这里为什么是3维呢?
因为h_prev.unsqueeze(0)就是在h_prev的第0维上进行扩展,将h_prev扩展维3维张量。
即output_api.shape:[2,4,3],h_n_api.shape[1,2,3]
- # random init the input
- input_one = torch.randn(batch_size, seq_len, input_size) # bs,seq_len,input_size 随机初始化一个特征序列
-
- # random init the init hidden state
- h_prev = torch.zeros(batch_size, hidden_size) # 初始隐含状态h_0 (bs,hidden_size) pytorch默认初始化全0
- # 本来应该是(1,batch_size,hidden_size) 这里为了简便传递参数和下面的计算 因为很多时候传递的参数都是二维
-
- # define the RNN layers
- rnn_layer = nn.RNN(input_size=input_size,
- hidden_size=hidden_size,
- num_layers=num_layers,
- batch_first=True)
-
- output_api, h_n_api = rnn_layer(input_one, h_prev.unsqueeze(0))
- # h_0 对于输入的是批次数据时维度为 (D∗num_layers,bs,hidden_size) 看官方参数
- # h_prev.unsqueeze(0) h_prev:(bs,hidden_size)->(1,bs,hidden_size) 这里D为1,num_layers也是1
进行验证:
证明我们的推导是没问题的。
对RNN进行前向传播:
h_t的计算公式如下:
我们现在需要把各参数的维度理清楚,这样才能更好地理解RNN的前向传播过程:
其中x_t是把t时间步长中的向量提取出来,在提取之前,x_t.shape:[batch_size,seq_size,input_size]提取之后形状变成[batch_size,input_size],即[2,4]
为什么要对x_t进行扩展呢?因为涉及到了x_t要与w_ih进行矩阵的乘法,对x_t进行扩展后,x_t.shape:[2,4,1],同理对w_ih进行扩展成3维张量,w_ih_batch.shape:[2,3,4];x_t与w_ih进行矩阵乘法后,得到结果形状为:[3,1],同理h_prev与w_hh做矩阵乘法后,得到的结果形状也为[3,1],之后加上3维向量,即可得到下一时刻的h_t。
- def custom_rnn_function(input,h_prev, w_ih, w_hh, b_ih, b_hh ): # h_prev就是h_t-1
- """
- h_t = tanh(w_{ih}*x_t+b_{ih}+w_{hh}*h_{t-1}+b_{hh})
- x_t is the input at time t
- :param input: input(batch_size,seq_len,input_size)
- :param h_prev: previous hidden h_prev (batch_size,hidden_size)
- # 本来应该是(1,batch_size,hidden_size) 这里为了简便传递参数和下面的计算 因为很多时候传递的参数都是二维
- :param w_ih: weight w_ih (hidden_size,input_size)
- :param w_hh: weight w_hh (hidden_size,hidden_size)
- :param b_ih: bias b_ih (hidden_size)
- :param b_hh: bias b_hh (hidden_size)
- :return: output ,h_n
- """
- # print("input:",input)
- # print("w_ih:",w_ih)
- # print("w_hh:",w_hh)
- # print("b_ih:",b_ih)
- # print("b_hh:",b_hh)
- # print("h_prev:",h_prev)
-
- batch_size, seq_len, input_size = input.shape
-
- hidden_size, input_size = w_ih.shape
-
- output = torch.zeros(batch_size, seq_len, hidden_size) # 初始化一个输出矩阵output 看官方参数来定义
-
- for t in range(seq_len): # t就相当于每个时刻
- # input[:,t,:].shape = [batch_size,input_size] -> (batch_size,input_size,1)
- x_t = input[:, t, :].unsqueeze(2)
-
- # w_ih_batch.shape = [hidden_size,input_size] -> (batch_size,hidden_size,input_size)
- # unsqueeze(0) -> (1,hidden_size,input_size)
- # tile(batch_size, 1, 1): 第0维变成原来的batch_size倍(默认行复制)其他两维为1保持不动-> (batch_size,hidden_size,input_size)
- w_ih_batch = w_ih.unsqueeze(0).tile(batch_size, 1, 1)
-
- # w_hh_batch = [hidden_size,hidden_size] -> (batch_size,hidden_size,hidden_size)
- w_hh_batch = w_hh.unsqueeze(0).tile(batch_size, 1, 1)
-
- # bmm() 含有批次大小的矩阵相乘 mm 矩阵相乘 具体看官方函数
-
- # w_ih_times_x.shape=(batch_size,hidden_size,1) -> (batch_size,hidden_size)
- w_ih_times_x = torch.bmm(w_ih_batch, x_t).squeeze(-1) # W_ih * x_t
-
- # h_prev.unsqueeze(2) : (batch_size,hidden_size,1)
- # w_hh_times_h.shape =(batch_size,hidden_size,1)->(batch_size,hidden_size)
- w_hh_times_h = torch.bmm(w_hh_batch, h_prev.unsqueeze(2)).squeeze(-1)
-
- # h_prev = (1,batch_size,hidden_size)->(batch_size, hidden_size)
- h_prev = torch.tanh(w_ih_times_x + b_ih + w_hh_times_h + b_hh)
-
- output[:, t, :] = h_prev # 将t-1时刻的输出放入输出矩阵中
-
- # 按官方api格式返回
- # h_prev.unsqueeze(0) : (1,batch_size,hidden_size) 因为官方参数为(D∗num_layers,bs,hidden_size)
- return output, h_prev.unsqueeze(0)
进行验证后得到的结果如下:
张量可以看作是矩阵的推广,其实就是一组有序数,但是张量是比向量和矩阵更高级的记号。凡是向量和矩阵能表示的,张量都能简洁地表示,例如(2,3,4)表示一个2x3x4的3维张量。
标量是0阶张量,矢量是1阶张量,2阶张量可以用矩阵表示。
什么是张量的阶呢?就是自由下标的个数。
例如,是1阶张量,因为i=1,2,3,它有3个分量。
是2阶张量,因为i=1,2,3;j=1,2,3,它有3*3=9个分量。
是4阶张量,因为m=1,2,3; n=1,2,3; k=1,2,3; l=1,2,3,它就有3*3*3*3=81个分量。
张量有加、减、乘。乘有三种:1. 点乘 2. 叉乘 3. 并乘
一、爱因斯坦求和约定与哑标
自由下标,与之对应的,就是哑标。哑标是会被消掉的。
爱因斯坦在推导相对论的时候,为了记号方便,就发明了张量表示法。他又发现经常会有相同下标求和的情况发生,于是规定:凡是在一项内有相同下标出现的,一律默认求和。
写起来,就是这样
其实说来,就是省略了一个求和符号 Σ
如果不省略,就是
加减很简单,对应的分量加减即可。
如:
首先说明,点乘是降阶的。这一点要牢记。
那么降低多少呢?
假如a有4阶,b有2阶,那么a点乘b得到的就是4-2=2阶
假如a有2阶,b有1阶,那么a点乘b得到的就是2-1=1阶(矩阵乘向量)
假如a有2阶,b有2阶,那么a点乘b得到的就是2-2=0阶(矩阵乘矩阵)
假如a有1阶,b有1阶,那么a点乘b得到的就是1-1=0阶(向量乘向量)
所以我们还明白了:点乘结果的阶数就是阶数大的减去阶数小的。
向量(也就是一阶张量)的点乘都写成一个点的点积。
而二阶张量的点乘都写成两个点的点积。如
a:b
这里我没有写下标。a和b都代表二阶张量。假如写上下标
你就会发现,ij都是哑标,直接就加没了。所以两个2阶张量点乘的结果是0阶张量,即一个数,或者说是标量。
为什么要写两个点呢?这是因为有两个下标被爱因斯坦求和约定给求和了,同时它又是两个二阶的张量相乘,所以就写成两个点。
双点积应该很常见,因为它其实就是两个矩阵对应分量一对一的相乘。
假如写成矩阵形式的话,
并乘是升阶的。并乘结果的阶数就是阶数之和。
可以想象,i和j都是自由下标,结果为2阶张量,所以这其实是9个分量
向量并乘又被称为外积(outer product)(与内积相对应)
矩阵并乘又被称为克罗内克积(kronecker product)
张量的并乘又被称为直积(direct product),或者就叫张量积(tensor product)。
叉乘是不升不降的
例如向量的叉乘:
克罗内克三角(Kronecker delta),或者叫克罗内克函数,它是一个二阶张量
可见,它其实就是单位阵。可用克罗内克三角来化简许多运算,他有一条很好的性质,那就是他能换下标。比如:
本周学习了关于张量的一些基础内容,下周将继续看张量的视频,进行系统的学习。初次接触,感觉不太好接受,争取多看几遍进行理解。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。