Skip to content

Commit cc169ba

Browse files
CopilotDimaBir
andcommitted
Add Streamlit interface for benchmark application
Co-authored-by: DimaBir <28827735+DimaBir@users.noreply.github.com>
1 parent 6bf4a13 commit cc169ba

3 files changed

Lines changed: 336 additions & 1 deletion

File tree

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ readme = "README.md"
1010
requires-python = ">=3.12"
1111
license = {file = "LICENSE"}
1212
authors = [
13-
{name = "DimaBir", email = ""}
13+
{name = "DimaBir"}
1414
]
1515
keywords = ["pytorch", "tensorrt", "onnx", "openvino", "inference", "deep-learning"]
1616
classifiers = [
@@ -33,6 +33,7 @@ dependencies = [
3333
"openvino>=2024.5.0",
3434
"seaborn>=0.13.0",
3535
"matplotlib>=3.8.0",
36+
"streamlit>=1.41.0",
3637
]
3738

3839
[project.optional-dependencies]

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ seaborn>=0.13.0
1010
matplotlib>=3.8.0
1111
pytest>=8.0.0
1212
pytest-cov>=4.1.0
13+
streamlit>=1.41.0

streamlit_app.py

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
"""
2+
Streamlit interface for ResNet TensorRT benchmark application.
3+
4+
This app provides a user-friendly web interface to:
5+
- Upload or select images for inference
6+
- Configure benchmark parameters
7+
- Run inference across different backends (PyTorch, ONNX, OpenVINO, TensorRT)
8+
- Display predictions and benchmark results
9+
"""
10+
11+
import os
12+
import tempfile
13+
from pathlib import Path
14+
15+
import streamlit as st
16+
import torch
17+
from PIL import Image
18+
19+
from common.utils import (
20+
DEFAULT_IMAGE_PATH,
21+
DEFAULT_ONNX_PATH,
22+
DEFAULT_OV_PATH,
23+
DEFAULT_TOPK,
24+
INFERENCE_MODES,
25+
)
26+
from src.image_processor import ImageProcessor
27+
from src.model import ModelLoader
28+
from src.onnx_inference import ONNXInference
29+
from src.ov_inference import OVInference
30+
from src.pytorch_inference import PyTorchInference
31+
32+
# Check CUDA availability
33+
CUDA_AVAILABLE = torch.cuda.is_available()
34+
if CUDA_AVAILABLE:
35+
try:
36+
import torch_tensorrt # noqa: F401
37+
from src.tensorrt_inference import TensorRTInference
38+
except ImportError:
39+
CUDA_AVAILABLE = False
40+
st.warning("torch-tensorrt not installed. TensorRT and CUDA modes will be unavailable.")
41+
42+
43+
def display_image(image_path: str):
44+
"""Display the input image."""
45+
img = Image.open(image_path)
46+
st.image(img, caption="Input Image", use_container_width=True)
47+
48+
49+
def run_inference(
50+
image_path: str,
51+
mode: str,
52+
topk: int,
53+
onnx_path: str,
54+
ov_path: str,
55+
debug_mode: bool = False,
56+
) -> dict[str, tuple[float, float]]:
57+
"""
58+
Run inference based on selected mode.
59+
60+
Args:
61+
image_path: Path to input image
62+
mode: Inference mode (onnx, ov, cpu, cuda, tensorrt, all)
63+
topk: Number of top predictions to show
64+
onnx_path: Path to ONNX model
65+
ov_path: Path to OpenVINO model
66+
debug_mode: Enable debug logging
67+
68+
Returns:
69+
Dictionary of benchmark results {model_name: (avg_time_ms, throughput)}
70+
"""
71+
benchmark_results = {}
72+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
73+
74+
# Load model and process image
75+
model_loader = ModelLoader(device=device)
76+
img_processor = ImageProcessor(img_path=image_path, device=device)
77+
img_batch = img_processor.process_image()
78+
79+
# Create a placeholder for predictions
80+
predictions_placeholder = st.empty()
81+
82+
# ONNX inference
83+
if mode in ["onnx", "all"]:
84+
with st.spinner("Running ONNX inference..."):
85+
onnx_inference = ONNXInference(model_loader, onnx_path, debug_mode=debug_mode)
86+
benchmark_result = onnx_inference.benchmark(img_batch)
87+
predictions = onnx_inference.predict(img_batch)
88+
benchmark_results["ONNX (CPU)"] = benchmark_result
89+
90+
if predictions is not None:
91+
display_predictions(predictions, model_loader.categories, topk, "ONNX (CPU)")
92+
93+
# OpenVINO inference
94+
if mode in ["ov", "all"]:
95+
with st.spinner("Running OpenVINO inference..."):
96+
ov_inference = OVInference(model_loader, ov_path, debug_mode=debug_mode)
97+
benchmark_result = ov_inference.benchmark(img_batch)
98+
predictions = ov_inference.predict(img_batch)
99+
benchmark_results["OpenVINO (CPU)"] = benchmark_result
100+
101+
if predictions is not None:
102+
display_predictions(predictions, model_loader.categories, topk, "OpenVINO (CPU)")
103+
104+
# PyTorch CPU inference
105+
if mode in ["cpu", "all"]:
106+
with st.spinner("Running PyTorch CPU inference..."):
107+
pytorch_cpu_inference = PyTorchInference(
108+
model_loader, device="cpu", debug_mode=debug_mode
109+
)
110+
benchmark_result = pytorch_cpu_inference.benchmark(img_batch)
111+
predictions = pytorch_cpu_inference.predict(img_batch)
112+
benchmark_results["PyTorch (CPU)"] = benchmark_result
113+
114+
if predictions is not None:
115+
display_predictions(predictions, model_loader.categories, topk, "PyTorch (CPU)")
116+
117+
# CUDA and TensorRT inference (only if CUDA available)
118+
if CUDA_AVAILABLE:
119+
# PyTorch CUDA inference
120+
if mode in ["cuda", "all"]:
121+
with st.spinner("Running PyTorch CUDA inference..."):
122+
pytorch_cuda_inference = PyTorchInference(
123+
model_loader, device=device, debug_mode=debug_mode
124+
)
125+
benchmark_result = pytorch_cuda_inference.benchmark(img_batch)
126+
predictions = pytorch_cuda_inference.predict(img_batch)
127+
benchmark_results["PyTorch (CUDA)"] = benchmark_result
128+
129+
if predictions is not None:
130+
display_predictions(
131+
predictions, model_loader.categories, topk, "PyTorch (CUDA)"
132+
)
133+
134+
# TensorRT inference
135+
if mode in ["tensorrt", "all"]:
136+
precisions = [torch.float16, torch.float32]
137+
for precision in precisions:
138+
precision_name = "FP16" if precision == torch.float16 else "FP32"
139+
with st.spinner(f"Running TensorRT {precision_name} inference..."):
140+
tensorrt_inference = TensorRTInference(
141+
model_loader, device=device, precision=precision, debug_mode=debug_mode
142+
)
143+
benchmark_result = tensorrt_inference.benchmark(img_batch)
144+
predictions = tensorrt_inference.predict(img_batch)
145+
benchmark_results[f"TRT_{precision}"] = benchmark_result
146+
147+
if predictions is not None:
148+
display_predictions(
149+
predictions, model_loader.categories, topk, f"TensorRT {precision_name}"
150+
)
151+
152+
return benchmark_results
153+
154+
155+
def display_predictions(prob, categories, topk: int, model_name: str):
156+
"""Display top-k predictions."""
157+
top_indices = prob.argsort()[-topk:][::-1]
158+
top_probs = prob[top_indices]
159+
160+
st.subheader(f"Predictions - {model_name}")
161+
for i in range(topk):
162+
probability = top_probs[i]
163+
class_label = categories[0][int(top_indices[i])]
164+
st.write(f"#{i + 1}: {int(probability * 100)}% {class_label}")
165+
166+
167+
def display_benchmark_results(results: dict[str, tuple[float, float]]):
168+
"""Display benchmark results in a table."""
169+
st.subheader("Benchmark Results")
170+
171+
# Create DataFrame for display
172+
import pandas as pd
173+
174+
data = {
175+
"Model": list(results.keys()),
176+
"Avg Time (ms)": [f"{results[model][0]:.2f}" for model in results.keys()],
177+
"Throughput (samples/sec)": [f"{results[model][1]:.2f}" for model in results.keys()],
178+
}
179+
df = pd.DataFrame(data)
180+
181+
st.dataframe(df, use_container_width=True)
182+
183+
# Display metrics in columns
184+
cols = st.columns(len(results))
185+
for idx, (model, (avg_time, throughput)) in enumerate(results.items()):
186+
with cols[idx]:
187+
st.metric(label=model, value=f"{avg_time:.2f} ms", delta=f"{throughput:.1f} img/s")
188+
189+
190+
def main():
191+
st.set_page_config(
192+
page_title="ResNet TensorRT Benchmark",
193+
page_icon="🚀",
194+
layout="wide",
195+
initial_sidebar_state="expanded",
196+
)
197+
198+
st.title("🚀 ResNet TensorRT Benchmark Interface")
199+
st.markdown(
200+
"""
201+
This application provides a user-friendly interface to benchmark ResNet inference
202+
across different backends: PyTorch (CPU/CUDA), ONNX, OpenVINO, and TensorRT.
203+
"""
204+
)
205+
206+
# Sidebar configuration
207+
st.sidebar.header("⚙️ Configuration")
208+
209+
# Image selection/upload
210+
st.sidebar.subheader("Image Input")
211+
image_source = st.sidebar.radio("Select image source:", ["Sample Images", "Upload Image"])
212+
213+
image_path = None
214+
if image_source == "Sample Images":
215+
sample_images = []
216+
inference_dir = Path("./inference")
217+
if inference_dir.exists():
218+
sample_images = [str(f) for f in inference_dir.glob("*.jpg")] + [
219+
str(f) for f in inference_dir.glob("*.png")
220+
]
221+
222+
if sample_images:
223+
selected_image = st.sidebar.selectbox("Choose a sample image:", sample_images)
224+
image_path = selected_image
225+
else:
226+
st.sidebar.warning("No sample images found in ./inference directory")
227+
image_path = DEFAULT_IMAGE_PATH
228+
else:
229+
uploaded_file = st.sidebar.file_uploader("Upload an image", type=["jpg", "jpeg", "png"])
230+
if uploaded_file is not None:
231+
# Save uploaded file to temporary location
232+
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as tmp_file:
233+
tmp_file.write(uploaded_file.read())
234+
image_path = tmp_file.name
235+
236+
# Inference mode selection
237+
st.sidebar.subheader("Inference Settings")
238+
239+
# Filter available modes based on CUDA availability
240+
available_modes = INFERENCE_MODES.copy()
241+
if not CUDA_AVAILABLE:
242+
available_modes = [m for m in available_modes if m not in ["cuda", "tensorrt"]]
243+
st.sidebar.info("CUDA/TensorRT modes unavailable (GPU not detected)")
244+
245+
mode = st.sidebar.selectbox(
246+
"Select inference mode:",
247+
available_modes,
248+
index=available_modes.index("all") if "all" in available_modes else 0,
249+
help="Choose which inference backend(s) to benchmark",
250+
)
251+
252+
topk = st.sidebar.slider(
253+
"Top-K predictions:",
254+
min_value=1,
255+
max_value=10,
256+
value=DEFAULT_TOPK,
257+
help="Number of top predictions to display",
258+
)
259+
260+
# Advanced settings
261+
with st.sidebar.expander("Advanced Settings"):
262+
onnx_path = st.text_input("ONNX model path:", value=DEFAULT_ONNX_PATH)
263+
ov_path = st.text_input("OpenVINO model path:", value=DEFAULT_OV_PATH)
264+
debug_mode = st.checkbox("Enable debug mode", value=False)
265+
266+
# Main content
267+
col1, col2 = st.columns([1, 2])
268+
269+
with col1:
270+
st.subheader("Input Image")
271+
if image_path and os.path.exists(image_path):
272+
display_image(image_path)
273+
else:
274+
st.warning("Please select or upload an image to proceed")
275+
276+
with col2:
277+
st.subheader("Actions")
278+
279+
# System info
280+
with st.expander("System Information"):
281+
st.write(f"**Device:** {'CUDA (GPU)' if CUDA_AVAILABLE else 'CPU'}")
282+
if CUDA_AVAILABLE:
283+
st.write(f"**GPU Name:** {torch.cuda.get_device_name(0)}")
284+
st.write(f"**PyTorch Version:** {torch.__version__}")
285+
286+
# Run benchmark button
287+
if st.button("▶️ Run Benchmark", type="primary", use_container_width=True):
288+
if image_path and os.path.exists(image_path):
289+
try:
290+
st.info(f"Running benchmark with mode: **{mode}**")
291+
292+
# Run inference and get results
293+
results = run_inference(
294+
image_path=image_path,
295+
mode=mode,
296+
topk=topk,
297+
onnx_path=onnx_path,
298+
ov_path=ov_path,
299+
debug_mode=debug_mode,
300+
)
301+
302+
# Display results
303+
st.success("Benchmark completed!")
304+
display_benchmark_results(results)
305+
306+
# Clean up temporary file if uploaded
307+
if image_source == "Upload Image" and image_path.startswith("/tmp"):
308+
try:
309+
os.unlink(image_path)
310+
except Exception:
311+
pass
312+
313+
except Exception as e:
314+
st.error(f"Error during benchmark: {str(e)}")
315+
st.exception(e)
316+
else:
317+
st.error("Please select or upload a valid image first!")
318+
319+
# Footer
320+
st.markdown("---")
321+
st.markdown(
322+
"""
323+
<div style='text-align: center'>
324+
<p>Built with ❤️ using Streamlit |
325+
<a href='https://github.com/DimaBir/ResNetTensorRT'>GitHub Repository</a></p>
326+
</div>
327+
""",
328+
unsafe_allow_html=True,
329+
)
330+
331+
332+
if __name__ == "__main__":
333+
main()

0 commit comments

Comments
 (0)