| |
| |
|
|
| from typing import Optional, Tuple |
| from dataclasses import dataclass |
| import math |
|
|
| import torch |
| from torch import nn |
| import torch.nn.functional as F |
| import awq_inference_engine |
| from transformers.models.llama.modeling_llama import LlamaRotaryEmbedding |
|
|
| |
|
|
| import tinychat.utils.constants |
|
|
| max_batch_size = tinychat.utils.constants.max_batch_size |
| global_max_seq_len = tinychat.utils.constants.max_seq_len |
|
|
|
|
| def gen_slopes(n_heads, alibi_bias_max=8): |
| _n_heads = 2 ** math.ceil(math.log2(n_heads)) |
| m = torch.arange(1, _n_heads + 1, dtype=torch.float32) |
| m = m.mul(alibi_bias_max / _n_heads) |
| slopes = 1.0 / torch.pow(2, m) |
| if _n_heads != n_heads: |
| slopes = torch.concat([slopes[1::2], slopes[::2]])[:n_heads] |
| return slopes.view(1, n_heads, 1, 1) |
|
|
|
|
| def build_alibi_bias( |
| n_heads, seq_len, full=False, alibi_bias_max=8, dtype=torch.float32 |
| ): |
| alibi_bias = torch.arange(1 - seq_len, 1, dtype=torch.int32).view(1, 1, 1, seq_len) |
| if full: |
| alibi_bias = alibi_bias - torch.arange(1 - seq_len, 1, dtype=torch.int32).view( |
| 1, 1, seq_len, 1 |
| ) |
| alibi_bias = alibi_bias.abs().mul(-1) |
| slopes = gen_slopes(n_heads, alibi_bias_max) |
| alibi_bias = alibi_bias * slopes |
| slopes = slopes.squeeze(0).squeeze(-1).squeeze(-1) |
| return slopes.to(dtype=dtype), alibi_bias.to(dtype=dtype) |
|
|
|
|
| def _cast_if_autocast_enabled(tensor): |
| if torch.is_autocast_enabled(): |
| if tensor.device.type == "cuda": |
| dtype = torch.get_autocast_gpu_dtype() |
| elif tensor.device.type == "cpu": |
| dtype = torch.get_autocast_cpu_dtype() |
| else: |
| raise NotImplementedError() |
| return tensor.to(dtype=dtype) |
| return tensor |
|
|
|
|
| class LPLayerNorm(torch.nn.LayerNorm): |
| def __init__(self, normalized_shape, eps=1e-05, elementwise_affine=True): |
| super().__init__( |
| normalized_shape=normalized_shape, |
| eps=eps, |
| elementwise_affine=elementwise_affine, |
| ) |
|
|
| def forward(self, x): |
| module_device = x.device |
| downcast_x = _cast_if_autocast_enabled(x) |
| downcast_weight = ( |
| _cast_if_autocast_enabled(self.weight) |
| if self.weight is not None |
| else self.weight |
| ) |
| downcast_bias = ( |
| _cast_if_autocast_enabled(self.bias) if self.bias is not None else self.bias |
| ) |
| with torch.autocast(enabled=False, device_type=module_device.type): |
| return torch.nn.functional.layer_norm( |
| downcast_x, |
| self.normalized_shape, |
| downcast_weight, |
| downcast_bias, |
| self.eps, |
| ) |
|
|
|
|
| class SharedEmbedding(nn.Embedding): |
| def forward(self, input: torch.Tensor, unembed: bool = False) -> torch.Tensor: |
| if unembed: |
| return F.linear(input, self.weight) |
| return super().forward(input) |
|
|
|
|
| class MPTAttentionFused(nn.Module): |
| def __init__(self, args): |
| super().__init__() |
| self.args = args |
| self.n_local_heads = args.n_heads |
| self.head_dim = args.d_model // args.n_heads |
| args.max_seq_len = min(args.max_seq_len, global_max_seq_len) |
|
|
| self.Wqkv = nn.Linear( |
| args.d_model, |
| args.n_heads * self.head_dim * 3, |
| bias=False, |
| ) |
|
|
| self.out_proj = nn.Linear( |
| args.n_heads * self.head_dim, |
| args.d_model, |
| bias=False, |
| ) |
|
|
| |
|
|
| self.cache_v = ( |
| torch.zeros( |
| ( |
| max_batch_size, |
| self.n_local_heads, |
| args.max_seq_len, |
| self.head_dim, |
| ) |
| ) |
| .cuda() |
| .half() |
| ) |
| |
| self.cache_k = ( |
| torch.zeros( |
| ( |
| max_batch_size, |
| self.n_local_heads, |
| self.head_dim // 8, |
| args.max_seq_len, |
| 8, |
| ) |
| ) |
| .cuda() |
| .half() |
| ) |
|
|
| alibi_slopes, alibi_bias = build_alibi_bias( |
| self.n_local_heads, args.max_seq_len |
| ) |
| |
| self.alibi_slopes = alibi_slopes.float().to("cuda:0") |
| self.alibi_bias = alibi_bias.to("cuda:0") |
|
|
| def forward( |
| self, |
| x: torch.Tensor, |
| start_pos: int, |
| mask: Optional[torch.Tensor], |
| ): |
| bsz, seqlen, _ = x.shape |
| xqkv = self.Wqkv(x) |
| xqkv = xqkv.view(bsz, seqlen, -1, self.n_local_heads, self.head_dim) |
| xq = xqkv[:, :, 0] |
| xk = xqkv[:, :, 1] |
| xv = xqkv[:, :, 2] |
|
|
| if seqlen > 1: |
| xq = xq.view(bsz, seqlen, self.n_local_heads, self.head_dim) |
| xk = xk.view(bsz, seqlen, self.n_local_heads, self.head_dim) |
| xv = xv.view(bsz, seqlen, self.n_local_heads, self.head_dim) |
|
|
| self.cache_k = self.cache_k.to(xq) |
| self.cache_v = self.cache_v.to(xq) |
|
|
| values_store = xv.transpose(2, 1) |
| keys_store = ( |
| xk.reshape(bsz, seqlen, self.n_local_heads, self.head_dim // 8, 8) |
| .permute(0, 2, 3, 1, 4) |
| .contiguous() |
| ) |
|
|
| self.cache_v[:bsz, :, start_pos : start_pos + seqlen, :] = values_store |
| self.cache_k[:bsz, :, :, start_pos : start_pos + seqlen, :] = keys_store |
|
|
| keys = xk |
| values = xv |
|
|
| xq = xq.transpose(1, 2) |
| keys = keys.transpose(1, 2) |
| values = values.transpose(1, 2) |
| scores = torch.matmul(xq, keys.transpose(2, 3)) / math.sqrt(self.head_dim) |
| scores += self.alibi_bias[..., :seqlen] |
| if mask is not None: |
| scores = scores + mask |
| scores = F.softmax(scores.float(), dim=-1).type_as(xq) |
| output = torch.matmul(scores, values) |
| output = output.transpose(1, 2).contiguous().view(bsz, seqlen, -1) |
| else: |
| |
| |
| |
| xq = xq.view(bsz, self.n_local_heads, self.head_dim) |
| xk = xk.view(bsz, self.n_local_heads, self.head_dim) |
| xv = xv.view(bsz, self.n_local_heads, self.head_dim) |
| output = awq_inference_engine.single_query_attention( |
| xq, |
| xk, |
| xv, |
| self.cache_k, |
| self.cache_v, |
| None, |
| |
| self.alibi_slopes.float(), |
| start_pos, |
| |
| 0, |
| 10000, |
| 1.0, |
| True, |
| ) |
| output = output.reshape(bsz, 1, -1) |
|
|
| return self.out_proj(output) |
|
|
|
|
| class MPTMLP(nn.Module): |
| def __init__(self, d_model: int, expansion_ratio: int): |
| super().__init__() |
| self.up_proj = nn.Linear(d_model, expansion_ratio * d_model, bias=False) |
| self.act = nn.GELU(approximate="none") |
| self.down_proj = nn.Linear(expansion_ratio * d_model, d_model, bias=False) |
| self.down_proj._is_residual = True |
|
|
| def forward(self, x): |
| return self.down_proj(self.act(self.up_proj(x))) |
|
|
|
|
| class MPTBlock(nn.Module): |
| def __init__(self, layer_id: int, args): |
| super().__init__() |
| self.n_heads = args.n_heads |
| self.dim = args.d_model |
| self.head_dim = args.d_model // args.n_heads |
| self.attn = MPTAttentionFused(args) |
| self.ffn = MPTMLP(d_model=args.d_model, expansion_ratio=4) |
| self.layer_id = layer_id |
| self.norm_1 = LPLayerNorm(args.d_model, eps=1e-6) |
| self.norm_2 = LPLayerNorm(args.d_model, eps=1e-6) |
|
|
| def forward( |
| self, |
| x: torch.Tensor, |
| start_pos: int, |
| mask: Optional[torch.Tensor], |
| ): |
| h = x + self.attn.forward(self.norm_1(x), start_pos, mask) |
| out = h + self.ffn.forward(self.norm_2(h)) |
| return out |
|
|
|
|
| class Transformer(nn.Module): |
| def __init__(self, params): |
| super().__init__() |
| self.params = params |
| self.vocab_size = params.vocab_size |
| self.n_layers = params.n_layers |
|
|
| self.wte = SharedEmbedding(params.vocab_size, params.d_model) |
|
|
| self.blocks = torch.nn.ModuleList() |
| for layer_id in range(params.n_layers): |
| self.blocks.append(MPTBlock(layer_id, params)) |
|
|
| self.norm_f = LPLayerNorm(params.d_model, eps=1e-6) |
|
|
| @torch.inference_mode() |
| def forward(self, tokens: torch.Tensor, start_pos: int): |
| _bsz, seqlen = tokens.shape |
| h = self.wte(tokens) |
|
|
| mask = None |
| if seqlen > 1: |
| mask = torch.full( |
| (1, 1, seqlen, seqlen), float("-inf"), device=tokens.device |
| ) |
| mask = torch.triu(mask, diagonal=start_pos + 1).type_as(h) |
| for layer in self.blocks: |
| h = layer(h, start_pos, mask) |
| h = self.norm_f(h) |
| return h |
|
|
|
|
| class MPTForCausalLM(nn.Module): |
| def __init__(self, params): |
| super().__init__() |
| self.config = params |
| self.transformer = Transformer(params) |
| if params.no_bias: |
| for module in self.modules(): |
| if hasattr(module, "bias") and isinstance(module.bias, nn.Parameter): |
| module.register_parameter("bias", None) |
|
|
| @torch.inference_mode() |
| def forward(self, tokens: torch.Tensor, start_pos: int): |
| h = self.transformer(tokens, start_pos) |
| output = self.transformer.wte(h, unembed=True) |
| return output.float() |
|
|