diff --git a/pyproject.toml b/pyproject.toml index 06099e0..0a4a9f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ serve = ["fastapi>=0.110", "uvicorn>=0.29"] vllm = ["fastapi>=0.110", "uvicorn>=0.29", "vllm>=0.12"] # decision-model support: vLLM nightly from 2026-10-15 fla = ["flash-linear-attention>=0.5"] # fast Gated DeltaNet kernels for Qwen3.5/3.8 backbones data = ["datasets>=3"] -dev = ["pytest>=8", "ruff>=0.6", "mypy>=1.11", "fastapi>=0.110", "httpx>=0.27"] +dev = ["pytest>=8", "ruff>=0.6", "mypy>=1.11", "fastapi>=0.110", "uvicorn>=0.29", "httpx>=0.27"] [project.scripts] decisionformer = "decisionformer.cli:main" diff --git a/src/decisionformer/serve.py b/src/decisionformer/serve.py index 7f934ba..00899d8 100644 --- a/src/decisionformer/serve.py +++ b/src/decisionformer/serve.py @@ -90,7 +90,7 @@ def load_decider(model: str, *, backend: str = "transformers", device: str | Non def serve(model: str, *, host: str = "127.0.0.1", port: int = 8000, device: str | None = None, backend: str = "transformers", api_key_env: str = "DECISIONFORMER_API_KEY", **load_options: Any) -> None: + decider = load_decider(model, backend=backend, device=device, **load_options) # model errors first import uvicorn - decider = load_decider(model, backend=backend, device=device, **load_options) uvicorn.run(create_app(decider, api_key=os.environ.get(api_key_env)), host=host, port=port) diff --git a/tests/conftest.py b/tests/conftest.py index 6ebdcfc..732f033 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -212,7 +212,8 @@ def data_dir(tmp_path_factory) -> Path: "qwen3_moe": {"num_experts": 4, "num_experts_per_tok": 2, "moe_intermediate_size": 32, "decoder_sparse_step": 1}, "olmoe": {"num_experts": 4, "num_experts_per_tok": 2}, "gpt_oss": {**_MOE, "layer_types": ["sliding_attention", "full_attention"], "sliding_window": 64}, - "deepseek_v3": {"n_routed_experts": 4, "num_experts_per_tok": 2, "moe_intermediate_size": 32, + # multi-head latent attention has as many key/value heads as query heads + "deepseek_v3": {"n_routed_experts": 4, "num_experts_per_tok": 2, "moe_intermediate_size": 32, "num_key_value_heads": 4, "first_k_dense_replace": 1, "kv_lora_rank": 16, "q_lora_rank": 16, "qk_rope_head_dim": 8, "qk_nope_head_dim": 8, "v_head_dim": 8, "n_group": 1, "topk_group": 1}, # hybrid linear attention (Gated DeltaNet) + full attention @@ -236,8 +237,9 @@ def build_zoo_model(root: Path, model_type: str) -> Path: tokenizer = make_tokenizer("encoder" if encoder else "decoder") kwargs = dict(_TINY, vocab_size=len(tokenizer), **(ZOO_ENCODERS if encoder else ZOO_DECODERS)[model_type]) if not encoder: - kwargs.update(num_key_value_heads=2, eos_token_id=SPECIALS.index("<|end|>"), bos_token_id=None, - tie_word_embeddings=True, **({} if model_type == "falcon" else {"head_dim": 8})) + kwargs = {"num_key_value_heads": 2, **kwargs} + kwargs.update(eos_token_id=SPECIALS.index("<|end|>"), bos_token_id=None, tie_word_embeddings=True, + **({} if model_type == "falcon" else {"head_dim": 8})) torch.manual_seed(0) config = AutoConfig.for_model(model_type, **kwargs) if getattr(config, "is_encoder_decoder", False):