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

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

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

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

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

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

H → t = ϕ ( X t W x h ( f ) + H → t − 1 W h h ( f ) + b h ( f ) ) , H ← t = ϕ ( X t W x h ( b ) + H ← t + 1 W h h ( b ) + b h ( 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} H tH t=ϕ(XtWxh(f)+H t1Whh(f)+bh(f)),=ϕ(XtWxh(b)+H t+1Whh(b)+bh(b)),

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

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

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

其中权重 W h q ∈ R 2 h × q \boldsymbol{W}_{hq} \in \mathbb{R}^{2h \times q} WhqR2h×q和偏差 b q ∈ R 1 × 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}}_t H t H ← t \overleftarrow{\boldsymbol{H}}_t H t,以及输出层计算输出 O t \boldsymbol{O}_t Ot的计算公式创建双向循环神经网络模型。

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
 - 分开的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我
 - 不分开我爱你 一朵莫默默默离开这样打我妈妈这样牵着你的手不放开离开我 不能承受我已无处可躲可以演戏 快使用
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

irober

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

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

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

打赏作者

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

抵扣说明:

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

余额充值