GRU(Gated Recurrent Unit)是一种循环神经网络,它包含了一些特殊的门控机制,用于控制信息的流动和更新。比起RNN(Recurrent Neural Network),GRU支持隐状态的门控,这意味着模型有专门的机制来确定应该何时更新隐状态,以及应该何时重置隐状态。
GRU中的更新门(Update Gate)是其中一种门控机制,它可以控制新状态中有多少个是旧状态的副本。在GRU中,每个时刻都会有一个新的输入向量和一个旧的状态向量。更新门是一个sigmoid函数,它的输出控制了新状态中有多少是由旧状态的副本组成的。如果更新门的输出接近1,那么新状态就会完全由旧状态的副本组成,新的输入信息就会被完全忽略掉。如果更新门的输出接近0,那么旧状态就会被完全忽略掉,新的输入信息就会完全覆盖旧状态。此门控机制的好处是:它可以让模型根据需要选择性地保留旧状态中有用的信息,并忽略不必要的信息,从而更好地适应不同的输入序列。这对于处理长序列的任务特别有用,因为长序列中可能包含很多无关信息,而GRU的更新门可以帮助模型过滤掉这些无关信息,只保留有用的信息。
重置门(Reset Gate)也是GRU中的一种门控机制,它的作用是控制模型在当前时间步是否需要“遗忘”过去的状态信息。更具体地说,重置门允许我们控制“可能还想记住”的过去状态的数量。在GRU中,每个时间步都有一个当前的输入向量和一个旧的状态向量。重置门是一个sigmoid函数,它的输出表示在当前时间步,模型是否需要丢弃之前的状态信息。如果重置门的输出接近0,那么模型会忽略之前的状态信息,只根据当前输入来更新状态,从而更好地适应短序列数据。如果重置门的输出接近1,那么模型会保留之前的状态信息,并结合当前输入来更新状态,从而更好地适应长序列数据。此门控机制的好处是:它允许我们控制模型在当前时间步是否需要“遗忘”过去的状态信息,并且可以自适应地调整遗忘的数量。这种门控机制的设计可以让模型更好地适应不同的序列数据,从而提高模型的泛化能力和性能。
候选隐状态是更新门(Update Gate)和重置门(Reset Gate)所计算出的隐状态。具体来说,GRU的候选隐状态由以下公式计算:
其中,
是当前时间步的输入,
是上一个时间步的隐状态,
是重置门,
表示按元素相乘,
、
、
和
是可学习的参数。 在计算候选隐状态时,重置门和上一个时间步的隐状态
相乘,得到的结果表示应该保留多少上一个时间步的信息。然后将当前时间步的输入
和上一步的隐状态
分别与对应的参数进行线性变换,再加上偏置项,得到两个向量。这两个向量分别与重置门相乘,得到的结果表示应该保留多少当前时间步的信息。将这两个向量相加,再通过tanh函数进行激活,得到候选隐状态
。
接下来我来展示以下如何利用Keras来实现GRU的方法:(讲个题外话,之前我的前一篇文章LSTM我是用Pytorch实现的,但我发现相比于Keras的API更面向人类编程,更适合初学者,所以本篇教程我将用Keras来实现)
from keras.models import Sequential
from keras.layers import GRU, Dense
model = Sequential()
model.add(GRU(units=64, activation='tanh', input_shape=(10, 1)))
model.add(Dense(units=1, activation='sigmoid'))
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# X_train shape: (batch_size, timesteps, input_dim)
# y_train shape: (batch_size, output_dim)
model.fit(X_train, y_train, batch_size=32, epochs=10)
首先导入了需要的库和模块,然后使用Sequential()
构建了一个序列模型。
在序列模型中,我添加了一个GRU层,该层具有64个神经元和tanh激活函数,并且输入形状为(10, 1)
。在此基础上我添加了一个全连接层,具有一个输出单元和sigmoid激活函数。
我使用compile()
方法来编译模型,指定优化器、损失函数和评估指标,并使用fit()
方法来训练模型。
GRU层的input_shape
应该是一个三元组(timesteps, input_dim)
,其中timesteps
表示输入序列的时间步数,input_dim
表示每个时间步的输入特征维度。在上面的代码中,我将timesteps
设置为10,input_dim
设置为1。
fit()
方法的输入数据X_train
和y_train
应该是Numpy数组,其中X_train
的形状应该是(batch_size, timesteps, input_dim)
,y_train
的形状应该是(batch_size, output_dim)
。
以下是使用Keras实现GRU模型来对MNIST手写数字数据集进行分类的代码示范,希望能对你对于如何代码实现GRU模型有更深的印象:
import tensorflow as tf
from keras.layers import GRU, Dense
from keras.models import Sequential
from keras.datasets import mnist
from keras.utils import to_categorical
# 加载数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 数据预处理
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
y_train = to_categorical(y_train, num_classes=10)
y_test = to_categorical(y_test, num_classes=10)
# 构建模型
model = Sequential()
model.add(GRU(units=128, activation='tanh', input_shape=(28, 28)))
model.add(Dense(units=10, activation='softmax'))
# 编译模型
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# 训练模型
model.fit(x_train, y_train, batch_size=128, epochs=10, validation_data=(x_test, y_test))
# 在测试集上评估模型
test_loss, test_acc = model.evaluate(x_test, y_test)
print('Test accuracy:', test_acc)