TSMixer.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. from __future__ import annotations
  2. import torch
  3. import torch.nn as nn
  4. import torch.nn.functional as F
  5. from layers.layers import MixerLayer, TimeBatchNorm2d, feature_to_time, time_to_feature
  6. class TSMixer(nn.Module):
  7. """TSMixer model for time series forecasting.
  8. This model uses a series of mixer layers to process time series data,
  9. followed by a linear transformation to project the output to the desired
  10. prediction length.
  11. Attributes:
  12. mixer_layers: Sequential container of mixer layers.
  13. temporal_projection: Linear layer for temporal projection.
  14. Args:
  15. sequence_length: Length of the input time series sequence.
  16. prediction_length: Desired length of the output prediction sequence.
  17. input_channels: Number of input channels.
  18. output_channels: Number of output channels. Defaults to None.
  19. activation_fn: Activation function to use. Defaults to "relu".
  20. num_blocks: Number of mixer blocks. Defaults to 2.
  21. dropout_rate: Dropout rate for regularization. Defaults to 0.1.
  22. ff_dim: Dimension of feedforward network inside mixer layer. Defaults to 64.
  23. normalize_before: Whether to apply layer normalization before or after mixer layer.
  24. norm_type: Type of normalization to use. "batch" or "layer". Defaults to "batch".
  25. """
  26. def __init__(
  27. self,
  28. sequence_length: int,
  29. prediction_length: int,
  30. input_channels: int,
  31. output_channels: int = 1,
  32. activation_fn: str = "relu",
  33. num_blocks: int = 2,
  34. dropout_rate: float = 0.1,
  35. ff_dim: int = 64,
  36. normalize_before: bool = True,
  37. norm_type: str = "batch",
  38. ):
  39. super().__init__()
  40. # Transform activation_fn to callable
  41. activation_fn = getattr(F, activation_fn)
  42. # Transform norm_type to callable
  43. assert norm_type in {
  44. "batch",
  45. "layer",
  46. }, f"Invalid norm_type: {norm_type}, must be one of batch, layer."
  47. # norm_type = TimeBatchNorm2d if norm_type == "batch" else nn.LayerNorm
  48. norm_type = TimeBatchNorm2d if input_channels == 1 else nn.LayerNorm
  49. # Build mixer layers
  50. self.mixer_layers = self._build_mixer(
  51. num_blocks,
  52. input_channels,
  53. output_channels,
  54. ff_dim=ff_dim,
  55. activation_fn=activation_fn,
  56. dropout_rate=dropout_rate,
  57. sequence_length=sequence_length,
  58. normalize_before=normalize_before,
  59. norm_type=norm_type,
  60. )
  61. # Temporal projection layer
  62. self.temporal_projection = nn.Linear(sequence_length, prediction_length)
  63. self.line = nn.Linear(input_channels,output_channels)
  64. def _build_mixer(
  65. self, num_blocks: int, input_channels: int, output_channels: int, **kwargs
  66. ):
  67. """Build the mixer blocks for the model.
  68. Args:
  69. num_blocks (int): Number of mixer blocks to be built.
  70. input_channels (int): Number of input channels for the first block.
  71. output_channels (int): Number of output channels for the last block.
  72. **kwargs: Additional keyword arguments for mixer layer configuration.
  73. Returns:
  74. nn.Sequential: Sequential container of mixer layers.
  75. """
  76. channels = [input_channels] * (num_blocks - 1) + [output_channels]
  77. return nn.Sequential(
  78. *[
  79. MixerLayer(input_channels=in_ch, output_channels=out_ch, **kwargs)
  80. for in_ch, out_ch in zip(channels[:-1], channels[1:])
  81. ]
  82. )
  83. def forward(self, x_hist: torch.Tensor) -> torch.Tensor:
  84. """Forward pass of the TSMixer model.
  85. Args:
  86. x_hist (torch.Tensor): Input time series tensor.
  87. Returns:
  88. torch.Tensor: The output tensor after processing by the model.
  89. """
  90. x = self.mixer_layers(x_hist)
  91. x_temp = feature_to_time(x)
  92. x_temp = self.temporal_projection(x_temp)
  93. x = time_to_feature(x_temp)
  94. x = self.line(x)
  95. B , L , C = x.shape
  96. x = x.reshape(B,-1)
  97. return x
  98. if __name__ == "__main__":
  99. m = TSMixer(288, 288, 17, output_channels=1)
  100. x = torch.randn(32, 288, 17)
  101. y = m(x)
  102. print(y.shape)