RNN神经网络-简单的序列预测问题

RNN神经网络-简单的序列预测问题

RNN神经网络能够实现记忆功能,被广泛地应用在时间序列分析上,在NLP、语音识别等方向有许多的应用。

原理:

rnn1.png

RNN神经网络是一个序列结构,在处理数据时,\(S_t\)的值不仅取决于当前的输入,还取决于上一层的输出,因此其在处理序列数据具有很明显的优势。

计算公式:

\(h_t=tanh(w_{ih} x_t+b_{ih}+w_{hh} h_{t-1}+b_{hh})\)

\(x_t\)是上一层时刻\(t\)的隐状态,或者是第一层在时刻\(t\)的输入。

使用Pytorch中RNN神经网络实现一个简单的序列预测问题

1. 构造初始数据

#训练数据横轴上的取值
x_num=50
#隐藏层特征数量
hidden_size=16
#输入x的特征数量。
input_size=1
output_size=1

#随机生成正弦函数左边界
start = np.random.randint(5)  # random in [0,3]
#将序列划分为等间距的区间
x_value = np.linspace(start,start+10,x_num)
#生成训练数据
data = np.sin(x_value)
#embedding,将数据转换为100*1的矩阵
data = data.reshape(x_num,1)
#输入是0-70的数据值
x = torch.tensor(data[:49]).float().view(1,x_num-1,1) 
#预测30-100的数据值
y = torch.tensor(data[1:]).float().view(1,x_num-30,1) 

​ note:

  • 由于网络需要训练很多次来降低误差,在训练时,需要让此左边界值是个随机值,否则每次的训练数据一致,导致模型过拟合。

  • view(**args*) → Tensor

    返回一个有相同数据但大小不同的tensor。 返回的tensor必须有与原tensor相同的数据和相同数目的元素,但可以有不同的大小。

2. 构建网络

#定义网络
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.rnn = nn.RNN(
            input_size = input_size,#输入x的特征数量
            hidden_size = hidden_size,#隐藏层的特征数量
            num_layers=1,#RNN层数
            batch_first=True,#[batch_size, time_step, feature]
        )
        self.linear = nn.Linear(hidden_size,output_size)

    #定义了每次执行的 计算步骤    
    def forward(self,x,hidden_prev):
        out, hidden_prev = self.rnn(x,hidden_prev)
        out = out.view(-1,hidden_size)
        out = self.linear(out)
        #在指定维度前插入维度1
        out = out.unsqueeze(dim=0) # [1,seq,1]
        return out,hidden_prev

​ note:

  • class torch.nn.RNN( args, * kwargs)[source]

    将一个多层的 RNN,激活函数为tanh或者ReLU,用于输入序列。

    对输入序列中每个元素,RNN每层的计算公式为 $ h_t=tanh(w_{ih} x_t+b_{ih}+w_{hh} h_{t-1}+b_{hh}) $ \(h_t\)是时刻\(t\)的隐状态。 \(x_t\)是上一层时刻\(t\)的隐状态,或者是第一层在时刻\(t\)的输入。如果nonlinearity=relu,那么将使用relu代替tanh作为激活函数。

    参数:

    • input_size – 输入x的特征数量。

    • hidden_size – 隐层的特征数量。

    • num_layers – RNN的层数。

    • nonlinearity – 指定非线性函数使用tanh还是relu。默认是tanh。

    • bias – 如果是False,那么RNN层就不会使用偏置权重 \(b_ih\)\(b_hh\),默认是True

    • batch_first – 如果True的话,那么输入Tensor的shape应该是[batch_size, time_step, feature],输出也是这样。

    • dropout – 如果值非零,那么除了最后一层外,其它层的输出都会套上一个dropout层。

    • bidirectional – 如果True,将会变成一个双向RNN,默认为False。

    • h_0 (num_layers * num_directions, batch, hidden_size): 保存着初始隐状态的tensor

    • output (seq_len, batch, hidden_size * num_directions): 保存着RNN最后一层的输出特征。如果输入是被填充过的序列,那么输出也是被填充的序列。

    • h_n (num_layers * num_directions, batch, hidden_size): 保存着最后一个时刻隐状态。

  • linear:对输入数据做线性变换:\(y=Ax+b\)

    参数:

    • in_features - 每个输入样本的大小
    • out_features - 每个输出样本的大小
    • bias - 若设置为False,这层不会学习偏置。默认值:True
  • torch.unsqueeze(input, dim, out=None): 返回一个新的张量,对输入的制定位置插入维度 1

    参数:

    • tensor (Tensor) – 输入张量
  • dim (int) – 插入维度的索引

    • out (Tensor, optional) – 结果张量

3. 模型训练

model = Net()
#MSE误差
criterion = nn.MSELoss()
#优化器
optimizer = optim.Adam(model.parameters(),lr=1e-2)
#初始化h0的值
hidden_prev = torch.zeros(1,1,hidden_size) # h0
#共训练1000次
for iter in range(3000):
    #随机生成正弦函数左边界
    start = np.random.randint(5)  # random in [0,5]
    #将序列划分为等间距的区间
    x_value = np.linspace(start,start+10,x_num)
    #生成训练数据
    data = np.sin(x_value)
    #embedding,将数据转换为100*1的矩阵
    data = data.reshape(x_num,1)
    #输入是0-48的数据值
    x = torch.tensor(data[:49]).float().view(1,x_num-1,1) 
    #预测1-49的数据值
    y = torch.tensor(data[1:]).float().view(1,x_num-1,1) 
    #训练模型
    output,hidden_prev = model(x,hidden_prev)
    hidden_prev = hidden_prev.detach()
    #计算损失函数
    loss = criterion(output,y)
    model.zero_grad()
    #计算与图中叶子结点有关的当前张量的梯度
    loss.backward()
    #优化
    optimizer.step()
    #输出损失函数值
    if iter%100 == 0:
        print('steps: {} loss {}'.format(iter,loss.item()))

​ note:

  • 这里每次训练都要重新对该batch中的数据赋值
  • detach: 返回一个新的Variable,从当前图中分离下来的。
  • zero_grad(): 将module中的所有模型参数的梯度设置为0.

4. 可视化

#绘制预测图
predictions = []#预测值
input = x[:,0,:]
for _ in range(x.shape[1]):
    input = input.view(1,1,1)
    (pred,hidden_prev) = model(input,hidden_prev)
    input = pred
    #根据当前值预测下一个值
    predictions.append(pred.detach().numpy().ravel()[0])
#绘制原图
x = x.data.numpy().ravel()
y = y.data.numpy()
plt.scatter(x_value[:-1],x.ravel(),s=90)
plt.plot(x_value[:-1],x.ravel())

plt.scatter(x_value[1:],predictions)
plt.show()

​ note:

  • numpy.ravel() 将多维数据降维,返回视图

    结果:

rnn2.png

参考:

Pytorch中文文档

Pytorch教程

posted @ 2021-10-15 13:38  流光之中  阅读(546)  评论(0编辑  收藏  举报