所以我想准确地理解如何计算GRU单元的输出和隐藏状态。
我从这里得到了预训练模型,GRU层被定义为nn.GRU(96, 96, bias=True)
。
我查看了PyTorch文档并确认了权重和偏差的尺寸:
weight_ih_l0
:(288, 96)
weight_hh_l0
:(288, 96)
bias_ih_l0
:(288)
bias_hh_l0
:(288)
我的输入大小和输出大小是(1000, 8, 96)
。我知道有1000
张量,每个张量的大小为(8, 96)
。隐藏状态为(1, 8, 96)
,是一个大小为(8, 96)
的张量。
我也打印了变量batch_first
,发现它是False
。这意味着:
- 序列长度:
L=1000
- 批量大小:
B=8
- 输入大小:
Hin=96
现在根据文档中的方程式,对于复位门,我需要将权重乘以输入x
。但是我的权重是二维的,而我的输入是三维的。
这是我所尝试的,我从我的输入中取出了第一个(8, 96)
矩阵,并将其与我的权重矩阵的转置相乘:
Input (8, 96) x Weight (96, 288) = (8, 288)
然后我通过复制(288)
8次来添加偏差,得到(8, 288)
。这将使r(t)
的大小为(8, 288)
。同理,z(t)
也可以是(8, 288)
。
这个r(t)
在n(t)
中使用,因为使用了Hadamard积,两个相乘的矩阵必须与(8, 288)
的大小相同。这意味着n(t)
也是(8, 288)
。
最后,h(t)
是Hadamard产品和矩阵加法,这将得到h(t)
的大小为(8, 288)
,这是错误的.
我在这个过程中哪里出错了?
;这种混淆来自于这样一个事实,即层的权重分别是input_hidden和hidden-hidden的串联。
-nn.GRU
层权重/偏置布局
你可以仔细看看GRU层实现torch.nn.GRU
的内部是什么,通过权重和偏差达到峰值。
>>> gru = nn.GRU(input_size=96, hidden_size=96, num_layers=1)
首先是GRU层参数:
>>> gru._all_weights
[['weight_ih_l0', 'weight_hh_l0', 'bias_ih_l0', 'bias_hh_l0']]
您可以查看gru.state_dict()
以获取层的权重字典。
我们有两个权值和两个偏置,_ih
代表'input-hidden',_hh
代表'hidden-hidden'。
为了更有效的计算,这些参数被连接在一起,正如文档页面清楚地解释的那样(|
意味着连接)。在这个特殊的例子中,num_layers=1
和k=0
:
~GRU.weight_ih_l[k]
-形状为(3*hidden_size, input_size)
的(W_ir | W_iz | W_in)
层的可学习输入隐藏权值。~GRU.weight_hh_l[k]
-形状为(3*hidden_size, hidden_size)
的(W_hr | W_hz | W_hn)
层的可学习的hidden-hidden权值。~GRU.bias_ih_l[k]
-形状为(3*hidden_size)
的(b_ir | b_iz | b_in)
层的可学习输入隐藏偏置。~GRU.bias_hh_l[k]
-(b_hr | b_hz | b_hn)
的可学习隐隐偏差。
为了进一步检查,我们可以使用以下代码将它们分开:
>>> W_ih, W_hh, b_ih, b_hh = gru._flat_weights
>>> W_ir, W_iz, W_in = W_ih.split(H_in)
>>> W_hr, W_hz, W_hn = W_hh.split(H_in)
>>> b_ir, b_iz, b_in = b_ih.split(H_in)
>>> b_hr, b_hz, b_hn = b_hh.split(H_in)
现在我们有了12张量参数。
——表达式GRU层的四个表达式:r_t
、z_t
、n_t
和h_t
,在每个时间步计算。
第一个操作是r_t = σ(W_ir@x_t + b_ir + W_hr@h + b_hr)
。我使用@
符号来指定矩阵乘法运算符(__matmul__
)。记住W_ir
的形状是(H_in=input_size, hidden_size)
,而x_t
包含x
序列中步骤t
的元素。张量x_t = x[t]
的形状为(N=batch_size, H_in=input_size)
。此时,它只是输入x[t]
和权重矩阵之间的矩阵乘法。得到的张量r
的形状为(N, hidden_size=H_in)
:
>>> (x[t]@W_ir.T).shape
(8, 96)
对于执行的所有其他权重乘法操作也是如此。结果,你最终得到一个形状为(N, H_out=hidden_size)
的输出张量。
在下面的表达式中,h
是包含批中每个元素前一步隐藏状态的张量,即形(N, hidden_size=H_out)
,由于num_layers=1
,即。只有一个隐藏层
>>> r_t = torch.sigmoid(x[t]@W_ir.T + b_ir + h@W_hr.T + b_hr)
>>> r_t.shape
(8, 96)
>>> z_t = torch.sigmoid(x[t]@W_iz.T + b_iz + h@W_hz.T + b_hz)
>>> z_t.shape
(8, 96)
层的输出是计算的h
张量在连续时间步长t
(介于0
和L-1
之间).
-
示范下面是人工计算nn.GRU
推理的最小示例:
参数 | 说明 | 值 | H_in | 特征尺寸 | 3 |
---|---|---|
H_out | 隐藏大小 | 2 |
L | 序列长度 | 3 |
N | 批量大小 | 1 |
k | 层数 | 1 |