[CI fix] Fix image download failures in VLM CI tests (#13613)

This commit is contained in:
Xiaoyu Zhang
2025-11-20 11:18:06 +08:00
committed by GitHub
parent 48ca9f7518
commit dc69462456
4 changed files with 24 additions and 14 deletions
+18
View File
@@ -16,6 +16,7 @@ import unittest
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from datetime import datetime from datetime import datetime
from functools import partial, wraps from functools import partial, wraps
from io import BytesIO
from pathlib import Path from pathlib import Path
from types import SimpleNamespace from types import SimpleNamespace
from typing import Any, Awaitable, Callable, List, Optional, Tuple from typing import Any, Awaitable, Callable, List, Optional, Tuple
@@ -25,6 +26,7 @@ import numpy as np
import requests import requests
import torch import torch
import torch.nn.functional as F import torch.nn.functional as F
from PIL import Image
from sglang.bench_serving import run_benchmark from sglang.bench_serving import run_benchmark
from sglang.global_config import global_config from sglang.global_config import global_config
@@ -129,6 +131,22 @@ DEFAULT_VIDEO_URL = "https://raw.githubusercontent.com/EvolvingLMMs-Lab/sglang/d
DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH = 600 DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH = 600
def download_image_with_retry(image_url: str, max_retries: int = 3) -> Image.Image:
for i in range(max_retries):
try:
response = requests.get(image_url, timeout=30)
response.raise_for_status()
image = Image.open(BytesIO(response.content))
image.load()
return image
except Exception as e:
if i == max_retries - 1:
raise RuntimeError(
f"Failed to download image after {max_retries} retries: {image_url}"
) from e
time.sleep(2**i)
def is_in_ci(): def is_in_ci():
"""Return whether it is in CI runner.""" """Return whether it is in CI runner."""
return get_bool_env_var("SGLANG_IS_IN_CI") return get_bool_env_var("SGLANG_IS_IN_CI")
+2 -4
View File
@@ -5,10 +5,8 @@ python3 -m unittest test_skip_tokenizer_init.TestSkipTokenizerInit.run_decode_st
import json import json
import unittest import unittest
from io import BytesIO
import requests import requests
from PIL import Image
from transformers import AutoProcessor, AutoTokenizer from transformers import AutoProcessor, AutoTokenizer
from sglang.lang.chat_template import get_chat_template_by_model_path from sglang.lang.chat_template import get_chat_template_by_model_path
@@ -20,6 +18,7 @@ from sglang.test.test_utils import (
DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH, DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
DEFAULT_URL_FOR_TEST, DEFAULT_URL_FOR_TEST,
CustomTestCase, CustomTestCase,
download_image_with_retry,
popen_launch_server, popen_launch_server,
) )
@@ -204,8 +203,7 @@ class TestSkipTokenizerInitVLM(TestSkipTokenizerInit):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.image_url = DEFAULT_IMAGE_URL cls.image_url = DEFAULT_IMAGE_URL
response = requests.get(cls.image_url) cls.image = download_image_with_retry(cls.image_url)
cls.image = Image.open(BytesIO(response.content))
cls.model = DEFAULT_SMALL_VLM_MODEL_NAME_FOR_TEST cls.model = DEFAULT_SMALL_VLM_MODEL_NAME_FOR_TEST
cls.tokenizer = AutoTokenizer.from_pretrained(cls.model, use_fast=False) cls.tokenizer = AutoTokenizer.from_pretrained(cls.model, use_fast=False)
cls.processor = AutoProcessor.from_pretrained(cls.model, trust_remote_code=True) cls.processor = AutoProcessor.from_pretrained(cls.model, trust_remote_code=True)
+2 -5
View File
@@ -2,14 +2,11 @@
""" """
import unittest import unittest
from io import BytesIO
from typing import List, Optional from typing import List, Optional
import numpy as np import numpy as np
import requests
import torch import torch
import torch.nn.functional as F import torch.nn.functional as F
from PIL import Image
from transformers import AutoModel, AutoProcessor, AutoTokenizer from transformers import AutoModel, AutoProcessor, AutoTokenizer
from sglang.srt.configs.model_config import ModelConfig from sglang.srt.configs.model_config import ModelConfig
@@ -24,6 +21,7 @@ from sglang.srt.model_executor.model_runner import ModelRunner
from sglang.srt.multimodal.processors.base_processor import BaseMultimodalProcessor from sglang.srt.multimodal.processors.base_processor import BaseMultimodalProcessor
from sglang.srt.parser.conversation import generate_chat_conv from sglang.srt.parser.conversation import generate_chat_conv
from sglang.srt.server_args import ServerArgs from sglang.srt.server_args import ServerArgs
from sglang.test.test_utils import download_image_with_retry
# Test the logits output between HF and SGLang # Test the logits output between HF and SGLang
@@ -35,8 +33,7 @@ class VisionLLMLogitsBase(unittest.IsolatedAsyncioTestCase):
cls.model_path = "" cls.model_path = ""
cls.chat_template = "" cls.chat_template = ""
cls.processor = "" cls.processor = ""
response = requests.get(cls.image_url) cls.main_image = download_image_with_retry(cls.image_url)
cls.main_image = Image.open(BytesIO(response.content))
def compare_outputs(self, sglang_output: torch.Tensor, hf_output: torch.Tensor): def compare_outputs(self, sglang_output: torch.Tensor, hf_output: torch.Tensor):
# Convert to float32 for numerical stability if needed # Convert to float32 for numerical stability if needed
+2 -5
View File
@@ -1,11 +1,8 @@
import json import json
import unittest import unittest
from io import BytesIO
from typing import Optional from typing import Optional
import requests
import torch import torch
from PIL import Image
from transformers import ( from transformers import (
AutoProcessor, AutoProcessor,
Gemma3ForConditionalGeneration, Gemma3ForConditionalGeneration,
@@ -15,6 +12,7 @@ from transformers import (
from sglang import Engine from sglang import Engine
from sglang.srt.entrypoints.openai.protocol import ChatCompletionRequest from sglang.srt.entrypoints.openai.protocol import ChatCompletionRequest
from sglang.srt.parser.conversation import generate_chat_conv from sglang.srt.parser.conversation import generate_chat_conv
from sglang.test.test_utils import download_image_with_retry
TEST_IMAGE_URL = "https://github.com/sgl-project/sglang/blob/main/examples/assets/example_image.png?raw=true" TEST_IMAGE_URL = "https://github.com/sgl-project/sglang/blob/main/examples/assets/example_image.png?raw=true"
@@ -31,8 +29,7 @@ class VLMInputTestBase:
assert cls.chat_template is not None, "Set chat_template in subclass" assert cls.chat_template is not None, "Set chat_template in subclass"
cls.image_url = TEST_IMAGE_URL cls.image_url = TEST_IMAGE_URL
cls.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") cls.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
response = requests.get(cls.image_url) cls.main_image = download_image_with_retry(cls.image_url)
cls.main_image = Image.open(BytesIO(response.content))
cls.processor = AutoProcessor.from_pretrained( cls.processor = AutoProcessor.from_pretrained(
cls.model_path, trust_remote_code=True, use_fast=True cls.model_path, trust_remote_code=True, use_fast=True
) )