神经网络学习之循环神经网络
第1关:循环神经网络
任务描述:本关任务是通过学习循环神经网络的基础知识,并完成单向循环网络的编写工作。
相关知识
为了完成本关任务,你需要掌握:
循环神经网络概述;
一般循环神经网络;
单向循环神经网络。
循环神经网络概述
对于我们已经学过的传统神经网络,它们能够实现分类以及标注任务,但一旦处理具有前后遗存关系的数据时,效果就不是十分理想了。这个问题主要由于传统神经网络的结构所导致。这时我们就需要一个不仅仅只依赖当前的输入,还需要结合前一时刻或后一时刻的输入作为参考。
循环神经网络就是根据这样的需求而设计的。循环神经网络的主要用途是处理和预测序列数据。循环神经网络最初就是为了刻画一个序列当前的输出与之前信息的关系。从网络结构上来看,循环神经网络会记忆之前的信息,并利用之前的信息影响后面节点的输出。也就是说,循环神经网络的隐藏层之间的节点是有连接的,隐藏层的输入不仅包含输入层的输出,还包括上一时刻隐藏层的输出。
import torch
def rnn(input,state,params):
"""
循环神经网络的前向传播
:param input: 输入,形状为 [ batch_size,num_inputs ]
:param state: 上一时刻循环神经网络的状态,形状为 [ batch_size,num_hiddens ]
:param params: 循环神经网络的所使用的权重以及偏置
:return: 输出结果和此时刻网络的状态
"""
W_xh,W_hh,b_h,W_hq,b_q = params
"""
W_xh : 输入层到隐藏层的权重
W_hh : 上一时刻状态隐藏层到当前时刻的权重
b_h : 隐藏层偏置
W_hq : 隐藏层到输出层的权重
b_q : 输出层偏置
"""
H = state
########## Begin ##########
# 输入层到隐藏层
H = torch.matmul(input, W_xh) + torch.matmul(H, W_hh) + b_h
H = torch.tanh(H)
# 隐藏层到输出层
Y = torch.matmul(H, W_hq) + b_q
########## End ##########
return Y,H
def init_rnn_state(num_inputs,num_hiddens):
"""
循环神经网络的初始状态的初始化
:param num_inputs: 输入层中神经元的个数
:param num_hiddens: 隐藏层中神经元的个数
:return: 循环神经网络初始状态
"""
########## Begin ##########
init_state = torch.zeros((num_inputs,num_hiddens),dtype=torch.float32)
########## End ##########
return init_state
第2关:梯度消失与梯度爆炸
本次任务要求深入学习梯度消失与梯度爆炸的相关知识,并掌握并应用梯度裁剪法。
相关知识
为了完成本关任务,你需要掌握:
BPTT算法;
梯度消失与梯度爆炸;
梯度裁剪法。
BPTT算法
循环神经网络在进行反向传播时,由于循环层包含两部分的输入,即当前时刻的输入与上一时刻循环层的输出,因此循环神经网络的训练算法相比较传统的神经网络训练算法多了 一步向前计算的过程,也被称为 BPTT(back propagation through time)。其基本步骤为:
完成每个神经元的前向输出值计算;
求取逆向误差项值;
通过梯度下降方法更新权重参数。
import torch
def grad_clipping(params,theta):
"""
梯度裁剪
:param params: 循环神经网络中所有的参数
:param theta: 阈值
"""
########## Begin ##########
norm = torch.tensor([0.0])
for param in params:
norm += (param.grad.data ** 2).sum()
norm = norm.sqrt().item() # 所有参数的L2范数
if norm > theta: # 大于阈值
for param in params:
param.grad.data *= (theta / norm) # 对每个参数的梯度进行裁剪
########## End ##########
第3关:长短时记忆网络
本次任务:在学习长短时记忆网络相关内容的过程中,请完成并具体实现该网络。
相关知识
为了完成本关任务,你需要掌握:
长短时记忆单元;
门控机制;
长短时记忆单元实现。
长短时记忆单元
传统的循环神经网络受限于梯度爆炸与梯度消失问题,在输入序列增长过程中容易导致内部参数震荡更加剧烈,从而使得模型难以有效学习相关任务。为了应对这一挑战,在深度学习领域中被提出了一种新型的记忆网络——长短时记忆单元( Long Short Term Memory Unit, LSTM)。该网络通过引入一个内部状态c来记录长期信息存储的能力,并以此为基础实现了对长期依赖关系的有效捕捉。
import torch
def lstm(X,state,params):
"""
LSTM
:param X: 输入
:param state: 上一时刻的单元状态和输出
:param params: LSTM 中所有的权值矩阵以及偏置
:return: 当前时刻的单元状态和输出
"""
W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c, W_hq, b_q = params
"""
W_xi,W_hi,b_i : 输入门中计算i的权值矩阵和偏置
W_xf,W_hf,b_f : 遗忘门的权值矩阵和偏置
W_xo,W_ho,b_o : 输出门的权值矩阵和偏置
W_xc,W_hc,b_c : 输入门中计算c_tilde的权值矩阵和偏置
W_hq,b_q : 输出层的权值矩阵和偏置
"""
#上一时刻的输出 H 和 单元状态 C。
(H,C) = state
########## Begin ##########
# 遗忘门
F = torch.matmul(X, W_xf) + torch.matmul(H, W_hf) + b_f
F = torch.sigmoid(F)
# 输入门
I = torch.sigmoid(torch.matmul(X,W_xi)+torch.matmul(H,W_hi) + b_i)
C_tilde = torch.tanh(torch.matmul(X, W_xc) + torch.matmul(H, W_hc) + b_c)
C = F * C + I * C_tilde
# 输出门
O = torch.sigmoid(torch.matmul(X,W_xo)+torch.matmul(H,W_ho) + b_o)
H = O * C.tanh()
# 输出层
Y = torch.matmul(H,W_hq) + b_q
########## End ##########
return Y,(H,C)
