pytorch自定义RNN结构(附代码)
pytorch自定义LSTM结构(附代码)
有时我们可能会需要修改LSTM的结构,比如用分段线性函数替代非线性函数,这篇博客主要写如何用pytorch自定义一个LSTM结构,并在IMDB数据集上搭建了一个单层反向的LSTM网络,验证了自定义LSTM结构的功能。
@
一、整体程序框架
如果要处理一个维度为【batch_size, length, input_dim】的输入,则需要的LSTM结构如图1所示:

layers表示LSTM的层数,batch_size表示批处理大小,length表示长度,input_dim表示每个输入的维度。
其中,每个LSTMcell执行的表达式如下所示:

二、LSTMcell
LSTMcell的计算函数如下所示;其中nn.Parameter表示该张量为模型可训练参数;
class LSTMCell(nn.Module):
def __init__(self, input_size, hidden_size):
super(LSTMCell, self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.weight_cx = nn.Parameter(torch.Tensor(hidden_size, input_size)) #初始化8个权重矩阵
self.weight_ch = nn.Parameter(torch.Tensor(hidden_size, hidden_size))
self.weight_fx = nn.Parameter(torch.Tensor(hidden_size, input_size))
self.weight_fh = nn.Parameter(torch.Tensor(hidden_size, hidden_size))
self.weight_ix = nn.Parameter(torch.Tensor(hidden_size, input_size))
self.weight_ih = nn.Parameter(torch.Tensor(hidden_size, hidden_size))
self.weight_ox = nn.Parameter(torch.Tensor(hidden_size, input_size))
self.weight_oh = nn.Parameter(torch.Tensor(hidden_size, hidden_size))
self.bias_c = nn.Parameter(torch.Tensor(hidden_size)) #初始化4个偏置bias
self.bias_f = nn.Parameter(torch.Tensor(hidden_size))
self.bias_i = nn.Parameter(torch.Tensor(hidden_size))
self.bias_o = nn.Parameter(torch.Tensor(hidden_size))
self.reset_parameters() #初始化参数
def reset_parameters(self):
stdv = 1.0 / math.sqrt(self.hidden_size)
for weight in self.parameters():
weight.data.uniform_(-stdv, stdv)
def forward(self, input, hc):
h, c = hc
i = F.linear(input, self.weight_ix, self.bias_i) + F.linear(h, self.weight_ih) #执行矩阵乘法运算
f = F.linear(input, self.weight_fx, self.bias_f) + F.linear(h, self.weight_fh)
g = F.linear(input, self.weight_cx, self.bias_c) + F.linear(h, self.weight_ch)
o = F.linear(input, self.weight_ox, self.bias_o) + F.linear(h, self.weight_oh)
i = F.sigmoid(i) #激活函数
f = F.sigmoid(f)
g = F.tanh(g)
o = F.sigmoid(o)
c = f * c + i * g
h = o * F.tanh(c)
return h, c
三、LSTM整体程序
如图1所示,一个完整的LSTM是由很多LSTMcell操作组成的,LSTMcell的数量,取决于layers的大小;每个LSTMcell运行的次数取决于length的大小
1. 多层LSTMcell
需要的库函数:
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import math
假如我们设计的LSTM层数layers大于1,第一层的LSTM输入维度是input_dim,输出维度是hidden_dim,那么其他各层的输入维度和输出维度都是hidden_dim(下层的输出会成为上层的输入),因此,定义layers个LSTMcell的函数如下所示:
self.lay0 = LSTMCell(input_size,hidden_size)
if layers > 1:
for i in range(1, layers):
lay = LSTMCell(hidden_size,hidden_size)
setattr(self, 'lay{}'.format(i), lay)
其中setattr()函数的作用是,把lay变成self.lay 'i' ,如果layers = 3,那么这段程序就和下面这段程序是一样的
self.lay0 = LSTMCell(input_size,hidden_size)
self.lay1 = LSTMCell(hidden_size,hidden_size)
self.lay2 = LSTMCell(hidden_size,hidden_size)
2. 多层LSTM处理不同长度的输入
每个LSTMcell都需要(h_t-1和c_t-1)作为状态信息输入,若没有指定初始状态,我们就自定义一个值为0的初始状态
if initial_states is None:
zeros = Variable(torch.zeros(input.size(0), self.hidden_size))
initial_states = [(zeros, zeros), ] * self.layers #初始状态
states = initial_states
outputs = []
length = input.size(1)
for t in range(length):
x = input[:, t, :]
for l in range(self.layers):
hc = getattr(self, 'lay{}'.format(l))(x, states[l])
states[l] = hc #如图1所示,左面的输出(h,c)做右面的状态信息输入
x = hc[0] #如图1所示,下面的LSTMcell的输出h做上面的LSTMcell的输入
outputs.append(hc) #将得到的最上层的输出存储起来
其中getattr()函数的作用是,获得括号内的字符串所代表的属性;若l = 3,则下面这两段代码等价:
hc = getattr(self, 'lay{}'.format(l))(x, states[l])
hc = self.lay3(x, states[3])
3. 整体程序
class LSTM(nn.Module):
def __init__(self, input_size, hidden_size, layers=1, sequences=True):
super(LSTM, self).__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.layers = layers
self.sequences = sequences
self.lay0 = LSTMCell(input_size,hidden_size)
if layers > 1:
for i in range(1, layers):
lay = LSTMCell(hidden_size,hidden_size)
setattr(self, 'lay{}'.format(i), lay)
def forward(self, input, initial_states=None):
if initial_states is None:
zeros = Variable(torch.zeros(input.size(0), self.hidden_size))
initial_states = [(zeros, zeros), ] * self.layers
states = initial_states
outputs = []
length = input.size(1)
for t in range(length):
x = input[:, t, :]
for l in range(self.layers):
hc = getattr(self, 'lay{}'.format(l))(x, states[l])
states[l] = hc
x = hc[0]
outputs.append(hc)
if self.sequences: #是否需要图1最上层里从左到右所有的LSTMcell的输出
hs, cs = zip(*outputs)
h = torch.stack(hs).transpose(0, 1)
c = torch.stack(cs).transpose(0, 1)
output = (h, c)
else:
output = outputs[-1] # #只输出图1最右上角的LSTMcell的输出
return output
三、反向LSTM
定义两个LSTM,然后将输入input1反向,作为input2,就可以了
代码如下所示:
import torch
input1 = torch.rand(2,3,4)
inp = input1.unbind(1)[::-1] #从batch_size所在维度拆开,并倒序排列
input2 = inp[0]
for i in range(1, len(inp)): #倒序后的tensor连接起来
input2 = torch.cat((input2, inp[i]), dim=1)
x, y, z = input1.size() #两个输入同维度
input2 = input2.resize(x, y, z)

OK,反向成功
四、实验
在IMDB上搭建一个单层,双向,LSTM结构,加一个FC层;
self.rnn1 = LSTM(embedding_dim, hidden_dim, layers = n_layers, sequences=False)
self.rnn2 = LSTM(embedding_dim, hidden_dim, layers = n_layers, sequences=False)
self.fc = nn.Linear(hidden_dim * 2, output_dim)
运行结果如图:

时间有限,只迭代了6次,实验证明,自定义的RNN程序,可以收敛。
pytorch自定义RNN结构(附代码)的更多相关文章
- Winform中实现向窗体中拖放照片并显示以及拖放文件夹显示树形结构(附代码下载)
场景 向窗体中拖拽照片并显示效果 向窗体中拖拽文件夹并显示树形结构效果 注: 博客主页: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 ...
- 使用achartengine实现自定义折线图 ----附代码 调试OK
achartengine作为android开发中最常用的实现图标的开源框架,使用比较方便,参考官方文档谢了如下Demo,实现了自定义折线图. package edu.ustb.chart; impor ...
- 分布式消息总线,基于.NET Socket Tcp的发布-订阅框架之离线支持,附代码下载
一.分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.N ...
- 刚开始学python——数据结构——“自定义队列结构“
自定义队列结构 (学习队列后,自己的码) 主要功能:用列表模拟队列结构,考虑了入队,出队,判断队列是否为空,是否已满以及改变队列大小等基本操作. 下面是封装的一个类,把代码保存在myQueue.py ...
- pytorch实现rnn并且对mnist进行分类
1.RNN简介 rnn,相比很多人都已经听腻,但是真正用代码操练起来,其中还是有很多细节值得琢磨. 虽然大家都在说,我还是要强调一次,rnn实际上是处理的是序列问题,与之形成对比的是cnn,cnn不能 ...
- Spring Security教程(三):自定义表结构
在上一篇博客中讲解了用Spring Security自带的默认数据库存储用户和权限的数据,但是Spring Security默认提供的表结构太过简单了,其实就算默认提供的表结构很复杂,也不一定能满足项 ...
- (转)Uri详解之——Uri结构与代码提取
前言:依然没有前言…… 相关博客:1.<Uri详解之——Uri结构与代码提取>2.<Uri详解之二——通过自定义Uri外部启动APP与Notification启动> 上几篇给大 ...
- Uri详解之——Uri结构与代码提取
目录(?)[+] 前言:依然没有前言…… 相关博客:1.<Uri详解之——Uri结构与代码提取>2.<Uri详解之二——通过自定义Uri外部启动APP与Notification启动& ...
- iOS开发 swift 3dTouch实现 附代码
iOS开发 swift 3dTouch实现 附代码 一.What? 从iphone6s开始,苹果手机加入了3d touch技术,最简单的理解就是可以读取用户的点击屏幕力度大小,根据力度大小给予不同的反 ...
- 从实例一步一步入门学习SpringCloud的Eureka、Ribbon、Feign、熔断器、Zuul的简单使用(附代码下载)
场景 SpringCloud -创建统一的依赖管理: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/102530574 Sprin ...
随机推荐
- IDEA启动报错 NoClassDefFound
很仔细的看了项目,发现jar包都齐全,没有问题,找了几天,都没有发现什么问题. 最后,想到可能是启动配置的问题,内存的问题 加了上面的配置-Xss2058k,设定程序启动时占用内存大小,正常启动
- P10_组件-text和rich-text组件的基本用法
常用的基础内容组件 text 文本组件 类似于 HTML 中的 span 标签,是一个行内元素 rich-text 富文本组件 支持把 HTML 字符串渲染为 WXML 结构 text 组件的基本使用 ...
- 看完这篇你不能再说不懂SSO原理了!
这一篇是原理篇,接下来还会有一篇实战篇,实战的相关代码是非常火的一个开源项目叫:xxl-sso 一.简介 单点登录(Single Sign On),简称为 SSO. 它的解释是在多个应用系统中,用户只 ...
- 学习Java Day14
今天进一步学习了Java的类,学习了LocalDay:
- Istio 升级后踩的坑
背景 前段时间我们将 istio 版本升级到 1.12 后导致现有的应用监控有部分数据丢失(页面上显示不出来). 一个是应用基础信息丢失. 再一个是应用 JVM 数据丢失. 接口维度的监控数据丢失. ...
- python-最近面试遇到的代码题,mark一下
1. 打印1000以内的质数 draft版本: def printlist(): a = [] for i in range(1, 1001): b.append(i) for j in range( ...
- 零基础解读ChatGPT:对人类未来工作是威胁还是帮助?
摘要:火到现在的ChatGPT到底是什么?它背后有哪些技术?对于我们的工作和生活会有啥影响?快来一起了解吧~ 本文分享自华为云社区<零基础解读ChatGPT:对人类未来工作是威胁还是帮助?> ...
- DESIR队列:早期axSpA的脊柱放射学进展
DESIR队列:早期axSpA的脊柱放射学进展 EULAR2015; PresentID: FRI0234 SPINAL RADIOGRAPHIC PROGRESSION IN EARLY AXIAL ...
- 触觉仿真系统:Force Dimension+CHAI 3D
推荐:将 NSDT场景编辑器 加入你的3D开发工具链 Force Dimension 成立于2001年,总部在瑞士,比sensable 晚了8年,开发的理念也不一样,他们开发是连杆式力反馈触觉系统,仿 ...
- LeetCode-838 推多米诺
来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/push-dominoes 题目描述 n 张多米诺骨牌排成一行,将每张多米诺骨牌垂直竖立.在开始时 ...