-
Notifications
You must be signed in to change notification settings - Fork 66
Arctic rl/integration #264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 45 commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
0a42e6f
[Rollout] Patch InprocClient.get_output() to ensure correct behavior …
sfc-gh-yewang 84636e6
[Rollout] Forest Cascade Attention (#20)
sfc-gh-yewang b1d2e0f
Bring ArcticForge code over (#21)
sfc-gh-mwyatt 9729a45
Surface logprobs (#23)
sfc-gh-yewang b7aaf10
ArcticInference server weight sync (#22)
sfc-gh-yewang 420418f
Multi-model support (#25)
sfc-gh-mwyatt b3a62c1
Extract multi-model support to separate module (#26)
sfc-gh-mwyatt 6ab2f5a
Surface wake_up/sleep API (#27)
sfc-gh-yewang 570d9e3
Update and expand server examples (#28)
sfc-gh-mwyatt 8812d31
Fix FP8 MoE weight sync (#29)
sfc-gh-yewang d8473bd
Small fixes (#30)
sfc-gh-yewang d5ddae9
Update CODEOWNERS with new org and user names (#32)
jenkins-snowci-mergequeue-0-emu[bot] ca36437
SNOW-2231554-EMU Migration - Update references for Wave 4 testing (#18)
svc-gh-sourcegraph-sa 62ca5b9
Revert "SNOW-2231554-EMU Migration - Update references for Wave 4 tes…
sfc-gh-yewang fad9d41
reflect vllm PR #32947 (#34)
sfc-gh-mhidayetoglu 4dc4bbe
Add reverse mode for weight sync and fix per-replica port assignment …
sfc-gh-yewang 7970df0
Fix spec decoding drafter model during sleep/wake cycles (#36)
sfc-gh-yewang 6a6acb9
Add spec (drafter) model weight sync API (#37)
sfc-gh-yewang a591018
Fix shift-parallel CUDA graph capture and dispatch (#258)
sfc-gh-yewang 830f92f
Feature: colocation support (#45)
sfc-gh-mwyatt f23d97c
feat: IPC shared-memory weight sync + placement group support for col…
sfc-gh-kganesan 60bea68
Disable health status
sfc-gh-truwase 3db6631
Verl colocate
sfc-gh-truwase e4d1740
Add reset_prefix_cache to inference worker (#73)
sfc-gh-mhidayetoglu 7a4f7e9
PG fixes
sfc-gh-truwase 99838c4
Merge branch 'tunji/verl_integration' into tunji/verl_32b_perf
sfc-gh-truwase 883dc95
support VLLM_BATCH_INVARIANT
sfc-gh-sbekman 85c762a
vllm version
sfc-gh-truwase 9f9ac4a
support VLLM_BATCH_INVARIANT note
sfc-gh-sbekman c86fee9
Merge branch 'tunji/verl_integration' of https://github.com/snowflake…
sfc-gh-sbekman dfb4f0a
weight sync; fca
sfc-gh-truwase 9aa69ae
Sync tunji/verl_integration with origin/main (vLLM 0.18.0 rebase) (#7…
sfc-gh-mhidayetoglu 4f051c5
fix vllm18 rebase mistake
sfc-gh-mhidayetoglu 07bb3e4
Fix vllm deps
sfc-gh-truwase 4cfc9d2
fix parallel config init
sfc-gh-mhidayetoglu 85391b1
Add strict weight-sync parameter name validation for CUDA IPC.
sfc-gh-truwase e80638d
Harden weight sync and add spec-weight HTTP endpoints
sfc-gh-truwase d4d0279
Add streaming CUDA IPC chunk loader for low-memory weight sync
sfc-gh-truwase 63ee7e8
Print one-shot [FCA] status banner (#85)
sfc-gh-mhidayetoglu e70bd99
Add min_batch_size tuning to Forest Cascade Attention (#93)
sfc-gh-mhidayetoglu 28a0f45
Strict group-balanced routing for GRPO rollouts (#92)
sfc-gh-mhidayetoglu c6f0a4f
add auxiliary compute_weight_norm API used in tests
sfc-gh-sbekman 1edefdf
Integrate Zorro Inference (FCA) and Arctic Speculative Decoding into …
sfc-gh-mhidayetoglu 6c73218
Add hard cut-off for speculative decoding at high batch size
sfc-gh-mhidayetoglu e51233f
Merge branch 'main' into arctic_rl/integration
sfc-gh-mhidayetoglu c771c22
fix codeowners
sfc-gh-mhidayetoglu 9803ba3
delete dev patches
sfc-gh-mhidayetoglu d8365b6
remove kvcached
sfc-gh-mhidayetoglu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| * @sfc-gh-aqiao @sfc-gh-jrasley @sfc-gh-mhidayetoglu @sfc-gh-yewang @sfc-gh-goliaro @sfc-gh-reyazda | ||
| * @sfc-gh-aqiao @jeff-rasley_snow @mert-hidayetoglu_snow @ye-wang_snow @gabriele-oliaro_snow @reza-yazdani_snow | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| from arctic_inference.server.config import ModelConfig | ||
| from arctic_inference.server.pipeline import Pipeline | ||
| from arctic_inference.server.replica_pool import ReplicaPool, ensure_ray | ||
| from arctic_inference.server.weight_sync import ( | ||
| NCCLEngine, WeightInfo, build_weights_info, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "ModelConfig", | ||
| "Pipeline", | ||
| "ReplicaPool", | ||
| "ensure_ray", | ||
| "NCCLEngine", | ||
| "WeightInfo", | ||
| "build_weights_info", | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,213 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from contextlib import asynccontextmanager | ||
| from typing import Any | ||
|
|
||
| from arctic_inference.server.replica_pool import ReplicaPool | ||
| from fastapi import FastAPI, HTTPException | ||
| from pydantic import BaseModel, Field, model_validator | ||
|
|
||
| from arctic_inference.server.config import ModelConfig | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Request models | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
|
|
||
| class InitRequest(BaseModel): | ||
| config: ModelConfig | ||
| model_id: str | None = None | ||
| num_replicas: int | None = None | ||
|
|
||
|
|
||
| class GenerateRequest(BaseModel): | ||
| model_id: str | None = None | ||
| prompts: list[str | list[int]] | ||
| sampling_params: dict[str, Any] = Field(default_factory=dict) | ||
| routing_key: str | list[str | None] | None = None | ||
| strict: bool = False | ||
|
|
||
|
|
||
| class GroupConfig(BaseModel): | ||
| group_id: int | ||
| master_addr: str | ||
| master_port: int | ||
| world_size: int | ||
| replica_ids: list[int] | ||
|
|
||
|
|
||
| class SleepRequest(BaseModel): | ||
| model_id: str | ||
| level: int = 1 | ||
|
|
||
|
|
||
| class WakeUpRequest(BaseModel): | ||
| model_id: str | ||
| tags: list[str] | None = None | ||
|
|
||
|
|
||
| class SyncWeightsRequest(BaseModel): | ||
| model_id: str | None = None | ||
| groups: list[GroupConfig] | None = None | ||
| bucket_size: int = 256 * 1024 * 1024 | ||
| strategy: str = "hotswap" | ||
| engine_only: bool = False | ||
| direct_mode: bool = False | ||
| reverse: bool = False | ||
|
|
||
| # Legacy flat fields | ||
| master_addr: str | None = None | ||
| master_port: int | None = None | ||
| world_size: int | None = None | ||
|
|
||
|
|
||
| class SyncSpecWeightsRequest(BaseModel): | ||
| model_id: str | None = None | ||
| groups: list[GroupConfig] | None = None | ||
| bucket_size: int = 256 * 1024 * 1024 | ||
| strategy: str = "hotswap" | ||
| engine_only: bool = False | ||
| reverse: bool = False | ||
|
|
||
| # Legacy flat fields | ||
| master_addr: str | None = None | ||
| master_port: int | None = None | ||
| world_size: int | None = None | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Backend – a bare ReplicaPool by default, swapped to Driver by multi_model.py | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| backend: Any = ReplicaPool() | ||
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # FastAPI app | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
|
|
||
| @asynccontextmanager | ||
| async def lifespan(_app: FastAPI): | ||
| yield | ||
| await backend.shutdown() | ||
|
|
||
|
|
||
| app = FastAPI(title="Arctic Inference", lifespan=lifespan) | ||
|
|
||
|
|
||
| @app.post("/init") | ||
| async def init_endpoint(request: InitRequest): | ||
| try: | ||
| n = await backend.initialize( | ||
| request.config, model_id=request.model_id, | ||
| num_replicas=request.num_replicas, | ||
| ) | ||
| return {"status": "ready", "model_id": request.model_id, "num_replicas": n} | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.post("/generate") | ||
| async def generate_endpoint(request: GenerateRequest): | ||
| try: | ||
| results = await backend.generate(**request.model_dump()) | ||
| return {"results": results} | ||
| except RuntimeError as e: | ||
| msg = str(e).lower() | ||
| if "paused" in msg or "cancelled" in msg: | ||
| raise HTTPException(status_code=503, detail=str(e)) | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.post("/sleep") | ||
| async def sleep_endpoint(request: SleepRequest): | ||
| """Free GPU memory for a model (drain in-flight requests first).""" | ||
| try: | ||
| return await backend.sleep(request.model_id, level=request.level) | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.post("/wake_up") | ||
| async def wake_up_endpoint(request: WakeUpRequest): | ||
| """Restore GPU memory for a model and resume serving.""" | ||
| try: | ||
| return await backend.wake_up(request.model_id, tags=request.tags) | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.get("/weights_info") | ||
| async def weights_info_endpoint(model_id: str | None = None): | ||
| try: | ||
| infos = backend.get_weights_info(model_id=model_id) | ||
| return {"weights_info": infos, "count": len(infos)} | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.post("/sync_weights") | ||
| async def sync_weights_endpoint(request: SyncWeightsRequest): | ||
| try: | ||
| return await backend.sync_weights(**request.model_dump()) | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.get("/spec_weights_info") | ||
| async def spec_weights_info_endpoint(model_id: str | None = None): | ||
| try: | ||
| infos = backend.get_spec_weights_info(model_id=model_id) | ||
| return {"weights_info": infos, "count": len(infos)} | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.post("/sync_spec_weights") | ||
| async def sync_spec_weights_endpoint(request: SyncSpecWeightsRequest): | ||
| try: | ||
| return await backend.sync_spec_weights(**request.model_dump()) | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.post("/close_weight_sync") | ||
| async def close_weight_sync_endpoint(model_id: str | None = None): | ||
| try: | ||
| return await backend.close_weight_sync(model_id=model_id) | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.get("/status") | ||
| async def status_endpoint(): | ||
| try: | ||
| return await backend.get_status() | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.get("/metrics") | ||
| async def metrics_endpoint(model_id: str | None = None): | ||
| """Drain per-replica snapshots and per-request records. | ||
|
|
||
| Each call empties the server-side ring buffers, so consumers see only | ||
| metrics produced since their previous call. | ||
| """ | ||
| try: | ||
| return await backend.drain_metrics(model_id=model_id) | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) | ||
|
|
||
|
|
||
| @app.post("/shutdown") | ||
| async def shutdown_endpoint(model_id: str | None = None): | ||
| try: | ||
| await backend.shutdown(model_id=model_id) | ||
| return {"status": "shutdown", "model_id": model_id} | ||
| except Exception as e: | ||
| raise HTTPException(status_code=500, detail=str(e)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| """CLI entry point: ``arctic-inference-server``.""" | ||
| from __future__ import annotations | ||
|
|
||
| import argparse | ||
|
|
||
|
|
||
| def main() -> None: | ||
| parser = argparse.ArgumentParser( | ||
| prog="arctic-inference-server", | ||
| description="Launch the Arctic Inference server", | ||
| ) | ||
| parser.add_argument("--host", default="0.0.0.0", help="Bind address (default: 0.0.0.0)") | ||
| parser.add_argument("--port", type=int, default=8000, help="Bind port (default: 8000)") | ||
| parser.add_argument("--workers", type=int, default=1, help="Number of uvicorn workers (default: 1)") | ||
| parser.add_argument("--log-level", default="info", help="Log level (default: info)") | ||
| args = parser.parse_args() | ||
|
|
||
| import uvicorn | ||
|
|
||
| uvicorn.run( | ||
| "arctic_inference.server.api:app", | ||
| host=args.host, | ||
| port=args.port, | ||
| workers=args.workers, | ||
| log_level=args.log_level, | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.