VNCoreMLRequest — це підклас VNRequest, який дозволяє запускати Core ML моделі всередині пайплайна Vision, поєднуючи переваги готових детекторів Vision (обличчя, текст, об'єкти) з кастомними ML-моделями для класифікації та регресії. За даними Apple Machine Learning Documentation (2024), VNCoreMLRequest автоматично обробляє попередню обробку зображення — масштабування, обрізку та конвертацію кольорового простору — відповідно до вимог Core ML моделі.
Головне
VNCoreMLRequest — це підклас VNRequest, доданий в iOS 11 разом з Vision, який дозволяє запускати Core ML моделі в контексті Vision. Він бере на себе всю попередню обробку зображення, необхідну для Core ML моделі: зміну розміру, обрізку, нормалізацію та конвертацію кольорового простору.
Без VNCoreMLRequest розробнику довелося б вручну перетворювати UIImage/CGImage в MultiArray (MLMultiArray) або PixelBuffer (CVPixelBuffer) потрібного розміру. VNCoreMLRequest автоматизує цей процес: ви передаєте CGImage через VNImageRequestHandler, а VNCoreMLRequest сам масштабує його під вхід моделі.
VNCoreMLRequest успадковує всі можливості VNRequest: completion handler, regionOfInterest, можливість виконувати кілька запитів одночасно, підтримку VNImageRequestHandler та VNSequenceRequestHandler.
import Vision
import CoreML
// 1. Завантажити та обгорнути модель
guard let model = try VNCoreMLModel(
for: MobileNetV2().model)
else { return }
// 2. Створити VNCoreMLRequest
let request = VNCoreMLRequest(model: model) { req, _ in
guard let results = req.results
as? [VNClassificationObservation]
else { return }
for r in results.prefix(3) {
print("\\(r.identifier): \\(r.confidence)")
}
}
// 3. Виконати через обробник
let handler = VNImageRequestHandler(cgImage: image, options: [:])
try handler.perform([request])
VNCoreMLRequest підтримує моделі з різними типами входу: зображення (Image Feature), MultiArray та Double. Для зображень Vision автоматично конвертує CGImage в CVPixelBuffer потрібного розміру та кольорового простору. Для інших типів вхідних даних потрібно використовувати Core ML безпосередньо без Vision.
За даними Apple WWDC 2023, VNCoreMLRequest використовується в 40% всіх iOS-додатків, що застосовують Core ML для роботи із зображеннями. Це найпопулярніший спосіб інтеграції ML-моделей в iOS-додатки.
VNCoreMLModel — це обгортка, яка адаптує Core ML модель (MLModel) для використання в Vision. Вона конвертує вхідні та вихідні дані моделі у формат, зрозумілий Vision: зображення → CVPixelBuffer, результат → VNObservation.
Ініціалізація VNCoreMLModel перевіряє сумісність моделі з Vision: модель повинна приймати зображення на вхід (Image Feature) та повертати класифікацію (MLMultiArray або Dictionary). Якщо модель несумісна, ініціалізатор викидає помилку.
import Vision
import CoreML
// Варіант 1: З .mlmodel (скомпільовано під час збірки)
let model1 = try VNCoreMLModel(
for: MyVisionModel().model)
// Варіант 2: З .mlmodelc (скомпільовано на пристрої)
let compiledURL = Bundle.main.url(
forResource: "MyVisionModel",
withExtension: "mlmodelc")!
let model2 = try VNCoreMLModel(
for: MLModel(contentsOf: compiledURL))
VNCoreMLModel кешує модель в пам'яті після першого завантаження. Повторне завантаження тієї ж моделі повертає кешований екземпляр, що прискорює наступні запити. Однак якщо модель важить більше 100 MB, iOS може вивантажити її з пам'яті при нестачі ресурсів — у цьому випадку VNCoreMLModel перезавантажить модель автоматично.
Для моделей, навчених через Create ML, VNCoreMLModel працює без додаткового налаштування. Create ML експортує моделі з правильними метаданими, які Vision розпізнає автоматично — достатньо передати модель в VNCoreMLModel(model:).
imageCropAndScaleOption — ключова властивість VNCoreMLRequest, яка визначає, як Vision перетворює вихідне зображення під розмір входу Core ML моделі. Вибір правильної опції безпосередньо впливає на точність класифікації.
.centerCrop — обрізає зображення по центру до квадрата, потім масштабує до розміру входу моделі. Підходить для моделей, навчених на центрованих об'єктах (більшість класифікаторів ImageNet). .scaleFill — розтягує зображення до розміру входу без збереження пропорцій. Швидко, але спотворює геометрію. .scaleFit — масштабує зі збереженням пропорцій, додаючи letterbox (чорні смуги) по краях.
import Vision
let request = VNCoreMLRequest(model: model)
// .centerCrop — для центрованих об'єктів (типово)
request.imageCropAndScaleOption = .centerCrop
// .scaleFill — для однорідних текстур (без спотворень)
request.imageCropAndScaleOption = .scaleFill
// .scaleFit — коли пропорції об'єкта мають значення
request.imageCropAndScaleOption = .scaleFit
Рекомендації: для більшості моделей класифікації використовуйте .centerCrop — він дає найкраще співвідношення точності та продуктивності. Якщо модель навчена на зображеннях зі збереженням пропорцій (наприклад, детекція аномалій на фотографіях документів), вибирайте .scaleFit з letterbox.
За даними Apple Developer Documentation 2024, неправильний вибір imageCropAndScaleOption може знизити точність моделі на 15–25%. Наприклад, .scaleFill для обличчя, розташованого біля краю кадру, може обрізати його частину при .centerCrop або спотворити пропорції при .scaleFill.
Головна сила VNCoreMLRequest — можливість комбінувати його з іншими VNRequest в одному виклику perform(). Це дозволяє будувати пайплайни: спочатку знайти обличчя (VNDetectFaceRectanglesRequest), потім класифікувати кожне обличчя через кастомну Core ML модель (VNCoreMLRequest).
VNCoreMLRequest також підтримує regionOfInterest — якщо встановити цю область, Vision обріже зображення до вказаного прямокутника перед передачею в Core ML модель. Це критично важливо для пайплайнів: після детекції обличчя ви передаєте його bounding box як regionOfInterest для VNCoreMLRequest.
import Vision
// 1. Детекція облич
let faceRequest = VNDetectFaceRectanglesRequest()
// 2. Класифікація емоцій через Core ML
guard let emotionModel = try VNCoreMLModel(
for: EmotionClassifier().model)
else { return }
let emotionRequest = VNCoreMLRequest(model: emotionModel)
try handler.perform([faceRequest, emotionRequest])
// 3. Встановити regionOfInterest для кожного обличчя
for face in faceRequest.results as? [VNFaceObservation] ?? [] {
emotionRequest.regionOfInterest = face.boundingBox
try handler.perform([emotionRequest])
// Обробити результат класифікації емоцій
}
Обмеження: regionOfInterest для VNCoreMLRequest має сенс, коли модель навчена на зображеннях одного розміру та пропорції. Якщо модель очікує строго квадратний вхід (224x224), .centerCrop з regionOfInterest дасть найкращий результат.
За даними Apple ML Research, пайплайн «детекція → класифікація» через regionOfInterest дає приріст точності на 20–30% порівняно з класифікацією цілого зображення, оскільки ML-модель отримує на вхід лише релевантну область без фонового шуму.
| Тип пайплайну | Запит 1 (детекція) | Запит 2 (ML) | Приклад |
|---|---|---|---|
| Обличчя → емоція | VNDetectFaceRectanglesRequest | VNCoreMLRequest | Визначення настрою |
| Об'єкт → бренд | VNDetectObjectAtPointRequest | VNCoreMLRequest | Розпізнавання логотипів |
| Текст → мова | VNRecognizeTextRequest | VNCoreMLRequest | Класифікація мови тексту |
| Сцена → опис | VNClassifyImageRequest | VNCoreMLRequest | Генерація тегів |
VNCoreMLRequest повертає результати у вигляді VNClassificationObservation (для класифікаційних моделей) або VNCoreMLFeatureValueObservation (для регресійних та інших типів). Тип результату залежить від вихідних даних Core ML моделі.
VNClassificationObservation містить identifier (назва класу) та confidence (впевненість). Моделі з softmax-виходом повертають масив таких спостережень, відсортованих за спаданням confidence. VNCoreMLFeatureValueObservation містить довільне значення MLFeatureValue — може бути MultiArray, Double, String або Dictionary.
// Для класифікаційних моделей
if let classificationResults = request.results
as? [VNClassificationObservation] {
for result in classificationResults
where result.confidence > 0.5 {
print("\\(result.identifier): \\(result.confidence)")
}
}
// Для регресійних моделей (значення ознак)
if let featureResults = request.results
as? [VNCoreMLFeatureValueObservation] {
for result in featureResults {
let value = result.featureValue
print("\\(result.featureName): \\(value)")
}
}
Фільтрація за confidence: Apple рекомендує відкидати результати з confidence < 0.3 для загальних класифікаторів та < 0.7 для критичних додатків. Для моделей, навчених на збалансованих датасетах, confidence корелює з імовірністю правильної відповіді, але не гарантує її.
VNCoreMLFeatureValueObservation.featureName відповідає імені вихідного шару моделі (наприклад, «classLabel» або «features»). Це дозволяє обробляти моделі з кількома виходами — кожен вихід представлений окремим observation з унікальним featureName.
VNCoreMLRequest оптимізований для роботи на Neural Engine (A12+), GPU та CPU. Vision автоматично вибирає найкращий пристрій для виконання моделі залежно від її типу та розміру. Однак продуктивність можна додатково покращити правильним налаштуванням.
Моделі Core ML завантажуються в пам'ять при першому VNCoreMLRequest і залишаються там до вивантаження додатку. Для моделей розміром більше 200 MB Apple рекомендує завантажувати їх за потреби та вивантажувати через MLModel.release(). VNCoreMLModel сама керує кешуванням, але ви можете контролювати це через autoreleasepool.
Для пакетної обробки зображень створюйте один VNCoreMLRequest та перевикористовуйте його з різними VNImageRequestHandler. Не створюйте новий VNCoreMLRequest на кожне зображення — це сповільнить обробку через повторне завантаження моделі. Перевикористання запиту дає приріст продуктивності до 40% при обробці 10+ зображень.
// Правильно: один запит для всіх зображень
let batchSize = 20
let batchRequest = VNCoreMLRequest(model: model)
for i in 0..<batchSize {
let handler = VNImageRequestHandler(
cgImage: images[i],
options: [:])
try handler.perform([batchRequest])
// batchRequest.results оновлюється при кожному виклику
}
Вибір пристрою: за замовчуванням Vision вибирає Neural Engine для сумісних моделей на пристроях A12+. Якщо модель не підтримує Neural Engine, Vision використовує GPU або CPU. Ви можете примусово вказати пристрій через MLModelConfiguration.computeUnits, але Apple рекомендує залишити автоматичний вибір.
За даними Apple Performance Benchmarks 2024, VNCoreMLRequest на Neural Engine (iPhone 15 Pro) обробляє класифікацію MobileNetV2 за 3–5 мс, на GPU — 8–12 мс, на CPU — 20–30 мс. Різниця стає критичною для real-time додатків, що обробляють 30+ кадрів на секунду.
Часто задавані питання
Так, Core ML можна використовувати безпосередньо через MLModel.prediction(), без Vision. Однак VNCoreMLRequest автоматизує попередню обробку зображень (масштабування, crop, конвертацію в CVPixelBuffer). Якщо модель приймає не зображення, а MultiArray або Double — використовуйте Core ML безпосередньо. VNCoreMLRequest тільки для моделей з Image Feature на вході.
Створіть нову VNCoreMLModel з оновленого MLModel та новий VNCoreMLRequest. Старий запит продовжить використовувати стару версію моделі. Для віддаленого оновлення моделей використовуйте MLModel.compileModel(at:) для компіляції моделі на пристрої з .mlmodelc файлу, завантаженого з сервера.
VNCoreMLRequest підтримує тільки моделі з одним Image Feature входом. Якщо у моделі кілька входів (наприклад, зображення + текст), використовуйте Core ML безпосередньо через MLModel. Vision не може передати додаткові параметри окрім зображення.
Обмеження — 8192 x 8192 пікселів для CGImage, що передається в VNImageRequestHandler. Однак Core ML моделі зазвичай очікують вхід 224x224, 299x299 або 512x512. Vision автоматично масштабує велике зображення під розмір входу. Якщо вихідне зображення занадто велике, попередньо зменшіть його через CGImage для економії пам'яті.
Так, встановіть preferBackgroundProcessing = true на VNRequest. Це дозволить Vision відкласти виконання запиту, якщо система знаходиться в ресурсоємному режимі (наприклад, завантаження контенту). Також обов'язково використовуйте DispatchQueue.global(qos: .background) для виклику handler.perform().
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також