2025-09-18 23:22:01 +08:00
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
2026-01-26 23:26:48 -06:00
|
|
|
import random
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
2025-09-18 23:22:01 +08:00
|
|
|
import pytest
|
|
|
|
|
import torch
|
|
|
|
|
from transformers import AutoModelForTokenClassification
|
|
|
|
|
|
|
|
|
|
from tests.models.utils import softmax
|
2026-01-08 22:04:33 -06:00
|
|
|
from vllm.platforms import current_platform
|
2025-09-18 23:22:01 +08:00
|
|
|
|
|
|
|
|
|
2026-01-26 23:26:48 -06:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
|
def seed_everything():
|
|
|
|
|
"""Seed all random number generators for reproducibility."""
|
|
|
|
|
seed = 0
|
|
|
|
|
random.seed(seed)
|
|
|
|
|
np.random.seed(seed)
|
|
|
|
|
torch.manual_seed(seed)
|
|
|
|
|
if torch.cuda.is_available():
|
|
|
|
|
torch.cuda.manual_seed_all(seed)
|
|
|
|
|
torch.backends.cudnn.deterministic = True
|
|
|
|
|
torch.backends.cudnn.benchmark = False
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
|
|
2026-03-13 11:23:53 +08:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
"model",
|
|
|
|
|
[
|
|
|
|
|
"boltuix/NeuroBERT-NER",
|
|
|
|
|
"gyr66/Ernie-3.0-base-chinese-finetuned-ner",
|
|
|
|
|
],
|
|
|
|
|
)
|
2025-09-18 23:22:01 +08:00
|
|
|
# The float32 is required for this tiny model to pass the test.
|
|
|
|
|
@pytest.mark.parametrize("dtype", ["float"])
|
|
|
|
|
@torch.inference_mode
|
2026-03-13 11:23:53 +08:00
|
|
|
def test_bert_like_models(
|
2025-10-07 16:29:19 +02:00
|
|
|
hf_runner,
|
|
|
|
|
vllm_runner,
|
|
|
|
|
example_prompts,
|
|
|
|
|
model: str,
|
|
|
|
|
dtype: str,
|
|
|
|
|
) -> None:
|
|
|
|
|
with vllm_runner(model, max_model_len=None, dtype=dtype) as vllm_model:
|
2025-10-15 19:14:41 +08:00
|
|
|
vllm_outputs = vllm_model.token_classify(example_prompts)
|
2025-10-07 16:29:19 +02:00
|
|
|
|
2026-01-08 22:04:33 -06:00
|
|
|
# Use eager attention on ROCm to avoid HF Transformers flash attention
|
|
|
|
|
# accuracy issues: https://github.com/vllm-project/vllm/issues/30167
|
|
|
|
|
hf_model_kwargs = {}
|
|
|
|
|
if current_platform.is_rocm():
|
|
|
|
|
hf_model_kwargs["attn_implementation"] = "eager"
|
|
|
|
|
|
2025-10-07 16:29:19 +02:00
|
|
|
with hf_runner(
|
2026-01-08 22:04:33 -06:00
|
|
|
model,
|
|
|
|
|
dtype=dtype,
|
|
|
|
|
auto_cls=AutoModelForTokenClassification,
|
|
|
|
|
model_kwargs=hf_model_kwargs,
|
2025-10-07 16:29:19 +02:00
|
|
|
) as hf_model:
|
|
|
|
|
tokenizer = hf_model.tokenizer
|
|
|
|
|
hf_outputs = []
|
|
|
|
|
for prompt in example_prompts:
|
|
|
|
|
inputs = tokenizer([prompt], return_tensors="pt")
|
|
|
|
|
inputs = hf_model.wrap_device(inputs)
|
|
|
|
|
output = hf_model.model(**inputs)
|
|
|
|
|
hf_outputs.append(softmax(output.logits[0]))
|
|
|
|
|
|
|
|
|
|
# check logits difference
|
|
|
|
|
for hf_output, vllm_output in zip(hf_outputs, vllm_outputs):
|
2026-01-01 22:19:08 -06:00
|
|
|
hf_output = hf_output.detach().clone().cpu().float()
|
|
|
|
|
vllm_output = vllm_output.detach().clone().cpu().float()
|
2026-01-18 12:19:59 +08:00
|
|
|
torch.testing.assert_close(hf_output, vllm_output, atol=3.2e-2, rtol=1e-3)
|
2025-10-07 16:29:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("model", ["disham993/electrical-ner-ModernBERT-base"])
|
|
|
|
|
@pytest.mark.parametrize("dtype", ["float"])
|
2026-01-26 23:26:48 -06:00
|
|
|
@pytest.mark.flaky(reruns=3)
|
2025-10-07 16:29:19 +02:00
|
|
|
@torch.inference_mode
|
|
|
|
|
def test_modernbert_models(
|
2025-09-18 23:22:01 +08:00
|
|
|
hf_runner,
|
|
|
|
|
vllm_runner,
|
|
|
|
|
example_prompts,
|
|
|
|
|
model: str,
|
|
|
|
|
dtype: str,
|
|
|
|
|
) -> None:
|
2026-01-26 23:26:48 -06:00
|
|
|
# NOTE: https://github.com/vllm-project/vllm/pull/32403
|
|
|
|
|
# `disham993/electrical-ner-ModernBERT-base` is a randomly initialized
|
|
|
|
|
# model, which can cause numerical precision variance and edge cases.
|
|
|
|
|
# We use @flaky(reruns=3) to mitigate intermittent failures.
|
|
|
|
|
print(
|
|
|
|
|
f"\n[NOTE] Testing {model} (randomly initialized weights) - "
|
|
|
|
|
"flaky tolerance enabled due to numerical precision variance."
|
|
|
|
|
)
|
|
|
|
|
|
2025-09-18 23:22:01 +08:00
|
|
|
with vllm_runner(model, max_model_len=None, dtype=dtype) as vllm_model:
|
2025-10-15 19:14:41 +08:00
|
|
|
vllm_outputs = vllm_model.token_classify(example_prompts)
|
2025-09-18 23:22:01 +08:00
|
|
|
|
2026-01-01 22:19:08 -06:00
|
|
|
# Use eager attention on ROCm to avoid HF Transformers flash attention
|
|
|
|
|
# accuracy issues: https://github.com/vllm-project/vllm/issues/30167
|
|
|
|
|
hf_model_kwargs = {}
|
|
|
|
|
if current_platform.is_rocm():
|
|
|
|
|
hf_model_kwargs["attn_implementation"] = "eager"
|
|
|
|
|
|
2025-09-18 23:22:01 +08:00
|
|
|
with hf_runner(
|
2026-01-01 22:19:08 -06:00
|
|
|
model,
|
|
|
|
|
dtype=dtype,
|
|
|
|
|
auto_cls=AutoModelForTokenClassification,
|
|
|
|
|
model_kwargs=hf_model_kwargs,
|
2025-09-18 23:22:01 +08:00
|
|
|
) as hf_model:
|
|
|
|
|
tokenizer = hf_model.tokenizer
|
|
|
|
|
hf_outputs = []
|
|
|
|
|
for prompt in example_prompts:
|
|
|
|
|
inputs = tokenizer([prompt], return_tensors="pt")
|
|
|
|
|
inputs = hf_model.wrap_device(inputs)
|
|
|
|
|
output = hf_model.model(**inputs)
|
|
|
|
|
hf_outputs.append(softmax(output.logits[0]))
|
|
|
|
|
|
|
|
|
|
# check logits difference
|
|
|
|
|
for hf_output, vllm_output in zip(hf_outputs, vllm_outputs):
|
2026-01-01 22:19:08 -06:00
|
|
|
hf_output = hf_output.detach().clone().cpu().float()
|
|
|
|
|
vllm_output = vllm_output.detach().clone().cpu().float()
|
2026-01-18 12:19:59 +08:00
|
|
|
torch.testing.assert_close(hf_output, vllm_output, atol=3.2e-2, rtol=1e-3)
|
2025-12-15 16:13:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("model", ["bd2lcco/Qwen3-0.6B-finetuned"])
|
|
|
|
|
@pytest.mark.parametrize("dtype", ["float"])
|
|
|
|
|
@torch.inference_mode
|
|
|
|
|
def test_auto_conversion(
|
|
|
|
|
hf_runner,
|
|
|
|
|
vllm_runner,
|
|
|
|
|
example_prompts,
|
|
|
|
|
model: str,
|
|
|
|
|
dtype: str,
|
|
|
|
|
) -> None:
|
|
|
|
|
with vllm_runner(model, max_model_len=1024, dtype=dtype) as vllm_model:
|
|
|
|
|
vllm_outputs = vllm_model.token_classify(example_prompts)
|
|
|
|
|
|
|
|
|
|
with hf_runner(
|
|
|
|
|
model, dtype=dtype, auto_cls=AutoModelForTokenClassification
|
|
|
|
|
) as hf_model:
|
|
|
|
|
tokenizer = hf_model.tokenizer
|
|
|
|
|
hf_outputs = []
|
|
|
|
|
for prompt in example_prompts:
|
|
|
|
|
inputs = tokenizer([prompt], return_tensors="pt")
|
|
|
|
|
inputs = hf_model.wrap_device(inputs)
|
|
|
|
|
output = hf_model.model(**inputs)
|
|
|
|
|
hf_outputs.append(softmax(output.logits[0]))
|
|
|
|
|
|
|
|
|
|
# check logits difference
|
|
|
|
|
for hf_output, vllm_output in zip(hf_outputs, vllm_outputs):
|
2026-01-01 22:19:08 -06:00
|
|
|
hf_output = hf_output.detach().clone().cpu().float()
|
|
|
|
|
vllm_output = vllm_output.detach().clone().cpu().float()
|
2025-12-15 16:13:00 +08:00
|
|
|
assert torch.allclose(hf_output, vllm_output, atol=1e-2)
|