148 lines
5.8 KiB
Python
148 lines
5.8 KiB
Python
"""Run smoke tests"""
|
|
|
|
import os
|
|
import sys
|
|
import sysconfig
|
|
from pathlib import Path
|
|
|
|
import torch
|
|
import torchvision
|
|
from torchvision.io import decode_avif, decode_heic, decode_image, decode_jpeg, read_file
|
|
from torchvision.models import resnet50, ResNet50_Weights
|
|
|
|
|
|
SCRIPT_DIR = Path(__file__).parent
|
|
|
|
|
|
def smoke_test_torchvision() -> None:
|
|
print(
|
|
"Is torchvision usable?",
|
|
all(x is not None for x in [torch.ops.image.decode_png, torch.ops.torchvision.roi_align]),
|
|
)
|
|
|
|
|
|
def smoke_test_torchvision_read_decode() -> None:
|
|
img_jpg = decode_image(str(SCRIPT_DIR / "assets" / "encode_jpeg" / "grace_hopper_517x606.jpg"))
|
|
if img_jpg.shape != (3, 606, 517):
|
|
raise RuntimeError(f"Unexpected shape of img_jpg: {img_jpg.shape}")
|
|
|
|
img_png = decode_image(str(SCRIPT_DIR / "assets" / "interlaced_png" / "wizard_low.png"))
|
|
if img_png.shape != (4, 471, 354):
|
|
raise RuntimeError(f"Unexpected shape of img_png: {img_png.shape}")
|
|
|
|
img_webp = decode_image(str(SCRIPT_DIR / "assets/fakedata/logos/rgb_pytorch.webp"))
|
|
if img_webp.shape != (3, 100, 100):
|
|
raise RuntimeError(f"Unexpected shape of img_webp: {img_webp.shape}")
|
|
|
|
if sys.platform == "linux":
|
|
pass
|
|
# TODO: Fix/uncomment below (the TODO below is mostly accurate but we're
|
|
# still observing some failures on some CUDA jobs. Most are working.)
|
|
# if torch.cuda.is_available():
|
|
# # TODO: For whatever reason this only passes on the runners that
|
|
# # support CUDA.
|
|
# # Strangely, on the CPU runners where this fails, the AVIF/HEIC
|
|
# # tests (ran with pytest) are passing. This is likely related to a
|
|
# # libcxx symbol thing, and the proper libstdc++.so get loaded only
|
|
# # with pytest? Ugh.
|
|
# img_avif = decode_avif(read_file(str(SCRIPT_DIR / "assets/fakedata/logos/rgb_pytorch.avif")))
|
|
# if img_avif.shape != (3, 100, 100):
|
|
# raise RuntimeError(f"Unexpected shape of img_avif: {img_avif.shape}")
|
|
|
|
# img_heic = decode_heic(
|
|
# read_file(str(SCRIPT_DIR / "assets/fakedata/logos/rgb_pytorch_incorrectly_encoded_but_who_cares.heic"))
|
|
# )
|
|
# if img_heic.shape != (3, 100, 100):
|
|
# raise RuntimeError(f"Unexpected shape of img_heic: {img_heic.shape}")
|
|
else:
|
|
try:
|
|
decode_avif(str(SCRIPT_DIR / "assets/fakedata/logos/rgb_pytorch.avif"))
|
|
except RuntimeError as e:
|
|
assert "torchvision-extra-decoders" in str(e)
|
|
|
|
try:
|
|
decode_heic(str(SCRIPT_DIR / "assets/fakedata/logos/rgb_pytorch_incorrectly_encoded_but_who_cares.heic"))
|
|
except RuntimeError as e:
|
|
assert "torchvision-extra-decoders" in str(e)
|
|
|
|
|
|
def smoke_test_torchvision_decode_jpeg(device: str = "cpu"):
|
|
img_jpg_data = read_file(str(SCRIPT_DIR / "assets" / "encode_jpeg" / "grace_hopper_517x606.jpg"))
|
|
img_jpg = decode_jpeg(img_jpg_data, device=device)
|
|
if img_jpg.shape != (3, 606, 517):
|
|
raise RuntimeError(f"Unexpected shape of img_jpg: {img_jpg.shape}")
|
|
|
|
|
|
def smoke_test_compile() -> None:
|
|
try:
|
|
model = resnet50().cuda()
|
|
model = torch.compile(model)
|
|
x = torch.randn(1, 3, 224, 224, device="cuda")
|
|
out = model(x)
|
|
print(f"torch.compile model output: {out.shape}")
|
|
except RuntimeError:
|
|
if sys.platform == "win32":
|
|
print("Successfully caught torch.compile RuntimeError on win")
|
|
else:
|
|
raise
|
|
|
|
|
|
def smoke_test_torchvision_resnet50_classify(device: str = "cpu") -> None:
|
|
img = decode_image(str(SCRIPT_DIR / ".." / "gallery" / "assets" / "dog2.jpg")).to(device)
|
|
|
|
# Step 1: Initialize model with the best available weights
|
|
weights = ResNet50_Weights.DEFAULT
|
|
model = resnet50(weights=weights, progress=False).to(device)
|
|
model.eval()
|
|
|
|
# Step 2: Initialize the inference transforms
|
|
preprocess = weights.transforms(antialias=True)
|
|
|
|
# Step 3: Apply inference preprocessing transforms
|
|
batch = preprocess(img).unsqueeze(0)
|
|
|
|
# Step 4: Use the model and print the predicted category
|
|
prediction = model(batch).squeeze(0).softmax(0)
|
|
class_id = prediction.argmax().item()
|
|
score = prediction[class_id].item()
|
|
category_name = weights.meta["categories"][class_id]
|
|
expected_category = "German shepherd"
|
|
print(f"{category_name} ({device}): {100 * score:.1f}%")
|
|
if category_name != expected_category:
|
|
raise RuntimeError(f"Failed ResNet50 classify {category_name} Expected: {expected_category}")
|
|
|
|
|
|
def main() -> None:
|
|
print(f"torchvision: {torchvision.__version__}")
|
|
print(f"torch.cuda.is_available: {torch.cuda.is_available()}")
|
|
|
|
print(f"{torch.ops.image._jpeg_version() = }")
|
|
if not torch.ops.image._is_compiled_against_turbo():
|
|
msg = "Torchvision wasn't compiled against libjpeg-turbo"
|
|
if os.getenv("IS_M1_CONDA_BUILD_JOB") == "1":
|
|
# When building the conda package on M1, it's difficult to enforce
|
|
# that we build against turbo due to interactions with the libwebp
|
|
# package. So we just accept it, instead of raising an error.
|
|
print(msg)
|
|
else:
|
|
raise ValueError(msg)
|
|
|
|
smoke_test_torchvision()
|
|
smoke_test_torchvision_read_decode()
|
|
smoke_test_torchvision_resnet50_classify()
|
|
smoke_test_torchvision_decode_jpeg()
|
|
if torch.cuda.is_available():
|
|
smoke_test_torchvision_decode_jpeg("cuda")
|
|
smoke_test_torchvision_resnet50_classify("cuda")
|
|
|
|
# torch.compile is not supported on Python 3.14+ and Python built with GIL disabled
|
|
if sys.version_info < (3, 14, 0) and not sysconfig.get_config_var("Py_GIL_DISABLED"):
|
|
smoke_test_compile()
|
|
|
|
if torch.backends.mps.is_available():
|
|
smoke_test_torchvision_resnet50_classify("mps")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|