flytekitplugins-inference 1.13.1__py3-none-any.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.
@@ -0,0 +1,13 @@
1
+ """
2
+ .. currentmodule:: flytekitplugins.inference
3
+
4
+ .. autosummary::
5
+ :nosignatures:
6
+ :template: custom.rst
7
+ :toctree: generated/
8
+
9
+ NIM
10
+ NIMSecrets
11
+ """
12
+
13
+ from .nim.serve import NIM, NIMSecrets
File without changes
@@ -0,0 +1,180 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ from ..sidecar_template import ModelInferenceTemplate
5
+
6
+
7
+ @dataclass
8
+ class NIMSecrets:
9
+ """
10
+ :param ngc_image_secret: The name of the Kubernetes secret containing the NGC image pull credentials.
11
+ :param ngc_secret_key: The key name for the NGC API key.
12
+ :param secrets_prefix: The secrets prefix that Flyte appends to all mounted secrets.
13
+ :param ngc_secret_group: The group name for the NGC API key.
14
+ :param hf_token_group: The group name for the HuggingFace token.
15
+ :param hf_token_key: The key name for the HuggingFace token.
16
+ """
17
+
18
+ ngc_image_secret: str # kubernetes secret
19
+ ngc_secret_key: str
20
+ secrets_prefix: str # _UNION_ or _FSEC_
21
+ ngc_secret_group: Optional[str] = None
22
+ hf_token_group: Optional[str] = None
23
+ hf_token_key: Optional[str] = None
24
+
25
+
26
+ class NIM(ModelInferenceTemplate):
27
+ def __init__(
28
+ self,
29
+ secrets: NIMSecrets,
30
+ image: str = "nvcr.io/nim/meta/llama3-8b-instruct:1.0.0",
31
+ health_endpoint: str = "v1/health/ready",
32
+ port: int = 8000,
33
+ cpu: int = 1,
34
+ gpu: int = 1,
35
+ mem: str = "20Gi",
36
+ shm_size: str = "16Gi",
37
+ env: Optional[dict[str, str]] = None,
38
+ hf_repo_ids: Optional[list[str]] = None,
39
+ lora_adapter_mem: Optional[str] = None,
40
+ ):
41
+ """
42
+ Initialize NIM class for managing a Kubernetes pod template.
43
+
44
+ :param image: The Docker image to be used for the model server container. Default is "nvcr.io/nim/meta/llama3-8b-instruct:1.0.0".
45
+ :param health_endpoint: The health endpoint for the model server container. Default is "v1/health/ready".
46
+ :param port: The port number for the model server container. Default is 8000.
47
+ :param cpu: The number of CPU cores requested for the model server container. Default is 1.
48
+ :param gpu: The number of GPU cores requested for the model server container. Default is 1.
49
+ :param mem: The amount of memory requested for the model server container. Default is "20Gi".
50
+ :param shm_size: The size of the shared memory volume. Default is "16Gi".
51
+ :param env: A dictionary of environment variables to be set in the model server container.
52
+ :param hf_repo_ids: A list of Hugging Face repository IDs for LoRA adapters to be downloaded.
53
+ :param lora_adapter_mem: The amount of memory requested for the init container that downloads LoRA adapters.
54
+ :param secrets: Instance of NIMSecrets for managing secrets.
55
+ """
56
+ if secrets.ngc_image_secret is None:
57
+ raise ValueError("NGC image pull secret must be provided.")
58
+ if secrets.ngc_secret_key is None:
59
+ raise ValueError("NGC secret key must be provided.")
60
+ if secrets.secrets_prefix is None:
61
+ raise ValueError("Secrets prefix must be provided.")
62
+
63
+ self._shm_size = shm_size
64
+ self._hf_repo_ids = hf_repo_ids
65
+ self._lora_adapter_mem = lora_adapter_mem
66
+ self._secrets = secrets
67
+
68
+ super().__init__(
69
+ image=image,
70
+ health_endpoint=health_endpoint,
71
+ port=port,
72
+ cpu=cpu,
73
+ gpu=gpu,
74
+ mem=mem,
75
+ env=env,
76
+ )
77
+
78
+ self.setup_nim_pod_template()
79
+
80
+ def setup_nim_pod_template(self):
81
+ from kubernetes.client.models import (
82
+ V1Container,
83
+ V1EmptyDirVolumeSource,
84
+ V1EnvVar,
85
+ V1LocalObjectReference,
86
+ V1ResourceRequirements,
87
+ V1SecurityContext,
88
+ V1Volume,
89
+ V1VolumeMount,
90
+ )
91
+
92
+ self.pod_template.pod_spec.volumes = [
93
+ V1Volume(
94
+ name="dshm",
95
+ empty_dir=V1EmptyDirVolumeSource(medium="Memory", size_limit=self._shm_size),
96
+ )
97
+ ]
98
+ self.pod_template.pod_spec.image_pull_secrets = [V1LocalObjectReference(name=self._secrets.ngc_image_secret)]
99
+
100
+ model_server_container = self.pod_template.pod_spec.init_containers[0]
101
+
102
+ if self._secrets.ngc_secret_group:
103
+ ngc_api_key = f"$({self._secrets.secrets_prefix}{self._secrets.ngc_secret_group}_{self._secrets.ngc_secret_key})".upper()
104
+ else:
105
+ ngc_api_key = f"$({self._secrets.secrets_prefix}{self._secrets.ngc_secret_key})".upper()
106
+
107
+ if model_server_container.env:
108
+ model_server_container.env.append(V1EnvVar(name="NGC_API_KEY", value=ngc_api_key))
109
+ else:
110
+ model_server_container.env = [V1EnvVar(name="NGC_API_KEY", value=ngc_api_key)]
111
+
112
+ model_server_container.volume_mounts = [V1VolumeMount(name="dshm", mount_path="/dev/shm")]
113
+ model_server_container.security_context = V1SecurityContext(run_as_user=1000)
114
+
115
+ # Download HF LoRA adapters
116
+ if self._hf_repo_ids:
117
+ if not self._lora_adapter_mem:
118
+ raise ValueError("Memory to allocate to download LoRA adapters must be set.")
119
+
120
+ if self._secrets.hf_token_group:
121
+ hf_key = f"{self._secrets.hf_token_group}_{self._secrets.hf_token_key}".upper()
122
+ elif self._secrets.hf_token_key:
123
+ hf_key = self._secrets.hf_token_key.upper()
124
+ else:
125
+ hf_key = ""
126
+
127
+ local_peft_dir_env = next(
128
+ (env for env in model_server_container.env if env.name == "NIM_PEFT_SOURCE"),
129
+ None,
130
+ )
131
+ if local_peft_dir_env:
132
+ mount_path = local_peft_dir_env.value
133
+ else:
134
+ raise ValueError("NIM_PEFT_SOURCE environment variable must be set.")
135
+
136
+ self.pod_template.pod_spec.volumes.append(V1Volume(name="lora", empty_dir={}))
137
+ model_server_container.volume_mounts.append(V1VolumeMount(name="lora", mount_path=mount_path))
138
+
139
+ self.pod_template.pod_spec.init_containers.insert(
140
+ 0,
141
+ V1Container(
142
+ name="download-loras",
143
+ image="python:3.12-alpine",
144
+ command=[
145
+ "sh",
146
+ "-c",
147
+ f"""
148
+ pip install -U "huggingface_hub[cli]"
149
+
150
+ export LOCAL_PEFT_DIRECTORY={mount_path}
151
+ mkdir -p $LOCAL_PEFT_DIRECTORY
152
+
153
+ TOKEN_VAR_NAME={self._secrets.secrets_prefix}{hf_key}
154
+
155
+ # Check if HF token is provided and login if so
156
+ if [ -n "$(printenv $TOKEN_VAR_NAME)" ]; then
157
+ huggingface-cli login --token "$(printenv $TOKEN_VAR_NAME)"
158
+ fi
159
+
160
+ # Download LoRAs from Huggingface Hub
161
+ {"".join([f'''
162
+ mkdir -p $LOCAL_PEFT_DIRECTORY/{repo_id.split("/")[-1]}
163
+ huggingface-cli download {repo_id} adapter_config.json adapter_model.safetensors --local-dir $LOCAL_PEFT_DIRECTORY/{repo_id.split("/")[-1]}
164
+ ''' for repo_id in self._hf_repo_ids])}
165
+
166
+ chmod -R 777 $LOCAL_PEFT_DIRECTORY
167
+ """,
168
+ ],
169
+ resources=V1ResourceRequirements(
170
+ requests={"cpu": 1, "memory": self._lora_adapter_mem},
171
+ limits={"cpu": 1, "memory": self._lora_adapter_mem},
172
+ ),
173
+ volume_mounts=[
174
+ V1VolumeMount(
175
+ name="lora",
176
+ mount_path=mount_path,
177
+ )
178
+ ],
179
+ ),
180
+ )
@@ -0,0 +1,77 @@
1
+ from typing import Optional
2
+
3
+ from flytekit import PodTemplate
4
+
5
+
6
+ class ModelInferenceTemplate:
7
+ def __init__(
8
+ self,
9
+ image: Optional[str] = None,
10
+ health_endpoint: str = "/",
11
+ port: int = 8000,
12
+ cpu: int = 1,
13
+ gpu: int = 1,
14
+ mem: str = "1Gi",
15
+ env: Optional[
16
+ dict[str, str]
17
+ ] = None, # https://docs.nvidia.com/nim/large-language-models/latest/configuration.html#environment-variables
18
+ ):
19
+ from kubernetes.client.models import (
20
+ V1Container,
21
+ V1ContainerPort,
22
+ V1EnvVar,
23
+ V1HTTPGetAction,
24
+ V1PodSpec,
25
+ V1Probe,
26
+ V1ResourceRequirements,
27
+ )
28
+
29
+ self._image = image
30
+ self._health_endpoint = health_endpoint
31
+ self._port = port
32
+ self._cpu = cpu
33
+ self._gpu = gpu
34
+ self._mem = mem
35
+ self._env = env
36
+
37
+ self._pod_template = PodTemplate()
38
+
39
+ if env and not isinstance(env, dict):
40
+ raise ValueError("env must be a dict.")
41
+
42
+ self._pod_template.pod_spec = V1PodSpec(
43
+ containers=[],
44
+ init_containers=[
45
+ V1Container(
46
+ name="model-server",
47
+ image=self._image,
48
+ ports=[V1ContainerPort(container_port=self._port)],
49
+ resources=V1ResourceRequirements(
50
+ requests={
51
+ "cpu": self._cpu,
52
+ "nvidia.com/gpu": self._gpu,
53
+ "memory": self._mem,
54
+ },
55
+ limits={
56
+ "cpu": self._cpu,
57
+ "nvidia.com/gpu": self._gpu,
58
+ "memory": self._mem,
59
+ },
60
+ ),
61
+ restart_policy="Always", # treat this container as a sidecar
62
+ env=([V1EnvVar(name=k, value=v) for k, v in self._env.items()] if self._env else None),
63
+ startup_probe=V1Probe(
64
+ http_get=V1HTTPGetAction(path=self._health_endpoint, port=self._port),
65
+ failure_threshold=100, # The model server initialization can take some time, so the failure threshold is increased to accommodate this delay.
66
+ ),
67
+ ),
68
+ ],
69
+ )
70
+
71
+ @property
72
+ def pod_template(self):
73
+ return self._pod_template
74
+
75
+ @property
76
+ def base_url(self):
77
+ return f"http://localhost:{self._port}"
@@ -0,0 +1 @@
1
+ import sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('flytekitplugins',));importlib = __import__('importlib.util');__import__('importlib.machinery');m = sys.modules.setdefault('flytekitplugins', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('flytekitplugins', [os.path.dirname(p)])));m = m or sys.modules.setdefault('flytekitplugins', types.ModuleType('flytekitplugins'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p)
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.1
2
+ Name: flytekitplugins-inference
3
+ Version: 1.13.1
4
+ Summary: This package enables seamless use of model inference sidecar services within Flyte
5
+ Author: flyteorg
6
+ Author-email: admin@flyte.org
7
+ License: apache2
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Scientific/Engineering
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Software Development
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.8
22
+ Requires-Dist: flytekit <2.0.0,>=1.13.0
23
+ Requires-Dist: kubernetes
24
+ Requires-Dist: openai
25
+
@@ -0,0 +1,11 @@
1
+ flytekitplugins_inference-1.13.1-py3.12-nspkg.pth,sha256=ya_zoT0ZM023a2lpUsRaqXsgDEknLucLLOWbbtFBPw4,512
2
+ flytekitplugins/inference/__init__.py,sha256=bbbo-H0lXf_TvEgPQnZAZ_w15W1jL-DAc-tWQqvYWzs,200
3
+ flytekitplugins/inference/sidecar_template.py,sha256=iYwSR63n6unLiLsZ8NhsLY0UMOZtKGcR5tTwyTUnsJ4,2572
4
+ flytekitplugins/inference/nim/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ flytekitplugins/inference/nim/serve.py,sha256=U11fTR7UkpF9c2KpHQ7MPeH9mz-fTIrLY3jt1zz2L-4,7488
6
+ flytekitplugins_inference-1.13.1.dist-info/METADATA,sha256=F53e1MqcpDC6lfPVOkWU753k3oRQ-leWJUXfTI8gAuI,1033
7
+ flytekitplugins_inference-1.13.1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
8
+ flytekitplugins_inference-1.13.1.dist-info/entry_points.txt,sha256=EQ6EAiE9IMGdtV3detqwGCowPbDj0pV8I3c1jSO9vbs,57
9
+ flytekitplugins_inference-1.13.1.dist-info/namespace_packages.txt,sha256=b2gTzXFHuV5afchaJ28HueRhYzj-8x5Ytr8n2twnAik,16
10
+ flytekitplugins_inference-1.13.1.dist-info/top_level.txt,sha256=b2gTzXFHuV5afchaJ28HueRhYzj-8x5Ytr8n2twnAik,16
11
+ flytekitplugins_inference-1.13.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (72.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [flytekit.plugins]
2
+ inference = flytekitplugins.inference
@@ -0,0 +1 @@
1
+ flytekitplugins
@@ -0,0 +1 @@
1
+ flytekitplugins