main
py 115 lines 4.53 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
5 # Adapted from
6 # https://github.com/huggingface/transformers/blob/v4.33.2/src/transformers/models/llama/modeling_llama.py
7 # Copyright 2023 The vLLM team.
8 # Copyright 2022 EleutherAI and the HuggingFace Inc. team. All rights reserved.
9 #
10 # This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
11 # and OPT implementations in this library. It has been modified from its
12 # original forms to accommodate minor architectural differences compared
13 # to GPT-NeoX and OPT used by the Meta AI team that trained the model.
14 #
15 # Licensed under the Apache License, Version 2.0 (the "License");
16 # you may not use this file except in compliance with the License.
17 # You may obtain a copy of the License at
18 #
19 # http://www.apache.org/licenses/LICENSE-2.0
20 #
21 # Unless required by applicable law or agreed to in writing, software
22 # distributed under the License is distributed on an "AS IS" BASIS,
23 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 # See the License for the specific language governing permissions and
25 # limitations under the License.
26 import torch
27
28 from .base import RotaryEmbedding
29
30
31 class LinearScalingRotaryEmbedding(RotaryEmbedding):
32 """RotaryEmbedding extended with linear scaling.
33
34 It supports multiple scaling factors. Since multiple LoRA adapters may have
35 different scaling factors, we need multiple cos/sin caches. In this way,
36 instead of running rotary embedding kernel per lora, we can run multiple
37 lora in a batched way.
38
39 In addition to that, we also keep the cos/sin cache for the scaling factor
40 of 1 (default) at all times.
41
42 Exemplary for two scaling factors x=1, y and z with embeddings
43 [[x11, x12, ... x1m], ..., [xn1, xn2, ..., xnm]] and
44 [[y11, y12, ... y1o], ..., [yn1, yn2, ..., yno]], and
45 [[z11, z12, ... z1p], ..., [zn1, zn2, ..., znp]],
46
47 we construct the cos/sin cache as follows:
48 [[x11, x12, ... x1m, y11, y12, ... y1o, z11, z12, ... z1p],
49 ...
50 [xn1, xn2, ... xnm, yn1, yn2, ... yno, zn1, zn2, ... znp]]
51
52 We then use offsets to index into the cos/sin cache for
53 the respective scaling factors.
54
55 The offset to cache can be accessed via `scaling_factor_to_offset` API.
56
57 Credits to the Reddit user /u/kaiokendev
58 """
59
60 def __init__(
61 self,
62 head_size: int,
63 rotary_dim: int,
64 max_position_embeddings: int,
65 base: float,
66 is_neox_style: bool,
67 scaling_factors: list[float] | float,
68 dtype: torch.dtype,
69 ) -> None:
70 if isinstance(scaling_factors, float):
71 scaling_factors = [scaling_factors]
72 self.scaling_factors: list[float] = scaling_factors # noqa
73 super().__init__(
74 head_size, rotary_dim, max_position_embeddings, base, is_neox_style, dtype
75 )
76 # Lazy initialized.
77 self._scaling_factor_to_offset: dict[float, int]
78
79 def _compute_cos_sin_cache(self) -> torch.Tensor:
80 inv_freq = self._compute_inv_freq(self.base)
81 cache_list: list[torch.Tensor] = []
82 # offsets to the next cache in a tensor.
83 # Each offset corresponds to the same index in scaling_factors.
84 offsets: list[int] = []
85 for scaling_factor in self.scaling_factors:
86 # NOTE(woosuk): self.max_position_embeddings is the original
87 # maximum length before applying the rope scaling.
88 # Thus, the maximum length after applying the rope scaling is
89 # self.max_position_embeddings * self.scaling_factor.
90 max_len = self.max_position_embeddings * scaling_factor
91 t = torch.arange(max_len, dtype=torch.float)
92 t = t / scaling_factor
93
94 freqs = torch.einsum("i,j -> ij", t, inv_freq)
95 cos = freqs.cos()
96 sin = freqs.sin()
97 cache = torch.cat((cos, sin), dim=-1)
98 if not cache_list:
99 offset = 0
100 else:
101 last_offset = offsets[-1]
102 next_max_len = cache_list[-1].shape[0]
103 offset = last_offset + next_max_len
104 offsets.append(offset)
105 cache_list.append(cache)
106 self._scaling_factor_to_offset = {
107 float(scaling_factor): offsets[i]
108 for i, scaling_factor in enumerate(self.scaling_factors)
109 }
110 assert len(self.scaling_factors) == len(offsets)
111 return torch.cat(cache_list, dim=0)
112
113 @property
114 def scaling_factor_to_offset(self) -> dict[float, int]:
115 return self._scaling_factor_to_offset