牛客题解 | 实现一个简单的基于时间反向传播(BPTT)的循环神经网络(RNN)

题目

题目链接

循环神经网络(RNN)是一种能够处理序列数据的神经网络,其特点是能够将前一时刻的输出作为下一时刻的输入。

BPTT是循环神经网络的一种训练方法,其数学推导可以参考相关资料。大体的更新步骤与BP神经网络类似,但是不同的是需要考虑时间步长的影响。

具体原理可以参考相关文献,这里不做赘述。

在本题中,用到的计算公式如下:

h t = tanh ⁡ ( W x h x t + W h h h t − 1 + b h ) h_t = \tanh(W_{xh} x_t + W_{hh} h_{t-1} + b_h) ht=tanh(Wxhxt+Whhht1+bh)
y t = W h y h t + b y y_t = W_{hy} h_t + b_y yt=Whyht+by

权重更新方式如下

W x h = W x h − η ∂ L ∂ W x h W_{xh} = W_{xh} - \eta \frac{\partial L}{\partial W_{xh}} Wxh=WxhηWxhL
W h h = W h h − η ∂ L ∂ W h h W_{hh} = W_{hh} - \eta \frac{\partial L}{\partial W_{hh}} Whh=WhhηWhhL
W h y = W h y − η ∂ L ∂ W h y W_{hy} = W_{hy} - \eta \frac{\partial L}{\partial W_{hy}} Why=WhyηWhyL
b h = b h − η ∂ L ∂ b h b_h = b_h - \eta \frac{\partial L}{\partial b_h} bh=bhηbhL
b y = b y − η ∂ L ∂ b y b_y = b_y - \eta \frac{\partial L}{\partial b_y} by=byηbyL

学习率 η \eta η在本题中为0.01这个固定值。

标准代码如下

class SimpleRNN:
    def __init__(self, input_size, hidden_size, output_size):
        self.hidden_size = hidden_size
        self.W_xh = np.random.randn(hidden_size, input_size) * 0.01
        self.W_hh = np.random.randn(hidden_size, hidden_size) * 0.01
        self.W_hy = np.random.randn(output_size, hidden_size) * 0.01
        self.b_h = np.zeros((hidden_size, 1))
        self.b_y = np.zeros((output_size, 1))

    def forward(self, x):
        h = np.zeros((self.hidden_size, 1))  # Initialize hidden state
        outputs = []
        self.last_inputs = []
        self.last_hiddens = [h]
        
        for t in range(len(x)):
            self.last_inputs.append(x[t].reshape(-1, 1))
            h = np.tanh(np.dot(self.W_xh, self.last_inputs[t]) + np.dot(self.W_hh, h) + self.b_h)
            y = np.dot(self.W_hy, h) + self.b_y
            outputs.append(y)
            self.last_hiddens.append(h)
        
        self.last_outputs = outputs
        return np.array(outputs)

    def backward(self, x, y, learning_rate):
        dW_xh = np.zeros_like(self.W_xh)
        dW_hh = np.zeros_like(self.W_hh)
        dW_hy = np.zeros_like(self.W_hy)
        db_h = np.zeros_like(self.b_h)
        db_y = np.zeros_like(self.b_y)

        dh_next = np.zeros((self.hidden_size, 1))

        for t in reversed(range(len(x))):
            dy = self.last_outputs[t] - y[t].reshape(-1, 1)  # (Predicted - Actual)
            dW_hy += np.dot(dy, self.last_hiddens[t+1].T)
            db_y += dy

            dh = np.dot(self.W_hy.T, dy) + dh_next
            dh_raw = (1 - self.last_hiddens[t+1] ** 2) * dh  # Derivative of tanh

            dW_xh += np.dot(dh_raw, self.last_inputs[t].T)
            dW_hh += np.dot(dh_raw, self.last_hiddens[t].T)
            db_h += dh_raw

            dh_next = np.dot(self.W_hh.T, dh_raw)

        # Update weights and biases
        self.W_xh -= learning_rate * dW_xh
        self.W_hh -= learning_rate * dW_hh
        self.W_hy -= learning_rate * dW_hy
        self.b_h -= learning_rate * db_h
        self.b_y -= learning_rate * db_y
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值