张力流。call() 方法创建一个基线模型,该模型对时间序列数据的 framework.ops.Tensor 类型为“输入”求平均值

Tensorflow. call() method to create a baseline model which averages the "inputs" with type framework.ops.Tensor for timeseries data

提问人:eliasmaxil 提问时间:11/4/2023 最后编辑:eliasmaxil 更新时间:11/9/2023 访问量:25

问:

我一直在遵循“时间序列预测”教程,在制作自己的多步基线模型时遇到了一些麻烦,该模型可以平均时间轴中的输入数据,并将其作为模型预测中的目标值重复。

在上面的链接中,本教程的作者使用简单的基线(如下面的代码)来获取输入的最后一个时间元素,并平铺(或重复)它的时间。OUT_STEPS

class MultiStepLastBaseline(tf.keras.Model):
  def call(self, inputs):
    return tf.tile(inputs[:, -1:, :], [1, OUT_STEPS, 1])

或者,根据模型的数据 () 中所述的步数,仅重复过去相同数据值的基线。windowinput_width

class RepeatBaseline(tf.keras.Model):
  def call(self, inputs):
    return inputs

我想把所有的元素都拿出来,并在它们之前对它们应用一个简单的平均值。基本上将平均值应用于 RepeatBaselineMultiStepLastBaseline'。inputstf.tileand repeat the average as in

生成 tf 的最小代码。可以使用教程中的代码(https://www.tensorflow.org/tutorials/structured_data/time_series)复制的数据集如下:

import numpy as np
import pandas as pd
import tensorflow as tf

n =  8
rng = np.random.default_rng(seed=0)
df = pd.DataFrame(np.around(rng.random((n, 4)), 1), columns=['a','b','c','y'])

在本教程中,数据由数据中的连续样本管理,可以使用以下方法进行模拟:window

# Settings of what a window object would have
OUT_STEPS = 2  
input_width = 2   # Take two rows (or time steps) of all columns as input
label_width = OUT_STEPS  # Size of the prediction (output)
shift = OUT_STEPS  # Time (or rows) offset between input and output
total_window_size = input_width + shift
batch_size = 1
label_index = None #In the future will be the index of 'y'

# Just a conversion of the df to an tf._.EagerTensor
data = np.array(df.values, dtype=np.float32)
def stack_data(data, total_window_size):
    batches = []
    start = 0
    end = total_window_size
    for start in range(data.shape[0]-1):
        batch = data[start:end]
        start = start + total_window_size + 1
        end = start
        if batch.shape[0] == total_window_size:
            batches.append(batch)
    return tf.stack(batches)

stacked_data = stack_data(data, total_window_size)

此外,数据纵并转换为.最小的代码是dataset

input_slice = slice(0, input_width)
label_slice = slice(total_window_size-label_width, None)
def split_stacked_data(stacked_data):
    """
    Split dataset into inputs and labels (or targets)
    https://www.tensorflow.org/tutorials/structured_data/time_series#2_split
    """
    inputs = stacked_data[:,input_slice, :] 
    labels = stacked_data[:,label_slice,label_index:] 
    inputs.set_shape([None, input_width, None])
    labels.set_shape([None, label_width, None])
    return inputs, labels
# inputs, labels = split_stacked_data(stacked_data)

input_dataset = tf.keras.utils.timeseries_dataset_from_array(
        data=data, targets=None, sequence_length=total_window_size,  
        sequence_stride=1, shuffle=False, batch_size=batch_size)
input_dataset = input_dataset.map(split_stacked_data)

到目前为止,在模型中,我已经成功地通过了一个模型并制作了数据。由于 具有四个特征,因此在 de 中声明了相似数量的单位。然而,结果并不是我所期望的。MyAverageBaselineinputsDenseAveragedfDense

class MyAverageBaseline(tf.keras.Model):
    def __init__(self, out_steps, label_index=None):
        super().__init__()
        self.label_index = label_index
        self.out_steps = out_steps
        self.a_model = tf.keras.layers.Dense(4, activation=tf.nn.relu, trainable=False)

    def call(self, inputs): 
        # type(inputs): <class 'tensorflow.python.framework.ops.Tensor'>
        if self.label_index is None:
            # How can I grab each input & average the values along the time?

            # Working but not delivering the results
            x = self.a_model(inputs)
            result = tf.keras.layers.Average()([x])
            
            # The **pseudocode** where each inputs is averaged in time dimension
            # average_time_dim = inputs[:, np.mean(:, axis=0), :] # SyntaxError
            # possible shape of average_time_dim: (4,)
            # average_reshaped = average_time_dim[tf.newaxis, tf.newaxis, :]
            # return tf.tile(average_reshaped, [1, self.out_steps, 1])

            return result

        # TODO. I would just have to pick a part of the resul
        # result = inputs[:, :, self.label_index]
        # return result[:, :, tf.newaxis]

伪代码中,将计算沿时间轴的平均值,然后计算平均时间。def call():inputstf.tileOUT_STEPS

我也尝试过,但我想我是 Tensorflow 的新手,可以在迭代器中进行计算。tf.mean_reduce()tf.mean()

期望的结果应该是,一旦我编译和评估基线模型:

baseline_model = MyAverageBaseline()
baseline_model.compile(loss=tf.keras.losses.MeanSquaredError(),
                metrics=[tf.keras.metrics.MeanAbsoluteError()])
evaluation = baseline_model.evaluate(input_dataset, verbose=2)
predictions = baseline_model.predict(input_dataset)

预测值将与以下结果相同,并考虑到生成随机 .seed=0df

>>> print(predictions) 
>>> array([[[0.7, 0.6, 0.3, 0.35],
        [0.7, 0.6, 0.3, 0.35]],

        [[0.65, 0.9, 0.7, 0.35],
        [0.65, 0.9, 0.7, 0.35]],

        ...  More data here  ]])

有人可以帮我弄清楚该方法应该包含在 ?def call(self, inputs):class MyAverageBaseline(tf.keras.Model):

python-3.x tf.keras tensorflow-datasets 多变量时间序列

评论


答:

0赞 eliasmaxil 11/9/2023 #1

几天后,我可以设法用该方法解决问题。使用是很好的方法,但我必须修复结果的维度。添加到基线模型的额外代码是。call ()tf.reduce_mean

out_steps = inputs. Shape[1]
averages = tf.reduce_mean(inputs, axis=1)
averages = averages[:,tf.newaxis,:]
result = tf.tile(averages, [1, out_steps, 1])

if self.label_index is None:
    return result