Продуктивність інференсу
П'ять засобів керування під час передбачення змінюють пропускну здатність або правильність: повторне виконання графа CUDA, точність, батчі, тайли й аугментація під час тестування. Кожен застосовується до певного набору сімейств, а два з них погіршують правильність або затримку, а не заощаджують їх.
Засоби керування та їхні типові значення
Кожен із наведених параметрів є аргументом predict, і всі вони типово вимкнені.
| Аргумент | Типове значення | Ефект |
|---|---|---|
batch | 1 | Кількість зображень на прямий прохід для джерел у вигляді папки чи списку |
cuda_graph | False | Повторне виконання прямого проходу із захопленого графа CUDA |
tiling | False | Поділ великого зображення на перекривні тайли |
overlap_ratio | 0.2 | Перекриття тайлів, коли ввімкнено tiling |
augment | False | Запуск віддзеркалених представлень та їх злиття |
half | Приймається, спричиняє попередження та ігнорується | |
device | None | Переміщення моделі перед передбаченням |
imgsz також впливає на витрати, оскільки задає роздільну здатність, з якою
працює модель, але передусім це аргумент правильності, пов'язаний із моделлю,
тому його тут не розглянуто.
Пакетна обробка
from pathlib import Pathfrom PIL import Image from libreyolo import LibreYOLO, SAMPLE_IMAGE folder = Path("batch_demo")folder.mkdir(exist_ok=True)image = Image.open(SAMPLE_IMAGE)for index in range(8): image.save(folder / f"frame_{index}.jpg") model = LibreYOLO("LibreYOLO9s.pt") # Один прямий прохід складеного тензора на кожну групу з 4 у сімействах, що це підтримують.results = model(str(folder), batch=4)print(len(results), "results")from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") for result in model("batch_demo", batch=4, stream=True): print(len(result.boxes))libreyolo predict model=LibreYOLO9s.pt source=batch_demo batch=4batch застосовується до джерел у вигляді папок і списків. За batch=1 для
кожного зображення виконується окремий прямий прохід. За значення понад 1
кожна група попередньо обробляється, складається в один тензор, запускається
один раз, а потім знову розділяється, щоб наявне постоброблення окремого
зображення в кожному сімействі отримувало очікувані дані.
Шлях зі складеним тензором використовується, лише якщо виконуються всі умови:
batchбільший за1tilingвимкнено- аугментація під час тестування не активна
- сімейство задає
SUPPORTS_BATCHED_PREDICT - базова мережа не перебуває в режимі навчання
Остання умова не є формальністю. Мережа в режимі навчання нормалізувала б складену групу за міжзображенневою статистикою батча, дозволяючи зображенням в одній групі змінювати передбачення одне одного, тому такі запуски залишаються послідовними.
Типове значення SUPPORTS_BATCHED_PREDICT істинне. Наведені сімейства
відмовляються від цієї можливості й виконують один прямий прохід на зображення
незалежно від batch: Depth Anything V2, Depth Anything 3, EoMT, Faster R-CNN,
FCOS, HRNet, L2CS-Net, LibreMODUS, MiDaS, MoGe-2, PP-OCRv5, Real-ESRGAN,
RetinaNet, SAM 3D Body, SwinIR, YOLOv1, ZipDepth, кожен детектор із відкритим
словником і кожна візуально-мовна модель.
Є ще один резервний шлях. Якщо попереднє оброблення не повертає для всієї групи
однорідні тензори (1, C, H, W) з однаковими формою, dtype та пристроєм, група
виконується послідовно, а не складається. Тому правильність ніколи не залежить
від випадкового збігу розмірів зображень.
Поєднайте batch зі stream=True для великої папки, щоб виконувати пакетні
прямі проходи, не зберігаючи всі результати в пам'яті.
Графи CUDA
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt", device="cuda") # Один раз виконати прогрівання та захоплення поза першим запитом.model.capture_graph() result = model(SAMPLE_IMAGE, cuda_graph=True)print(len(result.boxes))print(model.graph_info())from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt", device="cuda") # "auto" чекає, доки форму буде отримано двічі, тому одноразова робота# ніколи не витрачає ресурси на захоплення.for _ in range(3): model(SAMPLE_IMAGE, cuda_graph="auto") print(model.graph_info())model.release_graphs()Граф CUDA один раз записує прямий прохід і повторно виконує його як один запуск. Малі детектори витрачають значну частку часу батча 1 на запуск ядер, тому об'єднання цих запусків підвищує пропускну здатність, а результат повторного виконання побітово збігається з негайним виконанням.
cuda_graph приймає три значення. False є типовим і нічого не робить. True
захоплює граф під час першого використання кожної форми вхідних даних. "auto"
чекає повторення форми перед захопленням, тому одноразова робота й робота зі
змінними формами ніколи не сплачують вартість захоплення.
capture_graph(imgsz=None, batch=1, dtype=None) переносить цю вартість за межі
першого запиту. Граф дійсний лише для точної форми, яку він захопив, тому batch
тут має збігатися з подальшим викликом predict.
graph_info() повідомляє про захоплені графи, кількість повторних виконань і
причини переходу запуску до негайного режиму. release_graphs() звільняє графи
та їхні статичні буфери.
Для захоплення потрібні CUDA та сімейство, яке явно підтримує функцію через
SUPPORTS_CUDA_GRAPH, адже для неї потрібен прямий прохід без видимих хосту
операцій, що перевіряється окремо для кожного сімейства. Запит функції для
сімейства без такої підтримки спричиняє NotImplementedError, а не непомітний
запуск у негайному режимі.
Граф записує адреси пам'яті, а не значення, тому будь-яка операція, що переміщує
параметри, видаляє його. Зміна пристрою через predict(device=...), квантування
та деквантування роблять захоплені графи недійсними.
Повну матрицю підтримки за сімействами, межі поділу й гарантії числових результатів наведено в розділі Графи CUDA.
Точність
pip install "libreyolo[onnx]"from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt")path = model.export(format="onnx") exported = LibreYOLO(path)result = exported(SAMPLE_IMAGE)print(len(result.boxes))from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt", device="cuda")path = model.export(format="onnx", half=True) exported = LibreYOLO(path)result = exported(SAMPLE_IMAGE)print(len(result.boxes))from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt", device="cuda") # Рецепт перетворення не зчитує калібрувальних даних.model.quantize(recipe="fp16", calib=None) result = model(SAMPLE_IMAGE)print(len(result.boxes))half=True під час передбачення нічого не робить. Аргумент приймається для
сумісності з командним рядком, спричиняє попередження про відсутність дії та
відкидається до передавання будь-якому сімейству. Прапорець CLI --half
виводить те саме попередження для моделі .pt.
Є два справжні шляхи до нижчої точності.
Для експортованого артефакту точність вибирається під час експорту через
export(format=..., half=True), а отриманий файл завантажується назад через
LibreYOLO() без змін.
Для виконання PyTorch виклик model.quantize(recipe="fp16") перетворює модель
на float16 і встановлює перехоплювачі, які зберігають float32 на входах і виходах
моделі. "bf16" робить те саме з bfloat16. Жодне з перетворень не зчитує
калібрувальних даних, тому calib для них ігнорується. Зараз квантування
підтримує чотири сімейства: YOLOv9, RF-DETR, BiRefNet і FeyNobg. Перетворення
на CPU записує попередження про повільну роботу, тому ці рецепти призначені для GPU.
Обидва шляхи змінюють числові результати. Жоден не гарантує тих самих виявлень без додаткових дій, тому проведіть валідацію перед розгортанням.
Тайловий інференс
from PIL import Image from libreyolo import LibreYOLO, SAMPLE_IMAGE # Тайлова обробка вмикається, лише коли зображення перевищує розмір вхідних даних.large = Image.open(SAMPLE_IMAGE).resize((2048, 1536))large.save("large.jpg") model = LibreYOLO("LibreYOLO9s.pt") result = model("large.jpg", tiling=True, overlap_ratio=0.2)print(result.num_tiles, "tiles", len(result.boxes), "detections")Тайлова обробка розрізає велике зображення на перекривні квадратні тайли, робить передбачення для кожного й об'єднує результати. Цей варіант призначений для малих об'єктів на зображеннях високої роздільної здатності, де зміна розміру всього зображення зменшує цільові об'єкти нижче межі розпізнавання моделі.
Розмір тайла дорівнює розміру вхідних даних моделі або imgsz, якщо його задано,
і має бути квадратним. Типове значення overlap_ratio дорівнює 0.2. Перекривні
тайли узгоджуються за допомогою немаксимального придушення окремо для кожного
класу з порогом iou, а об'єднаний список потім обрізається до max_det. Отже,
iou впливає на тайлові передбачення навіть для сімейств, які не виконують
власного NMS.
Тайлова обробка повністю пропускається, а не просто мало коштує, якщо зображення
вже вміщується: коли обидва виміри не перевищують розмір вхідних даних,
виконується один звичайний прямий прохід. Вона також пропускається для
класифікації, семантичної сегментації та завдання embed, які переходять до
одного проходу, оскільки тайлова обробка для них не має змісту.
Виникає помилка для завдань, чиї корисні дані не можна зшити: маски сегментації
екземплярів, орієнтовані рамки, точки, глибина, краї та нормалі. Тайлову обробку
не можна поєднувати з augment.
Результат містить result.tiled і result.num_tiles. За save=True тайлові
запуски створюють у runs/tiled_detections каталог з усіма тайлами,
анотованим зображенням, візуалізацією сітки та файлом metadata.json, де
записано розмір тайла, перекриття й пороги. result.tiles_path і
result.grid_path указують на ці файли.
Аугментація під час тестування
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt") plain = model(SAMPLE_IMAGE)flipped = model(SAMPLE_IMAGE, augment=True) print(len(plain.boxes), "->", len(flipped.boxes))augment=True запускає зображення кілька разів і зливає виявлення за допомогою
немаксимального придушення окремо для кожного класу з порогом iou. Як і тайлова
обробка, це робить iou важливим для сімейств, які інакше його ігнорують.
На практиці використовується горизонтальне віддзеркалення. Типово список
масштабів TTA_SCALES містить єдиний масштаб 1.0, і жодне доступне сімейство
не перевизначає його, тому кожне сімейство виконує два проходи: початкове
зображення та його дзеркальну копію. Сімейства з позначкою TTA_FIXED_SIZE
змінюють розмір до фіксованого квадрата, через що багатомасштабність у будь-якому
разі не впливає на них.
Для семантичної та паноптичної сегментації використовується інше злиття. Їхнє віддзеркалене представлення віддзеркалюється назад, а два розподіли softmax усереднюються перед argmax замість злиття як рамок.
Аугментація під час тестування доступна не для кожного завдання. Вона спричиняє помилку для орієнтованих рамок, пози, точок, глибини, нормалей, країв, відновлення, OCR та моделей ембедінгів, а також не поєднується з тайловою обробкою.
Наведені сімейства повністю вимикають її, тому augment=True виконує один
звичайний прохід: BiRefNet, CenterNet, CLIP, DexiNed, FOMO, HRNet, L2CS-Net,
LibreMODUS, NAFNet, PP-OCRv5, Real-ESRGAN, RetinaNet, SAM 3D Body, SigLIP2,
SwinIR, TEED, кожен варіант SAM, кожен детектор із відкритим словником і кожна
візуально-мовна модель.
Вимірювання
На цій сторінці немає значень затримки, оскільки мілісекунда без зазначення
обладнання, середовища виконання, точності та розміру батча не є фактом. Виміряні
показники для різного обладнання й середовищ виконання опубліковано на
visionanalysis.org, а libreyolo profile
вимірює конкретну модель на машині перед вами.