cortexgrid-infer 0.3.7__tar.gz → 0.3.9__tar.gz
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.
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/PKG-INFO +48 -48
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/README.md +45 -46
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/__init__.py +7 -17
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/core.py +72 -60
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/importers/base.py +0 -4
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/registry.py +5 -13
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/anthropic.py +41 -53
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/base.py +2 -14
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/gemini/text2image.py +32 -28
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/gemini/text2text.py +45 -57
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/image2mesh.py +25 -29
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/streamed_completion.py +27 -40
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/text2image.py +35 -36
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/text2text.py +47 -73
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/text_rewriter.py +19 -20
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/utils.py +13 -24
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/pyproject.toml +3 -2
- cortexgrid_infer-0.3.7/cortexgrid_infer/protocols/__init__.py +0 -14
- cortexgrid_infer-0.3.7/cortexgrid_infer/protocols/completion.py +0 -92
- cortexgrid_infer-0.3.7/cortexgrid_infer/protocols/imaging.py +0 -74
- cortexgrid_infer-0.3.7/cortexgrid_infer/protocols/meshing.py +0 -72
- cortexgrid_infer-0.3.7/cortexgrid_infer/protocols/rewriting.py +0 -44
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/.gitignore +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/LICENSE +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/compiling.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/device.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/importers/__init__.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/importers/huggingface.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/py.typed +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/__init__.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/gemini/__init__.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.9}/cortexgrid_infer/serve_apps/gemini/base.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cortexgrid-infer
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: Serve apps per task (text-to-text, text-to-image, image-to-mesh) and importers per source (HuggingFace) for running models on cortexgrid
|
|
5
5
|
Project-URL: Homepage, https://github.com/robodatalab/cortexgrid-infer
|
|
6
6
|
Project-URL: Repository, https://github.com/robodatalab/cortexgrid-infer
|
|
@@ -9,7 +9,7 @@ License-File: LICENSE
|
|
|
9
9
|
Requires-Python: <3.12,>=3.11
|
|
10
10
|
Requires-Dist: accelerate>=0.33
|
|
11
11
|
Requires-Dist: anthropic>=0.40.0
|
|
12
|
-
Requires-Dist: cortexgrid>=0.3.
|
|
12
|
+
Requires-Dist: cortexgrid>=0.3.18
|
|
13
13
|
Requires-Dist: diffusers>=0.38
|
|
14
14
|
Requires-Dist: fastapi>=0.133
|
|
15
15
|
Requires-Dist: google-genai>=1.0
|
|
@@ -23,6 +23,7 @@ Requires-Dist: sentencepiece>=0.2
|
|
|
23
23
|
Requires-Dist: torch>=2.0.0
|
|
24
24
|
Requires-Dist: transformers>=4.47.0
|
|
25
25
|
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: parameterized>=0.9.0; extra == 'dev'
|
|
26
27
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
27
28
|
Description-Content-Type: text/markdown
|
|
28
29
|
|
|
@@ -50,23 +51,24 @@ Upgrading from 0.2.x? See [MIGRATION.md](https://github.com/robodatalab/cortexgr
|
|
|
50
51
|
A model is two things, and the library keeps them apart:
|
|
51
52
|
|
|
52
53
|
- **What runs it** — a serve app in `cortexgrid_infer.serve_apps`, named for the task
|
|
53
|
-
it runs, not for where the model came from. It loads the weights
|
|
54
|
-
|
|
55
|
-
them. One serve app runs every model of its task,
|
|
54
|
+
it runs, not for where the model came from. It loads the weights and serves the
|
|
55
|
+
task's endpoints, declared by the task's type (`CompletingModel`, say); cortexgrid
|
|
56
|
+
generates the client that calls them. One serve app runs every model of its task,
|
|
57
|
+
whichever source staged it.
|
|
56
58
|
- **Where its weights come from** — an importer in `cortexgrid_infer.importers`, one
|
|
57
59
|
per source. It names the model in the registry, downloads the weights, and sizes
|
|
58
60
|
them from the source's metadata. It is handed the serve app, so one importer takes
|
|
59
61
|
any model its source holds.
|
|
60
62
|
|
|
61
|
-
| Serve app | Task | Runs |
|
|
63
|
+
| Serve app | Task | Runs | Task type |
|
|
62
64
|
|---|---|---|---|
|
|
63
|
-
| `Text2Text` | text to text | any causal LM in the transformers layout, via `AutoModelForCausalLM` | `
|
|
64
|
-
| `Text2Image` | text (and image) to image | any diffusers pipeline | `
|
|
65
|
-
| `Image2Mesh` — a base: subclass it with the model's `load` and `make_mesh` | image to mesh | the model the subclass loads, behind the task's `
|
|
66
|
-
| `TextRewriter` | text to text, rewritten | any encoder-decoder LM (T5, BART, Marian, ...) in the transformers layout, via `AutoModelForSeq2SeqLM` | `
|
|
67
|
-
| `AnthropicText2Text` | text to text | the Anthropic API, forwarded from the cluster | `
|
|
68
|
-
| `GeminiText2Text` | text to text | the Gemini API, forwarded from the cluster | `
|
|
69
|
-
| `GeminiText2Image` | text to image | the Gemini API, forwarded from the cluster | `
|
|
65
|
+
| `Text2Text` | text to text | any causal LM in the transformers layout, via `AutoModelForCausalLM` | `CompletingModel` (`complete`), plus its own `loglikelihoods` and `last_hidden_states` |
|
|
66
|
+
| `Text2Image` | text (and image) to image | any diffusers pipeline | `GeneratingModel` (`generate`) |
|
|
67
|
+
| `Image2Mesh` — a base: subclass it with the model's `load` and `make_mesh` | image to mesh | the model the subclass loads, behind the task's `mesh` endpoint | `MeshingModel` (`mesh`: one picture in, a `GeneratedMesh` out) |
|
|
68
|
+
| `TextRewriter` | text to text, rewritten | any encoder-decoder LM (T5, BART, Marian, ...) in the transformers layout, via `AutoModelForSeq2SeqLM` | `RewritingModel` (`rewrite`: one text in, one text out) |
|
|
69
|
+
| `AnthropicText2Text` | text to text | the Anthropic API, forwarded from the cluster | `CompletingModel` (`complete`) |
|
|
70
|
+
| `GeminiText2Text` | text to text | the Gemini API, forwarded from the cluster | `CompletingModel` (`complete`) |
|
|
71
|
+
| `GeminiText2Image` | text to image | the Gemini API, forwarded from the cluster | `GeneratingModel` (`generate`) |
|
|
70
72
|
|
|
71
73
|
| Importer | Source |
|
|
72
74
|
|---|---|
|
|
@@ -85,11 +87,13 @@ need:
|
|
|
85
87
|
| `.serve_app` | the class cortexgrid bundles and runs on the cluster |
|
|
86
88
|
| `.requirements()` | what one replica needs to be placed and to run |
|
|
87
89
|
| `.config()` | settings the serve app reads at construction, if it needs any |
|
|
88
|
-
| `.client(url)` | a client that speaks the deployed app's routes |
|
|
89
90
|
| `.source` | *(importers only)* a callable that downloads the weights and returns the directory |
|
|
90
91
|
|
|
91
92
|
One with weights goes through `cortexgrid.import_model`, one without through
|
|
92
|
-
`cortexgrid.register_model`.
|
|
93
|
+
`cortexgrid.register_model`. Once deployed, the `cortexgrid.Deployment` hands back
|
|
94
|
+
the client that calls the app's endpoints, typed as the serve app and so as its task
|
|
95
|
+
type: `deployment.client()` once the app serves, or `deployment.client_async()` at
|
|
96
|
+
once, with `await model.is_ready()` to ask.
|
|
93
97
|
|
|
94
98
|
## Quick start
|
|
95
99
|
|
|
@@ -117,13 +121,11 @@ cortexgrid.remote(
|
|
|
117
121
|
import_weights, imp, imp.requirements(), num_gpus=0, num_cpus=2
|
|
118
122
|
).result()
|
|
119
123
|
|
|
120
|
-
# 2. Deploy
|
|
121
|
-
deployment = cortexgrid.deploy_model(
|
|
122
|
-
imp.family, imp.suffix, cortexgrid.IMPORTED, wait=True, timeout=1800
|
|
123
|
-
)
|
|
124
|
+
# 2. Deploy.
|
|
125
|
+
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED, timeout=1800)
|
|
124
126
|
|
|
125
|
-
# 3. Inference.
|
|
126
|
-
model =
|
|
127
|
+
# 3. Inference — the client blocks until the Ray Serve app is running.
|
|
128
|
+
model: mg.GeneratingModel = deployment.client()
|
|
127
129
|
|
|
128
130
|
async def run():
|
|
129
131
|
result = await mg.generate(model, "a red bicycle on a beach at sunrise")
|
|
@@ -278,11 +280,13 @@ it is the floor; only quantizing the weights or running fewer forwards moves it.
|
|
|
278
280
|
|
|
279
281
|
## Inference
|
|
280
282
|
|
|
281
|
-
`complete` streams `CompletionChunk`s (`.content`, `.thinking`, `.tool_calls`, `.finish_reason`)
|
|
283
|
+
`complete` streams `CompletionChunk`s (`.content`, `.thinking`, `.tool_calls`, `.finish_reason`).
|
|
284
|
+
`tools` are Python functions or tool specs; a function goes to the model as its spec,
|
|
285
|
+
and each `ToolCall` comes back as data (`.id`, `.name`, `.arguments`) for the caller
|
|
286
|
+
to run:
|
|
282
287
|
|
|
283
288
|
```python
|
|
284
|
-
|
|
285
|
-
model = imp.client(deployment.url)
|
|
289
|
+
model: mg.CompletingModel = deployment.client()
|
|
286
290
|
messages = [{"role": "user", "content": "Explain RAG in one sentence."}]
|
|
287
291
|
|
|
288
292
|
async for chunk in mg.complete(model, messages, max_new_tokens=512, temperature=0.7):
|
|
@@ -323,9 +327,9 @@ a re-deploy rather than a re-registration.
|
|
|
323
327
|
|
|
324
328
|
A replica asks for no hardware at all, so it is placed on any node, CPU-only
|
|
325
329
|
included. From there it deploys and streams exactly like a cluster-served model:
|
|
326
|
-
`
|
|
330
|
+
`deployment.client()` is a `CompletingModel` like `Text2Text`'s. Anthropic
|
|
327
331
|
reports tool calls as structured blocks rather than as generated text, so the
|
|
328
|
-
serve app
|
|
332
|
+
serve app turns them into `ToolCall`s as they come.
|
|
329
333
|
|
|
330
334
|
### Gemini
|
|
331
335
|
|
|
@@ -346,17 +350,16 @@ cortexgrid.register_model(
|
|
|
346
350
|
|
|
347
351
|
Everything said above for Anthropic holds: `config` carries the model name and
|
|
348
352
|
the name of the secret (`api_key_secret="..."` to use another), both editable on
|
|
349
|
-
the model card; a replica needs no hardware; and `
|
|
350
|
-
is a `
|
|
351
|
-
text form the client parses.
|
|
353
|
+
the model card; a replica needs no hardware; and `deployment.client()`
|
|
354
|
+
is a `CompletingModel`, with Gemini's function calls turned into `ToolCall`s.
|
|
352
355
|
|
|
353
|
-
`GeminiText2Image`
|
|
354
|
-
client is a `ServedGeneratingModel`:
|
|
356
|
+
`GeminiText2Image` is a `GeneratingModel` like `Text2Image`:
|
|
355
357
|
|
|
356
358
|
```python
|
|
357
359
|
entry = mg.Hosted("gemini-2.5-flash-image", mg.GeminiText2Image)
|
|
358
360
|
...
|
|
359
|
-
|
|
361
|
+
model: mg.GeneratingModel = deployment.client()
|
|
362
|
+
picture = await mg.generate(model, "a fox in the snow", size=2048)
|
|
360
363
|
```
|
|
361
364
|
|
|
362
365
|
It takes a prompt only, and makes a square picture. `size` picks Gemini's size
|
|
@@ -368,40 +371,37 @@ diffusion settings with no Gemini counterpart, and come back as `None`.
|
|
|
368
371
|
| | |
|
|
369
372
|
|---|---|
|
|
370
373
|
| `HuggingFaceImporter(hf_id, serve_app, token=None, ignore_patterns=None)` | Importer for a model on the HuggingFace Hub, run by `serve_app`. |
|
|
371
|
-
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()`
|
|
374
|
+
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()` taken from the serve app. A new source implements `download(local_dir)` and `weights()`. |
|
|
372
375
|
| `Hosted(model_id, serve_app, **settings)` | Entry for a model hosted elsewhere; no weights. `settings` are the serve app's `config` arguments. |
|
|
373
|
-
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()
|
|
376
|
+
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()`. |
|
|
374
377
|
| `Text2Text`, `Text2Image`, `TextRewriter`, `Image2Mesh` | Serve apps that run weights (`LocalModel`s). |
|
|
375
378
|
| `AnthropicText2Text` | Serve app that forwards to the Anthropic API (a `HostedModel`). |
|
|
376
379
|
| `GeminiText2Text`, `GeminiText2Image` | Serve apps that forward to the Gemini API (`HostedModel`s sharing the `GeminiModel` base). |
|
|
377
|
-
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them)
|
|
378
|
-
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()
|
|
380
|
+
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them). |
|
|
381
|
+
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()`. |
|
|
379
382
|
| `Weights(params=None, file_bytes=0)` | What an importer reads about the weights, handed to the serve app to size a replica. |
|
|
380
|
-
| `complete(model, messages, tools=None, max_new_tokens=
|
|
381
|
-
| `generate(model, prompt, *, image=None,
|
|
382
|
-
| `ServedCompletingModel(url, model_id)` | Client for any deployed completion app. |
|
|
383
|
-
| `ServedGeneratingModel(url, model_id)` | Client for any deployed text-to-image app. |
|
|
384
|
-
| `ServedMeshingModel(url, model_id)` | Client for any deployed image-to-mesh app. |
|
|
383
|
+
| `complete(model, messages, tools=None, max_new_tokens=None, temperature=0.7)` | Async stream of `CompletionChunk` for a `CompletingModel`. |
|
|
384
|
+
| `generate(model, prompt, *, image=None, steps=None, guidance=None, size=1024, seed=None) -> GeneratedImage` | One image from a `GeneratingModel`. |
|
|
385
385
|
| `split_model_id(model_id) -> (family, suffix)` | The registry identity an importer derives. |
|
|
386
386
|
| `detect_device()` | The torch device a serve app should load onto. |
|
|
387
387
|
| `compiling.Mode.GRAPHED` / `compiling.Mode.FUSED` | The two modes a serve app chooses between. See [Compilation](#compilation). |
|
|
388
388
|
| `compiling.supported(device)` / `compile_module(module, device, mode)` / `compile_pipeline(pipe, device, mode)` | Whether to compile here, and what a serve app calls to do it. |
|
|
389
389
|
| `ModelDeployFailed` | Re-exported from cortexgrid; subclasses `RuntimeError`. |
|
|
390
390
|
|
|
391
|
-
Types: `
|
|
391
|
+
Types: `CompletingModel`, `GeneratingModel`, `MeshingModel`, `RewritingModel` (each
|
|
392
|
+
the abstract base of its task's serve apps, declaring the task's endpoints),
|
|
392
393
|
`CompletionChunk`, `GeneratedImage`, `GeneratedMesh`, `ToolCall`, `Message`, `Tool`,
|
|
393
|
-
`ToolSpec`.
|
|
394
|
+
`ToolSpec`, `Tensor`.
|
|
394
395
|
|
|
395
396
|
Extending it:
|
|
396
397
|
|
|
397
398
|
- **A new source** is one importer: subclass `Importer` with `download(local_dir)`
|
|
398
399
|
and `weights()`, and every serve app whose weight format it delivers runs its
|
|
399
400
|
models unchanged.
|
|
400
|
-
- **A new hosted API** is one serve app: subclass `HostedModel
|
|
401
|
-
with `Hosted`. A text-to-text one
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
then `ServedCompletingModel` is its client, unchanged.
|
|
401
|
+
- **A new hosted API** is one serve app: subclass `HostedModel` and the task's type,
|
|
402
|
+
and register it with `Hosted`. A text-to-text one subclasses `CompletingModel` and
|
|
403
|
+
streams `CompletionChunk`s from its `complete` endpoint, with
|
|
404
|
+
`StreamedCompletionWriter` turning the upstream's text and tool calls into them.
|
|
405
405
|
- **A model no task's serve app can load** gets its own serve app — an `Image2Mesh`
|
|
406
406
|
subclass, say, with `load` and `make_mesh`, and `compile` if compiling it pays —
|
|
407
407
|
and, if its source is unusual too, its own importer.
|
|
@@ -22,23 +22,24 @@ Upgrading from 0.2.x? See [MIGRATION.md](https://github.com/robodatalab/cortexgr
|
|
|
22
22
|
A model is two things, and the library keeps them apart:
|
|
23
23
|
|
|
24
24
|
- **What runs it** — a serve app in `cortexgrid_infer.serve_apps`, named for the task
|
|
25
|
-
it runs, not for where the model came from. It loads the weights
|
|
26
|
-
|
|
27
|
-
them. One serve app runs every model of its task,
|
|
25
|
+
it runs, not for where the model came from. It loads the weights and serves the
|
|
26
|
+
task's endpoints, declared by the task's type (`CompletingModel`, say); cortexgrid
|
|
27
|
+
generates the client that calls them. One serve app runs every model of its task,
|
|
28
|
+
whichever source staged it.
|
|
28
29
|
- **Where its weights come from** — an importer in `cortexgrid_infer.importers`, one
|
|
29
30
|
per source. It names the model in the registry, downloads the weights, and sizes
|
|
30
31
|
them from the source's metadata. It is handed the serve app, so one importer takes
|
|
31
32
|
any model its source holds.
|
|
32
33
|
|
|
33
|
-
| Serve app | Task | Runs |
|
|
34
|
+
| Serve app | Task | Runs | Task type |
|
|
34
35
|
|---|---|---|---|
|
|
35
|
-
| `Text2Text` | text to text | any causal LM in the transformers layout, via `AutoModelForCausalLM` | `
|
|
36
|
-
| `Text2Image` | text (and image) to image | any diffusers pipeline | `
|
|
37
|
-
| `Image2Mesh` — a base: subclass it with the model's `load` and `make_mesh` | image to mesh | the model the subclass loads, behind the task's `
|
|
38
|
-
| `TextRewriter` | text to text, rewritten | any encoder-decoder LM (T5, BART, Marian, ...) in the transformers layout, via `AutoModelForSeq2SeqLM` | `
|
|
39
|
-
| `AnthropicText2Text` | text to text | the Anthropic API, forwarded from the cluster | `
|
|
40
|
-
| `GeminiText2Text` | text to text | the Gemini API, forwarded from the cluster | `
|
|
41
|
-
| `GeminiText2Image` | text to image | the Gemini API, forwarded from the cluster | `
|
|
36
|
+
| `Text2Text` | text to text | any causal LM in the transformers layout, via `AutoModelForCausalLM` | `CompletingModel` (`complete`), plus its own `loglikelihoods` and `last_hidden_states` |
|
|
37
|
+
| `Text2Image` | text (and image) to image | any diffusers pipeline | `GeneratingModel` (`generate`) |
|
|
38
|
+
| `Image2Mesh` — a base: subclass it with the model's `load` and `make_mesh` | image to mesh | the model the subclass loads, behind the task's `mesh` endpoint | `MeshingModel` (`mesh`: one picture in, a `GeneratedMesh` out) |
|
|
39
|
+
| `TextRewriter` | text to text, rewritten | any encoder-decoder LM (T5, BART, Marian, ...) in the transformers layout, via `AutoModelForSeq2SeqLM` | `RewritingModel` (`rewrite`: one text in, one text out) |
|
|
40
|
+
| `AnthropicText2Text` | text to text | the Anthropic API, forwarded from the cluster | `CompletingModel` (`complete`) |
|
|
41
|
+
| `GeminiText2Text` | text to text | the Gemini API, forwarded from the cluster | `CompletingModel` (`complete`) |
|
|
42
|
+
| `GeminiText2Image` | text to image | the Gemini API, forwarded from the cluster | `GeneratingModel` (`generate`) |
|
|
42
43
|
|
|
43
44
|
| Importer | Source |
|
|
44
45
|
|---|---|
|
|
@@ -57,11 +58,13 @@ need:
|
|
|
57
58
|
| `.serve_app` | the class cortexgrid bundles and runs on the cluster |
|
|
58
59
|
| `.requirements()` | what one replica needs to be placed and to run |
|
|
59
60
|
| `.config()` | settings the serve app reads at construction, if it needs any |
|
|
60
|
-
| `.client(url)` | a client that speaks the deployed app's routes |
|
|
61
61
|
| `.source` | *(importers only)* a callable that downloads the weights and returns the directory |
|
|
62
62
|
|
|
63
63
|
One with weights goes through `cortexgrid.import_model`, one without through
|
|
64
|
-
`cortexgrid.register_model`.
|
|
64
|
+
`cortexgrid.register_model`. Once deployed, the `cortexgrid.Deployment` hands back
|
|
65
|
+
the client that calls the app's endpoints, typed as the serve app and so as its task
|
|
66
|
+
type: `deployment.client()` once the app serves, or `deployment.client_async()` at
|
|
67
|
+
once, with `await model.is_ready()` to ask.
|
|
65
68
|
|
|
66
69
|
## Quick start
|
|
67
70
|
|
|
@@ -89,13 +92,11 @@ cortexgrid.remote(
|
|
|
89
92
|
import_weights, imp, imp.requirements(), num_gpus=0, num_cpus=2
|
|
90
93
|
).result()
|
|
91
94
|
|
|
92
|
-
# 2. Deploy
|
|
93
|
-
deployment = cortexgrid.deploy_model(
|
|
94
|
-
imp.family, imp.suffix, cortexgrid.IMPORTED, wait=True, timeout=1800
|
|
95
|
-
)
|
|
95
|
+
# 2. Deploy.
|
|
96
|
+
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED, timeout=1800)
|
|
96
97
|
|
|
97
|
-
# 3. Inference.
|
|
98
|
-
model =
|
|
98
|
+
# 3. Inference — the client blocks until the Ray Serve app is running.
|
|
99
|
+
model: mg.GeneratingModel = deployment.client()
|
|
99
100
|
|
|
100
101
|
async def run():
|
|
101
102
|
result = await mg.generate(model, "a red bicycle on a beach at sunrise")
|
|
@@ -250,11 +251,13 @@ it is the floor; only quantizing the weights or running fewer forwards moves it.
|
|
|
250
251
|
|
|
251
252
|
## Inference
|
|
252
253
|
|
|
253
|
-
`complete` streams `CompletionChunk`s (`.content`, `.thinking`, `.tool_calls`, `.finish_reason`)
|
|
254
|
+
`complete` streams `CompletionChunk`s (`.content`, `.thinking`, `.tool_calls`, `.finish_reason`).
|
|
255
|
+
`tools` are Python functions or tool specs; a function goes to the model as its spec,
|
|
256
|
+
and each `ToolCall` comes back as data (`.id`, `.name`, `.arguments`) for the caller
|
|
257
|
+
to run:
|
|
254
258
|
|
|
255
259
|
```python
|
|
256
|
-
|
|
257
|
-
model = imp.client(deployment.url)
|
|
260
|
+
model: mg.CompletingModel = deployment.client()
|
|
258
261
|
messages = [{"role": "user", "content": "Explain RAG in one sentence."}]
|
|
259
262
|
|
|
260
263
|
async for chunk in mg.complete(model, messages, max_new_tokens=512, temperature=0.7):
|
|
@@ -295,9 +298,9 @@ a re-deploy rather than a re-registration.
|
|
|
295
298
|
|
|
296
299
|
A replica asks for no hardware at all, so it is placed on any node, CPU-only
|
|
297
300
|
included. From there it deploys and streams exactly like a cluster-served model:
|
|
298
|
-
`
|
|
301
|
+
`deployment.client()` is a `CompletingModel` like `Text2Text`'s. Anthropic
|
|
299
302
|
reports tool calls as structured blocks rather than as generated text, so the
|
|
300
|
-
serve app
|
|
303
|
+
serve app turns them into `ToolCall`s as they come.
|
|
301
304
|
|
|
302
305
|
### Gemini
|
|
303
306
|
|
|
@@ -318,17 +321,16 @@ cortexgrid.register_model(
|
|
|
318
321
|
|
|
319
322
|
Everything said above for Anthropic holds: `config` carries the model name and
|
|
320
323
|
the name of the secret (`api_key_secret="..."` to use another), both editable on
|
|
321
|
-
the model card; a replica needs no hardware; and `
|
|
322
|
-
is a `
|
|
323
|
-
text form the client parses.
|
|
324
|
+
the model card; a replica needs no hardware; and `deployment.client()`
|
|
325
|
+
is a `CompletingModel`, with Gemini's function calls turned into `ToolCall`s.
|
|
324
326
|
|
|
325
|
-
`GeminiText2Image`
|
|
326
|
-
client is a `ServedGeneratingModel`:
|
|
327
|
+
`GeminiText2Image` is a `GeneratingModel` like `Text2Image`:
|
|
327
328
|
|
|
328
329
|
```python
|
|
329
330
|
entry = mg.Hosted("gemini-2.5-flash-image", mg.GeminiText2Image)
|
|
330
331
|
...
|
|
331
|
-
|
|
332
|
+
model: mg.GeneratingModel = deployment.client()
|
|
333
|
+
picture = await mg.generate(model, "a fox in the snow", size=2048)
|
|
332
334
|
```
|
|
333
335
|
|
|
334
336
|
It takes a prompt only, and makes a square picture. `size` picks Gemini's size
|
|
@@ -340,40 +342,37 @@ diffusion settings with no Gemini counterpart, and come back as `None`.
|
|
|
340
342
|
| | |
|
|
341
343
|
|---|---|
|
|
342
344
|
| `HuggingFaceImporter(hf_id, serve_app, token=None, ignore_patterns=None)` | Importer for a model on the HuggingFace Hub, run by `serve_app`. |
|
|
343
|
-
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()`
|
|
345
|
+
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()` taken from the serve app. A new source implements `download(local_dir)` and `weights()`. |
|
|
344
346
|
| `Hosted(model_id, serve_app, **settings)` | Entry for a model hosted elsewhere; no weights. `settings` are the serve app's `config` arguments. |
|
|
345
|
-
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()
|
|
347
|
+
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()`. |
|
|
346
348
|
| `Text2Text`, `Text2Image`, `TextRewriter`, `Image2Mesh` | Serve apps that run weights (`LocalModel`s). |
|
|
347
349
|
| `AnthropicText2Text` | Serve app that forwards to the Anthropic API (a `HostedModel`). |
|
|
348
350
|
| `GeminiText2Text`, `GeminiText2Image` | Serve apps that forward to the Gemini API (`HostedModel`s sharing the `GeminiModel` base). |
|
|
349
|
-
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them)
|
|
350
|
-
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()
|
|
351
|
+
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them). |
|
|
352
|
+
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()`. |
|
|
351
353
|
| `Weights(params=None, file_bytes=0)` | What an importer reads about the weights, handed to the serve app to size a replica. |
|
|
352
|
-
| `complete(model, messages, tools=None, max_new_tokens=
|
|
353
|
-
| `generate(model, prompt, *, image=None,
|
|
354
|
-
| `ServedCompletingModel(url, model_id)` | Client for any deployed completion app. |
|
|
355
|
-
| `ServedGeneratingModel(url, model_id)` | Client for any deployed text-to-image app. |
|
|
356
|
-
| `ServedMeshingModel(url, model_id)` | Client for any deployed image-to-mesh app. |
|
|
354
|
+
| `complete(model, messages, tools=None, max_new_tokens=None, temperature=0.7)` | Async stream of `CompletionChunk` for a `CompletingModel`. |
|
|
355
|
+
| `generate(model, prompt, *, image=None, steps=None, guidance=None, size=1024, seed=None) -> GeneratedImage` | One image from a `GeneratingModel`. |
|
|
357
356
|
| `split_model_id(model_id) -> (family, suffix)` | The registry identity an importer derives. |
|
|
358
357
|
| `detect_device()` | The torch device a serve app should load onto. |
|
|
359
358
|
| `compiling.Mode.GRAPHED` / `compiling.Mode.FUSED` | The two modes a serve app chooses between. See [Compilation](#compilation). |
|
|
360
359
|
| `compiling.supported(device)` / `compile_module(module, device, mode)` / `compile_pipeline(pipe, device, mode)` | Whether to compile here, and what a serve app calls to do it. |
|
|
361
360
|
| `ModelDeployFailed` | Re-exported from cortexgrid; subclasses `RuntimeError`. |
|
|
362
361
|
|
|
363
|
-
Types: `
|
|
362
|
+
Types: `CompletingModel`, `GeneratingModel`, `MeshingModel`, `RewritingModel` (each
|
|
363
|
+
the abstract base of its task's serve apps, declaring the task's endpoints),
|
|
364
364
|
`CompletionChunk`, `GeneratedImage`, `GeneratedMesh`, `ToolCall`, `Message`, `Tool`,
|
|
365
|
-
`ToolSpec`.
|
|
365
|
+
`ToolSpec`, `Tensor`.
|
|
366
366
|
|
|
367
367
|
Extending it:
|
|
368
368
|
|
|
369
369
|
- **A new source** is one importer: subclass `Importer` with `download(local_dir)`
|
|
370
370
|
and `weights()`, and every serve app whose weight format it delivers runs its
|
|
371
371
|
models unchanged.
|
|
372
|
-
- **A new hosted API** is one serve app: subclass `HostedModel
|
|
373
|
-
with `Hosted`. A text-to-text one
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
then `ServedCompletingModel` is its client, unchanged.
|
|
372
|
+
- **A new hosted API** is one serve app: subclass `HostedModel` and the task's type,
|
|
373
|
+
and register it with `Hosted`. A text-to-text one subclasses `CompletingModel` and
|
|
374
|
+
streams `CompletionChunk`s from its `complete` endpoint, with
|
|
375
|
+
`StreamedCompletionWriter` turning the upstream's text and tool calls into them.
|
|
377
376
|
- **A model no task's serve app can load** gets its own serve app — an `Image2Mesh`
|
|
378
377
|
subclass, say, with `load` and `make_mesh`, and `compile` if compiling it pays —
|
|
379
378
|
and, if its source is unusual too, its own importer.
|
|
@@ -7,9 +7,9 @@ nothing else, split along the two things a model is:
|
|
|
7
7
|
|
|
8
8
|
- where its weights come from - an importer per source (`importers`), which
|
|
9
9
|
names, fetches and sizes them;
|
|
10
|
-
- what runs it - a serve app per task (`serve_apps`), which loads the weights
|
|
11
|
-
|
|
12
|
-
them.
|
|
10
|
+
- what runs it - a serve app per task (`serve_apps`), which loads the weights
|
|
11
|
+
and serves the task's endpoints, declared by the task's type in `core`
|
|
12
|
+
(`CompletingModel`, say); cortexgrid generates the client that calls them.
|
|
13
13
|
|
|
14
14
|
imp = cortexgrid_infer.HuggingFaceImporter("Qwen/Qwen2.5-0.5B-Instruct", cortexgrid_infer.Text2Text)
|
|
15
15
|
with imp:
|
|
@@ -18,8 +18,8 @@ nothing else, split along the two things a model is:
|
|
|
18
18
|
family=imp.family, suffix=imp.suffix,
|
|
19
19
|
requirements=imp.requirements(),
|
|
20
20
|
)
|
|
21
|
-
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED
|
|
22
|
-
model =
|
|
21
|
+
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED)
|
|
22
|
+
model: cortexgrid_infer.CompletingModel = deployment.client()
|
|
23
23
|
|
|
24
24
|
A model hosted elsewhere has no weights and so no importer: its serve app
|
|
25
25
|
forwards to it, and a `Hosted` entry registers it.
|
|
@@ -31,7 +31,6 @@ from cortexgrid import ModelDeployFailed
|
|
|
31
31
|
|
|
32
32
|
from cortexgrid_infer.core import (
|
|
33
33
|
CompletionChunk,
|
|
34
|
-
DeployedModel,
|
|
35
34
|
CompletingModel,
|
|
36
35
|
GeneratedImage,
|
|
37
36
|
GeneratedMesh,
|
|
@@ -39,6 +38,7 @@ from cortexgrid_infer.core import (
|
|
|
39
38
|
MeshingModel,
|
|
40
39
|
Message,
|
|
41
40
|
RewritingModel,
|
|
41
|
+
Tensor,
|
|
42
42
|
Tool,
|
|
43
43
|
ToolCall,
|
|
44
44
|
ToolSpec,
|
|
@@ -47,12 +47,6 @@ from cortexgrid_infer.core import (
|
|
|
47
47
|
mesh,
|
|
48
48
|
rewrite,
|
|
49
49
|
)
|
|
50
|
-
from cortexgrid_infer.protocols import (
|
|
51
|
-
ServedCompletingModel,
|
|
52
|
-
ServedGeneratingModel,
|
|
53
|
-
ServedMeshingModel,
|
|
54
|
-
ServedRewritingModel,
|
|
55
|
-
)
|
|
56
50
|
from cortexgrid_infer.device import detect_device
|
|
57
51
|
from cortexgrid_infer.serve_apps import (
|
|
58
52
|
AnthropicText2Text,
|
|
@@ -71,7 +65,6 @@ from cortexgrid_infer.importers import HuggingFaceImporter, Importer
|
|
|
71
65
|
|
|
72
66
|
__all__ = [
|
|
73
67
|
"CompletionChunk",
|
|
74
|
-
"DeployedModel",
|
|
75
68
|
"CompletingModel",
|
|
76
69
|
"GeneratedImage",
|
|
77
70
|
"GeneratedMesh",
|
|
@@ -79,6 +72,7 @@ __all__ = [
|
|
|
79
72
|
"MeshingModel",
|
|
80
73
|
"RewritingModel",
|
|
81
74
|
"Message",
|
|
75
|
+
"Tensor",
|
|
82
76
|
"Tool",
|
|
83
77
|
"ToolCall",
|
|
84
78
|
"ToolSpec",
|
|
@@ -88,10 +82,6 @@ __all__ = [
|
|
|
88
82
|
"rewrite",
|
|
89
83
|
"ModelDeployFailed",
|
|
90
84
|
"detect_device",
|
|
91
|
-
"ServedCompletingModel",
|
|
92
|
-
"ServedGeneratingModel",
|
|
93
|
-
"ServedMeshingModel",
|
|
94
|
-
"ServedRewritingModel",
|
|
95
85
|
"LocalModel",
|
|
96
86
|
"HostedModel",
|
|
97
87
|
"Weights",
|