变分自动编码器在时间序列数据生成中的应用

2024年12月11日 由 alex 发表 71 0

通过变分自编码器(VAE)创新生成合成时间序列数据的方法


变分自编码器(VAE)已成为机器学习中的强大工具,特别是在从学习到的表示中生成新数据方面。在这篇文章中,我们将探索一个专为生成合成时间序列数据而设计的VAE的实际实现。


什么是变分自编码器?

变分自编码器是一种生成模型,它学习将数据表示在低维的潜在空间中。VAE由两个主要部分组成:编码器,它将输入数据压缩成潜在表示;以及解码器,它从这种表示中重构原始数据。与传统的自编码器不同,VAE假设潜在空间遵循概率分布,通常是高斯分布。这使得VAE能够通过从这个分布中采样来生成新数据,从而使它们在异常检测、数据生成和无监督学习等任务中特别有用。


VAE的关键特性:

  • 生成能力:VAE可以通过从潜在空间中采样来生成新的数据样本。
  • 潜在空间表示:潜在空间的结构揭示了数据中的模式。


为何使用VAE处理时间序列?

时间序列数据——如股票价格、天气模式或甚至脑电图信号——由于其时间性质,通常需要专门的方法。通过利用VAE,我们可以以压缩的形式捕获时间序列数据的底层模式。这有助于我们更有效地可视化数据、降低维度,甚至生成与原始数据集相似的新合成时间序列。


我们的方法

在这个实现中,我们生成合成时间序列数据,训练VAE以学习潜在表示,并使用t-SNE(t分布随机邻域嵌入)来可视化低维嵌入。我们还将重构数据,以查看VAE在重现原始时间序列方面的表现如何。


关键组件解释

数据生成:generate_timeseries_data函数为训练VAE创建合成时间序列数据。它在指定的形状内生成随机值。


def generate_timeseries_data(num_samples, num_timesteps):
    """
    Generate synthetic timeseries data.
    Parameters:
        num_samples (int): Number of samples in the dataset.
        num_timesteps (int): Number of timesteps in each sample.
    Returns:
        np.ndarray: Generated timeseries data with shape (num_samples, num_timesteps).
    """
    return np.random.rand(num_samples, num_timesteps)


VAE类:VAE类封装了自编码器的架构:

  • 编码器:使用密集层将输入数据映射到潜在空间。
  • 解码器:从潜在表示中重构输入数据。


class VAE(models.Model):
    """
    Variational Autoencoder (VAE) model.
    Parameters:
        input_dim (int): Dimension of input timeseries data.
        latent_dim (int): Dimension of the latent space.
    """
    def __init__(self, input_dim, latent_dim):
        super(VAE, self).__init__()
        self.input_dim = input_dim
        self.latent_dim = latent_dim
        self.encoder = self.build_encoder()
        self.decoder = self.build_decoder()
    def build_encoder(self):
        encoder_input = layers.Input(shape=(self.input_dim,))
        x = layers.Dense(128, activation='relu')(encoder_input)
        z_mean = layers.Dense(self.latent_dim)(x)
        z_log_var = layers.Dense(self.latent_dim)(x)
        encoder_output = layers.Lambda(self.sample_z, output_shape=(self.latent_dim,))([z_mean, z_log_var])
        return models.Model(encoder_input, [z_mean, z_log_var, encoder_output])  # Ensure to return all three outputs
    def build_decoder(self):
        decoder_input = layers.Input(shape=(self.latent_dim,))
        x = layers.Dense(128, activation='relu')(decoder_input)
        decoder_output = layers.Dense(self.input_dim, activation='sigmoid')(x)
        return models.Model(decoder_input, decoder_output)
    def sample_z(self, args):
        z_mean, z_log_var = args
        batch_size = tf.shape(z_mean)[0]
        latent_dim = tf.shape(z_mean)[1]
        epsilon = tf.random.normal(shape=(batch_size, latent_dim), mean=0., stddev=1.0)
        return z_mean + tf.exp(0.5 * z_log_var) * epsilon
    def call(self, inputs):
        z_mean, z_log_var, z = self.encoder(inputs)  # Correctly unpack all three outputs
        reconstructions = self.decoder(z)
        return reconstructions, z_mean, z_log_var


损失函数:vae_loss函数结合了重构损失和Kullback-Leibler(KL)散度,以确保模型学习到平滑的潜在空间。


def vae_loss(y_true, y_pred, z_mean, z_log_var):
    """
    Define the loss function for the VAE model.
    Parameters:
        y_true (tf.Tensor): Ground truth values.
        y_pred (tf.Tensor): Predicted values (reconstructed data).
        z_mean (tf.Tensor): Mean of the latent variable.
        z_log_var (tf.Tensor): Log variance of the latent variable.
    Returns:
        tf.Tensor: Total loss (reconstruction loss + KL divergence).
    """
    mse_loss = tf.keras.losses.MeanSquaredError()
    recon_loss = mse_loss(y_true, y_pred)
    kl_loss = -0.5 * tf.reduce_mean(1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var))
    return recon_loss + kl_loss


训练循环:主函数负责在指定的训练轮次中对VAE进行数据归一化和训练过程处理。


def main(num_samples, num_timesteps, latent_dim, epochs, batch_size):
    # Generate synthetic timeseries data
    data = generate_timeseries_data(num_samples, num_timesteps)
    # Normalize the data
    data_mean = data.mean()
    data_std = data.std()
    data_normalized = (data - data_mean) / data_std
    # Create VAE model
    vae = VAE(num_timesteps, latent_dim)
    vae.compile(optimizer='adam')  # Remove the custom loss from here
    # Custom training loop
    for epoch in range(epochs):
        with tf.GradientTape() as tape:
            reconstructions, z_mean, z_log_var = vae(data_normalized)
            loss = vae_loss(data_normalized, reconstructions, z_mean, z_log_var)  # Pass the outputs to the loss function
        
        grads = tape.gradient(loss, vae.trainable_variables)
        vae.optimizer.apply_gradients(zip(grads, vae.trainable_variables))
        print(f'Epoch {epoch + 1}, Loss: {loss.numpy()}')  # Print the loss for each epoch
    # Reduce dimensionality of timeseries using the trained encoder
    z_mean, z_log_var, encoded_data = vae.encoder.predict(data_normalized)


可视化:训练完成后,我们对原始时间序列数据、潜在空间中的编码数据以及重构数据进行可视化。


21


该代码生成了几种可视化内容:

  • 原始时间序列数据:显示输入数据。
  • 编码数据(t-SNE):展示降维至二维的潜在表示。
  • 潜在空间表示:可视化潜在空间中的编码数据。
  • 重构时间序列数据:说明模型能够多么准确地重构原始数据。


结论

VAE是理解和生成时间序列数据的强大工具,能够深入洞察数据中的底层模式。通过利用TensorFlow和Keras,此实现为实验提供了一个灵活且稳健的框架。

文章来源:https://ryanraymartin.medium.com/variational-autoencoders-for-timeseries-data-generation-9e80d1ed425e
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消