Naphula commited on
Commit
4868b25
·
verified ·
1 Parent(s): 6a2122d

Upload base_v2.py

Browse files
Files changed (1) hide show
  1. base_v2.py +159 -0
base_v2.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2025 Arcee AI
2
+ # SPDX-License-Identifier: LGPL-3.0-only
3
+
4
+ import torch
5
+ from abc import ABC, abstractmethod
6
+ from typing import Dict, List, Optional, Tuple
7
+
8
+ from pydantic import BaseModel, Field
9
+ from transformers import PretrainedConfig
10
+
11
+ from mergekit.common import get_config_value
12
+
13
+
14
+ class WeightInfo(BaseModel, frozen=True):
15
+ """Information about an individual weight tensor in a model.
16
+
17
+ Attributes:
18
+ name (str):
19
+ The name of the tensor representing the weight.
20
+ is_embed (bool):
21
+ Indicates whether the weight is for an embedding or language model head.
22
+ optional (bool):
23
+ Indicates whether the weight can be omitted from a model.
24
+ aliases (Optional[List[str]]):
25
+ List of alternative names for the weight, if applicable.
26
+ force_dtype (Optional[str]):
27
+ Mandatory dtype for the weight, if applicable.
28
+ """
29
+
30
+ name: str
31
+ is_embed: bool = False
32
+ optional: bool = False
33
+ aliases: Optional[Tuple[str, ...]] = None
34
+ force_dtype: Optional[str] = None
35
+ tied_names: Optional[Tuple[str, ...]] = None
36
+
37
+
38
+ def _prefix_weight(weight: WeightInfo, prefix: Optional[str] = None) -> WeightInfo:
39
+ if prefix is None:
40
+ return weight
41
+ return WeightInfo(
42
+ name=prefix + weight.name,
43
+ aliases=tuple(prefix + alias for alias in weight.aliases or ()) or None,
44
+ tied_names=tuple(prefix + tied_name for tied_name in weight.tied_names or ())
45
+ or None,
46
+ **weight.model_dump(exclude={"name", "aliases", "tied_names"}),
47
+ )
48
+
49
+
50
+ class ModuleArchitecture(ABC):
51
+ @abstractmethod
52
+ def pre_weights(self, config: PretrainedConfig) -> List[WeightInfo]:
53
+ """Return a list of all weights preceding the first layer."""
54
+ ...
55
+
56
+ @abstractmethod
57
+ def post_weights(self, config: PretrainedConfig) -> List[WeightInfo]:
58
+ """Return a list of all weights following the final layer."""
59
+ ...
60
+
61
+ @abstractmethod
62
+ def layer_weights(
63
+ self, index: int, config: PretrainedConfig
64
+ ) -> Optional[List[WeightInfo]]:
65
+ """Return a list of all weights associated with a given layer."""
66
+ ...
67
+
68
+ def num_layers_config_key(self) -> str:
69
+ """Key in config that represents number of layers"""
70
+ return "num_hidden_layers"
71
+
72
+ def num_layers(self, config: PretrainedConfig) -> int:
73
+ """Return the number of layers in a model."""
74
+ return get_config_value(config, self.num_layers_config_key())
75
+
76
+ def all_weights(self, config: PretrainedConfig) -> List[WeightInfo]:
77
+ """Return all weights associated with a model."""
78
+ num_layers = self.num_layers(config)
79
+ res = list(self.pre_weights(config))
80
+ for layer_idx in range(num_layers):
81
+ res.extend(self.layer_weights(layer_idx, config))
82
+ res.extend(self.post_weights(config))
83
+ return res
84
+
85
+
86
+ class ConfiguredModuleArchitecture(
87
+ BaseModel, frozen=True, arbitrary_types_allowed=True
88
+ ):
89
+ info: ModuleArchitecture
90
+ config: PretrainedConfig
91
+ weight_prefix: Optional[str] = None
92
+
93
+ def num_layers(self) -> int:
94
+ return self.info.num_layers(self.config)
95
+
96
+ def pre_weights(self) -> List[WeightInfo]:
97
+ return [
98
+ _prefix_weight(w, self.weight_prefix)
99
+ for w in self.info.pre_weights(self.config)
100
+ ]
101
+
102
+ def post_weights(self) -> List[WeightInfo]:
103
+ return [
104
+ _prefix_weight(w, self.weight_prefix)
105
+ for w in self.info.post_weights(self.config)
106
+ ]
107
+
108
+ def layer_weights(self, index: int) -> List[WeightInfo]:
109
+ return [
110
+ _prefix_weight(w, self.weight_prefix)
111
+ for w in self.info.layer_weights(index, self.config)
112
+ ]
113
+
114
+ def all_weights(self) -> List[WeightInfo]:
115
+ return [
116
+ _prefix_weight(w, self.weight_prefix)
117
+ for w in self.info.all_weights(self.config)
118
+ ]
119
+
120
+
121
+ class ModuleDefinition(BaseModel, frozen=True, arbitrary_types_allowed=True):
122
+ architecture: ModuleArchitecture
123
+ weight_prefix: Optional[str] = None
124
+ subfolder: Optional[str] = None
125
+
126
+
127
+ class ModelArchitecture(BaseModel, frozen=True):
128
+ modules: Dict[str, ModuleDefinition]
129
+ architectures: List[str]
130
+ expected_model_type: str = Field(alias="model_type")
131
+ tagalong_files: Optional[List[str]] = None
132
+ vocab_size_config_key: Optional[str] = None
133
+
134
+ def all_weights(self, config: PretrainedConfig) -> List[WeightInfo]:
135
+ res = []
136
+ for module in self.modules.values():
137
+ for weight_info in module.architecture.all_weights(config=config):
138
+ res.append(_prefix_weight(weight_info, module.weight_prefix))
139
+ return res
140
+
141
+
142
+ class ConfiguredModelArchitecture(BaseModel, frozen=True, arbitrary_types_allowed=True):
143
+ info: ModelArchitecture
144
+ config: PretrainedConfig
145
+
146
+ def all_weights(self) -> List[WeightInfo]:
147
+ return self.info.all_weights(self.config)
148
+
149
+ def get_module(self, module_name: str) -> ConfiguredModuleArchitecture:
150
+ return ConfiguredModuleArchitecture(
151
+ info=self.info.modules[module_name].architecture,
152
+ config=self.config,
153
+ weight_prefix=self.info.modules[module_name].weight_prefix,
154
+ )
155
+
156
+ # Manually rebuild Pydantic models to resolve forward references
157
+ # This fixes the "not fully defined" error with Pydantic v2
158
+ ConfiguredModuleArchitecture.model_rebuild()
159
+ ConfiguredModelArchitecture.model_rebuild()