AI Hints
Computer Vision · Lesson 33 of 111

Running on Devices

Making models small and fast.

⏱ 2 min read▶ Video at 56:07🎓 Free
Watch this lesson in the Computer Vision courseWatch on YouTube ↗Full Computer Vision course

At Orchard Vision, the camera is at the end of a dusty barn, with slow internet. Each apple must be graded in a fraction of a second. Sending every photo to the cloud isn't an option. The model has to run right there, on a small box next to the belt. That's called edge computing.

Running on Devices
From the video: Running on Devices
  • A dusty barn, slow internet
  • A fraction of a second per apple
  • The model runs on the box

Exporting to ONNX

ONNX is a standard format for models, and it runs almost anywhere. We export a small network with one call, then load it into a fast runtime, with no PyTorch needed. Run it. A tiny file, and speed measured in milliseconds per image. Devices like the Jetson and the Raspberry Pi run files like this. Exporting is the usual first step toward any real deployment.

export.pypython
import os
import time
import numpy as np
import torch
from torch import nn
import onnxruntime as ort

net = nn.Sequential(nn.Conv2d(3, 16, 3, 2, 1), nn.ReLU(), nn.Conv2d(16, 32, 3, 2, 1),
                    nn.ReLU(), nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(32, 2)).eval()
x = torch.rand(1, 3, 128, 128)

torch.onnx.export(net, x, "model.onnx", input_names=["image"], output_names=["score"],
                  dynamo=False)

run = ort.InferenceSession("model.onnx")
a = np.random.rand(1, 3, 128, 128).astype(np.float32)
start = time.time()
for _ in range(100):
    out = run.run(None, {"image": a})
print(f"File: {os.path.getsize('model.onnx') / 1000:.0f} KB")
print(f"Speed: {(time.time() - start) * 10:.2f} ms per image")
Output
File: 22 KB
Speed: 0.10 ms per image

Budgeting your time

Everything starts with a time budget. A belt moves at a metre per second, and each apple stays in view for half a second. We compare three image sizes. Run it. Bigger images find small defects, but they cost much more time. Doubling the resolution makes it about four times slower. So choose the smallest size that still shows a bruise. This sum decides your hardware.

budget.pypython
budget_ms = 100
resolutions = {320: 12, 640: 45, 1280: 180}

for size, ms in resolutions.items():
    fps = 1000 / ms
    verdict = "fits" if ms < budget_ms else "too slow"
    print(f"{size:>4}px  {ms:>3} ms  {fps:>5.1f} fps  {verdict}")

belt_speed_m_s, view_m = 1.0, 0.5
print("Time each apple stays in view:", view_m / belt_speed_m_s, "seconds")
Output
 320px   12 ms   83.3 fps  fits
 640px   45 ms   22.2 fps  fits
1280px  180 ms    5.6 fps  too slow
Time each apple stays in view: 0.5 seconds

The hidden costs

The model isn't the only cost. Resizing and compressing frames can take as long as inference. We time both. Run it. These steps take real time, on every frame. Compression shrinks the image a great deal, which matters if you're sending it across a slow link. Measure your whole pipeline, not just the model. The bottleneck is often somewhere else.

costs.pypython
import cv2
import time
import numpy as np

frame = np.random.randint(0, 255, (1080, 1920, 3), np.uint8)

start = time.time()
for _ in range(100):
    small = cv2.resize(frame, (640, 360))
print(f"Resize: {(time.time() - start) * 10:.1f} ms")

start = time.time()
for _ in range(100):
    _, jpg = cv2.imencode(".jpg", frame)
print(f"JPEG encode: {(time.time() - start) * 10:.1f} ms")
print(f"Size: {frame.size / 1e6:.1f} MB -> {jpg.size / 1e6:.2f} MB")
Output
Resize: 0.2 ms
JPEG encode: 10.3 ms
Size: 6.2 MB -> 2.43 MB

Summary

Export, budget your time, and measure the full pipeline. Next, the other way to deploy, sending images to a server, and how to keep everything healthy after launch.

Key takeaways
  • ONNX runs anywhere
  • Resolution costs time fast
  • Measure the whole pipeline
Next up: Serving and Monitoring — keeping vision systems healthy