NLP学习日记3:LSTM 从矩阵角度认识LSTM

 *************引入*******************(可跳过直接看后面的完整过程)

1. 矩阵的列视角定义

在神经网络矩阵运算中,我们通常遵循以下约定:

  • 矩阵的列(Columns):表示输入特征维度

  • 矩阵的行(Rows):表示输出特征维度

例如,一个权重矩阵 W∈Rm×n:

  • 左列(第一列):对应第一个输入特征的权重

  • 上列(第一行):对应第一个输出特征的权重计算


2. LSTM核心矩阵的列结构

2.1 输入到隐藏层的权重矩阵 W∗​

以遗忘门的权重矩阵 WfWf​ 为例:

  • 维度:Wf​∈R (h×d)

    • h:hidden_size(行数,输出维度)

    • d:input_size(列数,输入维度)

  • 列视角

    • 每一列对应输入的一个特征(如词向量的某一维)

    • 第k列:Wf​[:,k] 是输入第k个特征对所有隐藏层神经元的权重

# 示例:输入维度d=3,隐藏层h=2
W_f = [[w11, w12, w13],  # 上列:输出h1的权重
       [w21, w22, w23]]  # 下行:输出h2的权重
# 左列[w11, w21]:输入x1对h1,h2的权重

2.2 隐藏层到隐藏层的权重矩阵 U∗

以输入门的 Ui​ 为例:

  • 维度:Ui​∈R (h×h)

  • 列视角

    • 每一列对应前一时刻隐藏状态的一个神经元

    • 第k列:Ui​[:,k] 是前一时刻第k个隐藏神经元对当前所有隐藏神经元的影响


3. 参数与矩阵维度的对应关系

3.1 单层LSTM的矩阵布局

对于单层LSTM,所有门(遗忘门、输入门、输出门、候选记忆)的权重矩阵会被纵向拼接

W = [W_f; W_i; W_o; W_c]  # 维度 (4h × d)
U = [U_f; U_i; U_o; U_c]  # 维度 (4h × h)
  • 列数

    • W 的列数 = input_size(输入特征维度)

    • U 的列数 = hidden_size(隐藏层维度)

  • 行数:4×hidden_size(因为4个门)

3.2 多层LSTM的堆叠

对于num_layers > 1的多层LSTM:

  • 第k层的输入

    • 第1层的输入:原始输入 xt​(维度 input_size

    • 第k层(k≥2)的输入:前一层的隐藏状态 htk−1​(维度 hidden_size

  • 权重矩阵的调整

    • 第1层的 W 维度:(4h×d)

    • 第k层的 W 维度:(4h×h)(因为输入来自前一层的隐藏状态)


4. 矩阵运算的跟踪示例

4.1 输入和隐藏状态的拼接

LSTM的实际计算会将输入 xt 和前一隐藏状态 ht−1​ 横向拼接

z = [x_t; h_{t-1}]  # 维度 (d + h) × 1

此时:

  • 矩阵左列:对应输入 xt​ 的特征

  • 矩阵右列:对应隐藏状态 ht−1​ 的神经元

4.2 合并权重矩阵的列视角

将 W 和 U 横向拼接得到大矩阵 W=[W U]     维度 4h×(d+h):

  • 左半部分列(前d列):处理输入的权重

  • 右半部分列(后h列):处理隐藏状态的权重

# 示例:h=2, d=3
W = [[w11, w12, w13 | u11, u12],  # 遗忘门(上列)
     [w21, w22, w23 | u21, u22],  # 遗忘门(下行)
     [..., ..., ... | ..., ...],   # 其他门...
     ...]

4.3 分块计算的门控信号

通过矩阵乘法 W⋅z 得到4个门的信号:

gates = W_f x_t + U_f h_{t-1}  # 遗忘门部分
       = W_f[:, :d] @ x_t + W_f[:, d:] @ h_{t-1}  # 列分块乘法

5. 代码实现与列视角验证

以下代码验证矩阵的列布局:

import numpy as np

input_size = 3
hidden_size = 2
num_layers = 2

# 单层LSTM的权重初始化
W = np.random.randn(4 * hidden_size, input_size + hidden_size)
print("W的维度:", W.shape)  # (8, 5)

# 列分块验证
W_input = W[:, :input_size]    # 处理输入的列 (8 × 3)
W_hidden = W[:, input_size:]   # 处理隐藏状态的列 (8 × 2)
assert W_input.shape == (4*hidden_size, input_size)
assert W_hidden.shape == (4*hidden_size, hidden_size)

6. 关键总结

参数矩阵列意义维度关系
input_sizeW 的左半部分列数输入特征维度
hidden_sizeU 的列数或 W 的右半列数隐藏神经元数量
num_layers每层的 W 列数可能变化第1层用input_size,之后用hidden_size

核心规则

  1. 左列永远对应输入特征(无论是原始输入还是前一层的隐藏状态)

  2. 上列对应输出门控信号(如遗忘门、输入门等)

  3. 多层LSTM中,第k≥2层的输入维度=hidden_size,因此其 W 的列数会减少。

 ——————————————————————————————————————————

************完整过程*****************

 ——————————————————————————————————————————

以下是LSTM从输入到最终输出的矩阵变换全过程的逐步解析,通过维度跟踪和分步计算展示每个阶段的矩阵变化:

  1. 输入一致性
    所有门和候选记忆共享相同输入拼接 [ht−1​,xt​],体现参数分工差异。

    • 符号说明:[ht−1,xt][ht−1​,xt​] 表示向量纵向拼接(如 torch.cat((h_prev, x), dim=-1)

  2. 激活函数分工

    • 门控(ft,it,ot​)用 Sigmoid(σσ)压缩到 [0,1],实现二值筛选。

    • 候选记忆(c~t​)用 Tanh 压缩到 [-1,1],生成规范化新信息。

  3. 逐元素运算(⊙)

    • 遗忘门 ft​ 与旧记忆 ct−1 相乘 → 选择性丢弃。

    • 输入门 it 与候选记忆 c~t 相乘 → 选择性新增。

    • 输出门 ot​ 与 tanh⁡(ct) 相乘 → 选择性输出。


1. 输入准备阶段

输入矩阵
  • 单时间步输入:xt​∈R(d×1) (d = input_size

  • 批量输入(更常见):X∈R(d×B) (B = batch_size

  • 前一时刻隐藏状态:ht−1​∈R(h×1) (h = hidden_size

拼接输入和隐藏状态

zt=[xt  ,ht−1]∈R(d+h)×1 注意:Zt是列向量,(d+h)x1

 

维度变化
(d×1)+(h×1)→((d+h)×1)


2. 合并权重矩阵

权重矩阵结构
  • 所有门的权重合并为一个大矩阵:(遗忘,输入,输出,候选激活单元)

W=[WfWiWoWc]∈R 4h×(d+h),其中 W∗∈R  h×(d+h)

  • 分块解释

    • 左半部分(前d列):处理输入的权重 W∗,input

    • 右半部分(后h列):处理隐藏状态的权重 W∗,hidden

偏置向量

b=[bfbibobc]∈R4 (h×1)


3. 门控信号计算

合并矩阵乘法

gates=W⋅zt+b∈R4 (h×1)

展开计算

[ft it ot c~t]=[Wf Wi Wo Wc]⋅zt+[bf bi bo bc] 

分步维度验证
  1. W⋅zt​:(4h×(d+h))⋅((d+h)×1)→(4h×1)

  2. 加偏置后仍为 (4h×1)


4. 激活函数应用

对门控信号逐元素应用激活函数:

ft=σ(gates[0:h])∈R (h×1)

it=σ(gates[h:2h])∈R (h×1)

ot=σ(gates[2h:3h])∈R (h×1)

c~t=tanh⁡(gates[3h:4h])∈R (h×1)


5. 记忆单元更新

逐元素运算

ct=ft⊙ct−1+it⊙c~t∈R (h×1)

  • ⊙ 表示哈达玛积(对应位置相乘)

  • 维度不变:所有操作保持 h×1


6. 隐藏状态输出

ht=ot⊙tanh⁡(ct)∈R (h×1)


7. 批量处理的扩展

当输入为批量数据(X∈R d×B)时:

  1. 隐藏状态扩展:Ht−1∈Rh×B

  2. 拼接输入

    Z=[X ,Ht−1]∈R (d+h)×B
  3. 矩阵乘法

    gates=W⋅Z+b∈R (4h×B)
    • 这里 b 通过广播机制扩展到每列


8. 多层LSTM的堆叠

对于第 k 层(k≥2):

  • 输入:前一层的隐藏状态 ht k−1∈R(h×B)

  • 权重矩阵调整

    • Wk∈R(4h×h)(因为输入来自上一层,维度为 h

    • 计算过程与第1层相同,仅输入维度变化


全过程维度跟踪表

步骤操作输入维度输出维度
输入拼接zt=[xt;ht−1]d×1, h×1(d+h)×1
合并权重乘法W⋅zt+b4h×(d+h), (d+h)×14h×1
门控分割[ft,it,ot,c~t]4h×14个 h×1
记忆更新ct=ft⊙ct−1+it⊙c~th×1, h×1h×1
隐藏状态输出ht=ot⊙tanh⁡(ct)h×1h×1

代码实现验证

import numpy as np

# 参数定义
d, h, B = 3, 2, 4  # input_size, hidden_size, batch_size
np.random.seed(0)

# 初始化
W = np.random.randn(4*h, d+h)  # 合并权重矩阵
b = np.random.randn(4*h, 1)
X = np.random.randn(d, B)      # 当前输入
H_prev = np.random.randn(h, B) # 前一时刻隐藏状态
C_prev = np.random.randn(h, B) # 前一时刻记忆单元

# 步骤1:拼接输入
Z = np.vstack((X, H_prev))     # (d+h) × B

# 步骤2:合并矩阵乘法
gates = np.dot(W, Z) + b       # 4h × B

# 步骤3:分割并激活
f_t = 1 / (1 + np.exp(-gates[:h]))         # 遗忘门 (h × B)
i_t = 1 / (1 + np.exp(-gates[h:2*h]))      # 输入门 (h × B)
o_t = 1 / (1 + np.exp(-gates[2*h:3*h]))    # 输出门 (h × B)
c̃_t = np.tanh(gates[3*h:])                 # 候选记忆 (h × B)

# 步骤4:更新记忆单元
C_t = f_t * C_prev + i_t * c̃_t             # h × B

# 步骤5:输出隐藏状态
H_t = o_t * np.tanh(C_t)                   # h × B

print("最终隐藏状态维度:", H_t.shape)  # 应输出 (2, 4)

关键点总结

  1. 列视角的核心:权重矩阵的列数始终等于输入的维度(无论是原始输入还是前一层的隐藏状态)。

  2. 维度一致性:所有操作通过矩阵乘法和逐元素运算保持维度匹配。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值