Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / losses / linear_ce.py: 35%
20 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-25 05:45 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-25 05:45 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""FusedLinearCrossEntropy — stub for fused lm_head + CE loss.
17Reference: nemo_automodel.components.loss.linear_ce
18Full implementation requires cut_cross_entropy package.
19"""
21from typing import Optional
23import torch
24from torch import nn
25import torch.nn.functional as F
28class FusedLinearCrossEntropy(nn.Module):
29 """Fused linear + cross-entropy loss.
31 Stub implementation: falls back to separate linear + CE.
32 The production version fuses lm_head matmul with CE computation
33 for memory efficiency (avoids materializing the full logits tensor).
34 """
36 def __init__(self, fp32_upcast: bool = True, ignore_index: int = -100) -> None:
37 """Initialize the fused linear + cross-entropy loss module.
39 Args:
40 fp32_upcast: Whether to upcast inputs to float32 before the
41 matmul / CE computation for numerical stability.
42 ignore_index: Label index ignored by the cross-entropy loss.
43 """
44 super().__init__()
45 self.fp32_upcast = fp32_upcast
46 self.ignore_index = ignore_index
48 def forward(
49 self,
50 hidden_states: torch.Tensor,
51 labels: torch.Tensor,
52 lm_weight: Optional[torch.Tensor] = None,
53 num_label_tokens: Optional[int] = None,
54 ) -> torch.Tensor:
55 """Compute fused linear + cross-entropy loss.
57 Args:
58 hidden_states: [B, S, H] final hidden states (when ``lm_weight``
59 is provided), or pre-computed logits [N, V] (when
60 ``lm_weight=None``, i.e. the logits fallback path of the
61 ``calculate_loss`` dispatcher).
62 labels: [B, S] or [N] target indices.
63 lm_weight: [V, H] LM head weight; when None, ``hidden_states`` is
64 treated as pre-computed logits.
65 num_label_tokens: Optional token count for normalization.
67 Returns:
68 Scalar loss (reduction="sum").
69 """
70 if lm_weight is not None:
71 logits = torch.matmul(hidden_states.float() if self.fp32_upcast else hidden_states, lm_weight.t())
72 else:
73 # dispatcher fallback path: hidden_states are pre-computed logits
74 logits = hidden_states.float() if self.fp32_upcast else hidden_states
75 logits = logits.view(-1, logits.size(-1))
76 labels = labels.view(-1)
77 loss = F.cross_entropy(logits, labels, reduction="sum", ignore_index=self.ignore_index)
78 if num_label_tokens is not None:
79 if num_label_tokens > 0:
80 loss = loss / num_label_tokens
81 return loss