Source code for tfts.models.tide

"""
`Long-term Forecasting with TiDE: Time-series Dense Encoder
<https://arxiv.org/pdf/2304.08424v1.pdf>`_
"""

import logging
from typing import Optional

import tensorflow as tf
from tensorflow.keras.layers import Dense, Dropout, LayerNormalization

from ..layers.attention_layer import Attention, SelfAttention
from ..layers.dense_layer import FeedForwardNetwork
from ..layers.embed_layer import DataEmbedding
from .base import BaseConfig, BaseModel

logger = logging.getLogger(__name__)


[docs] class TideConfig(BaseConfig): model_type: str = "tide" def __init__( self, hidden_size: int = 256, num_layers: int = 2, num_attention_heads: int = 4, attention_probs_dropout_prob: float = 0.0, hidden_dropout_prob: float = 0.0, ffn_intermediate_size: int = 256, max_position_embeddings: int = 512, initializer_range: float = 0.02, layer_norm_eps: float = 1e-12, pad_token_id: int = 0, **kwargs ): super().__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.num_attention_heads = num_attention_heads self.attention_probs_dropout_prob = attention_probs_dropout_prob self.hidden_dropout_prob = hidden_dropout_prob self.ffn_intermediate_size = ffn_intermediate_size self.max_position_embeddings = max_position_embeddings self.initializer_range = initializer_range self.layer_norm_eps = layer_norm_eps self.pad_token_id = pad_token_id self.update(kwargs)
[docs] class Tide(BaseModel): """TiDE model for time series forecasting""" def __init__(self, predict_sequence_length=1, config: Optional[TideConfig] = None): super(Tide, self).__init__() self.config = config or TideConfig() self.predict_sequence_length = predict_sequence_length # Embedding layer self.embedding = DataEmbedding(self.config.hidden_size, positional_type="positional encoding") # Dense encoder layers self.dense_layers = [] for _ in range(self.config.num_layers): self.dense_layers.append( DenseEncoderBlock( hidden_size=self.config.hidden_size, ffn_intermediate_size=self.config.ffn_intermediate_size, dropout_rate=self.config.hidden_dropout_prob, layer_norm_eps=self.config.layer_norm_eps, ) ) # Output projection self.output_projection = Dense(1) def __call__(self, x: tf.Tensor, output_hidden_states: Optional[bool] = None, return_dict: Optional[bool] = None): """Process inputs through the TiDE model. Parameters ---------- x : tf.Tensor Input tensor of shape (batch_size, sequence_length, features). output_hidden_states : bool, optional Whether to output hidden states, by default None. return_dict : bool, optional Whether to return a dictionary of outputs, by default None. Returns ------- tf.Tensor Output tensor of shape (batch_size, predict_sequence_length, 1). """ # Prepare inputs x, encoder_feature, decoder_feature = self._prepare_3d_inputs(x, ignore_decoder_inputs=False) # Embed inputs embedded = self.embedding(encoder_feature) # Process through dense encoder layers for layer in self.dense_layers: embedded = layer(embedded) # Project to output output = self.output_projection(embedded) # Slice the output to only include the last predict_sequence_length steps output = output[:, -self.predict_sequence_length :, :] return output
[docs] class DenseEncoderBlock(tf.keras.layers.Layer): """Dense encoder block with feed-forward networks and layer normalization.""" def __init__( self, hidden_size: int, ffn_intermediate_size: int, dropout_rate: float = 0.1, layer_norm_eps: float = 1e-9, **kwargs ) -> None: super().__init__(**kwargs) self.ffn = FeedForwardNetwork(hidden_size, ffn_intermediate_size, dropout_rate) self.layernorm = LayerNormalization(epsilon=layer_norm_eps) self.dropout = Dropout(dropout_rate) def call(self, inputs: tf.Tensor, training: bool = False) -> tf.Tensor: ffn_output = self.ffn(inputs) ffn_output = self.dropout(ffn_output, training=training) return self.layernorm(inputs + ffn_output)