maxframe 2.2.0__cp311-cp311-macosx_10_9_universal2.whl → 2.3.0rc1__cp311-cp311-macosx_10_9_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of maxframe might be problematic. Click here for more details.
- maxframe/_utils.cpython-311-darwin.so +0 -0
- maxframe/codegen/core.py +3 -2
- maxframe/codegen/spe/dataframe/merge.py +4 -0
- maxframe/codegen/spe/dataframe/misc.py +2 -0
- maxframe/codegen/spe/dataframe/reduction.py +18 -0
- maxframe/codegen/spe/dataframe/sort.py +9 -1
- maxframe/codegen/spe/dataframe/tests/test_reduction.py +13 -0
- maxframe/codegen/spe/dataframe/tseries.py +9 -0
- maxframe/codegen/spe/learn/contrib/lightgbm.py +4 -3
- maxframe/codegen/spe/tensor/datasource.py +1 -0
- maxframe/config/config.py +3 -0
- maxframe/conftest.py +10 -0
- maxframe/core/base.py +2 -1
- maxframe/core/entity/tileables.py +2 -0
- maxframe/core/graph/core.cpython-311-darwin.so +0 -0
- maxframe/core/graph/entity.py +7 -1
- maxframe/core/mode.py +6 -1
- maxframe/dataframe/__init__.py +2 -2
- maxframe/dataframe/arithmetic/__init__.py +4 -0
- maxframe/dataframe/arithmetic/maximum.py +33 -0
- maxframe/dataframe/arithmetic/minimum.py +33 -0
- maxframe/dataframe/core.py +98 -106
- maxframe/dataframe/datasource/core.py +6 -0
- maxframe/dataframe/datasource/direct.py +57 -0
- maxframe/dataframe/datasource/read_csv.py +19 -11
- maxframe/dataframe/datasource/read_odps_query.py +29 -6
- maxframe/dataframe/datasource/read_odps_table.py +32 -10
- maxframe/dataframe/datasource/read_parquet.py +38 -39
- maxframe/dataframe/datastore/__init__.py +6 -0
- maxframe/dataframe/datastore/direct.py +268 -0
- maxframe/dataframe/datastore/to_odps.py +6 -0
- maxframe/dataframe/extensions/flatjson.py +2 -1
- maxframe/dataframe/groupby/__init__.py +5 -1
- maxframe/dataframe/groupby/aggregation.py +10 -6
- maxframe/dataframe/groupby/apply_chunk.py +1 -3
- maxframe/dataframe/groupby/core.py +20 -4
- maxframe/dataframe/indexing/__init__.py +2 -1
- maxframe/dataframe/indexing/insert.py +45 -17
- maxframe/dataframe/merge/__init__.py +3 -0
- maxframe/dataframe/merge/combine.py +244 -0
- maxframe/dataframe/misc/__init__.py +14 -3
- maxframe/dataframe/misc/check_unique.py +41 -10
- maxframe/dataframe/misc/drop.py +31 -0
- maxframe/dataframe/misc/infer_dtypes.py +251 -0
- maxframe/dataframe/misc/map.py +31 -18
- maxframe/dataframe/misc/repeat.py +159 -0
- maxframe/dataframe/misc/tests/test_misc.py +35 -1
- maxframe/dataframe/missing/checkna.py +3 -2
- maxframe/dataframe/reduction/__init__.py +10 -5
- maxframe/dataframe/reduction/aggregation.py +6 -6
- maxframe/dataframe/reduction/argmax.py +7 -4
- maxframe/dataframe/reduction/argmin.py +7 -4
- maxframe/dataframe/reduction/core.py +18 -9
- maxframe/dataframe/reduction/mode.py +144 -0
- maxframe/dataframe/reduction/nunique.py +10 -3
- maxframe/dataframe/reduction/tests/test_reduction.py +12 -0
- maxframe/dataframe/sort/__init__.py +9 -2
- maxframe/dataframe/sort/argsort.py +7 -1
- maxframe/dataframe/sort/core.py +1 -1
- maxframe/dataframe/sort/rank.py +147 -0
- maxframe/dataframe/tseries/__init__.py +19 -0
- maxframe/dataframe/tseries/at_time.py +61 -0
- maxframe/dataframe/tseries/between_time.py +122 -0
- maxframe/dataframe/utils.py +30 -26
- maxframe/learn/contrib/llm/core.py +16 -7
- maxframe/learn/contrib/llm/deploy/__init__.py +13 -0
- maxframe/learn/contrib/llm/deploy/config.py +221 -0
- maxframe/learn/contrib/llm/deploy/core.py +247 -0
- maxframe/learn/contrib/llm/deploy/framework.py +35 -0
- maxframe/learn/contrib/llm/deploy/loader.py +360 -0
- maxframe/learn/contrib/llm/deploy/tests/__init__.py +13 -0
- maxframe/learn/contrib/llm/deploy/tests/test_register_models.py +359 -0
- maxframe/learn/contrib/llm/models/__init__.py +1 -0
- maxframe/learn/contrib/llm/models/dashscope.py +12 -6
- maxframe/learn/contrib/llm/models/managed.py +76 -11
- maxframe/learn/contrib/llm/models/openai.py +72 -0
- maxframe/learn/contrib/llm/tests/__init__.py +13 -0
- maxframe/learn/contrib/llm/tests/test_core.py +34 -0
- maxframe/learn/contrib/llm/tests/test_openai.py +187 -0
- maxframe/learn/contrib/llm/tests/test_text_gen.py +155 -0
- maxframe/learn/contrib/llm/text.py +348 -42
- maxframe/learn/contrib/models.py +4 -1
- maxframe/learn/contrib/xgboost/classifier.py +2 -0
- maxframe/learn/contrib/xgboost/core.py +31 -7
- maxframe/learn/contrib/xgboost/predict.py +4 -2
- maxframe/learn/contrib/xgboost/regressor.py +5 -0
- maxframe/learn/contrib/xgboost/train.py +2 -0
- maxframe/learn/preprocessing/_data/min_max_scaler.py +34 -23
- maxframe/learn/preprocessing/_data/standard_scaler.py +34 -25
- maxframe/learn/utils/__init__.py +1 -0
- maxframe/learn/utils/extmath.py +42 -9
- maxframe/learn/utils/odpsio.py +80 -11
- maxframe/lib/filesystem/_oss_lib/common.py +2 -0
- maxframe/lib/mmh3.cpython-311-darwin.so +0 -0
- maxframe/opcodes.py +9 -1
- maxframe/remote/core.py +4 -0
- maxframe/serialization/core.cpython-311-darwin.so +0 -0
- maxframe/serialization/tests/test_serial.py +2 -2
- maxframe/tensor/arithmetic/__init__.py +1 -1
- maxframe/tensor/arithmetic/core.py +2 -2
- maxframe/tensor/arithmetic/tests/test_arithmetic.py +0 -9
- maxframe/tensor/core.py +3 -0
- maxframe/tensor/misc/copyto.py +1 -1
- maxframe/tests/test_udf.py +61 -0
- maxframe/tests/test_utils.py +8 -5
- maxframe/udf.py +103 -7
- maxframe/utils.py +61 -8
- {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/METADATA +1 -2
- {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/RECORD +113 -90
- maxframe_client/session/task.py +8 -1
- maxframe_client/tests/test_session.py +24 -0
- maxframe/dataframe/arrays.py +0 -864
- {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/WHEEL +0 -0
- {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Copyright 1999-2025 Alibaba Group Holding 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
|
+
from typing import Any, Dict, List, Optional, Union
|
|
16
|
+
|
|
17
|
+
from odps.models import Resource as ODPSResource
|
|
18
|
+
|
|
19
|
+
from .....serialization.serializables import Serializable, StringField
|
|
20
|
+
from .config import ModelDeploymentConfig
|
|
21
|
+
from .framework import InferenceFrameworkEnum
|
|
22
|
+
|
|
23
|
+
_registered_llm_models = {}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ResourceNameTemplate(Serializable):
|
|
27
|
+
"""
|
|
28
|
+
A template-based resource name builder that supports variable substitution.
|
|
29
|
+
All values in the substitution dict will have their hyphens (-) replaced with underscores (_).
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
template = ResourceNameTemplate(
|
|
33
|
+
project="my_project",
|
|
34
|
+
schema="schema_{region_id}",
|
|
35
|
+
name="resource_{env}"
|
|
36
|
+
)
|
|
37
|
+
# Render with variables
|
|
38
|
+
full_name = template.build_full_resource_name({"region_id": "cn-hangzhou", "env": "prod"})
|
|
39
|
+
# Result: resource name with cn_hangzhou and prod substituted
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
project: str = StringField("project", default=None)
|
|
43
|
+
schema: str = StringField("schema", default=None)
|
|
44
|
+
name: str = StringField("name")
|
|
45
|
+
|
|
46
|
+
def build_full_resource_name(self, template_vars: Dict[str, Any]):
|
|
47
|
+
"""
|
|
48
|
+
Build full resource name with template variable substitution.
|
|
49
|
+
"""
|
|
50
|
+
normalized_vars = {
|
|
51
|
+
key: str(value).replace("-", "_") for key, value in template_vars.items()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
project, schema, name = self.project, self.schema, self.name
|
|
55
|
+
res_name = ODPSResource.build_full_resource_name(
|
|
56
|
+
name=name, project_name=project, schema_name=schema
|
|
57
|
+
)
|
|
58
|
+
try:
|
|
59
|
+
return res_name.format(**normalized_vars)
|
|
60
|
+
except KeyError:
|
|
61
|
+
# If template variable is missing, return as-is
|
|
62
|
+
return res_name
|
|
63
|
+
|
|
64
|
+
def __eq__(self, other):
|
|
65
|
+
if not isinstance(other, ResourceNameTemplate):
|
|
66
|
+
return False
|
|
67
|
+
return (
|
|
68
|
+
self.project == other.project
|
|
69
|
+
and self.schema == other.schema
|
|
70
|
+
and self.name == other.name
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def __hash__(self):
|
|
74
|
+
return hash((self.project, self.schema, self.name))
|
|
75
|
+
|
|
76
|
+
def to_json(self) -> dict:
|
|
77
|
+
ret = {"name": self.name}
|
|
78
|
+
if self.project:
|
|
79
|
+
ret["project"] = self.project
|
|
80
|
+
if self.schema:
|
|
81
|
+
ret["schema"] = self.schema
|
|
82
|
+
return ret
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_json(cls, serialized: dict) -> "ResourceNameTemplate":
|
|
86
|
+
kw = serialized.copy()
|
|
87
|
+
return cls(
|
|
88
|
+
project=kw.get("project"),
|
|
89
|
+
schema=kw.get("schema"),
|
|
90
|
+
name=kw["name"],
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def create_model_deployments(
|
|
95
|
+
model_name: str,
|
|
96
|
+
model_file: str,
|
|
97
|
+
inference_frameworks: Union[
|
|
98
|
+
str, InferenceFrameworkEnum, List[InferenceFrameworkEnum]
|
|
99
|
+
],
|
|
100
|
+
required_resources: List[Union[str, ResourceNameTemplate]] = None,
|
|
101
|
+
default_load_params: Optional[Dict[str, Any]] = None,
|
|
102
|
+
required_cpu: Optional[float] = None,
|
|
103
|
+
required_memory: Optional[int] = None,
|
|
104
|
+
required_gu: Optional[int] = None,
|
|
105
|
+
required_gpu_memory: Optional[int] = None,
|
|
106
|
+
device: str = None,
|
|
107
|
+
properties: Optional[Dict[str, Any]] = None,
|
|
108
|
+
tags: Optional[List[str]] = None,
|
|
109
|
+
):
|
|
110
|
+
frameworks_to_register = (
|
|
111
|
+
[inference_frameworks]
|
|
112
|
+
if isinstance(inference_frameworks, (str, InferenceFrameworkEnum))
|
|
113
|
+
else inference_frameworks
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
deployment_configs = []
|
|
117
|
+
for inference_framework in frameworks_to_register:
|
|
118
|
+
inference_framework = (
|
|
119
|
+
InferenceFrameworkEnum.from_string(inference_framework)
|
|
120
|
+
if isinstance(inference_framework, str)
|
|
121
|
+
else inference_framework
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
model_config = ModelDeploymentConfig(
|
|
125
|
+
model_name=model_name,
|
|
126
|
+
model_file=model_file,
|
|
127
|
+
inference_framework_type=inference_framework,
|
|
128
|
+
required_resource_files=required_resources,
|
|
129
|
+
load_params=default_load_params,
|
|
130
|
+
required_cpu=required_cpu,
|
|
131
|
+
required_memory=required_memory,
|
|
132
|
+
required_gu=required_gu,
|
|
133
|
+
required_gpu_memory=required_gpu_memory,
|
|
134
|
+
device=device,
|
|
135
|
+
properties=properties,
|
|
136
|
+
tags=tags,
|
|
137
|
+
)
|
|
138
|
+
deployment_configs.append(model_config)
|
|
139
|
+
return deployment_configs
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def register_model_deployments(
|
|
143
|
+
model_name: str,
|
|
144
|
+
model_file: str,
|
|
145
|
+
inference_frameworks: Union[
|
|
146
|
+
str, InferenceFrameworkEnum, List[InferenceFrameworkEnum]
|
|
147
|
+
],
|
|
148
|
+
required_resources: List[Union[str, ResourceNameTemplate]] = None,
|
|
149
|
+
default_load_params: Optional[Dict[str, Any]] = None,
|
|
150
|
+
required_cpu: Optional[float] = None,
|
|
151
|
+
required_memory: Optional[int] = None,
|
|
152
|
+
required_gu: Optional[int] = None,
|
|
153
|
+
required_gpu_memory: Optional[int] = None,
|
|
154
|
+
device: str = None,
|
|
155
|
+
properties: Optional[Dict[str, Any]] = None,
|
|
156
|
+
tags: Optional[List[str]] = None,
|
|
157
|
+
):
|
|
158
|
+
"""
|
|
159
|
+
Register model deployments
|
|
160
|
+
|
|
161
|
+
Notes
|
|
162
|
+
-----
|
|
163
|
+
- Alpha version for model deployments, all fields could be changed in the future.
|
|
164
|
+
"""
|
|
165
|
+
model_name = model_name.lower()
|
|
166
|
+
if not isinstance(inference_frameworks, (InferenceFrameworkEnum, List, str)):
|
|
167
|
+
raise TypeError(
|
|
168
|
+
f"inference_framework_type must be type InferenceFrameworkEnum or List[InferenceFrameworkEnum] but {type(inference_frameworks)}"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
model_deployments = create_model_deployments(
|
|
172
|
+
model_name=model_name,
|
|
173
|
+
model_file=model_file,
|
|
174
|
+
inference_frameworks=inference_frameworks,
|
|
175
|
+
required_resources=required_resources,
|
|
176
|
+
default_load_params=default_load_params,
|
|
177
|
+
required_cpu=required_cpu,
|
|
178
|
+
required_memory=required_memory,
|
|
179
|
+
required_gu=required_gu,
|
|
180
|
+
required_gpu_memory=required_gpu_memory,
|
|
181
|
+
device=device,
|
|
182
|
+
properties=properties,
|
|
183
|
+
tags=tags,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
for deployment in model_deployments:
|
|
187
|
+
if model_name not in _registered_llm_models:
|
|
188
|
+
_registered_llm_models[model_name] = {}
|
|
189
|
+
if deployment.device not in _registered_llm_models[model_name]:
|
|
190
|
+
_registered_llm_models[model_name][deployment.device] = {}
|
|
191
|
+
|
|
192
|
+
existing = _registered_llm_models[model_name][deployment.device].get(
|
|
193
|
+
deployment.inference_framework_type
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
if existing:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
f"Model {model_name} with {deployment.inference_framework_type} on {deployment.device} already registered"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
_registered_llm_models[model_name][deployment.device][
|
|
202
|
+
deployment.inference_framework_type
|
|
203
|
+
] = deployment
|
|
204
|
+
|
|
205
|
+
return model_deployments
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def get_registered_model_config(
|
|
209
|
+
model_name: str,
|
|
210
|
+
expected_device: Optional[str] = None,
|
|
211
|
+
expected_inference_framework: Optional[InferenceFrameworkEnum] = None,
|
|
212
|
+
) -> Optional[ModelDeploymentConfig]:
|
|
213
|
+
model_name = model_name.lower()
|
|
214
|
+
|
|
215
|
+
def _load_model_framework_config(framework_configs, expected_framework):
|
|
216
|
+
if expected_framework is not None:
|
|
217
|
+
return framework_configs[expected_framework]
|
|
218
|
+
else:
|
|
219
|
+
model_config = next(iter(framework_configs.values()))
|
|
220
|
+
return model_config
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
if expected_device is not None:
|
|
224
|
+
model_framework_configs = _registered_llm_models[model_name][
|
|
225
|
+
expected_device
|
|
226
|
+
]
|
|
227
|
+
return _load_model_framework_config(
|
|
228
|
+
model_framework_configs, expected_inference_framework
|
|
229
|
+
)
|
|
230
|
+
else:
|
|
231
|
+
model_all_configs = _registered_llm_models[model_name]
|
|
232
|
+
for device, model_framework_configs in model_all_configs.items():
|
|
233
|
+
model_config = _load_model_framework_config(
|
|
234
|
+
model_framework_configs, expected_inference_framework
|
|
235
|
+
)
|
|
236
|
+
if model_config:
|
|
237
|
+
return model_config
|
|
238
|
+
except KeyError:
|
|
239
|
+
pass
|
|
240
|
+
except StopIteration:
|
|
241
|
+
pass
|
|
242
|
+
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def clean_registered_model():
|
|
247
|
+
_registered_llm_models.clear()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copyright 1999-2025 Alibaba Group Holding 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
|
+
from enum import Enum
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class InferenceFrameworkEnum(Enum):
|
|
19
|
+
LLAMA_CPP_PYTHON_TEXT = "LLAMA_CPP_PYTHON:TEXT"
|
|
20
|
+
LLAMA_CPP_SERVE_TEXT = "LLAMA_CPP_SERVE:TEXT"
|
|
21
|
+
DASH_SCOPE_TEXT = "DASH_SCOPE:TEXT"
|
|
22
|
+
DASH_SCOPE_MULTIMODAL = "DASH_SCOPE:MULTIMODAL"
|
|
23
|
+
VLLM_SERVE_TEXT = "VLLM_SERVE:TEXT"
|
|
24
|
+
OPENAI_REMOTE_TEXT = "OPENAI_REMOTE:TEXT"
|
|
25
|
+
OTHER = "OTHER"
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def from_string(cls, label):
|
|
29
|
+
if label is None:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
if isinstance(label, cls):
|
|
33
|
+
return label
|
|
34
|
+
|
|
35
|
+
return cls(label)
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Copyright 1999-2025 Alibaba Group Holding 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
|
+
import json
|
|
16
|
+
from typing import Any, Dict, List, Optional
|
|
17
|
+
|
|
18
|
+
from .....protocol import JsonSerializable
|
|
19
|
+
from .....serialization.serializables import (
|
|
20
|
+
DictField,
|
|
21
|
+
FieldTypes,
|
|
22
|
+
Int32Field,
|
|
23
|
+
ListField,
|
|
24
|
+
ReferenceField,
|
|
25
|
+
StringField,
|
|
26
|
+
)
|
|
27
|
+
from .core import ResourceNameTemplate, register_model_deployments
|
|
28
|
+
|
|
29
|
+
_ALLOWED_DEVICES = {"cpu", "gpu", "ppu", "tpu", "cuda"}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DeploymentConfigResourceRequirement(JsonSerializable):
|
|
33
|
+
cpu: int = Int32Field("cpu", default=1)
|
|
34
|
+
memory: int = Int32Field("memory", default=4)
|
|
35
|
+
gu: int = Int32Field("gu", default=0)
|
|
36
|
+
gpu_memory: int = Int32Field("gpu_memory", default=0)
|
|
37
|
+
|
|
38
|
+
def __init__(self, cpu, memory, **kw):
|
|
39
|
+
gu = kw.get("gu")
|
|
40
|
+
gpu_memory = kw.get("gpu_memory")
|
|
41
|
+
if (
|
|
42
|
+
not isinstance(cpu, int)
|
|
43
|
+
or not isinstance(memory, int)
|
|
44
|
+
or (gu and not isinstance(gu, int))
|
|
45
|
+
or (gpu_memory and not isinstance(gpu_memory, int))
|
|
46
|
+
):
|
|
47
|
+
raise TypeError("cpu, memory, gpu and gpu_memory must be int")
|
|
48
|
+
super().__init__(cpu=cpu, memory=memory, gu=gu, gpu_memory=gpu_memory)
|
|
49
|
+
|
|
50
|
+
def to_json(self) -> dict:
|
|
51
|
+
ret = {
|
|
52
|
+
"cpu": self.cpu,
|
|
53
|
+
"memory": self.memory,
|
|
54
|
+
"gu": self.gu,
|
|
55
|
+
"gpu_memory": self.gpu_memory,
|
|
56
|
+
}
|
|
57
|
+
return ret
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_json(cls, serialized: dict) -> "DeploymentConfigResourceRequirement":
|
|
61
|
+
return cls(
|
|
62
|
+
cpu=serialized.get("cpu", 1),
|
|
63
|
+
memory=serialized.get("memory", 4),
|
|
64
|
+
gu=serialized.get("gu", 0),
|
|
65
|
+
gpu_memory=serialized.get("gpu_memory", 0),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class DeploymentConfigBase(JsonSerializable):
|
|
70
|
+
model_file: Optional[str] = StringField("model_file", default=None)
|
|
71
|
+
model_file_resources: List[ResourceNameTemplate] = ListField(
|
|
72
|
+
"model_file_resources", field_type=FieldTypes.reference, default_factory=list
|
|
73
|
+
)
|
|
74
|
+
resource_requirements: Optional[
|
|
75
|
+
DeploymentConfigResourceRequirement
|
|
76
|
+
] = ReferenceField(
|
|
77
|
+
"resource_requirements", DeploymentConfigResourceRequirement, default=None
|
|
78
|
+
)
|
|
79
|
+
load_params: Optional[Dict[str, Any]] = DictField(
|
|
80
|
+
"load_params",
|
|
81
|
+
key_type=FieldTypes.string,
|
|
82
|
+
value_type=FieldTypes.any,
|
|
83
|
+
default_factory=dict,
|
|
84
|
+
)
|
|
85
|
+
properties: Dict[str, Any] = DictField(
|
|
86
|
+
"properties",
|
|
87
|
+
key_type=FieldTypes.string,
|
|
88
|
+
value_type=FieldTypes.any,
|
|
89
|
+
default_factory=dict,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def __init__(
|
|
93
|
+
self,
|
|
94
|
+
model_file=None,
|
|
95
|
+
model_file_resources=None,
|
|
96
|
+
resource_requirements=None,
|
|
97
|
+
load_params=None,
|
|
98
|
+
properties=None,
|
|
99
|
+
**kw,
|
|
100
|
+
):
|
|
101
|
+
if model_file and not isinstance(model_file, str):
|
|
102
|
+
raise TypeError("model_file must be a string")
|
|
103
|
+
if resource_requirements and not isinstance(
|
|
104
|
+
resource_requirements, DeploymentConfigResourceRequirement
|
|
105
|
+
):
|
|
106
|
+
raise TypeError(
|
|
107
|
+
"resource_requirements must be a DeploymentConfigResourceRequirement"
|
|
108
|
+
)
|
|
109
|
+
if load_params and not isinstance(load_params, dict):
|
|
110
|
+
raise TypeError("load_params must be a dict")
|
|
111
|
+
if properties and not isinstance(properties, dict):
|
|
112
|
+
raise TypeError("properties must be a dict")
|
|
113
|
+
if model_file_resources:
|
|
114
|
+
if not isinstance(model_file_resources, list):
|
|
115
|
+
raise TypeError("model_file_resources must be a list")
|
|
116
|
+
if not all(
|
|
117
|
+
isinstance(res, ResourceNameTemplate) for res in model_file_resources
|
|
118
|
+
):
|
|
119
|
+
raise TypeError(
|
|
120
|
+
"model_file_resources must be a list of ResourceNameTemplate"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
super().__init__(
|
|
124
|
+
model_file=model_file,
|
|
125
|
+
model_file_resources=model_file_resources,
|
|
126
|
+
load_params=load_params,
|
|
127
|
+
resource_requirements=resource_requirements,
|
|
128
|
+
properties=properties,
|
|
129
|
+
**kw,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def from_json(cls, serialized: dict) -> "DeploymentConfigBase":
|
|
134
|
+
kw = serialized.copy()
|
|
135
|
+
resource_requirements_data = kw.get("resource_requirements")
|
|
136
|
+
return cls(
|
|
137
|
+
model_file=kw.get("model_file"),
|
|
138
|
+
model_file_resources=[
|
|
139
|
+
ResourceNameTemplate.from_json(res)
|
|
140
|
+
for res in kw.get("model_file_resources", [])
|
|
141
|
+
],
|
|
142
|
+
load_params=kw.get("load_params", {}),
|
|
143
|
+
resource_requirements=(
|
|
144
|
+
DeploymentConfigResourceRequirement.from_json(
|
|
145
|
+
resource_requirements_data
|
|
146
|
+
)
|
|
147
|
+
if resource_requirements_data
|
|
148
|
+
else None
|
|
149
|
+
),
|
|
150
|
+
properties=kw.get("properties", {}),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def to_json(self) -> dict:
|
|
154
|
+
return {
|
|
155
|
+
"properties": self.properties,
|
|
156
|
+
"load_params": self.load_params,
|
|
157
|
+
"model_file": self.model_file,
|
|
158
|
+
"model_file_resources": [
|
|
159
|
+
res.to_json() for res in self.model_file_resources
|
|
160
|
+
],
|
|
161
|
+
"resource_requirements": (
|
|
162
|
+
self.resource_requirements.to_json()
|
|
163
|
+
if self.resource_requirements
|
|
164
|
+
else None
|
|
165
|
+
),
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class FrameworkDeploymentConfig(DeploymentConfigBase):
|
|
170
|
+
framework: str = StringField("framework")
|
|
171
|
+
device: str = StringField("device", default="cpu")
|
|
172
|
+
|
|
173
|
+
def __init__(
|
|
174
|
+
self,
|
|
175
|
+
**kw,
|
|
176
|
+
):
|
|
177
|
+
framework = kw.get("framework")
|
|
178
|
+
if not framework:
|
|
179
|
+
raise ValueError("framework is required")
|
|
180
|
+
|
|
181
|
+
device = kw.get("device")
|
|
182
|
+
if not device:
|
|
183
|
+
device = "cpu"
|
|
184
|
+
if device not in _ALLOWED_DEVICES:
|
|
185
|
+
raise ValueError(f"device must be one of {_ALLOWED_DEVICES}")
|
|
186
|
+
|
|
187
|
+
super().__init__(**kw)
|
|
188
|
+
|
|
189
|
+
@classmethod
|
|
190
|
+
def from_json(cls, serialized: dict) -> "FrameworkDeploymentConfig":
|
|
191
|
+
kw = serialized.copy()
|
|
192
|
+
resource_requirements_data = kw.get("resource_requirements")
|
|
193
|
+
return cls(
|
|
194
|
+
model_file=kw.get("model_file"),
|
|
195
|
+
model_file_resources=[
|
|
196
|
+
ResourceNameTemplate.from_json(res)
|
|
197
|
+
for res in kw.get("model_file_resources", [])
|
|
198
|
+
],
|
|
199
|
+
load_params=kw.get("load_params", {}),
|
|
200
|
+
resource_requirements=(
|
|
201
|
+
DeploymentConfigResourceRequirement.from_json(
|
|
202
|
+
resource_requirements_data
|
|
203
|
+
)
|
|
204
|
+
if resource_requirements_data
|
|
205
|
+
else None
|
|
206
|
+
),
|
|
207
|
+
properties=kw.get("properties", {}),
|
|
208
|
+
framework=kw["framework"],
|
|
209
|
+
device=kw.get("device", "cpu"),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def to_json(self):
|
|
213
|
+
ret = super().to_json()
|
|
214
|
+
ret["framework"] = self.framework
|
|
215
|
+
ret["device"] = self.device
|
|
216
|
+
return ret
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class ModelDeploymentConfig(JsonSerializable):
|
|
220
|
+
model_name: str = StringField("model_name")
|
|
221
|
+
common_config: DeploymentConfigBase = ReferenceField(
|
|
222
|
+
"common_config", DeploymentConfigBase, default_factory=DeploymentConfigBase
|
|
223
|
+
)
|
|
224
|
+
deployments: List[FrameworkDeploymentConfig] = ListField(
|
|
225
|
+
"deployments", field_type=FieldTypes.reference, default_factory=list
|
|
226
|
+
)
|
|
227
|
+
tags: List[str] = ListField(
|
|
228
|
+
"tags", field_type=FieldTypes.string, default_factory=list
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def __init__(self, model_name, deployments, **kwargs):
|
|
232
|
+
if not model_name:
|
|
233
|
+
raise ValueError("model_name is required")
|
|
234
|
+
if not deployments:
|
|
235
|
+
raise ValueError("deployments is required")
|
|
236
|
+
else:
|
|
237
|
+
if not isinstance(deployments, list):
|
|
238
|
+
raise TypeError("deployments must be a list")
|
|
239
|
+
if not all(
|
|
240
|
+
isinstance(deployment, FrameworkDeploymentConfig)
|
|
241
|
+
for deployment in deployments
|
|
242
|
+
):
|
|
243
|
+
raise TypeError(
|
|
244
|
+
"deployments must be a list of FrameworkDeploymentConfig"
|
|
245
|
+
)
|
|
246
|
+
super().__init__(model_name=model_name, deployments=deployments, **kwargs)
|
|
247
|
+
|
|
248
|
+
def to_json(self) -> dict:
|
|
249
|
+
ret = {
|
|
250
|
+
"model_name": self.model_name,
|
|
251
|
+
"tags": self.tags,
|
|
252
|
+
}
|
|
253
|
+
if self.common_config:
|
|
254
|
+
ret["common_config"] = self.common_config.to_json()
|
|
255
|
+
if self.deployments:
|
|
256
|
+
ret["deployments"] = [
|
|
257
|
+
deployment.to_json() for deployment in self.deployments
|
|
258
|
+
]
|
|
259
|
+
return ret
|
|
260
|
+
|
|
261
|
+
@classmethod
|
|
262
|
+
def from_json(cls, serialized: dict) -> "ModelDeploymentConfig":
|
|
263
|
+
kw = serialized.copy()
|
|
264
|
+
return cls(
|
|
265
|
+
model_name=kw["model_name"],
|
|
266
|
+
common_config=(
|
|
267
|
+
DeploymentConfigBase.from_json(kw.get("common_config", {}))
|
|
268
|
+
if kw.get("common_config")
|
|
269
|
+
else None
|
|
270
|
+
),
|
|
271
|
+
deployments=[
|
|
272
|
+
FrameworkDeploymentConfig.from_json(deployment)
|
|
273
|
+
for deployment in kw.get("deployments", [])
|
|
274
|
+
],
|
|
275
|
+
tags=kw.get("tags", []),
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _model_config_from_json(json_content: str) -> List[ModelDeploymentConfig]:
|
|
280
|
+
data_list = json.loads(json_content)
|
|
281
|
+
if not isinstance(data_list, list):
|
|
282
|
+
raise ValueError("JSON root must be a list of model configurations.")
|
|
283
|
+
return [ModelDeploymentConfig.from_json(item_data) for item_data in data_list]
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _model_config_to_json(
|
|
287
|
+
model_configs: List[ModelDeploymentConfig],
|
|
288
|
+
) -> str:
|
|
289
|
+
data_list = [config.to_json() for config in model_configs]
|
|
290
|
+
return json.dumps(data_list, ensure_ascii=False)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def register_models_from_json_file(config_path):
|
|
294
|
+
"""
|
|
295
|
+
Loads model configurations from a JSON file and registers them.
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
with open(config_path, "r") as f:
|
|
299
|
+
model_list = _model_config_from_json(f.read())
|
|
300
|
+
|
|
301
|
+
if not model_list:
|
|
302
|
+
return
|
|
303
|
+
|
|
304
|
+
for model in model_list:
|
|
305
|
+
common_config = model.common_config or DeploymentConfigBase()
|
|
306
|
+
deployments = model.deployments
|
|
307
|
+
|
|
308
|
+
for deployment in deployments:
|
|
309
|
+
model_file = deployment.model_file or common_config.model_file
|
|
310
|
+
model_file_resources = (
|
|
311
|
+
deployment.model_file_resources
|
|
312
|
+
or common_config.model_file_resources
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
properties = deployment.properties or common_config.properties
|
|
316
|
+
load_params = deployment.load_params or common_config.load_params
|
|
317
|
+
calc_resources = (
|
|
318
|
+
deployment.resource_requirements
|
|
319
|
+
or common_config.resource_requirements
|
|
320
|
+
)
|
|
321
|
+
tags = list(set(model.tags or []))
|
|
322
|
+
|
|
323
|
+
register_model_deployments(
|
|
324
|
+
model_name=model.model_name,
|
|
325
|
+
model_file=model_file,
|
|
326
|
+
inference_frameworks=deployment.framework,
|
|
327
|
+
required_resources=[
|
|
328
|
+
ResourceNameTemplate(
|
|
329
|
+
project=resource_item.project,
|
|
330
|
+
schema=resource_item.schema,
|
|
331
|
+
name=resource_item.name,
|
|
332
|
+
)
|
|
333
|
+
for resource_item in model_file_resources
|
|
334
|
+
],
|
|
335
|
+
default_load_params=load_params,
|
|
336
|
+
required_cpu=calc_resources.cpu,
|
|
337
|
+
required_memory=calc_resources.memory,
|
|
338
|
+
required_gu=calc_resources.gu,
|
|
339
|
+
required_gpu_memory=calc_resources.gpu_memory,
|
|
340
|
+
device=deployment.device,
|
|
341
|
+
properties=properties,
|
|
342
|
+
tags=tags,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def register_models_from_dir(config_dir):
|
|
347
|
+
"""
|
|
348
|
+
Loads model configurations from a directory and registers them.
|
|
349
|
+
"""
|
|
350
|
+
from pathlib import Path
|
|
351
|
+
|
|
352
|
+
model_json_files = list(Path(config_dir).glob("*_models.json"))
|
|
353
|
+
|
|
354
|
+
for file_path in model_json_files:
|
|
355
|
+
try:
|
|
356
|
+
register_models_from_json_file(file_path)
|
|
357
|
+
except Exception as e:
|
|
358
|
+
raise ValueError(
|
|
359
|
+
f"Failed to load model config from {file_path}, error: {e}"
|
|
360
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 1999-2025 Alibaba Group Holding 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.
|