ds5110-lazy-loading / lazyloading_model.py
natalieseah's picture
Update lazyloading_model.py
27eb67e verified
Raw
History Blame Contribute Delete
3.3 kB
import time
import hashlib
import spaces
import torch
from PIL import Image
from transformers import BlipProcessor, BlipForConditionalGeneration
MODEL_NAME = "Salesforce/blip-image-captioning-base"
# LAZY: not loaded at startup. These stay None until the first request, then
# live in the MAIN (CPU) process so they persist across later requests.
# Only run_inference runs in the stateless GPU process.
processor = None
model = None
caption_cache = {}
def load_model():
"""Load the model on first use (CPU, main process) and reuse it after."""
global processor, model
start_load = time.time()
if processor is None or model is None:
processor = BlipProcessor.from_pretrained(MODEL_NAME)
model = BlipForConditionalGeneration.from_pretrained(MODEL_NAME)
model.eval()
load_time = time.time() - start_load # >0 on the first request, ~0 after
return load_time
@spaces.GPU
def run_inference(model, inputs):
"""The ONLY function that touches the GPU."""
device = "cuda" if torch.cuda.is_available() else "cpu"
model = model.to(device)
inputs = {k: v.to(device) for k, v in inputs.items()}
print("inference device:", next(model.parameters()).device) # confirm GPU
with torch.no_grad():
output = model.generate(**inputs)
return output.to("cpu")
def _cache_key(image):
return hashlib.sha256(image.tobytes()).hexdigest()
def generate_caption(image, use_cache=True):
start_total = time.time()
# ---- CPU: preprocessing ----
start_preprocess = time.time()
if not isinstance(image, Image.Image):
image = Image.fromarray(image)
image = image.convert("RGB")
key = _cache_key(image)
preprocess_time = time.time() - start_preprocess
# ---- CPU: cache check (no GPU on a hit) ----
if use_cache and key in caption_cache:
cached = caption_cache[key].copy()
cached["cache_hit"] = True
cached["total_time"] = round(time.time() - start_total, 3)
cached["preprocess_time"] = round(preprocess_time, 3)
cached["model_load_time"] = 0.0
cached["inference_time"] = 0.0
cached["postprocess_time"] = 0.0
cached["approx_gpu_time"] = 0.0
return cached
# ---- CPU: lazy load (first request only) + tokenize ----
load_time = load_model()
inputs = processor(image, return_tensors="pt")
# ---- GPU: the only step that holds the GPU ----
start_inference = time.time()
output = run_inference(model, inputs)
inference_time = time.time() - start_inference
# ---- CPU: postprocessing ----
start_postprocess = time.time()
caption = processor.decode(output[0], skip_special_tokens=True)
postprocess_time = time.time() - start_postprocess
total_time = time.time() - start_total
result = {
"caption": caption,
"total_time": round(total_time, 3),
"preprocess_time": round(preprocess_time, 3),
"model_load_time": round(load_time, 3),
"inference_time": round(inference_time, 3),
"postprocess_time": round(postprocess_time, 3),
"approx_gpu_time": round(inference_time, 3),
"cache_hit": False,
"model": MODEL_NAME,
}
if use_cache:
caption_cache[key] = result.copy()
return result