Fix launch-timeout crash and remove dead Dockerfile
Browse filesRoot cause: the yolov5 package's torch.hub download of the yolov5 repo
code, combined with unpinned CUDA torch wheels on cpu-basic hardware,
pushed the build well past the 30-minute health-check window. Redirect
Torch caches to /tmp, pin CPU-only torch/torchvision, patch torch.load
for PyTorch 2.6+'s weights_only default so the legacy yolov5 checkpoint
still loads, and drop the unused Dockerfile/tator_inference.py/tator
dependency left over from an old pipeline the gradio-SDK space never
actually used. Bump gradio to 6.9.0.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Dockerfile +0 -10
- README.md +1 -1
- inference.py +19 -0
- requirements.txt +4 -1
- tator_inference.py +0 -100
Dockerfile
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
FROM python:3.7
|
| 2 |
-
|
| 3 |
-
RUN apt-get update \
|
| 4 |
-
&& apt-get install ffmpeg libsm6 libxext6 -y
|
| 5 |
-
|
| 6 |
-
RUN pip install yolov5 tator gradio
|
| 7 |
-
|
| 8 |
-
COPY . ./
|
| 9 |
-
|
| 10 |
-
CMD [ "python", "-u", "./tator_inference.py" ]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
|
@@ -4,7 +4,7 @@ emoji: 🐠
|
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: gray
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
---
|
|
|
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: gray
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 6.9.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
---
|
inference.py
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import glob
|
| 2 |
import numpy as np
|
| 3 |
import torch
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
import yolov5
|
| 5 |
from typing import Union, List, Optional
|
| 6 |
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
# Keep Torch/YOLO hub caches off the Space's persistent disk so repeated
|
| 4 |
+
# loads don't exceed the storage quota:
|
| 5 |
+
# https://discuss.huggingface.co/t/how-to-fix-workload-evicted-storage-limit-exceeded-50g-error-in-huggingface-spaces/169258
|
| 6 |
+
os.environ.setdefault("TORCH_HOME", "/tmp/torch_cache")
|
| 7 |
+
os.environ.setdefault("HUB_DIR", "/tmp/torch_hub")
|
| 8 |
+
os.environ.setdefault("TMPDIR", "/tmp")
|
| 9 |
+
|
| 10 |
import glob
|
| 11 |
import numpy as np
|
| 12 |
import torch
|
| 13 |
+
|
| 14 |
+
# PyTorch >=2.6 defaults torch.load(weights_only=True), which can't unpickle
|
| 15 |
+
# this legacy yolov5 checkpoint format. We trust this checkpoint (it's our
|
| 16 |
+
# own model), so restore the old default for it.
|
| 17 |
+
_torch_load = torch.load
|
| 18 |
+
def _torch_load_compat(*args, **kwargs):
|
| 19 |
+
kwargs.setdefault("weights_only", False)
|
| 20 |
+
return _torch_load(*args, **kwargs)
|
| 21 |
+
torch.load = _torch_load_compat
|
| 22 |
+
|
| 23 |
import yolov5
|
| 24 |
from typing import Union, List, Optional
|
| 25 |
|
requirements.txt
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
numpy<2.0
|
| 2 |
yolov5==6.2.3
|
| 3 |
-
|
|
|
|
| 1 |
+
--extra-index-url https://download.pytorch.org/whl/cpu
|
| 2 |
+
torch==2.14.0
|
| 3 |
+
torchvision==0.29.0
|
| 4 |
numpy<2.0
|
| 5 |
yolov5==6.2.3
|
| 6 |
+
setuptools<81
|
tator_inference.py
DELETED
|
@@ -1,100 +0,0 @@
|
|
| 1 |
-
import os
|
| 2 |
-
import logging
|
| 3 |
-
from tempfile import TemporaryFile
|
| 4 |
-
|
| 5 |
-
import cv2
|
| 6 |
-
import numpy as np
|
| 7 |
-
from PIL import Image
|
| 8 |
-
|
| 9 |
-
import tator
|
| 10 |
-
import inference
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
logger = logging.getLogger(__name__)
|
| 14 |
-
logger.setLevel(logging.INFO)
|
| 15 |
-
|
| 16 |
-
# Read environment variables that are provided from TATOR
|
| 17 |
-
host = os.getenv('HOST')
|
| 18 |
-
token = os.getenv('TOKEN')
|
| 19 |
-
project_id = int(os.getenv('PROJECT_ID'))
|
| 20 |
-
media_ids = [int(id_) for id_ in os.getenv('MEDIA_IDS').split(',')]
|
| 21 |
-
frames_per_inference = int(os.getenv('FRAMES_PER_INFERENCE', 30))
|
| 22 |
-
|
| 23 |
-
# Set up the TATOR API.
|
| 24 |
-
api = tator.get_api(host, token)
|
| 25 |
-
|
| 26 |
-
# Iterate through each video.
|
| 27 |
-
for media_id in media_ids:
|
| 28 |
-
|
| 29 |
-
# Download video.
|
| 30 |
-
media = api.get_media(media_id)
|
| 31 |
-
logger.info(f"Downloading {media.name}...")
|
| 32 |
-
out_path = f"/tmp/{media.name}"
|
| 33 |
-
for progress in tator.util.download_media(api, media, out_path):
|
| 34 |
-
logger.info(f"Download progress: {progress}%")
|
| 35 |
-
|
| 36 |
-
# Do inference on each video.
|
| 37 |
-
logger.info(f"Doing inference on {media.name}...")
|
| 38 |
-
localizations = []
|
| 39 |
-
vid = cv2.VideoCapture(out_path)
|
| 40 |
-
frame_number = 0
|
| 41 |
-
|
| 42 |
-
# Read *every* frame from the video, break when at the end.
|
| 43 |
-
while True:
|
| 44 |
-
ret, frame = vid.read()
|
| 45 |
-
if not ret:
|
| 46 |
-
break
|
| 47 |
-
|
| 48 |
-
# Create a temporary file, access the image data, save data to file.
|
| 49 |
-
framefile = TemporaryFile(suffix='.jpg')
|
| 50 |
-
im = Image.fromarray(frame)
|
| 51 |
-
im.save(framefile)
|
| 52 |
-
|
| 53 |
-
# For every N frames, make a prediction; append prediction results
|
| 54 |
-
# to a list, increase the frame count.
|
| 55 |
-
if frame_number % frames_per_inference == 0:
|
| 56 |
-
|
| 57 |
-
spec = {}
|
| 58 |
-
|
| 59 |
-
# Predictions contains all information inside pandas dataframe
|
| 60 |
-
predictions = inference.run_inference(framefile)
|
| 61 |
-
|
| 62 |
-
for i, r in predictions.pandas().xyxy[0].iterrows:
|
| 63 |
-
|
| 64 |
-
spec['media_id'] = media_id
|
| 65 |
-
spec['type'] = None # Unsure, docs not specific
|
| 66 |
-
spec['frame'] = frame_number
|
| 67 |
-
|
| 68 |
-
x, y, x2, y2 = r['xmin'], r['ymin'], r['xmax'], r['ymax']
|
| 69 |
-
w, h = x2 - x, y2 - y
|
| 70 |
-
|
| 71 |
-
spec['x'] = x
|
| 72 |
-
spec['y'] = y
|
| 73 |
-
spec['width'] = w
|
| 74 |
-
spec['height'] = h
|
| 75 |
-
spec['class_category'] = r['name']
|
| 76 |
-
spec['confidence'] = r['confidence']
|
| 77 |
-
|
| 78 |
-
localizations.append(spec)
|
| 79 |
-
|
| 80 |
-
frame_number += 1
|
| 81 |
-
|
| 82 |
-
# End interaction with video properly.
|
| 83 |
-
vid.release()
|
| 84 |
-
|
| 85 |
-
logger.info(f"Uploading object detections on {media.name}...")
|
| 86 |
-
|
| 87 |
-
# Create the localizations in the video.
|
| 88 |
-
num_created = 0
|
| 89 |
-
for response in tator.util.chunked_create(api.create_localization_list,
|
| 90 |
-
project_id,
|
| 91 |
-
localization_spec=localizations):
|
| 92 |
-
num_created += len(response.id)
|
| 93 |
-
|
| 94 |
-
# Output pretty logging information.
|
| 95 |
-
logger.info(f"Successfully created {num_created} localizations on "
|
| 96 |
-
f"{media.name}!")
|
| 97 |
-
|
| 98 |
-
logger.info("-------------------------------------------------")
|
| 99 |
-
|
| 100 |
-
logger.info(f"Completed inference on {len(media_ids)} files.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|