LSTM

LSTM(Long short-term memory)  长短期记忆

是RNN(循环神经网络)的一种

用得非常多,主要解决时间序列问题,是专门为时间序列设计的人工神经网络

 

LSTM结构

标准RNN中,其内部A是这样的,tanh是激活函数

 

LSTM

      输入门控制输入(新记忆)的输入幅度;

      遗忘门控制之前记忆状态的输入幅度;

      输出门控制最终记忆的输出幅度

 

Sigmoid层起到一个gate门的作用(0代表不通过任何信息,1代表全部通过)

 

 

换种画法

本时刻输入前的参数 W(i), W(f), W(o)和3个上一时刻隐状态前的参数U(i),U(f),U(o)

 

 

LSTM的关键点是细胞状态,就是穿过图中的水平线。
单元状态有点像是个传送带。它贯穿整个链条,只有一些线性相互作用。这很容易让信息以不变的方式向下流动。

 

分层详解

黄颜色矩形表示人工神经网络层,就是1层、2层、3层那样,只不过用了一个矩形代替
粉色点代表矩阵运算
汇总是两个标量变成向量

分开是复制一份,分别传送一份

 

       考虑一个问题,让你来写个paper来解决一个问题,给你看一本书,这本书就是关系你要解决的那个问题的。让你在看这本书之前先写一次报告,然后看完这本书之后再写一次报告。这两次不同的报告中间发生了什么变化呢?你是因为读了这本书之后,会有一部分东西依赖于这本书,无形当中对你造成了影响。但是你又不可能100%完全依赖于这本书,你也有先验知识,所以你第二份报告一定是我的认识+书的知识,衡量一下它俩的权重,然后做一个权重加和,得出报告。

确定有多少信息来自于我们的内部经验,来自于历史
套sigma函数是为了得到一个百分比


tanh是到-1~1
sigma是0~1

负的表明这本书可能会对你带来误导,比如你读一本书,这本书完全不对,也会对带来影响


Ct~告诉我们这本书读完之后,能给我们提供多少新的信息
it告诉我们新的信息里面有多少信息是可靠的,是我们可以拿来用的

这两个激活函数不一样,所以他们的意义就完全不一样


ft,我有多相信之前的历史
it,我有多相信当前学的这本书


我们基于这个新的Ct来帮我们做预测
 


Ct是你对整个问题最新的认识
把你所有的想法,整体的思想,有选择的输出一些,而不是全部输出(人的想法就是这样。会有所保留,不会全部说出来,或者只选择一些和当前主题有关的说,或者是当某些情况满足的时候才会说)
所以说Ct并不是全部都要输出,要经过tanh激活之后才会输出

这些信息你想输出但是最后真正输出了多少呢  ot


ht-1是上一时刻的ht
xt是你新观测到的数据

ht-1到ht这也是为什么叫循环神经网络,他在不断作循环

 

 

 

 

 


这个图还是上面框架,但是换了一种画图方式


state t-1就是Ct-1,state t 就是Ct


ft决定了C,t-1是有多少信息流入Ct


at是新的信息能给我们提供多少有效的信息,就是Ct~
it是新的信息有多少是我们想保留的

黄色的Ct直接网上传,变成下一时刻的Ct-1
通过tanh激活,激活之后乘上ot,就变成输出了


用真实值来套模型

x,y是告诉的,是一致的(y就是x的标签)
W,U,b是不知道的,一开始随便猜一个值,不断去优化

用这些值来套刚才的公式

最开始输入的是x和ht-1的汇总(concatenate)

[1 2 0]流进来之后,0会在U0的位置,[1 2]会放在out-1的位置,[1 2]会放在x-的位置,就得出了a0,就是当前时刻我学到的

.......

然后用输出的结果0.536和真值 0.5之间的差异,作为代价函数来去优化我们的参数W、U、b

t=1时刻的输出0.77197和1.25差的就挺多了

优化

一般加了帽子的是值的输出,没加的就是真值
E就是代价函数,损失函数。我们优化就是要不断调试参数,使E最小

通过求斜率,导数

 

用优化好的参数再套回到模型的那些参数W、U、b,再求出来的结果就和y值很接近了。
也就是说模型已经可以很好得模拟过去了,那我们接下来就要让他模拟未来

衡量它的好坏也是用confusion matrix来衡量,把它预测是和实际观测的来比较


看它的   TP+TN(即判断对了多少次)/总次数

 

LSTM变体

       GRU则是LSTM的一个变体,GRU只有两个门了,分别为更新门和重置门。更新门用于控制前一时刻的状态信息被带入到当前状态中的程度,更新门的值越大说明前一时刻的状态信息带入越多。重置门用于控制忽略前一时刻的状态信息的程度,重置门的值越小说明忽略得越多。

 

 

RNN(LSTM)进行图像分类实战

 RNN 特别适合做序列类型的数据,那么 RNN 能不能想 CNN 一样用来做图像分类呢?下面我们用 mnist 手写字体的例子来展示一下如何用 RNN 做图像分类,但是这种方法并不是主流,这里我们只是作为举例。

 

对于一张手写字体的图片,其大小是 28 * 28,我们可以将其看做是一个长为 28 的序列,每个序列的特征都是 28,也就是

这样我们解决了输入序列的问题,对于输出序列怎么办呢?其实非常简单,虽然我们的输出是一个序列,但是我们只需要保留其中一个作为输出结果就可以了,这样的话肯定保留最后一个结果是最好的,因为最后一个结果有前面所有序列的信息,就像下面这样

 

 

# RNN循环神经网络  分类 (时间顺序,图片从上往下读取)
import torch
import torch.nn as nn
import torchvision.datasets
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import torch.utils.data as Data



class RNN(nn.Module):
    def __init__(self):
        super(RNN, self).__init__()
        self.rnn = nn.LSTM(
            input_size=28,  # 每行的像素点
            hidden_size=64,
            num_layers=1,  # the num of RNN layers
            batch_first=True,  # 表示在输入数据的时候,数据的维度为(batch,time_step,input)
            # 如果自己定义的维度为(time_step,batch,input),则为False
        )
        self.out = nn.Linear(64, 10)

    def forward(self, x):  # x :(batch,time_step,input_size)

        # 每步对输入的x进行计算,每次计算完之后产生一个自己生成的理解;下一次传入神经网络的不只是这次的input,还有上一次生成的(h_n,h_c)
        # 然后生成输出结果r_out和自己的理解(h_n,h_c); (h_n,h_c)为分线和主线层的hidden state
        # None:第一次输入的时候没有hidden state
        # r_out 中有从第一次到最后一次一共28个output
        r_out, (h_n, h_c) = self.rnn(x, None)  # r_out: (batch,time_step,output_size)
        # h_n,h_c: (n_layers,batch,hidden_size)
        # 选取最后一次的r_out进行输出
        # r_out[:,-1,:]的值也是h_n的值
        out = self.out(r_out[:, -1, :])
        return out




torch.manual_seed(1)

# Hyper parameters
# 图片大小28*28,一共读取28次,每次读取一行28个数据点
EPOCH = 1
BATCH_SIZE = 64
TIME_STEP = 28  # RNN time step/image_height
INPUT_SIZE = 28  # 每个时间点包含多少个数据点, image_width
LR = 0.01
DOWNLOAD_MNIST = False

train_data = torchvision.datasets.MNIST(
    root='dataset/',
    train=True,
    transform=torchvision.transforms.ToTensor(),
    download=DOWNLOAD_MNIST,
)

# plt.imshow(train_data.data[0].numpy(),cmap='gray')
# plt.title(train_data.targets[0].numpy())
# plt.show()

test_data = torchvision.datasets.MNIST(root='dataset/', train=False)
# 批训练 50samples,1 channel,28*28  (50,1,28,28)
train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
# 去前2000个测试数据进行测试
test_x = torch.unsqueeze(test_data.data, dim=1).type(torch.FloatTensor)[:2000] / 255  # shape from(2000,28,28)to(2000,1,28,28)
test_y = test_data.targets[:2000]



rnn = RNN()
# print(rnn)
'''
RNN(
  (rnn): LSTM(28, 64, batch_first=True)
  (out): Linear(in_features=64, out_features=10, bias=True)
)
'''
# 训练和测试
optimizer = torch.optim.Adam(rnn.parameters(), lr=LR)
loss_func = nn.CrossEntropyLoss()  # 分类标签不是one-hot的形式

for epoch in range(EPOCH):
    for step, (x, b_y) in enumerate(train_loader):
        b_x = x.view(-1, 28, 28)  # reshape x to (batch,time_step,input_size)

        output = rnn(b_x)
        loss = loss_func(output, b_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if step % 50 == 0:
            x = test_x.view(-1, 28, 28)
            test_out = rnn(x)
            pred_y = torch.max(test_out, 1)[1].data.squeeze()  # torch.max(input,dim)返回每一行中的最大值的标签
            accuracy = (pred_y == test_y).numpy().sum() / test_y.size(0)
            print('step: {} | train loss: {} | test accuracy: {} '.format(step, loss.data, accuracy))

# 取前十个数据看一下结果
test_out = rnn(test_x[:10].view(-1, 28, 28))
pred_y = torch.max(test_out, 1)[1].data.squeeze()
print('prediction:', pred_y)
print('real value:', test_y[:10])

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值