传统上,RNN 的状态计算为
对于 RNN,为什么要将术语加起来而不是只有一个矩阵乘以一个级联向量:
在哪里是串联。
换句话说,我们最终会得到一个长向量乘以.
似乎第二种方法会有一个更大的矩阵,它的元素比和结合。
这是否意味着和是一种简化,使用它们并把结果加起来我们会失去什么?
传统上,RNN 的状态计算为
对于 RNN,为什么要将术语加起来而不是只有一个矩阵乘以一个级联向量:
在哪里是串联。
换句话说,我们最终会得到一个长向量乘以.
似乎第二种方法会有一个更大的矩阵,它的元素比和结合。
这是否意味着和是一种简化,使用它们并把结果加起来我们会失去什么?
从理论上讲,两个矩阵的公式更清晰,不言而喻,我认为这就是它被更多使用的原因。在实践中,这两种方法实际上都在生产中使用,因此是等效的。这只是一个偏好问题。
例如,Tensorflow 通常针对性能进行优化。以下是基本 RNN 单元的实现方式(tensorflow/python/ops/rnn_cell_impl.py
):
def call(self, inputs, state):
"""Most basic RNN: output = new_state = act(W * input + U * state + B)."""
gate_inputs = math_ops.matmul(
array_ops.concat([inputs, state], 1), self._kernel)
gate_inputs = nn_ops.bias_add(gate_inputs, self._bias)
output = self._activation(gate_inputs)
return output, output
单个矩阵乘法更有效,因此它被应用,即使注释描述了具有两个矩阵的扩展公式。
另一方面,Keras 经常选择简单和清晰而不是性能。这是它的实现(keras/layers/recurrent.py
):
def call(self, inputs, states, training=None):
prev_output = states[0]
...
if dp_mask is not None:
h = K.dot(inputs * dp_mask, self.kernel)
else:
h = K.dot(inputs, self.kernel)
if self.bias is not None:
h = K.bias_add(h, self.bias)
...
output = h + K.dot(prev_output, self.recurrent_kernel)
if self.activation is not None:
output = self.activation(output)
因此,该类可以轻松地分别访问两个矩阵(self.kernel
和self.recurrent_kernel
)。
Pytorch 方法更接近于 keras。此外,它们不仅使用单独的内核矩阵,还具有两个偏置向量,并且客户端代码可以访问这四个数组。
尽管存在这些差异,所有三个库在功能上都是等效的。