双向循环神经网络 讨论区

http://zh.diveintodeeplearning.org/chapter_recurrent-neural-networks/bi-rnn.html

楼主您好,关于birnn我有一个疑问想在这个地方提一下,希望能够得到解答。


假如我需要做一个birnn做一个文本分类,那么我该选哪个时刻的输出呢?是y0还是yt呢 yt包含只包含正向x0 - xt的信息反向只包含xt的信息,y0反之,总之不管是y0 y1 y2还是yt都不包含正向和反向的所有序列信息。

1赞

hello~能不能把你的code分享一下啊?
我不知道反向的code该怎么写,用for/in实现吗?但是那不是只能正向依次取X的数据吗?怎么反着取啊?

我是双向lstm,你去看看lstm的代码 说的很清楚模仿一下 正向看完反向自然而然就清楚了

之前一直是同层放在水平线上,图6.12画风突变,把同一层纵向放了。而H上的左右箭头还是水平的,看着好别扭。反而是try_123截的图好,画法合理,容易理解。建议作者也把图改成水平风格

X[::-1]不就是反着取了吗

有没有用循环神经网络做数值回归的例子呢,想学习一下。

时间步正向两层,逆向两层,简单快速实现,没有封装~

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

    # 时间步正向第 1 层
    w_xh1 = _one((num_input, num_hidden))
    w_hh1 = _one((num_hidden, num_hidden))
    b_h1 = nd.zeros(num_hidden, ctx=ctx)

    # 时间步正向第 2 层
    w_xh2 = _one((num_hidden, num_hidden))
    w_hh2 = _one((num_hidden, num_hidden))
    b_h2 = nd.zeros(num_hidden, ctx=ctx)

    # 时间步逆向第 1 层
    w_xh1_b = _one((num_input, num_hidden))
    w_hh1_b = _one((num_hidden, num_hidden))
    b_h1_b = nd.zeros(num_hidden, ctx=ctx)

    # 时间步逆向第 2 层
    w_xh2_b = _one((num_hidden, num_hidden))
    w_hh2_b = _one((num_hidden, num_hidden))
    b_h2_b = nd.zeros(num_hidden, ctx=ctx)

    w_hq = _one((num_hidden * 2, num_output))
    b_q = nd.zeros(num_output, ctx=ctx)
    params = [
        w_xh1, w_hh1, b_h1,
        w_xh2, w_hh2, b_h2,

        w_xh1_b, w_hh1_b, b_h1_b,
        w_xh2_b, w_hh2_b, b_h2_b,

        w_hq, b_q,
    ]
    for p in params:
        p.attach_grad()
    return params


def init_rnn_state(_batch_size, _num_hidden, _ctx):
    return (
        # 时间步正向第 1 层
        nd.zeros(shape=(_batch_size, _num_hidden), ctx=ctx),
        # 时间步正向第 2 层
        nd.zeros(shape=(_batch_size, _num_hidden), ctx=ctx),
        # 时间步逆向第 1 层
        nd.zeros(shape=(_batch_size, _num_hidden), ctx=ctx),
        # 时间步逆向第 2 层
        nd.zeros(shape=(_batch_size, _num_hidden), ctx=ctx),
    )


def deep_rnn(_input: nd.NDArray, state: tuple, params: list):
    w_xh1, w_hh1, b_h1, w_xh2, w_hh2, b_h2, w_xh1_b, w_hh1_b, b_h1_b, w_xh2_b, w_hh2_b, b_h2_b, w_hq, b_q = params
    state_forward_1, state_forward_2, state_backward_1, state_backward_2 = state
    # 时间步逆向第 2 层缓存,索引是时间步正向
    time_state_backward_final = [None] * len(_input)
    output = []
    for _i in range(len(_input)):
        # 逆序遍历 _input
        i = len(_input) - 1 - _i
        x = _input[i]
        state_backward_1 = nd.tanh(nd.dot(x, w_xh1_b) + nd.dot(state_backward_1, w_hh1_b) + b_h1_b)
        state_backward_2 = nd.tanh(nd.dot(state_forward_1, w_xh2_b) + nd.dot(state_backward_2, w_hh2_b) + b_h2_b)
        # 按时间步顺序缓存时间步逆向第 2 层
        time_state_backward_final[i] = state_backward_2.copy()
    for i, x in enumerate(_input):
        state_forward_1 = nd.tanh(nd.dot(x, w_xh1) + nd.dot(state_forward_1, w_hh1) + b_h1)
        state_forward_2 = nd.tanh(nd.dot(state_forward_1, w_xh2) + nd.dot(state_forward_2, w_hh2) + b_h2)
        state = nd.concat(state_forward_2, time_state_backward_final[i])
        y_hat = nd.dot(state, w_hq) + b_q
        output.append(y_hat)
    return output, (state_forward_1, state_forward_2, state_backward_1, state_backward_2)