MXNet双向循环神经网络----单个隐藏层的双向循环神经网络(程序)

本文详细介绍并实现了一个含单隐藏层的双向循环神经网络(RNN)模型,通过《动手学深度学习》一书的练习题进行深入解析。文中不仅讲解了双向RNN的数学原理,还提供了具体代码实现,展示了如何利用MXNet搭建和训练模型。

MXNet双向循环神经网络----单个隐藏层的双向循环神经网络(程序)

《动手学深度学习》第六章 第10节的练习题,个人解答。

下图演示了一个含单隐藏层的双向循环神经网络的架构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LfdILbao-1587711783753)(../img/birnn.svg)]

下面我们来介绍具体的定义。
给定时间步ttt的小批量输入Xt∈Rn×d\boldsymbol{X}_t \in \mathbb{R}^{n \times d}XtRn×d(样本数为nnn,输入个数为ddd)和隐藏层激活函数为ϕ\phiϕ。在双向循环神经网络的架构中,
设该时间步正向隐藏状态为H→t∈Rn×h\overrightarrow{\boldsymbol{H}}_t \in \mathbb{R}^{n \times h}HtRn×h(正向隐藏单元个数为hhh),
反向隐藏状态为H←t∈Rn×h\overleftarrow{\boldsymbol{H}}_t \in \mathbb{R}^{n \times h}HtRn×h(反向隐藏单元个数为hhh)。我们可以分别计算正向隐藏状态和反向隐藏状态:

H→t=ϕ(XtWxh(f)+H→t−1Whh(f)+bh(f)),H←t=ϕ(XtWxh(b)+H←t+1Whh(b)+bh(b)), \begin{aligned} \overrightarrow{\boldsymbol{H}}_t &= \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh}^{(f)} + \overrightarrow{\boldsymbol{H}}_{t-1} \boldsymbol{W}_{hh}^{(f)} + \boldsymbol{b}_h^{(f)}),\\ \overleftarrow{\boldsymbol{H}}_t &= \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh}^{(b)} + \overleftarrow{\boldsymbol{H}}_{t+1} \boldsymbol{W}_{hh}^{(b)} + \boldsymbol{b}_h^{(b)}), \end{aligned} HtHt=ϕ(XtWxh(f)+Ht1Whh(f)+bh(f)),=ϕ(XtWxh(b)+Ht+1Whh(b)+bh(b)),

其中权重Wxh(f)∈Rd×h\boldsymbol{W}_{xh}^{(f)} \in \mathbb{R}^{d \times h}Wxh(f)Rd×hWhh(f)∈Rh×h\boldsymbol{W}_{hh}^{(f)} \in \mathbb{R}^{h \times h}Whh(f)Rh×hWxh(b)∈Rd×h\boldsymbol{W}_{xh}^{(b)} \in \mathbb{R}^{d \times h}Wxh(b)Rd×hWhh(b)∈Rh×h\boldsymbol{W}_{hh}^{(b)} \in \mathbb{R}^{h \times h}Whh(b)Rh×h和偏差 bh(f)∈R1×h\boldsymbol{b}_h^{(f)} \in \mathbb{R}^{1 \times h}bh(f)R1×hbh(b)∈R1×h\boldsymbol{b}_h^{(b)} \in \mathbb{R}^{1 \times h}bh(b)R1×h均为模型参数。

然后我们连结两个方向的隐藏状态H→t\overrightarrow{\boldsymbol{H}}_tHtH←t\overleftarrow{\boldsymbol{H}}_tHt来得到隐藏状态Ht∈Rn×2h\boldsymbol{H}_t \in \mathbb{R}^{n \times 2h}HtRn×2h,并将其输入到输出层。输出层计算输出Ot∈Rn×q\boldsymbol{O}_t \in \mathbb{R}^{n \times q}OtRn×q(输出个数为qqq):

Ot=HtWhq+bq,\boldsymbol{O}_t = \boldsymbol{H}_t \boldsymbol{W}_{hq} + \boldsymbol{b}_q,Ot=HtWhq+bq,

其中权重Whq∈R2h×q\boldsymbol{W}_{hq} \in \mathbb{R}^{2h \times q}WhqR2h×q和偏差bq∈R1×q\boldsymbol{b}_q \in \mathbb{R}^{1 \times q}bqR1×q为输出层的模型参数。不同方向上的隐藏单元个数也可以不同。

小结

  • 双向循环神经网络在每个时间步的隐藏状态同时取决于该时间步之前和之后的子序列(包括当前时间步的输入)。

练习

  • 参考上图设计含多个隐藏层的双向循环神经网络。
import d2lzh as d2l
from mxnet import nd
from mxnet.gluon import rnn

(corpus_indices, char_to_idx, idx_to_char,
 vocab_size) = d2l.load_data_jay_lyrics()

初始化模型参数

创建公式中出现的参数,并初始化。

num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
ctx = d2l.try_gpu()

def get_params():
    def _one(shape):
        return nd.random.normal(scale=0.01, shape=shape, ctx=ctx)

    def _three():
        return (_one((num_inputs, num_hiddens)),
                _one((num_hiddens, num_hiddens)),
                nd.zeros(num_hiddens, ctx=ctx))

    W_xhf, W_hhf, b_hf = _three()  # 前向参数
    W_xhb, W_hhb, b_hb = _three()  # 反向参数

    # 输出层参数
    W_hq = _one((2*num_hiddens, num_outputs))
    b_q = nd.zeros(num_outputs, ctx=ctx)
    # 附上梯度
    params = [W_xhf, W_hhf, b_hf, W_xhb, W_hhb, b_hb,
              W_hq, b_q]
    for param in params:
        param.attach_grad()
    return params

定义模型

根据两个方向的隐藏状态H→t\overrightarrow{\boldsymbol{H}}_tHtH←t\overleftarrow{\boldsymbol{H}}_tHt,以及输出层计算输出Ot\boldsymbol{O}_tOt的计算公式创建双向循环神经网络模型。

def init_bi_state(batch_size, num_hiddens, ctx):
    return (nd.zeros(shape=(batch_size, num_hiddens), ctx=ctx),
            nd.zeros(shape=(batch_size, num_hiddens), ctx=ctx),)
def birnn(inputs, state, params):
    [W_xhf, W_hhf, b_hf,W_xhb, W_hhb, b_hb,
    W_hq, b_q] = params
    (Hf,Hb,) = state
    outputs = []
    for X in inputs:
        Hf = nd.sigmoid(nd.dot(X, W_xhf) + nd.dot(Hf, W_hhf) + b_hf)
        Hb = nd.sigmoid(nd.dot(X, W_xhb) + nd.dot(Hb, W_hhb) + b_hb)
        
        H = nd.concat(Hf,Hb,dim=1)
        Y = nd.dot(H, W_hq) + b_q
        outputs.append(Y)
    return outputs, (Hf, Hb,)
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-1  #lr设小后,没输出
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']

中间测试

[W_xhf, W_hhf, b_hf,W_xhb, W_hhb, b_hb,W_hq, b_q] = get_params()
(Hf,Hb,) = init_bi_state(batch_size, num_hiddens, ctx)
Hf,Hb,W_xhf
H = nd.concat(Hf,Hb,dim=1)
H
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]
<NDArray 32x512 @gpu(0)>

训练预测

d2l.train_and_predict_rnn(birnn, get_params, init_bi_state, num_hiddens,
                          vocab_size, ctx, corpus_indices, idx_to_char,
                          char_to_idx, False, num_epochs, num_steps, lr,
                          clipping_theta, batch_size, pred_period, pred_len,
                          prefixes)
epoch 40, perplexity 153.796754, time 1.32 sec
 - 分开 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我
 - 不分开哼不能 我不能 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 我不 
epoch 80, perplexity 33.458324, time 1.34 sec
 - 分开 我不能够不起 我不能够不起 我不能够不起 我不能够不起 我不能够不起 我不能够不起 我不能够不起 
 - 不分开始的我 我不能够不起 我不能够不起 我不能够不起 我不能够不起 我不能够不起 我不能够不起 我不能够
epoch 120, perplexity 10.509801, time 1.32 sec
 - 分开 我 这里什么 不会B血 我想就这样牵着你的手 不会B血 我想就这样牵着你的手 不会B血 我想就这样
 - 不分开不 我不能再想 我不能再想 我不能再想 我不能再想 我不能再想 我不能再想 我不能再想 我不能再想 
epoch 160, perplexity 4.527863, time 1.29 sec
 - 分开的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我
 - 不分开我爱你 一朵莫默默默离开这样打我妈妈这样牵着你的手不放开离开我 不能承受我已无处可躲可以演戏 快使用
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

irober

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值