PyTorch深度学习 学习记录7_1

循环神经网络(RNN)

CNN处理图而RNN则用于处理序列,它会记录上一时刻的结果并影响这一时刻的计算,这样说起来其实与马尔科夫链有些相似
在这里插入图片描述
RNN的结构相当简单,而RNN层本质上就是一个线性网络不过为了更加直观通常会把他拉直:在这里插入图片描述
这样子就有“序列”的感觉了,这里可能会有人会有误区(比如我)误认为这里有多个层而 x t x_t xt则对应多个输入, x t x_t xt实际对应于同一序列不同时刻的输入。除此之外每一个RNN层输出的 h t h_t ht也会传递到下一层,其中 h 0 h_0 h0是我们的先验知识或是零向量

在这里插入图片描述RNN内部的模样就张这样,虽然看上去有两个线性层,但通常我们会把通过如下运算把 x t x_t xt h t h_t ht拼起来在这里插入图片描述当然RNN也可以构造多层,同时我们也需要多个 h 0 h_0 h0
在这里插入图片描述

Pytorch中的RNN

CLASS torch.nn.RNN(*args, **kwargs):
将具有非线性tanh或ReLU的多层Elman RNN应用于输入序列。
对输入序列中的每个元素做如下运算
h t ​ = t a n h ( x t ​ W i h T ​ + b i h ​ + h t − 1 ​ W h h T ​ + b h h ​ ) h_t​=tanh(x_t​W_{ih}^T​+b_{ih​}+h_{t−1​}W_{hh}^T​+b_{hh}​) ht=tanh(xtWihT+bih+ht1WhhT+bhh)参数:

input_size: 输入x的特征数
hidden_size: 隐层的特征数
num_layers: 循环层的层数
nonlinearity: 使用的非线性函数,‘tanh’ 或 ‘relu’。默认为‘tanh’
bias: 是否使用bias。默认是True。
batch_first: 如果是True,那么输入和输出张量使用格式(batch, seq, feature)而不是(seq, batch, feature)。这不会影响RNN中的计算
dropout: 非0值则表示,除了最后一层外,给每一层都添加一个Dropout层,默认是0。
bidirectional: 如果为Ture,则表示建立的是双向RNN。默认是False。

输入:input, h 0 h_0 h0

input:
不使用batch,则输入的tensor是(seq_len, input_size)
使用batch,则输入的tensor是(seq_len, batch_size, input_size)
如果batch_first为True,则输入的tensor是(batch_size, seq_len, input_size)
h 0 h_0 h0:
不使用batch,则初始隐层 h 0 h_0 h0就是(D * num_layers, hidden_size)
使用batch,则初始隐层 h 0 h_0 h0就是(D * num_layers, batch_size, hidden_size)
其中当为双向RNN时D=2否则D=1
注意:batch_first为True时 h 0 h_0 h0不会变

输出:output, h n h_n hn

output:
不使用batch,则输出就是(seq_len, D * hidden_size)
使用batch,则输出就是(seq_len, batch_size, D * hidden_size)
如果batch_first为True,则输入的tensor是(seq_len, batch_size, input_size)
h n h_n hn:
不使用batch,则输出就是(D* num_layers, hidden_size)
使用batch,则输出就是(D * num_layers, batch_size, hidden_size)

一个栗子

字符级的自然语言处理会先为字符构造一个词典,为每个字符分配一个索引,然后用独热编码将各字符转换为一个向量在这里插入图片描述然后处理一个简单的问题:
在这里插入图片描述既然都出现了独热编码,这个问题也就自然而然地转换成了多分类问题:
在这里插入图片描述代码(使用RNNCell):

import torch

input_size=4
hidden_size=4
batch_size=1

idx2char=['e','h','l','o']
x_data=[1,0,2,2,3]
y_data=[3,1,2,3,2]

one_hot_lookup=[[1,0,0,0],
                [0,1,0,0],
                [0,0,1,0],
                [0,0,0,10]]
x_one_hot=[one_hot_lookup[x] for x in x_data]

inputs=torch.Tensor(x_one_hot).view(-1,batch_size,input_size)
labels=torch.LongTensor(y_data).view(-1,1)

class Model(torch.nn.Module):
    def __init__(self,input_size,hidden_size,batch_size):
        super().__init__()
        self.batch_size=batch_size
        self.input_size=input_size
        self.hidden_size=hidden_size
        self.rnncell=torch.nn.RNNCell(input_size=self.input_size,hidden_size=self.hidden_size)#这里用的是Cell,序列长度会在循环中体现
        #相当于做了RNN中的单步

    def forward(self,input,hidden):
        hidden=self.rnncell(input,hidden)
        return hidden
    
    def init_hidden(self):
        return torch.zeros(self.batch_size,self.hidden_size)

net=Model(input_size,hidden_size,batch_size)
critrion=torch.nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(net.parameters(),lr=0.1)

for epoch in range(30):
    loss=0.0
    optimizer.zero_grad()
    hidden=net.init_hidden()
    print('Predicted string:',end='')
    for input,label in zip(inputs,labels):
        hidden=net(input,hidden)
        loss+=critrion(hidden,label)#每次只计算了一个时刻,所以要将每个时刻的损失相加
        _,idx=hidden.max(dim=1)
        print(idx2char[idx.item()],end='')
    loss.backward()
    optimizer.step()
    print(',Epoch[%d/30] loss=%.4f'%(epoch+1,loss.item()))

使用RNN:

import torch

input_size=4
hidden_size=4
batch_size=1
seq_len=5
num_layers=1

idx2char=['e','h','l','o']
x_data=[1,0,2,2,3]
y_data=[3,1,2,3,2]

one_hot_lookup=[[1,0,0,0],
                [0,1,0,0],
                [0,0,1,0],
                [0,0,0,10]]
x_one_hot=[one_hot_lookup[x] for x in x_data]

inputs=torch.Tensor(x_one_hot).view(seq_len,batch_size,input_size)
labels=torch.LongTensor(y_data)

class Model(torch.nn.Module):
    def __init__(self,input_size,hidden_size,batch_size,num_layers):
        super().__init__()
        self.batch_size=batch_size
        self.input_size=input_size
        self.hidden_size=hidden_size
        self.num_layers=num_layers
        self.rnn=torch.nn.RNN(input_size=self.input_size,
                            hidden_size=self.hidden_size,
                            num_layers=self.num_layers)

    def forward(self,input,h0):
        out,hidden=self.rnn(input,h0)
        return out.view(-1,self.hidden_size)#(seqlen*batchsize,hiddensize)
        #方便做交叉熵
    
    def init_hidden(self):
        return torch.zeros(self.num_layers,self.batch_size,self.hidden_size)

net=Model(input_size,hidden_size,batch_size,num_layers)
critrion=torch.nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(net.parameters(),lr=0.1)

for epoch in range(30):
    optimizer.zero_grad()
    h0=net.init_hidden()
    outputs=net(inputs,h0)
    loss=critrion(outputs,labels)
    loss.backward()
    optimizer.step()

    _,idx=outputs.max(dim=1)
    idx=idx.data.numpy()
    print('Predicted:',''.join([idx2char[x] for x in idx]),end='')
    print(',Epoch[%d/30] loss=%.4f'%(epoch+1,loss.item()))

虽然独热编码简单有效,但还是有着诸多缺点:1.矩阵稀疏,2.维度高,3.硬编码(即人为指定不可学习)。
为了解决这个问题于是就有了词嵌入,词嵌入实际与卷积核相当类似,通过这种方式也能够表征序列中各个状态间的关联,具体一点可以看这里在这里插入图片描述这样我们的模型能够变得稍微复杂一点:
在这里插入图片描述代码:

import torch

input_size=4
hidden_size=8
batch_size=1
seq_len=5
num_layers=2
num_class=4
embedding_size=10

idx2char=['e','h','l','o']
x_data=[[1,0,2,2,3]]
y_data=[3,1,2,3,2]


inputs=torch.LongTensor(x_data)
labels=torch.LongTensor(y_data)

class Model(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.emb=torch.nn.Embedding(input_size,embedding_size)
        self.rnn=torch.nn.RNN(input_size=embedding_size,
                            hidden_size=hidden_size,
                            num_layers=num_layers,
                            batch_first=True)
        self.fc=torch.nn.Linear(hidden_size,num_class)
    
    def forward(self,x):
        h0=torch.zeros(num_layers,x.size(0),hidden_size)
        x=self.emb(x)#(batch,seqlen,embeddingSize)
        
        x,_=self.rnn(x,h0)
        x=self.fc(x)
        return x.view(-1,num_class)

net=Model()
critrion=torch.nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(net.parameters(),lr=0.05)
for epoch in range(15):
    optimizer.zero_grad()
    outputs=net(inputs)
    loss=critrion(outputs,labels)
    loss.backward()
    optimizer.step()

    _,idx=outputs.max(dim=1)
    idx=idx.data.numpy()
    print('Predicted:',''.join([idx2char[x] for x in idx]),end='')
    print(',Epoch[%d/15] loss=%.4f'%(epoch+1,loss.item()))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值