File size: 2,719 Bytes
eca5751
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"""
RMSNorm + SwiGLU layers v0.3
============================
- RMSNorm (Zhang & Sennrich, 2019) — unchanged
- SwiGLU — adds MLP-parallel variant (compute gate/up in parallel)
"""
from __future__ import annotations

import torch
import torch.nn as nn
import torch.nn.functional as F


class RMSNorm(nn.Module):
    """Root Mean Square LayerNorm (Zhang & Sennrich, 2019).
    Hiệu quả hơn LayerNorm truyền thống, không có bias và không trừ mean.
    """

    def __init__(self, hidden_size: int, eps: float = 1e-6):
        super().__init__()
        self.weight = nn.Parameter(torch.ones(hidden_size))
        self.eps = eps

    def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
        input_dtype = hidden_states.dtype
        hidden_states = hidden_states.to(torch.float32)
        variance = hidden_states.pow(2).mean(-1, keepdim=True)
        hidden_states = hidden_states * torch.rsqrt(variance + self.eps)
        return self.weight * hidden_states.to(input_dtype)


class SwiGLU(nn.Module):
    """SwiGLU activation: SiLU(gate(x)) * up(x).

    v0.3: adds MLP-parallel variant — gate_proj and up_proj are computed
    as a single concatenated matmul (faster on modern GPUs).
    """

    def __init__(self, hidden_size: int, intermediate_size: int, parallel: bool = True):
        super().__init__()
        self.parallel = parallel
        if parallel:
            # Concatenated gate + up projection (mathematically identical, faster)
            self.gate_up_proj = nn.Linear(
                hidden_size, 2 * intermediate_size, bias=False,
            )
            self.gate_proj = None
            self.up_proj = None
        else:
            self.gate_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
            self.up_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
            self.gate_up_proj = None
        self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
        self.intermediate_size = intermediate_size

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        if self.parallel:
            gate_up = self.gate_up_proj(x)
            gate, up = gate_up[..., : self.intermediate_size], gate_up[..., self.intermediate_size :]
            gate = F.silu(gate)
        else:
            gate = F.silu(self.gate_proj(x))
            up = self.up_proj(x)
        return self.down_proj(gate * up)


def _expand_token_ids_to_mask(token_ids: torch.Tensor, seq_len: int) -> torch.Tensor:
    """Helper: chuyển token ids thành attention mask."""
    mask = torch.zeros(token_ids.shape[0], seq_len, device=token_ids.device)
    for i, ids in enumerate(token_ids):
        mask[i, : len(ids)] = 1
    return mask