89、循环神经网络(RNN)梯度推导详解

RNN与LSTM梯度推导详解

循环神经网络(RNN)梯度推导详解

1. 因果机器学习基础

在机器学习策略中,因果假设并非经常被引入,但它能增强机器学习解决方案的泛化能力。拓展因果机器学习概念的一个关键工具是反事实探究,即设想特定过程 a 导致结果 b 的情况,也就是针对与观察结果相关的假设性回溯干预进行反事实解释。

为实现更广泛的应用,除了采用因果分解公式,还可假设图中每个节点信号的生成方式为:
[x_i = f_i(pa(x_i),u_i)]
其中,随机信号 (u_i) 表示对 (x_i) 的解释性贡献,(f_i(\cdot)) 为确定性函数。通常情况下,噪声项 (u_1,u_2,\cdots,u_i,\cdots) 被假定为联合独立。通过人类行为或学习方法,这些工具可用于分析反事实、干预和观察。结构因果模型(SCM)不仅能像因果有向图模型(DGM)一样灵活计算基于干预的分布,还能通过固定噪声信号的值来实现反事实分析。

2. 标准 RNN 的梯度推导

基于梯度的学习算法的进一步发展需要计算所选成本函数关于网络参数的多个偏导数,这些表达式均运用了链式法则。

  • 关于 (W_o) 和 (b_o) 的梯度
    [
    \begin{align }
    \frac{\partial\overline{J}(\hat{y},y)}{\partial W_o}&=\sum_{k = 1}^{K}\left(\frac{\partial J^{(k)}}{\partial\hat{y}^{(k)}}\right)^T\frac{\partial\hat{y}^{(

<think>我们正在讨论循环神经网络RNN)中的反向传播算法,特别是BPTT(Backpropagation Through Time)。用户要求了解反向传播算法在RNN中如何实现参数更新。根据引用内容,BPTT是RNN中用于训练的特殊反向传播技术,它通过时间展开RNN,将其视为一个深度前馈网络,然后应用反向传播计算梯度并更新参数。 核心要点: 1. RNN的参数在时间步之间共享(即U, W, V, b, c等参数在所有时间步都是相同的)。 2. BPTT的基本思想是将RNN按时间序列展开,形成一个虚拟的深层网络,每一层对应一个时间步。 3. 在展开的网络中,使用标准的反向传播算法计算梯度,但由于参数共享,我们需要将所有时间步上相同参数的梯度累加起来,然后进行更新。 步骤: 1. 前向传播:从时间t=1到t=T(序列长度)进行前向计算,保存每个时间步的隐藏状态和输出。 2. 计算损失:通常是对每个时间步的损失求和(如交叉熵损失)。 3. 反向传播:从t=T开始,反向计算每个时间步的梯度,一直回溯到t=1。 4. 梯度累加:由于参数共享,每个时间步的梯度都会贡献给相同的参数,因此需要将每个时间步的梯度累加。 5. 参数更新:使用累加的梯度(通常也会除以序列长度或批次大小进行归一化)来更新参数。 数学推导: 考虑一个简单的RNN模型,其结构如下: - 输入:$x_t$(时间步t的输入向量) - 隐藏状态:$h_t = \tanh(W_{xh} x_t + W_{hh} h_{t-1} + b_h)$ - 输出:$y_t = \text{softmax}(W_{hy} h_t + b_y)$ 损失函数:假设我们使用交叉熵损失,对于每个时间步的损失为$L_t = - \sum y_{t, \text{true}} \log y_{t, \text{pred}}$,总损失$L = \sum_{t=1}^T L_t$。 在反向传播中,我们需要计算损失函数对参数$W_{xh}, W_{hh}, W_{hy}, b_h, b_y$的梯度。 以$W_{hh}$为例,由于它在每个时间步都被使用,因此梯度计算为: $$\frac{\partial L}{\partial W_{hh}} = \sum_{t=1}^T \frac{\partial L}{\partial h_t} \frac{\partial h_t}{\partial W_{hh}}$$ 但是注意,$h_t$不仅依赖于当前时间步的$W_{hh}$,还通过$h_{t-1}$依赖于之前所有时间步的$W_{hh}$(因为$h_{t-1}$也是$W_{hh}$的函数)。因此,我们需要使用链式法则沿着时间展开。 具体地,对于$h_t$,它的梯度来自两部分: - 直接来自当前时间步的输出层(通过$y_t$) - 来自下一个时间步的隐藏状态(因为$h_t$会影响到$h_{t+1}$) 因此,在反向传播时,从最后一个时间步T开始,我们计算损失对$h_T$的梯度,然后传递到$h_{T-1}$,依此类推直到$h_1$。 定义: - $\delta_t = \frac{\partial L}{\partial h_t}$ 表示损失对t时刻隐藏状态的梯度。 那么,$\delta_t$的计算包括: - 来自当前时间步的输出层:$\frac{\partial L_t}{\partial h_t} = (y_t - \text{true\_label}_t) \cdot W_{hy}^\top$(这里假设是分类任务,softmax输出) - 来自下一个时间步的隐藏状态:$\frac{\partial L}{\partial h_{t+1}} \cdot \frac{\partial h_{t+1}}{\partial h_t} = \delta_{t+1} \cdot W_{hh}^\top \cdot (1 - h_t^2)$ (因为$h_{t+1}$中使用了$h_t$,且激活函数是tanh,其导数为$1-\tanh^2$) 所以: $$\delta_t = W_{hy}^\top (y_t - \text{true\_label}_t) + W_{hh}^\top \delta_{t+1} \cdot (1 - h_t^2)$$ 注意:对于最后一个时间步T,没有来自未来的梯度,所以$\delta_T = W_{hy}^\top (y_T - \text{true\_label}_T)$。 然后,对于参数$W_{hh}$,梯度为: $$\frac{\partial L}{\partial W_{hh}} = \sum_{t=1}^T \delta_t \cdot (1 - h_t^2) \cdot h_{t-1}^\top$$ 其中,$h_{t-1}$是上一时刻的隐藏状态(注意:在t=1时,$h_0$通常是初始化为0向量)。 同样,对于其他参数,如$W_{xh}$: $$\frac{\partial L}{\partial W_{xh}} = \sum_{t=1}^T \delta_t \cdot (1 - h_t^2) \cdot x_t^\top$$ 对于偏置$b_h$: $$\frac{\partial L}{\partial b_h} = \sum_{t=1}^T \delta_t \cdot (1 - h_t^2)$$ 对于输出层的参数$W_{hy}$和$b_y$,由于它们不依赖于时间(每个时间步独立),所以梯度计算更直接: $$\frac{\partial L}{\partial W_{hy}} = \sum_{t=1}^T (y_t - \text{true\_label}_t) \cdot h_t^\top$$ $$\frac{\partial L}{\partial b_y} = \sum_{t=1}^T (y_t - \text{true\_label}_t)$$ 最后,使用梯度下降更新参数: $$W = W - \eta \frac{\partial L}{\partial W}$$ 其中$\eta$是学习率。 注意:在实际实现中,由于序列可能很长,BPTT可能会遇到梯度消失或爆炸问题。因此,通常使用截断的BPTT(Truncated BPTT),即只反向传播固定步数(例如,只回传k步)。 总结步骤: 1. 前向传播:计算并保存每个时间步的输入、隐藏状态、输出。 2. 计算每个时间步的损失,并累加得到总损失。 3. 反向传播:从最后一个时间步开始,计算损失对隐藏状态的梯度($\delta_t$),并反向传递,同时累加各个参数的梯度。 4. 使用累加的梯度更新参数。 注意:参数共享意味着在更新时,所有时间步的相同参数使用同一个梯度(即累加后的梯度)进行更新。 引用说明: 根据引用[1][2][3],BPTT是RNN训练中使用的特殊反向传播算法,通过时间展开,将RNN视为深度网络,然后进行反向传播,同时参数共享是RNN的特点,因此梯度更新时需要对所有时间步的梯度进行累加[^1][^2][^3]。 下面,我们将按照上述思路组织回答。</think>### 循环神经网络RNN)中的反向传播算法(BPTT)实现详解 循环神经网络通过**时间展开结构**和**参数共享机制**实现序列建模,其反向传播采用**通过时间反向传播(BPTT)算法**,核心是通过时间维度展开网络结构并计算梯度。以下是具体实现步骤: --- #### 一、BPTT 算法核心原理 1. **时间展开结构** 将长度为 $T$ 的序列展开为 $T$ 层前馈网络,每层对应一个时间步: $$ \text{RNN} \rightarrow \underbrace{\text{NN}_1 \rightarrow \text{NN}_2 \rightarrow \cdots \rightarrow \text{NN}_T}_{\text{时间展开}} $$ 其中每层共享相同参数 $(W_{xh}, W_{hh}, W_{hy}, b_h, b_y)$[^1][^2]。 2. **梯度传播路径** 损失函数 $L$ 的梯度需沿时间反向传播: $$ \frac{\partial L}{\partial \theta} = \sum_{t=1}^T \frac{\partial L_t}{\partial \theta} \quad (\theta \in \{W_{xh}, W_{hh}, \cdots\}) $$ 梯度需从 $t=T$ 逐层传递至 $t=1$[^2][^3]。 --- #### 二、BPTT 具体实现步骤 ##### 1. 前向传播(保存中间状态) ```python # 初始化隐藏状态 h_0 = np.zeros(hidden_size) for t in range(1, T+1): # 计算当前隐藏状态 h_t = np.tanh(W_{xh} @ x_t + W_{hh} @ h_{t-1} + b_h) # 计算输出 y_t = softmax(W_{hy} @ h_t + b_y) # 保存 h_t 用于反向传播 cache[t] = (x_t, h_t, h_{t-1}) ``` ##### 2. 反向传播(梯度计算) 以参数 $W_{hh}$ 为例,梯度计算需考虑时间依赖: $$ \frac{\partial L}{\partial W_{hh}} = \sum_{t=1}^T \frac{\partial L}{\partial h_t} \frac{\partial h_t}{\partial W_{hh}} + \frac{\partial L}{\partial h_t} \frac{\partial h_t}{\partial h_{t-1}} \frac{\partial h_{t-1}}{\partial W_{hh}} + \cdots $$ 具体实现: ```python # 初始化梯度 dW_{hh} = np.zeros_like(W_{hh}) dh_next = np.zeros_like(h_T) # 从最后时间步开始 for t in reversed(range(1, T+1)): x_t, h_t, h_{t-1} = cache[t] # 计算当前 h_t 的梯度 (来自输出层 + 下一时间步) dh_t = dL/dy_t @ W_{hy} * (1 - h_t**2) + dh_next # 累积 W_{hh} 梯度 dW_{hh} += dh_t @ h_{t-1}.T # 计算传递到前一时间步的梯度 dh_next = dh_t @ W_{hh} * (1 - h_{t-1}**2) ``` ##### 3. 参数更新(梯度累加) 所有时间步共享参数,梯度需累加后统一更新: $$ W_{hh} \leftarrow W_{hh} - \eta \cdot \frac{1}{T} \sum_{t=1}^T \frac{\partial L_t}{\partial W_{hh}} $$ 其中 $\eta$ 为学习率[^2][^3]。 --- #### 三、BPTT 的数学推导(以 $W_{hh}$ 为例) 1. **隐藏状态梯度**: $$ \delta_t = \frac{\partial L}{\partial h_t} = \underbrace{\frac{\partial L}{\partial y_t} \frac{\partial y_t}{\partial h_t}}_{\text{输出层梯度}} + \underbrace{\frac{\partial L}{\partial h_{t+1}} \frac{\partial h_{t+1}}{\partial h_t}}_{\text{时间传播}} $$ 2. **参数梯度分解**: $$ \frac{\partial L}{\partial W_{hh}} = \sum_{k=1}^T \sum_{t=k}^T \frac{\partial L}{\partial h_t} \frac{\partial h_t}{\partial h_k} \frac{\partial h_k}{\partial W_{hh}} $$ 3. **梯度计算通式**: $$ \frac{\partial h_t}{\partial h_k} = \prod_{j=k}^{t-1} \left( \frac{\partial h_{j+1}}{\partial h_j} \right) = \prod_{j=k}^{t-1} W_{hh}^\top \cdot \text{diag}(1 - h_j^2) $$ 其中 $\text{diag}(1 - h_j^2)$ 是 $\tanh$ 激活函数的 Jacobian 矩阵[^1][^3]。 --- #### 四、BPTT 的优化挑战 | 问题 | 原因 | 解决方案 | |---------------------|----------------------------------------------------------------------|------------------------------| | **梯度消失** | 长期依赖中 $\prod_{j=k}^{t-1} \| \frac{\partial h_{j+1}}{\partial h_j} \| \ll 1$ | LSTM/GRU 门控机制[^3] | | **梯度爆炸** | $\prod \| \cdot \| \gg 1$ | 梯度裁剪(Gradient Clipping)| | **计算复杂度高** | $O(T^2)$ 时间复杂度和 $O(T)$ 空间复杂度 | 截断 BPTT(Truncated BPTT) | > **截断 BPTT 示例**:仅回传 $k$ 步梯度 > $$ \frac{\partial \tilde{L}}{\partial W_{hh}} = \sum_{t=\max(1,T-k)}^T \frac{\partial L_t}{\partial W_{hh}} $$ --- ### 总结 BPTT 算法通过时间展开将 RNN 转化为虚拟深度网络,在反向传播时: 1. **按时间逆序计算梯度**:从 $t=T$ 到 $t=1$ 逐层回溯 2. **梯度累加更新**:共享参数需聚合所有时间步梯度 3. **处理时序依赖**:通过 $\frac{\partial h_t}{\partial h_{t-1}}$ 传递历史信息[^1][^2][^3] 该算法虽存在梯度问题,但为 RNN 训练提供了理论基础,后续改进模型(如 LSTM)通过门控机制优化了梯度流动。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值