mirror of
https://git.datalinker.icu/vllm-project/vllm.git
synced 2025-12-09 10:15:24 +08:00
401 lines
14 KiB
Python
401 lines
14 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
import importlib.metadata
|
|
import importlib.util
|
|
|
|
import pytest
|
|
import torch
|
|
|
|
DTYPE = ["bfloat16"]
|
|
|
|
TORCHAO_AVAILABLE = importlib.util.find_spec("torchao") is not None
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
def test_pre_quantized_model(vllm_runner):
|
|
with vllm_runner(
|
|
"drisspg/fp8-opt-125m",
|
|
quantization="torchao",
|
|
dtype="bfloat16",
|
|
enforce_eager=True,
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
@pytest.mark.parametrize(
|
|
"pt_load_map_location",
|
|
[
|
|
"cuda:0",
|
|
# {"": "cuda"},
|
|
],
|
|
)
|
|
def test_opt_125m_int8wo_model_loading_with_params(vllm_runner, pt_load_map_location):
|
|
torch._dynamo.reset()
|
|
model_name = "jerryzh168/opt-125m-int8wo-partial-quant"
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
quantization="torchao",
|
|
dtype="bfloat16",
|
|
pt_load_map_location=pt_load_map_location,
|
|
enforce_eager=True,
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
def test_opt_125m_int4wo_model_per_module_quant(vllm_runner):
|
|
torch._dynamo.reset()
|
|
model_name = "jerryzh168/opt-125m-int4wo-per-module"
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
quantization="torchao",
|
|
dtype="bfloat16",
|
|
pt_load_map_location="cuda:0",
|
|
enforce_eager=True,
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
def test_qwenvl_int8wo_model_loading_with_params(vllm_runner):
|
|
torch._dynamo.reset()
|
|
model_name = "mobicham/Qwen2.5-VL-3B-Instruct_int8wo_ao"
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
quantization="torchao",
|
|
dtype="bfloat16",
|
|
pt_load_map_location="cuda:0",
|
|
enforce_eager=True,
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
@pytest.mark.skip(
|
|
reason="since torchao nightly is only compatible with torch nightly"
|
|
"currently https://github.com/pytorch/ao/issues/2919, we'll have to skip "
|
|
"torchao tests that requires newer versions (0.14.0.dev+) for now"
|
|
)
|
|
def test_opt_125m_awq_int4wo_model_loading_with_params(vllm_runner):
|
|
torch._dynamo.reset()
|
|
model_name = "torchao-testing/opt-125m-AWQConfig-Int4WeightOnlyConfig-v2-0.14.0.dev"
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
quantization="torchao",
|
|
dtype="bfloat16",
|
|
pt_load_map_location="cuda:0",
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
def test_online_quant_config_dict_json(vllm_runner):
|
|
"""Testing on the fly quantization, load_weights integration point,
|
|
with config dict serialized to json string
|
|
"""
|
|
torch._dynamo.reset()
|
|
model_name = "facebook/opt-125m"
|
|
|
|
import json
|
|
|
|
from torchao.core.config import config_to_dict
|
|
from torchao.quantization import Float8DynamicActivationFloat8WeightConfig, PerRow
|
|
|
|
torchao_quant_config = Float8DynamicActivationFloat8WeightConfig(
|
|
granularity=PerRow()
|
|
)
|
|
hf_overrides = {
|
|
"quantization_config_dict_json": json.dumps(
|
|
config_to_dict(torchao_quant_config)
|
|
)
|
|
}
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
dtype="bfloat16",
|
|
pt_load_map_location="cuda:0",
|
|
quantization="torchao",
|
|
hf_overrides=hf_overrides,
|
|
enforce_eager=True,
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
def test_online_quant_config_file(vllm_runner):
|
|
"""Testing on the fly quantization, load_weights integration point,
|
|
with config file
|
|
"""
|
|
torch._dynamo.reset()
|
|
model_name = "facebook/opt-125m"
|
|
import json
|
|
from tempfile import NamedTemporaryFile
|
|
|
|
from torchao.core.config import config_to_dict
|
|
from torchao.quantization import Float8DynamicActivationFloat8WeightConfig, PerRow
|
|
|
|
config = Float8DynamicActivationFloat8WeightConfig(granularity=PerRow())
|
|
|
|
with NamedTemporaryFile(mode="w", delete=False) as f:
|
|
f.write(json.dumps(config_to_dict(config)))
|
|
# close the file to save it
|
|
f.close()
|
|
config_file_name = str(f.name)
|
|
|
|
hf_overrides = {"quantization_config_file": config_file_name}
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
dtype="bfloat16",
|
|
pt_load_map_location="cuda:0",
|
|
quantization="torchao",
|
|
hf_overrides=hf_overrides,
|
|
enforce_eager=True,
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
def test_reload_weights():
|
|
import json
|
|
|
|
from torchao.core.config import config_to_dict
|
|
from torchao.quantization import Float8DynamicActivationFloat8WeightConfig, PerRow
|
|
|
|
from vllm import LLM, SamplingParams
|
|
|
|
torchao_quant_config = Float8DynamicActivationFloat8WeightConfig(
|
|
granularity=PerRow()
|
|
)
|
|
|
|
hf_overrides = {
|
|
"quantization_config_dict_json": json.dumps(
|
|
config_to_dict(torchao_quant_config)
|
|
)
|
|
}
|
|
|
|
llm = LLM(
|
|
model="Qwen/Qwen3-0.6B",
|
|
dtype="bfloat16",
|
|
load_format="dummy",
|
|
enforce_eager=True,
|
|
quantization="torchao",
|
|
hf_overrides=hf_overrides,
|
|
)
|
|
# Update load format from `dummy` to `auto`
|
|
llm.collective_rpc(
|
|
"update_config", args=({"load_config": {"load_format": "auto"}},)
|
|
)
|
|
# Now reload real weights inplace
|
|
llm.collective_rpc("reload_weights")
|
|
prompts = [
|
|
"Hello, my name is",
|
|
"The president of the United States is",
|
|
"The capital of France is",
|
|
"The future of AI is",
|
|
]
|
|
# Create a sampling params object.
|
|
sampling_params = SamplingParams(temperature=0, top_p=0.95)
|
|
outputs = llm.generate(prompts, sampling_params)
|
|
# make sure it runs
|
|
for output in outputs:
|
|
generated_text = output.outputs[0].text
|
|
assert generated_text
|
|
# can also uncomment locally to make sure the generated
|
|
# output makes sense
|
|
# prompt = output.prompt
|
|
# print(f"Prompt: {prompt!r}")
|
|
# print(f"Output: {generated_text!r}")
|
|
# print("-" * 60)
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
@pytest.mark.skip(
|
|
reason="since torchao nightly is only compatible with torch nightly"
|
|
"currently https://github.com/pytorch/ao/issues/2919, we'll have to skip "
|
|
"torchao tests that requires newer versions (0.15.0.dev+) for now"
|
|
)
|
|
def test_safetensors_model_loading_with_params(vllm_runner):
|
|
torch._dynamo.reset()
|
|
# using this model to test safetensors loading with file sharding
|
|
model_name = "torchao-testing/Qwen3-8B-INT4-0.15.0dev-safetensors"
|
|
with vllm_runner(model_name=model_name, dtype="bfloat16") as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
@pytest.mark.skip(
|
|
reason="since torchao nightly is only compatible with torch nightly"
|
|
"currently https://github.com/pytorch/ao/issues/2919, we'll have to skip "
|
|
"torchao tests that requires newer versions (0.14.0.dev+) for now"
|
|
)
|
|
def test_opt_125m_module_fqn_to_config_regex_model(vllm_runner):
|
|
torch._dynamo.reset()
|
|
model_name = "torchao-testing/opt-125m-ModuleFqnToConfig-v1-regex-0.14.0.dev"
|
|
with vllm_runner(
|
|
model_name=model_name, dtype="bfloat16", pt_load_map_location="cuda:0"
|
|
) as llm:
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
@pytest.mark.skip(
|
|
reason="since torchao nightly is only compatible with torch nightly"
|
|
"currently https://github.com/pytorch/ao/issues/2919, we'll have to skip "
|
|
"torchao tests that requires newer versions (0.14.0.dev+) for now"
|
|
)
|
|
def test_opt_125m_int4wo_model_running_preshuffled_kernel(vllm_runner, monkeypatch):
|
|
"""We load a model with Int4Tensor (plain format) linear weights
|
|
and verify that the weight is updated to Int4PreshuffledTensor
|
|
after loading in vllm
|
|
"""
|
|
from torchao.quantization import Int4PreshuffledTensor
|
|
from torchao.utils import _is_fbgemm_gpu_genai_available, is_sm_at_least_90
|
|
|
|
torch._dynamo.reset()
|
|
monkeypatch.setenv("VLLM_ALLOW_INSECURE_SERIALIZATION", "1")
|
|
model_name = "torchao-testing/opt-125m-Int4WeightOnlyConfig-v2-0.14.0.dev"
|
|
# Note: using enforce_eager=True because the `bf16i4bf16_shuffled` doesn't
|
|
# have meta kernel implemented yet, can remove this flag after that is implemented
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
quantization="torchao",
|
|
dtype="bfloat16",
|
|
pt_load_map_location="cuda:0",
|
|
enforce_eager=True,
|
|
) as llm:
|
|
|
|
def has_int4_preshuffled_tensor_weight(model):
|
|
return isinstance(
|
|
model.model.decoder.layers[0].self_attn.qkv_proj.weight,
|
|
Int4PreshuffledTensor,
|
|
)
|
|
|
|
def get_weight_attrs(model):
|
|
weight = model.model.decoder.layers[0].self_attn.qkv_proj.weight
|
|
return [
|
|
weight.requires_grad,
|
|
weight.input_dim,
|
|
weight.output_dim,
|
|
hasattr(weight, "weight_loader"),
|
|
]
|
|
|
|
llm_engine = llm.get_llm().llm_engine
|
|
has_int4_preshuffled_tensor = any(
|
|
llm_engine.apply_model(has_int4_preshuffled_tensor_weight)
|
|
)
|
|
weight_attrs = llm_engine.apply_model(get_weight_attrs)[0]
|
|
|
|
# making sure we are using Int4PreshuffledTensor on H100 GPU, when
|
|
# fbgemm_gpu_genai
|
|
# library is installed, otherwise it should be using Int4Tensor
|
|
if _is_fbgemm_gpu_genai_available() and is_sm_at_least_90():
|
|
assert has_int4_preshuffled_tensor
|
|
else:
|
|
assert not has_int4_preshuffled_tensor
|
|
|
|
assert weight_attrs == [False, 1, 0, True]
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=32)
|
|
|
|
assert output
|
|
|
|
|
|
@pytest.mark.skipif(not TORCHAO_AVAILABLE, reason="torchao is not available")
|
|
@pytest.mark.skip(
|
|
reason="since torchao nightly is only compatible with torch nightly"
|
|
"currently https://github.com/pytorch/ao/issues/2919, we'll have to skip "
|
|
"torchao tests that requires newer versions (0.14.0.dev+) for now"
|
|
)
|
|
def test_opt_125m_int4wo_model_running_preshuffled_kernel_online_quant(
|
|
vllm_runner, monkeypatch
|
|
):
|
|
"""We load a bf16 model and online quantize the model to int4, then verify that
|
|
the weights are updated to Int4PreshuffledTensor after online quantization
|
|
"""
|
|
from torchao.quantization import Int4PreshuffledTensor
|
|
from torchao.utils import _is_fbgemm_gpu_genai_available, is_sm_at_least_90
|
|
|
|
torch._dynamo.reset()
|
|
model_name = "facebook/opt-125m"
|
|
|
|
monkeypatch.setenv("VLLM_ALLOW_INSECURE_SERIALIZATION", "1")
|
|
|
|
import json
|
|
|
|
from torchao.core.config import config_to_dict
|
|
from torchao.quantization import Int4WeightOnlyConfig
|
|
|
|
torchao_quant_config = Int4WeightOnlyConfig(
|
|
group_size=128, int4_packing_format="plain"
|
|
)
|
|
hf_overrides = {
|
|
"quantization_config_dict_json": json.dumps(
|
|
config_to_dict(torchao_quant_config)
|
|
)
|
|
}
|
|
|
|
# Note: using enforce_eager=True because the `bf16i4bf16_shuffled` doesn't
|
|
# have meta kernel implemented yet, can remove this flag after that is implemented
|
|
with vllm_runner(
|
|
model_name=model_name,
|
|
quantization="torchao",
|
|
dtype="bfloat16",
|
|
pt_load_map_location="cuda:0",
|
|
hf_overrides=hf_overrides,
|
|
enforce_eager=True,
|
|
) as llm:
|
|
|
|
def has_int4_preshuffled_tensor_weight(model):
|
|
return isinstance(
|
|
model.model.decoder.layers[0].self_attn.qkv_proj.weight,
|
|
Int4PreshuffledTensor,
|
|
)
|
|
|
|
def get_weight_attrs(model):
|
|
weight = model.model.decoder.layers[0].self_attn.qkv_proj.weight
|
|
return [
|
|
weight.requires_grad,
|
|
weight.input_dim,
|
|
weight.output_dim,
|
|
hasattr(weight, "weight_loader"),
|
|
]
|
|
|
|
llm_engine = llm.get_llm().llm_engine
|
|
has_int4_preshuffled_tensor = any(
|
|
llm_engine.apply_model(has_int4_preshuffled_tensor_weight)
|
|
)
|
|
weight_attrs = llm_engine.apply_model(get_weight_attrs)[0]
|
|
|
|
# making sure we are using Int4PreshuffledTensor on H100 GPU, when
|
|
# fbgemm_gpu_genai
|
|
# library is installed, otherwise it should be using Int4Tensor
|
|
if _is_fbgemm_gpu_genai_available() and is_sm_at_least_90():
|
|
assert has_int4_preshuffled_tensor
|
|
else:
|
|
assert not has_int4_preshuffled_tensor
|
|
|
|
assert weight_attrs == [False, 1, 0, True]
|
|
output = llm.generate_greedy(["The capital of France is"], max_tokens=4)
|
|
|
|
assert output
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__])
|