Skip to content

Commit 9bafe5a

Browse files
mzusmanErezSC42Mor Zusmantomeras91zhuohan123
authored andcommitted
[Model] Jamba support (vllm-project#4115)
Signed-off-by: Muralidhar Andoorveedu <muralidhar.andoorveedu@centml.ai> Co-authored-by: Erez Schwartz <erezs@ai21.com> Co-authored-by: Mor Zusman <morz@ai21.com> Co-authored-by: tomeras91 <57313761+tomeras91@users.noreply.github.com> Co-authored-by: Tomer Asida <tomera@ai21.com> Co-authored-by: Zhuohan Li <zhuohan123@gmail.com> Co-authored-by: Muralidhar Andoorveedu <muralidhar.andoorveedu@centml.ai> Signed-off-by: LeiWang1999 <leiwang1999@outlook.com>
1 parent 277f0ab commit 9bafe5a

21 files changed

Lines changed: 1192 additions & 34 deletions

.buildkite/run-cpu-test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ docker exec cpu-test-avx2 bash -c "python3 examples/offline_inference.py"
2323
docker exec cpu-test bash -c "cd tests;
2424
pip install pytest Pillow protobuf
2525
cd ../
26-
pytest -v -s tests/models -m \"not vlm\" --ignore=tests/models/test_embedding.py --ignore=tests/models/test_registry.py"
26+
pytest -v -s tests/models -m \"not vlm\" --ignore=tests/models/test_embedding.py --ignore=tests/models/test_registry.py --ignore=tests/models/test_jamba.py" # Mamba on CPU is not supported

Dockerfile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ COPY requirements-cuda.txt requirements-cuda.txt
4343
RUN --mount=type=cache,target=/root/.cache/pip \
4444
python3 -m pip install -r requirements-cuda.txt
4545

46+
COPY requirements-mamba.txt requirements-mamba.txt
47+
RUN python3 -m pip install packaging
48+
RUN python3 -m pip install -r requirements-mamba.txt
49+
4650
# cuda arch list used by torch
4751
# can be useful for both `dev` and `test`
4852
# explicitly set the list to avoid issues with torch 2.2
@@ -123,6 +127,21 @@ RUN --mount=type=cache,target=/root/.cache/pip \
123127
python3 -m pip install -r requirements-dev.txt
124128

125129
#################### DEV IMAGE ####################
130+
#################### MAMBA Build IMAGE ####################
131+
FROM dev as mamba-builder
132+
# max jobs used for build
133+
ARG max_jobs=2
134+
ENV MAX_JOBS=${max_jobs}
135+
136+
WORKDIR /usr/src/mamba
137+
138+
COPY requirements-mamba.txt requirements-mamba.txt
139+
140+
# Download the wheel or build it if a pre-compiled release doesn't exist
141+
RUN pip --verbose wheel -r requirements-mamba.txt \
142+
--no-build-isolation --no-deps --no-cache-dir
143+
144+
#################### MAMBA Build IMAGE ####################
126145

127146
#################### vLLM installation IMAGE ####################
128147
# image with vLLM installed
@@ -143,6 +162,10 @@ RUN ldconfig /usr/local/cuda-$(echo $CUDA_VERSION | cut -d. -f1,2)/compat/
143162
RUN --mount=type=bind,from=build,src=/workspace/dist,target=/vllm-workspace/dist \
144163
--mount=type=cache,target=/root/.cache/pip \
145164
python3 -m pip install dist/*.whl --verbose
165+
166+
RUN --mount=type=bind,from=mamba-builder,src=/usr/src/mamba,target=/usr/src/mamba \
167+
--mount=type=cache,target=/root/.cache/pip \
168+
python3 -m pip install /usr/src/mamba/*.whl --no-cache-dir
146169
#################### vLLM installation IMAGE ####################
147170

148171

docs/source/models/supported_models.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ Alongside each architecture, we include some popular models that use it.
8787
- Jais
8888
- :code:`core42/jais-13b`, :code:`core42/jais-13b-chat`, :code:`core42/jais-30b-v3`, :code:`core42/jais-30b-chat-v3`, etc.
8989
-
90+
* - :code:`JambaForCausalLM`
91+
- Jamba
92+
- :code:`ai21labs/Jamba-v0.1`, etc.
93+
- ✅︎
9094
* - :code:`LlamaForCausalLM`
9195
- LLaMA, Llama 2, Meta Llama 3, Vicuna, Alpaca, Yi
9296
- :code:`meta-llama/Meta-Llama-3-8B-Instruct`, :code:`meta-llama/Meta-Llama-3-70B-Instruct`, :code:`meta-llama/Llama-2-13b-hf`, :code:`meta-llama/Llama-2-70b-hf`, :code:`openlm-research/open_llama_13b`, :code:`lmsys/vicuna-13b-v1.3`, :code:`01-ai/Yi-6B`, :code:`01-ai/Yi-34B`, etc.

requirements-mamba.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Mamba dependencies
2+
mamba-ssm>=1.2.2
3+
causal-conv1d>=1.2.0

tests/models/test_jamba.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import pytest
2+
3+
MODELS = ["ai21labs/Jamba-tiny-random"]
4+
5+
6+
@pytest.mark.parametrize("model", MODELS)
7+
@pytest.mark.parametrize("dtype", ["float"])
8+
@pytest.mark.parametrize("max_tokens", [20])
9+
def test_models(
10+
hf_runner,
11+
vllm_runner,
12+
example_prompts,
13+
model: str,
14+
dtype: str,
15+
max_tokens: int,
16+
) -> None:
17+
# To pass the small model tests, we need full precision.
18+
assert dtype == "float"
19+
20+
with hf_runner(model, dtype=dtype) as hf_model:
21+
hf_outputs = hf_model.generate_greedy(example_prompts, max_tokens)
22+
23+
with vllm_runner(model, dtype=dtype) as vllm_model:
24+
vllm_outputs = vllm_model.generate_greedy(example_prompts, max_tokens)
25+
26+
for i in range(len(example_prompts)):
27+
hf_output_ids, hf_output_str = hf_outputs[i]
28+
vllm_output_ids, vllm_output_str = vllm_outputs[i]
29+
assert hf_output_str == vllm_output_str, (
30+
f"Test{i}:\nHF: {hf_output_str!r}\nvLLM: {vllm_output_str!r}")
31+
assert hf_output_ids == vllm_output_ids, (
32+
f"Test{i}:\nHF: {hf_output_ids}\nvLLM: {vllm_output_ids}")
33+
34+
35+
@pytest.mark.parametrize("model", MODELS)
36+
@pytest.mark.parametrize("dtype", ["float"])
37+
def test_state_cleanup(
38+
vllm_runner,
39+
model: str,
40+
dtype: str,
41+
example_prompts,
42+
) -> None:
43+
# This test is for verifying that the Jamba state is cleaned up between
44+
# steps, If its not cleaned, an error would be expected.
45+
try:
46+
with vllm_runner(model, dtype=dtype) as vllm_model:
47+
for _ in range(10):
48+
vllm_model.generate_greedy([example_prompts[0]] * 100, 1)
49+
except ValueError:
50+
pytest.fail("Jamba inner state wasn't cleaned up between states, "
51+
"could be related to finished_requests_ids")
52+
53+
54+
@pytest.mark.parametrize("model", MODELS)
55+
@pytest.mark.parametrize("dtype", ["float"])
56+
def test_model_print(
57+
vllm_runner,
58+
model: str,
59+
dtype: str,
60+
) -> None:
61+
with vllm_runner(model, dtype=dtype) as vllm_model:
62+
# This test is for verifying whether the model's extra_repr
63+
# can be printed correctly.
64+
print(vllm_model.model.llm_engine.model_executor.driver_worker.
65+
model_runner.model)

vllm/config.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,9 +428,36 @@ def get_num_attention_heads(self,
428428
return num_heads // parallel_config.tensor_parallel_size
429429

430430
def get_num_layers(self, parallel_config: "ParallelConfig") -> int:
431-
total_num_hidden_layers = self.hf_text_config.num_hidden_layers
431+
total_num_hidden_layers = getattr(self.hf_text_config,
432+
"num_hidden_layers", 0)
432433
return total_num_hidden_layers // parallel_config.pipeline_parallel_size
433434

435+
def contains_seqlen_agnostic_layers(
436+
self, parallel_config: "ParallelConfig") -> bool:
437+
"""True for Mamba/SSM models (Jamba)"""
438+
return self._get_num_seqlen_agnostic_layers(parallel_config) > 0
439+
440+
def get_layers_block_type(self,
441+
parallel_config: "ParallelConfig") -> List[str]:
442+
num_layers = self.get_num_layers(parallel_config)
443+
# Transformers supports layers_block_type @property
444+
return getattr(self.hf_config, "layers_block_type",
445+
["attention"] * num_layers)
446+
447+
def get_num_attention_layers(self,
448+
parallel_config: "ParallelConfig") -> int:
449+
return len([
450+
t for t in self.get_layers_block_type(parallel_config)
451+
if t == "attention"
452+
])
453+
454+
def _get_num_seqlen_agnostic_layers(
455+
self, parallel_config: "ParallelConfig") -> int:
456+
return len([
457+
t for t in self.get_layers_block_type(parallel_config)
458+
if t != "attention"
459+
])
460+
434461

435462
class CacheConfig:
436463
"""Configuration for the KV cache.

vllm/core/scheduler.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,10 @@ def __init__(
299299
# Sequence groups in the SWAPPED state.
300300
# Contain decode requests that are swapped out.
301301
self.swapped: Deque[SequenceGroup] = deque()
302-
302+
# Sequence groups finished requests ids since last step iteration.
303+
# It lets the model know that any state associated with these requests
304+
# can and must be released after the current step.
305+
self._finished_requests_ids: List[str] = list()
303306
# Time at previous scheduling step
304307
self.prev_time = 0.0
305308
# Did we schedule a prompt at previous step?
@@ -373,6 +376,12 @@ def has_unfinished_seqs(self) -> bool:
373376
def get_num_unfinished_seq_groups(self) -> int:
374377
return len(self.waiting) + len(self.running) + len(self.swapped)
375378

379+
def get_and_reset_finished_requests_ids(self) -> List[str]:
380+
"""Flushes the list of request ids of previously finished seq_groups."""
381+
finished_requests_ids = self._finished_requests_ids
382+
self._finished_requests_ids = list()
383+
return finished_requests_ids
384+
376385
def _schedule_running(
377386
self,
378387
running_queue: deque,
@@ -1036,6 +1045,11 @@ def free_seq(self, seq: Sequence) -> None:
10361045
self.block_manager.free(seq)
10371046

10381047
def free_finished_seq_groups(self) -> None:
1048+
for queue in [self.running, self.swapped, self.waiting]:
1049+
self._finished_requests_ids += [
1050+
seq_group.request_id for seq_group in queue
1051+
if seq_group.is_finished()
1052+
]
10391053
self.running = deque(seq_group for seq_group in self.running
10401054
if not seq_group.is_finished())
10411055

vllm/engine/async_llm_engine.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ async def step_async(
224224
"""
225225
seq_group_metadata_list, scheduler_outputs = self.scheduler[
226226
virtual_engine].schedule()
227+
finished_requests_ids = self.scheduler[
228+
virtual_engine].get_and_reset_finished_requests_ids()
227229

228230
if not scheduler_outputs.is_empty():
229231
# Execute the model.
@@ -235,7 +237,7 @@ async def step_async(
235237
virtual_engine=virtual_engine,
236238
num_lookahead_slots=scheduler_outputs.num_lookahead_slots,
237239
running_queue_size=scheduler_outputs.running_queue_size,
238-
)
240+
finished_requests_ids=finished_requests_ids)
239241
output = await self.model_executor.execute_model_async(
240242
execute_model_req)
241243
else:

vllm/engine/llm_engine.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,8 @@ def step(self) -> List[Union[RequestOutput, EmbeddingRequestOutput]]:
846846
"as performance will be severely degraded otherwise.")
847847
seq_group_metadata_list, scheduler_outputs = self.scheduler[
848848
0].schedule()
849+
finished_requests_ids = self.scheduler[
850+
0].get_and_reset_finished_requests_ids()
849851

850852
if not scheduler_outputs.is_empty():
851853
execute_model_req = ExecuteModelRequest(
@@ -855,7 +857,7 @@ def step(self) -> List[Union[RequestOutput, EmbeddingRequestOutput]]:
855857
blocks_to_copy=scheduler_outputs.blocks_to_copy,
856858
num_lookahead_slots=scheduler_outputs.num_lookahead_slots,
857859
running_queue_size=scheduler_outputs.running_queue_size,
858-
)
860+
finished_requests_ids=finished_requests_ids)
859861
output = self.model_executor.execute_model(
860862
execute_model_req=execute_model_req)
861863
else:

vllm/model_executor/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"XverseForCausalLM": ("xverse", "XverseForCausalLM"),
6565
"Phi3SmallForCausalLM": ("phi3_small", "Phi3SmallForCausalLM"),
6666
"MLPSpeculatorPreTrainedModel": ("mlp_speculator", "MLPSpeculator"),
67+
"JambaForCausalLM": ("jamba", "JambaForCausalLM")
6768
}
6869

6970
_EMBEDDING_MODELS = {

0 commit comments

Comments
 (0)