在普通的神经网络中,信息是单项的,这种限制虽然使得网络变得更容易学习,但也在一定程度上减弱了神经网络模型的能力。特别是在很多现实任务中,网络的输出不仅和当前时刻的输入相关,也和过去一段时间内的输出相关。此外,普通网络难以处理时序数据,比如视频、语音、文本等,时间数据的长度一般不是固定的,而前馈神经网络要求输入和输出的位数都是固定的,不能任意改变。因此,当处理这一类和时序相关的问题时,就需要一种更强的模型。
循环神经网络(Recurrent Neural Network, RNN)是一类具有短期记忆能力的神经网络。在循环神经网络中,神经元不但可以接受其他神经元的信息,也可以接受自身的信息,形成具有环路的网络结构。换句话说:神经元的输出可以在下一个时间步直接作用到自身(作为输入)
通过简化图,可以看到RNN比传统神经网络多了一个循环圈,这个循环圈表示的是在下一个时间步(Time step)上会返回作为输入的一部分,把RNN在时间点上展开,得到的图形如下:
或者是:
在不同的时间步,RNN的输入都将与之前的时间状态有关,tn时刻网络的输出结果是该时刻的输入和所有历史共同作用的结果,这就达到了对使时间序列建模的目的。
one to one
图1: 固定长度的输入和输出(e.g.图像分类)
最基本的单层网络,输入是 x x x,经过变换 W x + b Wx+b Wx+b和激活函数 f f f得到输出 y y y。
one to n
图2:序列输出(e.g.图像转文字)
输入不是序列而输出为序列的情况,只在序列开始进行输入计算:
圆圈或方块表示的是向量。一个箭头就表示对该向量做一次变换。如上图中 h 0 h_0 h0和 x x x分别有一个箭头连接,就表示对 h 0 h_0 h0和 x x x各做了一次变换。
还有一种结构是把输入信息 X X X作为每个阶段的输入:
下图省略了一些X的圆圈,是一个等价表示:
这种 one-to-n 的结构可以处理的问题有:
(1) 从图像生成文字(image caption),此时输入的X就是图像的特征,而输出的y序列就是一段句子,就像看图说话等
(2) 从类别生成语音或音乐等
n to one
图3:数列输入(e.g.文本分类)
要处理的问题输入是一个序列,输出是一个单独的值而不是序列,应该怎样建模呢?实际上,我们只在最后一个h上进行输出变换就可以了:
这种结构通常用来处理序列分类问题。如输入一段文字判别它所属的类别,输入一个句子判断其情感倾向,输入一段视频并判断它的类别等等。
n to n
图4:异步的序列输入和输出(e.g.文本翻译)。图5:同步的序列输入和输出(e.g.根据视频的每一帧来对视频进行分类)
最经典的RNN结构,输入、输出都是等长的序列数据。假设输入为 X = ( x 1 , x 2 , x 3 , x 4 ) X=(x_1, x_2, x_3, x_4) X=(x1,x2,x3,x4),每个 x i x_i xi是一个单词的词向量。
为了建模序列问题,RNN引入了隐状态 h h h(hidden state)的概念, h h h可以对序列形的数据提取特征,接着再转换为输出。先从 h 1 h_1 h1的计算开始看:
h 2 h_2 h2的计算和 h 1 h_1 h1类似。要注意的是,在计算时,每一步使用的参数 U 、 W 、 b U、W、b U、W、b都是一样的,也就是说每个步骤的参数都是共享的,这是RNN的重要特点,一定要牢记。
依次计算剩下来的(使用相同的参数 U 、 W 、 b U、W、b U、W、b):
这里为了方便起见,只画出序列长度为4的情况,实际上,这个计算过程可以无限地持续下去。得到输出值的方法就是直接通过 h h h进行计算:
正如之前所说,一个箭头就表示对对应的向量做一次类似于 f ( V x + c ) f(Vx+c) f(Vx+c)的变换,这里的这个箭头就表示对 h 1 h_1 h1进行一次变换,得到输出 y 1 y_1 y1。
剩下的输出类似进行(使用和 y 1 y_1 y1同样的参数 V V V和 c c c):
这就是最经典的RNN结构,它的输入是 x 1 , x 2 , … . . x n x_1, x_2, …..x_n x1,x2,…..xn,输出为 y 1 , y 2 , … y n y_1, y_2, …y_n y1,y2,…yn,也就是说,输入和输出序列必须要是等长的。由于这个限制的存在,经典RNN的适用范围比较小,但也有一些问题适合用经典的RNN结构建模,如:
计算视频中每一帧的分类标签。因为要对每一帧进行计算,因此输入和输出序列等长。
输入为字符,输出为下一个字符的概率。这就是著名的Char RNN(详细介绍请参考:The Unreasonable Effectiveness of Recurrent Neural Networks,Char RNN可以用来生成文章,诗歌,甚至是代码,非常有意思)。
其实RNN存在着两种训练模式(mode):
free-running mode就是大家常见的那种训练网络的方式: 上一个state的输出作为下一个state的输入。
teacher-forcing mode是一种快速有效地训练循环神经网络模型的方法,该模型每次不使用上一个state的输出作为下一个state的输入,而是直接使用训练数据的标准答案(ground truth)的对应上一项作为下一个state的输入。所谓Teacher Forcing,就是在学习时跟着老师(ground truth)走!它是一种网络训练方法,对于开发用于机器翻译,文本摘要,图像字幕的深度学习语言模型以及许多其他应用程序至关重要。
①RNN优点
②RNN缺点
import torch
import datetime
import numpy as np
import torch.nn as nn
import torch.optim as optim
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['FangSong']
mpl.rcParams['axes.unicode_minus'] = False
###########################设置全局变量###################################
num_time_steps = 16 # 训练时时间窗的步长
input_size = 3 # 输入数据维度
hidden_size = 16 # 隐含层维度
output_size = 3 # 输出维度
num_layers = 1
lr=0.01
####################定义RNN类##############################################
class Net(nn.Module):
def __init__(self, input_size, hidden_size, num_layers):
super(Net, self).__init__()
self.rnn = nn.RNN(
input_size=input_size,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True,
)
for p in self.rnn.parameters():
nn.init.normal_(p, mean=0.0, std=0.001)
self.linear = nn.Linear(hidden_size, output_size)
def forward(self, x, hidden_prev):
out, hidden_prev = self.rnn(x, hidden_prev)
# [b, seq, h]
out = out.view(-1, hidden_size)
out = self.linear(out)#[seq,h] => [seq,3]
out = out.unsqueeze(dim=0) # => [1,seq,3]
return out, hidden_prev
####################初始化训练集#################################
def getdata():
x1 = np.linspace(1,10,30).reshape(30,1)
y1 = (np.zeros_like(x1)+2)+np.random.rand(30,1)*0.1
z1 = (np.zeros_like(x1)+2).reshape(30,1)
tr1 = np.concatenate((x1,y1,z1),axis=1)
# mm = MinMaxScaler()
# data = mm.fit_transform(tr1) #数据归一化
return tr1
#####################开始训练模型#################################
def tarin_RNN(data):
model = Net(input_size, hidden_size, num_layers)
print('model:\n',model)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr)
#初始化h
hidden_prev = torch.zeros(1, 1, hidden_size)
l = []
# 训练3000次
for iter in range(3000):
# loss = 0
start = np.random.randint(10, size=1)[0]
end = start + 15
x = torch.tensor(data[start:end]).float().view(1, num_time_steps - 1, 3)
# 在data里面随机选择15个点作为输入,预测第16
y = torch.tensor(data[start + 5:end + 5]).float().view(1, num_time_steps - 1, 3)
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("Iteration: {} loss {}".format(iter, loss.item()))
l.append(loss.item())
##############################绘制损失函数#################################
plt.plot(l,'r')
plt.xlabel('训练次数')
plt.ylabel('loss')
plt.title('RNN损失函数下降曲线')
return hidden_prev,model
#############################预测#########################################
def RNN_pre(model,data,hidden_prev):
data_test = data[19:29]
data_test = torch.tensor(np.expand_dims(data_test, axis=0),dtype=torch.float32)
pred1,h1 = model(data_test,hidden_prev )
print('pred1.shape:',pred1.shape)
pred2,h2 = model(pred1,hidden_prev )
print('pred2.shape:',pred2.shape)
pred1 = pred1.detach().numpy().reshape(10,3)
pred2 = pred2.detach().numpy().reshape(10,3)
predictions = np.concatenate((pred1,pred2),axis=0)
# predictions= mm.inverse_transform(predictions)
print('predictions.shape:',predictions.shape)
#############################预测可视化########################################
fig = plt.figure(figsize=(9, 6))
ax = Axes3D(fig)
ax.scatter3D(data[:, 0],data[:, 1],data[:,2],c='red')
ax.scatter3D(predictions[:,0],predictions[:,1],predictions[:,2],c='y')
ax.set_xlabel('X')
ax.set_xlim(0, 8.5)
ax.set_ylabel('Y')
ax.set_ylim(0, 10)
ax.set_zlabel('Z')
ax.set_zlim(0, 4)
plt.title("RNN航迹预测")
plt.show()
def main():
data = getdata()
start = datetime.datetime.now()
hidden_pre, model = tarin_RNN(data)
end = datetime.datetime.now()
print('The training time: %s' % str(end - start))
plt.show()
RNN_pre(model, data, hidden_pre)
if __name__ == '__main__':
main()
Encoder-Decoder 框架,Encoder-Decoder 不是一个具体的模型,是一种框架。在不同的NLP任务中,Encoder框架及Decoder框架均是由多个单独的特征提取器堆叠而成,比如说我们之前提到的LSTM结构或CNN结构。由最初的one-hot向量通过Encoder框架,我们将得到一个矩阵(或是一个向量),这就可以看作其对输入序列的一个编码。而对于Decoder结构就比较灵活了,我们可以根据任务的不同,对我们得到的“特征”矩阵或“特征”向量进行解码,输出为我们任务需要的输出结果。因此,对于不同的任务,如果我们堆叠的特征抽取器能够提取到更好的特征,那么理论上来说,在所有的NLP任务中我们都能够得到更好的表现。
Encoder-Decoder结构是 n-to-m,输入、输出为不等长的序列,也叫Seq2Seq,是RNN的一个重要变种。原始的n-to-n的RNN要求序列等长,然而我们遇到的大部分问题序列都是不等长的,如机器翻译中,源语言和目标语言的句子往往并没有相同的长度。为此,Encoder-Decoder结构先将输入数据编码成一个上下文语义向量 c c c:
语义向量 c c c可以有多种表达方式,最简单的方法就是把Encoder的最后一个隐状态赋值给c,还可以对最后的隐状态做一个变换得到c,也可以对所有的隐状态做变换。
拿到c之后,就用另一个RNN网络对其进行解码,这部分RNN网络被称为Decoder。Decoder的RNN可以与Encoder的一样,也可以不一样。具体做法就是将c当做之前的初始状态 h 0 h_0 h0输入到Decoder中:
还有一种做法是将c当做每一步的输入:
Encoder-Decoder 应用
由于这种Encoder-Decoder结构不限制输入和输出的序列长度,因此应用的范围非常广泛,比如:
Encoder:将 input序列 →转成→ 固定长度的向量
Decoder:将 固定长度的向量 →转成→ output序列
Encoder 与 Decoder 可以彼此独立使用,实际上经常一起使用
因为最早出现的机器翻译领域,最早广泛使用的转码模型是RNN。其实模型可以是 CNN /RNN /BiRNN /LSTM /GRU /…
Encoder-Decoder 缺点
最大的局限性:编码和解码之间的唯一联系是固定长度的语义向量c
编码要把整个序列的信息压缩进一个固定长度的语义向量c,语义向量c无法完全表达整个序列的信息。先输入的内容携带的信息,会被后输入的信息稀释掉,或者被覆盖掉。输入序列越长,这样的现象越严重,这样使得在Decoder解码时一开始就没有获得足够的输入序列信息,解码效果会打折扣。因此,为了弥补基础的 Encoder-Decoder 的局限性,提出了attention机制。
注意力机制(attention mechanism)是对基础Encoder-Decoder的改良。Attention机制通过在每个时间输入不同的c来解决问题,下图是带有Attention机制的Decoder:
每一个c会自动去选取与当前所要输出的 y y y最合适的上下文信息。具体来说,我们用 a i j a_{ij} aij衡量Encoder中第 j j j阶段的 h j h_j hj和解码时第 i i i阶段的相关性,最终Decoder中第 i i i阶段的输入的上下文信息 c i c_i ci就来自于所有 h j h_j hj 对 a i j a_{ij} aij 的加权和。以机器翻译为例(将中文翻译成英文):
输入的序列是“我爱中国”,因此,Encoder中的 h 1 、 h 2 、 h 3 、 h 4 h_1、h_2、h_3、h_4 h1、h2、h3、h4就可以分别看做是“我”、“爱”、“中”、“国”所代表的信息。在翻译成英语时,第一个上下文 c 1 c_1 c1应该和 “我” 这个字最相关,因此对应的 a 11 a_{11} a11 就比较大,而相应的 a 12 、 a 13 、 a 14 a_{12}、a_{13}、a_{14} a12、a13、a14 就比较小。 c 2 c_2 c2应该和“爱”最相关,因此对应的 a 22 a_{22} a22 就比较大。最后的 c 3 c_3 c3和 h 3 、 h 4 h_3、h_4 h3、h4最相关,因此 a 33 、 a 34 a_{33}、a_{34} a33、a34 的值就比较大。
文章浏览阅读2.9k次,点赞8次,收藏14次。测试主要做什么?这完全都体现在测试流程中,同时测试流程是面试问题中出现频率最高的,这不仅是因为测试流程很重要,而是在面试过程中这短短的半小时到一个小时的时间,通过测试流程就可以判断出应聘者是否合适,故在测试流程中包含了测试工作的核心内容,例如需求分析,测试用例的设计,测试执行,缺陷等重要的过程。..._测试过程管理中包含哪些过程
文章浏览阅读870次,点赞16次,收藏19次。1.背景介绍政府数字化政务是指政府利用数字技术、互联网、大数据、人工智能等新技术手段,对政府政务进行数字化改革,提高政府工作效率,提升政府服务质量的过程。随着人工智能(AI)和机器学习(ML)技术的快速发展,政府数字化政务中的人工智能与机器学习应用也逐渐成为政府改革的重要内容。政府数字化政务的人工智能与机器学习应用涉及多个领域,包括政策决策、政府服务、公共安全、社会治理等。在这些领域,人工...
文章浏览阅读219次,点赞2次,收藏4次。系统主要的用户为用户、管理员,他们的具体权限如下:用户:用户登录后可以对管理员上传的学习视频进行学习。用户可以选择题型进行练习。用户选择小程序提供的考研科目进行相关训练。用户可以进行水平测试,并且查看相关成绩用户可以进行错题集的整理管理员:管理员登录后可管理个人基本信息管理员登录后可管理个人基本信息管理员可以上传、发布考研的相关例题及其分析,并对题型进行管理管理员可以进行查看、搜索考研题目及错题情况。_mysql刷题软件
文章浏览阅读1.4k次。myelipse里有UML1和UML2两种方式,UML2功能更强大,但是两者生成过程差别不大1.建立Test工程,如下图,uml包存放uml类图package com.zz.domain;public class User {private int id;private String name;public int getId() {return id;}public void setId(int..._根据以下java代码画出类图
文章浏览阅读174次。需求:一个topic包含很多个表信息,需要自动根据json字符串中的字段来写入到hive不同的表对应的路径中。发送到Kafka中的数据原本最外层原本没有pkDay和project,只有data和name。因为担心data里面会空值,所以根同事商量,让他们在最外层添加了project和pkDay字段。pkDay字段用于表的自动分区,proejct和name合起来用于自动拼接hive表的名称为 ..._flume拦截器自定义开发 kafka
文章浏览阅读380次。原标题:Java Spring中同时访问多种不同数据库 多样的工作要求,可以使用不同的工作方法,只要能获得结果,就不会徒劳。开发企业应用时我们常常遇到要同时访问多种不同数据库的问题,有时是必须把数据归档到某种数据仓库中,有时是要把数据变更推送到第三方数据库中。使用Spring框架时,使用单一数据库是非常容易的,但如果要同时访问多个数据库的话事件就变得复杂多了。本文以在Spring框架下开发一个Sp..._根据输入的不同连接不同的数据库
文章浏览阅读3.6k次,点赞9次,收藏25次。本案例描述了晶振屏蔽以及开关电源变压器屏蔽对系统稳定工作的影响, 硬件设计时应考虑。_eft电路图
文章浏览阅读1.1k次。对于物料价格的更改,可以采取不同的手段:首先,我们来介绍MR21的方式。 需要说明的是,如果要对某一产品进行价格修改,必须满足的前提条件是: ■ 1、必须对价格生效的物料期间与对应会计期间进行开启; ■ 2、该产品在该物料期间未发生物料移动。执行MR21,例如更改物料1180051689的价格为20000元,系统提示“对于物料1180051689 存在一个当前或未来标准价格”,这是因为已经对该..._mr21 对于物料 zba89121 存在一个当前或未来标准价格
文章浏览阅读7.4k次,点赞3次,收藏13次。[文章导读]联想启天M420是一款商用台式电脑,预装的是win10系统,用户还是喜欢win7系统,该台式机采用的intel 8代i5 8500CPU,在安装安装win7时有很多问题,在安装win7时要在BIOS中“关闭安全启动”和“开启兼容模式”,并且安装过程中usb不能使用,要采用联想win7新机型安装,且默认采用的uefi+gpt模式,要改成legacy+mbr引导,那么联想启天M420台式电..._启天m420刷bios
文章浏览阅读2.7k次,点赞2次,收藏9次。一,为什么要冗余数据互联网数据量很大的业务场景,往往数据库需要进行水平切分来降低单库数据量。水平切分会有一个patition key,通过patition key的查询能..._保证冗余性
文章浏览阅读88次。是时候闭环Java应用了 原创 2016-08-16 张开涛 你曾经因为部署/上线而痛苦吗?你曾经因为要去运维那改配置而烦恼吗?在我接触过的一些部署/上线方式中,曾碰到过以下一些问题:1、程序代码和依赖都是人工上传到服务器,不是通过工具进行部署和发布;2、目录结构没有规范,jar启动时通过-classpath任意指定;3、fat jar,把程序代码、配置文件和依赖jar都打包到一个jar中,改配置..._那么需要把上面的defaultjavatyperesolver类打包到插件中
文章浏览阅读909次。1.得下载一个番茄插件,按alt+g才可以有函数跳转功能。2.不安装番茄插件,按F12也可以有跳转功能。3.进公司的VS工程是D:\sync\build\win路径,.sln才是打开工程的方式,一个是VS2005打开的,一个是VS2013打开的。4.公司库里的线程接口,在CmThreadManager.h 里,这个里面是我们的线程库,可以直接拿来用。CreateUserTaskThre..._番茄助手颜色