在子类化tf.keras.Model的call方法中使用GRUCell的for循环

我已经子类化了tf.keras.Model,并在for循环中使用tf.keras.layers.GRUCell来计算序列’y_t’(n, 时间步, 隐藏单元)和最终隐藏状态’h_t’(n, 隐藏单元)。为了让我的循环输出’y_t’,我在每次循环迭代后更新一个tf.Variable。使用model(input)调用模型没有问题,但是当我在call方法中使用for循环来拟合模型时,我会得到TypeError或ValueError错误

请注意,我不能简单地使用tf.keras.layers.GRU,因为我试图实现这篇论文。与其仅仅将x_t传递给RNN中的下一个单元,论文在for循环中执行了一些计算作为一个步骤(他们在PyTorch中实现),并将这些计算的结果传递给RNN单元。他们最终基本上是这样做的:h_t = f(special_x_t, h_t-1)。

请查看下面导致错误的模型:

class CustomGruRNN(tf.keras.Model):    def __init__(self, batch_size, timesteps, hidden_units, features, **kwargs):        # 继承        super().__init__(**kwargs)        # 参数        self.batch_size = batch_size        self.timesteps = timesteps        self.hidden_units = hidden_units                # 存储y_t        self.rnn_outputs = tf.Variable(tf.zeros(shape=(batch_size, timesteps, hidden_units)), trainable=False)        # 在call方法中的for循环中使用        self.gru_cell = tf.keras.layers.GRUCell(units=hidden_units)        # 调整形状以匹配输入维度        self.dense = tf.keras.layers.Dense(units=features)    def call(self, inputs):        """Inputs是形状为(n, 时间步, 特征)的3阶张量 """        # 初始状态为gru单元        h_t = tf.zeros(shape=(self.batch_size, self.hidden_units))        for timestep in tf.range(self.timesteps):            # 获取输入的时间步            x_t = tf.gather(inputs, timestep, axis=1)  # 等同于x_t = inputs[:, timestep, :]            # 计算输出和隐藏状态            y_t, h_t = self.gru_cell(x_t, h_t)                        # 在第t个时间步更新y_t            self.rnn_outputs = self.rnn_outputs[:, timestep, :].assign(y_t)        # 输出需要与输入的最后一个维度相同        outputs = self.dense(self.rnn_outputs)        return outputs

一个会引发错误的示例:

# 数据集的任意值num_samples = 128batch_size = 4timesteps = 5features = 10# 任意数据集x = tf.random.uniform(shape=(num_samples, timesteps, features))y = tf.random.uniform(shape=(num_samples, timesteps, features))train_data = tf.data.Dataset.from_tensor_slices((x, y))train_data = train_data.shuffle(batch_size).batch(batch_size, drop_remainder=True)# 具有任意隐藏单元的模型model = CustomGruRNN(batch_size, timesteps, hidden_units=5)model.compile(loss=tf.keras.losses.MeanSquaredError(), optimizer=tf.keras.optimizers.Adam())

在急切运行时:

model.fit(train_data, epochs=2, run_eagerly=True)

第1/2个周期警告:tensorflow:当最小化损失时,变量[‘stack_overflow_gru_rnn/gru_cell/kernel:0′,’stack_overflow_gru_rnn/gru_cell/recurrent_kernel:0′,’stack_overflow_gru_rnn/gru_cell/bias:0’]的梯度不存在。ValueError: 未找到子字符串 ValueError

在非急切运行时:

model.fit(train_data, epochs=2, run_eagerly=False)

第1/2个周期TypeError: 在用户代码中:TypeError: 无法将NoneType转换为Tensor或Operation。


回答:

编辑

虽然TensorFlow指南的答案足够,但我认为我自己回答的关于RNN的自定义单元的问题是一个更好的选择。请查看这个回答。使用自定义RNN单元可以避免使用tf.Transposetf.TensorArray,从而降低代码的复杂性,同时提高可读性。

原始自我回答

TensorFlow的有效TensorFlow2指南末尾描述的DynamicRNN解决了我的问题。

简单扩展一下DynamicRNN的概念使用,定义一个RNN单元,在我的情况下是GRU,然后可以在tf.range循环内定义任意数量的自定义步骤。变量应该在循环外部但在call方法内部使用tf.TensorArray对象进行跟踪,这类数组的大小可以通过简单地调用(输入)张量的.shape方法来确定。值得注意的是,DynamicRNN对象在模型拟合中工作,其默认执行模式是’图形’模式,而不是较慢的’急切执行’模式。

最后,可能需要使用’DynamicRNN’,因为默认情况下,tf.keras.layers.GRU的计算可以大致描述为以下递归逻辑(假设’f’定义了一个GRU单元):

# 这里使用Numpy是为了便于索引,但通常应该使用张量并相应地转置它们(请参阅之前链接的指南)inputs = np.random.randn((batch, total_timesteps, features))# 用于跟踪输出的列表 - 仅为简单演示...再次请参阅指南以获取更多细节outputs = []# 初始化RNN单元的'隐藏状态'(通常称为h_naught并表示为h_0)state_at_t_minus_1 = tf.zeros(shape=(batch, hidden_cell_units))# 遍历输入,直到GRU单元函数'f'已经'看到'序列中的所有时间步for timestep_t in total_timesteps:    # 这形状为(batch, features)    input_at_t = inputs[:, timestep_t, :]    # output_at_t形状为(batch, hidden_units_of_cell)和state_at_t (batch, hidden_units_of_cell)    output_at_t, state_at_t = f(input_at_t, state_at_t_minus_1)    outputs.append(output_at_t)    # 当循环重新开始时,这个变量将在下一个GRU单元函数调用'f'中使用    state_at_t_minus_1 = state_at_t

可能希望在递归逻辑的for循环中添加其他步骤(例如,密集层,其他层等)来修改传递给GRU单元函数’f’的输入和状态。这是DynamicRNN的一个动机。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注