CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
modeling_timesfm.py846 linesDownload Raw Back to timesfm
1#                ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ2#           This file was automatically generated from src/transformers/models/timesfm/modular_timesfm.py.3#               Do NOT edit this file manually as any edits will be overwritten by the generation of4#             the file from the modular. If any change should be done, please apply the change to the5#                          modular_timesfm.py file directly. One of our CI enforces this.6#                ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ๐Ÿšจ7# coding=utf-88# Copyright 2025 Google LLC and HuggingFace Inc. team.9#10# Licensed under the Apache License, Version 2.0 (the "License");11# you may not use this file except in compliance with the License.12# You may obtain a copy of the License at13#14#     http://www.apache.org/licenses/LICENSE-2.015#16# Unless required by applicable law or agreed to in writing, software17# distributed under the License is distributed on an "AS IS" BASIS,18# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.19# See the License for the specific language governing permissions and20# limitations under the License.21 22import math23from collections.abc import Sequence24from dataclasses import dataclass25from typing import Callable, Optional, Union26 27import torch28import torch.nn as nn29import torch.nn.functional as F30 31from ...integrations import use_kernel_forward_from_hub32from ...modeling_flash_attention_utils import FlashAttentionKwargs33from ...modeling_outputs import BaseModelOutput34from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel35from ...processing_utils import Unpack36from ...utils import TransformersKwargs, auto_docstring, can_return_tuple, logging37from .configuration_timesfm import TimesFmConfig38 39 40logger = logging.get_logger(__name__)41 42 43@dataclass44@auto_docstring45class TimesFmOutput(BaseModelOutput):46    r"""47    loc (`torch.Tensor` of shape `(batch_size, )`):48        The mean of the time series inputs.49    scale (`torch.Tensor` of shape `(batch_size,)`):50        The scale of the time series inputs.51    """52 53    loc: Optional[torch.Tensor] = None54    scale: Optional[torch.Tensor] = None55 56 57@dataclass58@auto_docstring59class TimesFmOutputForPrediction(BaseModelOutput):60    r"""61    mean_predictions (`torch.Tensor` of shape `(batch_size, sequence_length)`):62        The mean predictions of the time series.63    full_predictions (`torch.Tensor` of shape `(batch_size, sequence_length)`):64        The full predictions of the time series including the mean and the quantiles.65    loss (`torch.Tensor` of shape `(1,)`, *optional*, returned when `future_values` is provided):66        The loss of the TimesFM model.67    """68 69    mean_predictions: Optional[torch.Tensor] = None70    full_predictions: Optional[torch.Tensor] = None71    loss: Optional[Union[torch.Tensor, float]] = None72 73 74class TimesFmMLP(nn.Module):75    """Pax MLP in pytorch."""76 77    def __init__(self, config: TimesFmConfig):78        super().__init__()79        hidden_size = config.hidden_size80        intermediate_size = config.intermediate_size81 82        self.gate_proj = nn.Linear(hidden_size, intermediate_size)83        self.down_proj = nn.Linear(intermediate_size, hidden_size)84        self.layer_norm = nn.LayerNorm(normalized_shape=hidden_size, eps=1e-6)85 86    def forward(self, x, paddings=None):87        gate_inp = self.layer_norm(x)88        gate = self.gate_proj(gate_inp)89        gate = F.relu(gate)90        outputs = self.down_proj(gate)91        if paddings is not None:92            outputs = outputs * (1.0 - paddings[:, :, None])93        return outputs + x94 95 96class TimesFmResidualBlock(nn.Module):97    """TimesFM residual block."""98 99    def __init__(self, input_dims, hidden_dims, output_dims):100        super().__init__()101        self.input_dims = input_dims102        self.hidden_dims = hidden_dims103        self.output_dims = output_dims104 105        self.input_layer = nn.Linear(input_dims, hidden_dims)106        self.activation = nn.SiLU()107        self.output_layer = nn.Linear(hidden_dims, output_dims)108        self.residual_layer = nn.Linear(input_dims, output_dims)109 110    def forward(self, x):111        hidden = self.input_layer(x)112        hidden = self.activation(hidden)113        output = self.output_layer(hidden)114        residual = self.residual_layer(x)115        return output + residual116 117 118@use_kernel_forward_from_hub("RMSNorm")119class TimesFmRMSNorm(nn.Module):120    def __init__(self, hidden_size, eps=1e-6):121        """122        TimesFmRMSNorm is equivalent to T5LayerNorm123        """124        super().__init__()125        self.weight = nn.Parameter(torch.ones(hidden_size))126        self.variance_epsilon = eps127 128    def forward(self, hidden_states):129        input_dtype = hidden_states.dtype130        hidden_states = hidden_states.to(torch.float32)131        variance = hidden_states.pow(2).mean(-1, keepdim=True)132        hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)133        return self.weight * hidden_states.to(input_dtype)134 135    def extra_repr(self):136        return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"137 138 139class TimesFmPositionalEmbedding(nn.Module):140    """Generates position embedding for a given 1-d sequence."""141 142    def __init__(self, config: TimesFmConfig):143        super().__init__()144        min_timescale = config.min_timescale145        max_timescale = config.max_timescale146        self.embedding_dims = config.hidden_size147 148        num_timescales = self.embedding_dims // 2149        log_timescale_increment = math.log(float(max_timescale) / float(min_timescale)) / max(num_timescales - 1, 1)150        self.register_buffer(151            "inv_timescales",152            min_timescale * torch.exp(torch.arange(num_timescales, dtype=torch.float32) * -log_timescale_increment),153        )154 155    def forward(self, seq_length=None, position=None):156        """Generates a Tensor of sinusoids with different frequencies.157 158        Args:159            seq_length: an optional Python int defining the output sequence length.160              if the `position` argument is specified.161            position: [B, seq_length], optional position for each token in the162              sequence, only required when the sequence is packed.163 164        Returns:165            [B, seqlen, D] if `position` is specified, else [1, seqlen, D]166        """167        if position is None and seq_length is None:168            raise ValueError("Either position or seq_length must be provided")169 170        if position is None:171            # [1, seqlen]172            position = torch.arange(seq_length, dtype=torch.float32, device=self.inv_timescales.device).unsqueeze(0)173        elif position.ndim != 2:174            raise ValueError(f"position must be 2-dimensional, got shape {position.shape}")175 176        scaled_time = position.view(*position.shape, 1) * self.inv_timescales.view(1, 1, -1)177        signal = torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], dim=2)178 179        # Padding to ensure correct embedding dimension180        signal = F.pad(signal, (0, 0, 0, self.embedding_dims % 2))181        return signal182 183 184def simple_eager_attention_forward(185    module: nn.Module,186    query_states: torch.Tensor,187    key_states: torch.Tensor,188    value_states: torch.Tensor,189    attention_mask: Optional[torch.Tensor],190    scaling: float,191    dropout: float = 0.0,192    **kwargs: Unpack[TransformersKwargs],193):194    attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) * scaling195    if attention_mask is not None:196        causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]197        attn_weights = attn_weights + causal_mask198 199    attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query_states.dtype)200    attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)201    attn_output = torch.matmul(attn_weights, value_states)202    attn_output = attn_output.transpose(1, 2).contiguous()203 204    return attn_output, attn_weights205 206 207class TimesFmAttention(nn.Module):208    """Implements the attention used in TimesFM. One key difference is that there is _per_dim_scaling of the query."""209 210    def __init__(self, config: TimesFmConfig, layer_idx: int):211        super().__init__()212        self.config = config213        self.is_causal = True214        self.attention_dropout = config.attention_dropout215        self.layer_idx = layer_idx216 217        self.num_heads = config.num_attention_heads218        self.hidden_size = config.hidden_size219        self.head_dim = config.head_dim220 221        self.q_size = self.num_heads * self.head_dim222        self.kv_size = self.num_heads * self.head_dim223        self.scaling = nn.Parameter(torch.empty((self.head_dim,)))224 225        self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim)226        self.k_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim)227        self.v_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim)228        self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size)229 230    def _scale_query(self, query: torch.Tensor) -> torch.Tensor:231        scale = F.softplus(self.scaling).mul(1.442695041 / math.sqrt(self.head_dim))232        return query * scale[None, None, None, :]233 234    def forward(235        self,236        hidden_states: torch.Tensor,237        attention_mask: Optional[torch.Tensor] = None,238        **kwargs: Unpack[FlashAttentionKwargs],239    ) -> tuple[torch.Tensor, Optional[torch.Tensor]]:240        input_shape = hidden_states.shape[:-1]241        hidden_shape = (*input_shape, -1, self.head_dim)242 243        query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)244        query_states = self._scale_query(query_states)245        key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)246        value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)247 248        attention_interface: Callable = simple_eager_attention_forward249        if self.config._attn_implementation != "eager":250            attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]251 252        attn_output, attn_weights = attention_interface(253            self,254            query_states,255            key_states,256            value_states,257            attention_mask,258            dropout=0.0 if not self.training else self.attention_dropout,259            scaling=1.0,260            **kwargs,261        )262        attn_output = attn_output.reshape(*input_shape, -1).contiguous()263        attn_output = self.o_proj(attn_output)264        return attn_output, attn_weights265 266 267class TimesFmDecoderLayer(nn.Module):268    """Transformer layer."""269 270    def __init__(self, config: TimesFmConfig, layer_idx: int):271        super().__init__()272 273        self.self_attn = TimesFmAttention(config, layer_idx=layer_idx)274        self.mlp = TimesFmMLP(config)275        self.input_layernorm = TimesFmRMSNorm(config.hidden_size, eps=config.rms_norm_eps)276 277    def forward(278        self,279        hidden_states: torch.Tensor,280        attention_mask: torch.Tensor,281        paddings: torch.Tensor,282        output_attentions: bool = False,283    ) -> tuple[Optional[torch.Tensor], torch.Tensor]:284        # Self Attention285        residual = hidden_states286        hidden_states = self.input_layernorm(hidden_states)287        hidden_states, scores = self.self_attn(288            hidden_states=hidden_states,289            attention_mask=attention_mask,290            output_attentions=output_attentions,291        )292        hidden_states = residual + hidden_states293 294        # MLP295        hidden_states = self.mlp(hidden_states, paddings=paddings)296 297        return scores, hidden_states298 299 300@auto_docstring301class TimesFmPreTrainedModel(PreTrainedModel):302    config: TimesFmConfig303    base_model_prefix = "timesfm"304    _no_split_modules = ["TimesFmDecoderLayer"]305    main_input_name = "past_values"306    _supports_sdpa = True307 308    def _init_weights(self, module):309        super()._init_weights(module)310        if isinstance(module, TimesFmAttention):311            # Initialize scaling parameter312            nn.init.ones_(module.scaling)313 314 315@auto_docstring316class TimesFmModel(TimesFmPreTrainedModel):317    def __init__(self, config: TimesFmConfig):318        super().__init__(config)319 320        self.config = config321        self.input_ff_layer = TimesFmResidualBlock(322            input_dims=2 * config.patch_length,323            output_dims=config.hidden_size,324            hidden_dims=config.intermediate_size,325        )326        self.freq_emb = nn.Embedding(num_embeddings=config.freq_size, embedding_dim=config.hidden_size)327        self.layers = nn.ModuleList(328            [TimesFmDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]329        )330        if self.config.use_positional_embedding:331            self.position_emb = TimesFmPositionalEmbedding(config=config)332 333        # Initialize weights and apply final processing334        self.post_init()335 336    def _forward_transform(337        self, inputs: torch.Tensor, patched_pads: torch.Tensor338    ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:339        """Input is of shape [B, N, P]."""340        mu, sigma = self._timesfm_masked_mean_std(inputs, patched_pads)341        sigma = torch.where(342            sigma < self.config.tolerance,343            torch.tensor(1.0, dtype=sigma.dtype, device=sigma.device),344            sigma,345        )346 347        # Normalize each patch348        outputs = (inputs - mu[:, None, None]) / sigma[:, None, None]349        outputs = torch.where(350            torch.abs(inputs - self.config.pad_val) < self.config.tolerance,351            torch.tensor(self.config.pad_val, dtype=outputs.dtype, device=outputs.device),352            outputs,353        )354        return outputs, (mu, sigma)355 356    @can_return_tuple357    @auto_docstring358    def forward(359        self,360        past_values: torch.Tensor,361        past_values_padding: torch.LongTensor,362        freq: torch.Tensor,363        output_attentions: bool = False,364        output_hidden_states: bool = False,365    ) -> TimesFmOutput:366        r"""367        past_values (`torch.FloatTensor` of shape `(batch_size, sequence_length)`):368            Past values of the time series that serves as input to the model.369        past_values_padding (`torch.LongTensor` of shape `(batch_size, sequence_length)`):370            The padding indicator of the time series.371        freq (`torch.LongTensor` of shape `(batch_size,)`):372            Frequency indices for the time series data.373        """374        # Reshape into patches (using view for efficiency)375        bsize = past_values.shape[0]376        patched_inputs = past_values.view(bsize, -1, self.config.patch_length)377        patched_pads = past_values_padding.view(bsize, -1, self.config.patch_length)378 379        patched_inputs = torch.where(380            torch.abs(patched_pads - 1.0) < self.config.tolerance,381            torch.tensor(0.0, dtype=patched_inputs.dtype, device=patched_inputs.device),382            patched_inputs,383        )384        patched_pads = torch.where(385            torch.abs(patched_inputs - self.config.pad_val) < self.config.tolerance,386            torch.tensor(1.0, dtype=patched_pads.dtype, device=patched_pads.device),387            patched_pads,388        )389        patched_inputs, stats = self._forward_transform(patched_inputs, patched_pads)390 391        # B x N x D392        patched_inputs = patched_inputs * (1.0 - patched_pads)393        concat_inputs = torch.cat([patched_inputs, patched_pads], dim=-1)394        model_input = self.input_ff_layer(concat_inputs)395 396        # A patch should not be padded even if there is at least one zero.397        patched_padding = torch.min(patched_pads, dim=-1)[0]  # Get the values from the min result398        if self.config.use_positional_embedding:399            pos_emb = self.position_emb(model_input.shape[1])400            pos_emb = torch.concat([pos_emb] * model_input.shape[0], dim=0)401            pos_emb = self._timesfm_shift_padded_seq(patched_padding, pos_emb)402            model_input += pos_emb403 404        f_emb = self.freq_emb(freq)  # B x 1 x D405        model_input += f_emb406 407        # Convert paddings to attention mask and combine with causal mask408        hidden_states = model_input409        attention_mask = self._prepare_4d_attention_mask(410            attention_mask=patched_padding,411            sequence_length=hidden_states.shape[1],412            dtype=hidden_states.dtype,413            device=hidden_states.device,414            is_causal=True,415        )416 417        all_attentions = []418        all_hidden_states = []419 420        for layer in self.layers[: self.config.num_hidden_layers]:421            scores, hidden_states = layer(422                hidden_states=hidden_states,423                attention_mask=attention_mask,424                paddings=patched_padding,425                output_attentions=output_attentions,426            )427            if output_attentions:428                all_attentions.append(scores)429            if output_hidden_states:430                all_hidden_states.append(hidden_states)431 432        if output_hidden_states:433            all_hidden_states = [model_input] + all_hidden_states434        else:435            all_hidden_states = None436 437        return TimesFmOutput(438            last_hidden_state=hidden_states,439            hidden_states=all_hidden_states,440            attentions=all_attentions if output_attentions else None,441            loc=stats[0],442            scale=stats[1],443        )444 445    @staticmethod446    def _prepare_4d_attention_mask(447        attention_mask: Optional[torch.Tensor],448        sequence_length: int,449        dtype: torch.dtype,450        device: torch.device,451        is_causal: bool = True,452    ) -> Optional[torch.Tensor]:453        """454        Creates 4D attention mask and combines causal and padding masks if needed.455 456        Args:457            attention_mask: Optional tensor of shape (batch_size, seq_length) containing padding mask458            sequence_length: Length of the sequence459            dtype: Data type of the mask460            device: Device of the mask461            is_causal: Whether to apply causal masking462 463        Returns:464            4D attention mask of shape (batch_size, 1, seq_length, seq_length)465        """466        # Get minimum value for the dtype467        min_value = torch.finfo(dtype).min if dtype.is_floating_point else torch.iinfo(dtype).min468 469        # Handle padding mask470        if attention_mask is not None:471            # Convert 2D padding mask to 4D attention mask472            attention_mask = attention_mask.view(attention_mask.shape[0], 1, 1, -1)473            attention_mask = attention_mask * min_value474 475        # Create causal mask if needed476        if is_causal:477            causal_mask = torch.triu(478                torch.ones((sequence_length, sequence_length), dtype=dtype, device=device) * min_value,479                diagonal=1,480            )481            causal_mask = causal_mask.view(1, 1, sequence_length, sequence_length)482 483            # Combine with padding mask if it exists484            if attention_mask is not None:485                attention_mask = torch.minimum(attention_mask, causal_mask)486            else:487                attention_mask = causal_mask488 489        return attention_mask490 491    @staticmethod492    def _timesfm_masked_mean_std(inputs: torch.Tensor, padding: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:493        """Calculates mean and standard deviation of `inputs` across axis 1.494 495        It excludes values where `padding` is 1.496 497        Args:498            inputs: A PyTorch tensor of shape [b, n, p].499            padding: A PyTorch tensor of shape [b, n, p] with values 0 or 1.500 501        Returns:502            A tuple containing the mean and standard deviation.503            We return the statistics of the first patch with more than three non-padded values.504        """505 506        # Selecting the first patch with more than 3 unpadded values.507        def _get_patch_index(arr: torch.Tensor):508            indices = torch.argmax((arr >= 3).to(torch.int32), dim=1)509            row_sum = (arr >= 3).to(torch.int32).sum(dim=1)510            return torch.where(row_sum == 0, arr.shape[1] - 1, indices)511 512        pad_sum = torch.sum(1 - padding, dim=2)513        patch_indices = _get_patch_index(pad_sum)514        bidxs = torch.arange(inputs.shape[0])515 516        arr = inputs[bidxs, patch_indices, :]517        pad = padding[bidxs, patch_indices, :]518 519        # Create a mask where padding is 0520        mask = 1 - pad521 522        # Calculate the number of valid elements523        num_valid_elements = torch.sum(mask, dim=1)524        num_valid_elements = torch.where(525            num_valid_elements == 0,526            torch.tensor(1, dtype=num_valid_elements.dtype, device=num_valid_elements.device),527            num_valid_elements,528        )529 530        # Calculate the masked sum and squared sum531        masked_sum = torch.sum(arr * mask, dim=1)532        masked_squared_sum = torch.sum((arr * mask) ** 2, dim=1)533 534        # Calculate the masked mean and standard deviation535        masked_mean = masked_sum / num_valid_elements536        masked_var = masked_squared_sum / num_valid_elements - masked_mean**2537        masked_var = torch.where(538            masked_var < 0.0,539            torch.tensor(0.0, dtype=masked_var.dtype, device=masked_var.device),540            masked_var,541        )542        masked_std = torch.sqrt(masked_var)543 544        return masked_mean, masked_std545 546    @staticmethod547    def _timesfm_shift_padded_seq(mask: torch.Tensor, seq: torch.Tensor) -> torch.Tensor:548        """Shifts rows of seq based on the first 0 in each row of the mask.549 550        Args:551            mask: mask tensor of shape [B, N]552            seq: seq tensor of shape [B, N, P]553 554        Returns:555            The shifted sequence.556        """557        batch_size, num_seq, feature_dim = seq.shape558 559        new_mask: torch.BoolTensor = mask == 0560 561        # Use argmax to find the first True value in each row562        indices = new_mask.to(torch.int32).argmax(dim=1)563 564        # Handle rows with all zeros565        indices[~new_mask.any(dim=1)] = -1566 567        # Create index ranges for each sequence in the batch568        idx_range = torch.arange(num_seq, device=seq.device).view(1, -1, 1).expand(batch_size, -1, feature_dim)569 570        # Calculate shifted indices for each element in each sequence571        shifted_idx = (idx_range - indices[:, None, None]) % num_seq572 573        # Gather values from seq using shifted indices574        shifted_seq = seq.gather(1, shifted_idx)575 576        return shifted_seq577 578 579class TimesFmModelForPrediction(TimesFmPreTrainedModel):580    """TimesFM model for quantile and mean prediction."""581 582    def __init__(self, config: TimesFmConfig):583        super().__init__(config)584 585        self.config = config586        self.context_len = config.context_length587        self.horizon_len = config.horizon_length588 589        self.decoder = TimesFmModel(config)590 591        # quantile and mean output592        self.horizon_ff_layer = TimesFmResidualBlock(593            input_dims=config.hidden_size,594            output_dims=config.horizon_length * (1 + len(config.quantiles)),595            hidden_dims=config.intermediate_size,596        )597 598        # Initialize weights and apply final processing599        self.post_init()600 601    def _preprocess(602        self, inputs: Sequence[torch.Tensor], freq: Sequence[int]603    ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:604        """Formats and pads raw inputs to feed into the model.605 606        This function both pads each time series to match the context length, and607        pads the inputs to meet the SPMD shape requirement.608 609        Args:610          inputs: A list of 1d Tensors. Each Tensor is the context time series of611            a single forecast task.612          freq: list of frequencies613 614        Returns:615        A tuple of:616        - the padded input time series to meet the model required context.617        - the padding indicator.618        - the number of padded examples for SPMD so that each core has the same619            number (a multiple of `batch_size`) of examples.620        """621        input_ts, input_padding, inp_freq = [], [], []622 623        for i, ts in enumerate(inputs):624            input_len = ts.shape[0]625            padding = torch.zeros(input_len + self.horizon_len, dtype=ts.dtype, device=ts.device)626            if input_len < self.context_len:627                num_front_pad = self.context_len - input_len628                ts = torch.cat([torch.zeros(num_front_pad, dtype=ts.dtype, device=ts.device), ts], dim=0)629                padding = torch.cat([torch.ones(num_front_pad, dtype=ts.dtype, device=padding.device), padding], dim=0)630            elif input_len > self.context_len:631                ts = ts[-self.context_len :]632                padding = padding[-(self.context_len + self.horizon_len) :]633 634            input_ts.append(ts)635            input_padding.append(padding)636            inp_freq.append(freq[i])637 638        return (639            torch.stack(input_ts, dim=0),640            torch.stack(input_padding, dim=0),641            torch.tensor(inp_freq, dtype=torch.int32).reshape(-1, 1),642        )643 644    def _postprocess_output(645        self, model_output: torch.Tensor, stats: tuple[torch.Tensor, torch.Tensor]646    ) -> torch.Tensor:647        """Postprocess output of stacked transformer."""648 649        # B x N x (H.Q)650        output_ts = self.horizon_ff_layer(model_output)651 652        # Reshape using view653        b, n, _ = output_ts.shape654        output_ts = output_ts.view(b, n, self.config.horizon_length, len(self.config.quantiles) + 1)655 656        mu, sigma = stats657        return output_ts * sigma[:, None, None, None] + mu[:, None, None, None]658 659    def _quantile_loss(self, predictions: torch.Tensor, targets: torch.Tensor) -> torch.Tensor:660        losses = []661        for i, q in enumerate(self.config.quantiles):662            errors = targets - predictions[..., i]663            loss = torch.max((q - 1) * errors, q * errors)664            losses.append(loss.mean())665        return torch.stack(losses).mean()666 667    @can_return_tuple668    @auto_docstring669    def forward(670        self,671        past_values: Sequence[torch.Tensor],672        freq: Optional[Sequence[Union[torch.Tensor, int]]] = None,673        window_size: Optional[int] = None,674        future_values: Optional[torch.Tensor] = None,675        forecast_context_len: Optional[int] = None,676        return_forecast_on_context: bool = False,677        truncate_negative: bool = False,678        output_attentions: Optional[bool] = None,679        output_hidden_states: Optional[bool] = None,680    ) -> TimesFmOutputForPrediction:681        r"""682        past_values (`torch.FloatTensor` of shape `(batch_size, sequence_length)`):683            Past values of the time series that serves as input to the model.684        freq (`torch.LongTensor` of shape `(batch_size,)`):685            Frequency indices for the time series data.686        window_size (`int`, *optional*):687            Window size of trend + residual decomposition. If None then we do not do decomposition.688        future_values (`torch.Tensor`, *optional*):689            Optional future time series values to be used for loss computation.690        forecast_context_len (`int`, *optional*):691            Optional max context length.692        return_forecast_on_context (`bool`, *optional*):693            True to return the forecast on the context when available, i.e. after the first input patch.694        truncate_negative (`bool`, *optional*):695            Truncate to only non-negative values if any of the contexts have non-negative values,696            otherwise do nothing.697        output_attentions (`bool`, *optional*):698            Whether to output the attentions.699        output_hidden_states (`bool`, *optional*):700            Whether to output the hidden states.701 702        Example:703 704        ```python705        >>> from transformers import TimesFmModelForPrediction706 707        >>> model = TimesFmModelForPrediction.from_pretrained("google/timesfm-2.0-500m-pytorch")708 709        >>> forecast_input = [torch.linspace(0, 20, 100).sin(), torch.linspace(0, 20, 200).sin(), torch.linspace(0, 20, 400).sin()]710        >>> frequency_input = torch.tensor([0, 1, 2], dtype=torch.long)711 712        >>> # Generate713        >>> with torch.no_grad():714        >>>     outputs = model(past_values=forecast_input, freq=frequency_input, return_dict=True)715        >>>     point_forecast_conv = outputs.mean_predictions716        >>>     quantile_forecast_conv = outputs.full_predictions717        ```718        """719        if forecast_context_len is None:720            fcontext_len = self.context_len721        else:722            fcontext_len = forecast_context_len723 724        # Get device from first input tensor725        device = past_values[0].device726 727        # Truncate inputs to forecast_context_len728        inputs = [ts[-fcontext_len:] for ts in past_values]729        inp_min = torch.min(torch.stack([torch.min(ts) for ts in inputs]))730 731        if window_size is not None:732            new_inputs = []733            new_freqs = []734            for i, ts in enumerate(inputs):735                new_inputs.extend(self._timesfm_moving_average(ts, window_size))736                if freq is not None:737                    new_freqs.extend([freq[i]] * 2)738            inputs = new_inputs739            if freq is not None:740                freq = new_freqs741 742        if freq is None:743            logger.info("No frequency provided via `freq`. Default to high (0).")744            freq = [0] * len(inputs)745 746        if output_attentions is None:747            output_attentions = self.config.output_attentions748        if output_hidden_states is None:749            output_hidden_states = self.config.output_hidden_states750 751        input_ts, input_padding, inp_freq = self._preprocess(inputs, freq)752        # Move tensors to the same device as input753        input_ts = input_ts.to(device)754        input_padding = input_padding.to(device)755        inp_freq = inp_freq.to(device)756 757        final_out = input_ts758        context_len = final_out.shape[1]759        full_outputs = []760 761        if input_padding.shape[1] != final_out.shape[1] + self.horizon_len:762            raise ValueError(763                "Length of paddings must match length of input + horizon_len:"764                f" {input_padding.shape[1]} != {final_out.shape[1]} + {self.horizon_len}"765            )766        output_patch_len = self.config.horizon_length767 768        num_decode_patches = (self.horizon_len + output_patch_len - 1) // output_patch_len769        for step_index in range(num_decode_patches):770            current_padding = input_padding[:, 0 : final_out.shape[1]]771            input_ts = final_out[:, -fcontext_len:]772            input_padding = current_padding[:, -fcontext_len:]773            decoder_output = self.decoder(774                past_values=input_ts,775                past_values_padding=input_padding,776                freq=inp_freq,777                output_attentions=output_attentions,778                output_hidden_states=output_hidden_states,779            )780            fprop_outputs = self._postprocess_output(781                decoder_output.last_hidden_state,782                (decoder_output.loc, decoder_output.scale),783            )784 785            if return_forecast_on_context and step_index == 0:786                # For the first decodings step, collect the model forecast on the787                # context except the unavailable first input batch forecast.788                new_full_ts = fprop_outputs[:, :-1, : self.config.patch_length, :]789                # We have to use reshape and not view for non-contiguous memory790                new_full_ts = new_full_ts.reshape(new_full_ts.size(0), -1, new_full_ts.size(3))791 792                full_outputs.append(new_full_ts)793 794            # (full batch, last patch, output_patch_len, index of mean forecast = 0)795            new_ts = fprop_outputs[:, -1, :output_patch_len, 0]796            new_full_ts = fprop_outputs[:, -1, :output_patch_len, :]797            # (full batch, last patch, output_patch_len, all output indices)798            full_outputs.append(new_full_ts)799            final_out = torch.concatenate([final_out, new_ts], axis=-1)800 801        if return_forecast_on_context:802            # `full_outputs` indexing starts at after the first input patch.803            full_outputs = torch.concatenate(full_outputs, axis=1)[804                :, : (context_len - self.config.patch_length + self.horizon_len), :805            ]806        else:807            # `full_outputs` indexing starts at the forecast horizon.808            full_outputs = torch.concatenate(full_outputs, axis=1)[:, 0 : self.horizon_len, :]809 810        mean_outputs = full_outputs[:, :, 0]811        if window_size is not None:812            mean_outputs = mean_outputs[0::2, ...] + mean_outputs[1::2, ...]813            full_outputs = full_outputs[0::2, ...] + full_outputs[1::2, ...]814        if inp_min >= 0 and truncate_negative:815            mean_outputs = torch.maximum(mean_outputs, 0.0)816            full_outputs = torch.maximum(full_outputs, 0.0)817 818        loss = None819        if future_values is not None:820            mse_loss = F.mse_loss(mean_outputs, future_values)821            quantile_loss = self._quantile_loss(full_outputs[:, :, 1:], future_values)822            loss = mse_loss + quantile_loss823 824        return TimesFmOutputForPrediction(825            last_hidden_state=decoder_output.last_hidden_state,826            attentions=decoder_output.attentions if output_attentions else None,827            hidden_states=decoder_output.hidden_states if output_hidden_states else None,828            mean_predictions=mean_outputs,829            full_predictions=full_outputs,830            loss=loss,831        )832 833    @staticmethod834    def _timesfm_moving_average(arr: torch.Tensor, window_size: int) -> list[torch.Tensor]:835        """Calculates the moving average using PyTorch's convolution function."""836        # Pad with zeros to handle initial window positions837        arr_padded = F.pad(arr, (window_size - 1, 0), "constant", 0)838        # Create a convolution kernel839        kernel = torch.ones(window_size, dtype=arr.dtype, device=arr.device) / window_size840        # Apply convolution to calculate the moving average841        smoothed_arr = F.conv1d(arr_padded.view(1, 1, -1), kernel.view(1, 1, -1)).squeeze()842        return [smoothed_arr, arr - smoothed_arr]843 844 845__all__ = ["TimesFmModelForPrediction", "TimesFmPreTrainedModel", "TimesFmModel"]846 
Aluode/PerceptionLabPortable ยท CoolFace