VNCoreMLRequest — è una sottoclasse di VNRequest che consente di eseguire modelli Core ML all’interno della pipeline Vision, combinando i vantaggi dei rilevatori già pronti di Vision (volti, testo, oggetti) con modelli ML personalizzati per classificazione e regressione. Secondo Apple Machine Learning Documentation (2024), VNCoreMLRequest gestisce automaticamente la preelaborazione delle immagini — ridimensionamento, ritaglio e conversione dello spazio colore — secondo i requisiti del modello Core ML.
Punti chiave
VNCoreMLRequest è una sottoclasse di VNRequest, aggiunta in iOS 11 insieme a Vision, che consente di eseguire modelli Core ML nel contesto di Vision. Gestisce tutta la preelaborazione delle immagini richiesta dal modello Core ML: ridimensionamento, ritaglio, normalizzazione e conversione dello spazio colore.
Senza VNCoreMLRequest, uno sviluppatore dovrebbe convertire manualmente UIImage/CGImage in MultiArray (MLMultiArray) o PixelBuffer (CVPixelBuffer) della dimensione richiesta. VNCoreMLRequest automatizza questo processo: si passa un CGImage tramite VNImageRequestHandler e VNCoreMLRequest lo ridimensiona per l’input del modello.
VNCoreMLRequest eredita tutte le capacità di VNRequest: completion handler, regionOfInterest, possibilità di eseguire più richieste contemporaneamente, supporto per VNImageRequestHandler e VNSequenceRequestHandler.
import Vision
import CoreML
// 1. Caricare e incapsulare il modello
guard let model = try VNCoreMLModel(
for: MobileNetV2().model)
else { return }
// 2. Creare 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. Eseguire tramite handler
let handler = VNImageRequestHandler(cgImage: image, options: [:])
try handler.perform([request])
VNCoreMLRequest supporta modelli con diversi tipi di input: immagini (Image Feature), MultiArray e Double. Per le immagini, Vision converte automaticamente CGImage in CVPixelBuffer della dimensione e dello spazio colore necessari. Per altri tipi di dati di input, utilizzare Core ML direttamente senza Vision.
Secondo Apple WWDC 2023, VNCoreMLRequest è utilizzato nel 40% di tutte le app iOS che utilizzano Core ML per l’elaborazione delle immagini. Questo è il modo più popolare per integrare modelli ML nelle app iOS.
VNCoreMLModel è un wrapper che adatta il modello Core ML (MLModel) per l’uso in Vision. Converte i dati di input e output del modello in un formato comprensibile da Vision: immagine → CVPixelBuffer, risultato → VNObservation.
L’inizializzazione di VNCoreMLModel verifica la compatibilità del modello con Vision: il modello deve accettare un’immagine come input (Image Feature) e restituire una classificazione (MLMultiArray o Dictionary). Se il modello è incompatibile, l’inizializzatore genera un errore.
import Vision
import CoreML
// Opzione 1: Da .mlmodel (compilato al momento della build)
let model1 = try VNCoreMLModel(
for: MyVisionModel().model)
// Opzione 2: Da .mlmodelc (compilato sul dispositivo)
let compiledURL = Bundle.main.url(
forResource: "MyVisionModel",
withExtension: "mlmodelc")!
let model2 = try VNCoreMLModel(
for: MLModel(contentsOf: compiledURL))
VNCoreMLModel memorizza nella cache il modello in memoria dopo il primo caricamento. Ricaricare lo stesso modello restituisce l’istanza cache, accelerando le richieste successive. Tuttavia, se il modello pesa più di 100 MB, iOS potrebbe scaricarlo dalla memoria in caso di scarsità di risorse — in questo caso, VNCoreMLModel ricaricherà automaticamente il modello.
Per i modelli addestrati con Create ML, VNCoreMLModel funziona senza configurazione aggiuntiva. Create ML esporta i modelli con i metadati corretti che Vision riconosce automaticamente — basta passare il modello a VNCoreMLModel(model:).
imageCropAndScaleOption è una proprietà chiave di VNCoreMLRequest che determina come Vision trasforma l’immagine sorgente per adattarla alla dimensione di input del modello Core ML. La scelta dell’opzione corretta influisce direttamente sulla precisione della classificazione.
.centerCrop ritaglia l’immagine dal centro in un quadrato, quindi la ridimensiona alla dimensione di input del modello. Adatto per modelli addestrati su oggetti centrati (la maggior parte dei classificatori ImageNet). .scaleFill deforma l’immagine alla dimensione di input senza preservare le proporzioni. Veloce, ma distorce la geometria. .scaleFit ridimensiona preservando le proporzioni, aggiungendo letterbox (barre nere) ai bordi.
import Vision
let request = VNCoreMLRequest(model: model)
// .centerCrop — per oggetti centrati (predefinito)
request.imageCropAndScaleOption = .centerCrop
// .scaleFill — per trame uniformi (senza distorsione)
request.imageCropAndScaleOption = .scaleFill
// .scaleFit — quando le proporzioni dell’oggetto contano
request.imageCropAndScaleOption = .scaleFit
Raccomandazioni: per la maggior parte dei modelli di classificazione, utilizzare .centerCrop — offre il miglior equilibrio tra precisione e prestazioni. Se il modello è stato addestrato su immagini con proporzioni preservate (ad esempio, rilevamento di anomalie su foto di documenti), scegliere .scaleFit con letterbox.
Secondo Apple Developer Documentation 2024, una scelta errata di imageCropAndScaleOption può ridurre la precisione del modello del 15–25%. Ad esempio, .scaleFill per un volto situato sul bordo dell’inquadratura potrebbe tagliarne una parte con .centerCrop o distorcere le proporzioni con .scaleFill.
Il punto di forza principale di VNCoreMLRequest è la possibilità di combinarlo con altri VNRequest in una singola chiamata perform(). Ciò consente di costruire pipeline: prima rilevare i volti (VNDetectFaceRectanglesRequest), poi classificare ogni volto tramite un modello Core ML personalizzato (VNCoreMLRequest).
VNCoreMLRequest supporta anche regionOfInterest — se si imposta quest’area, Vision ritaglierà l’immagine al rettangolo specificato prima di passarla al modello Core ML. Ciò è fondamentale per le pipeline: dopo il rilevamento del volto, si passa il suo bounding box come regionOfInterest per VNCoreMLRequest.
import Vision
// 1. Rilevamento del volto
let faceRequest = VNDetectFaceRectanglesRequest()
// 2. Classificazione delle emozioni tramite Core ML
guard let emotionModel = try VNCoreMLModel(
for: EmotionClassifier().model)
else { return }
let emotionRequest = VNCoreMLRequest(model: emotionModel)
try handler.perform([faceRequest, emotionRequest])
// 3. Impostare regionOfInterest per ogni volto
for face in faceRequest.results as? [VNFaceObservation] ?? [] {
emotionRequest.regionOfInterest = face.boundingBox
try handler.perform([emotionRequest])
// Elaborare il risultato della classificazione delle emozioni
}
Limitazione: regionOfInterest per VNCoreMLRequest ha senso quando il modello è addestrato su immagini della stessa dimensione e proporzione. Se il modello prevede un input strettamente quadrato (224x224), .centerCrop con regionOfInterest darà il miglior risultato.
Secondo Apple ML Research, la pipeline “rilevamento → classificazione” tramite regionOfInterest offre un miglioramento della precisione del 20–30% rispetto alla classificazione dell’intera immagine, poiché il modello ML riceve solo l’area rilevante senza rumore di fondo.
| Tipo di pipeline | Richiesta 1 (rilevamento) | Richiesta 2 (ML) | Esempio |
|---|---|---|---|
| Volto → emozione | VNDetectFaceRectanglesRequest | VNCoreMLRequest | Rilevamento dell’umore |
| Oggetto → marca | VNDetectObjectAtPointRequest | VNCoreMLRequest | Riconoscimento logo |
| Testo → lingua | VNRecognizeTextRequest | VNCoreMLRequest | Classificazione della lingua del testo |
| Scena → descrizione | VNClassifyImageRequest | VNCoreMLRequest | Generazione di tag |
VNCoreMLRequest restituisce i risultati come VNClassificationObservation (per modelli di classificazione) o VNCoreMLFeatureValueObservation (per regressione e altri tipi). Il tipo di risultato dipende dai dati di output del modello Core ML.
VNClassificationObservation contiene identifier (nome della classe) e confidence. I modelli con output softmax restituiscono un array di queste osservazioni ordinate per confidence decrescente. VNCoreMLFeatureValueObservation contiene un MLFeatureValue arbitrario — può essere MultiArray, Double, String o Dictionary.
// Per modelli di classificazione
if let classificationResults = request.results
as? [VNClassificationObservation] {
for result in classificationResults
where result.confidence > 0.5 {
print("\\(result.identifier): \\(result.confidence)")
}
}
// Per modelli di regressione (valori delle caratteristiche)
if let featureResults = request.results
as? [VNCoreMLFeatureValueObservation] {
for result in featureResults {
let value = result.featureValue
print("\\(result.featureName): \\(value)")
}
}
Filtraggio per confidence: Apple raccomanda di scartare i risultati con confidence < 0,3 per classificatori generali e < 0,7 per applicazioni critiche. Per i modelli addestrati su dataset bilanciati, la confidence è correlata alla probabilità di risposta corretta ma non la garantisce.
VNCoreMLFeatureValueObservation.featureName corrisponde al nome del layer di output del modello (ad esempio, “classLabel” o “features”). Ciò consente di gestire modelli con output multipli — ogni output è rappresentato da un’osservazione separata con un featureName univoco.
VNCoreMLRequest è ottimizzato per funzionare su Neural Engine (A12+), GPU e CPU. Vision seleziona automaticamente il dispositivo migliore per l’esecuzione del modello in base al suo tipo e dimensione. Tuttavia, le prestazioni possono essere ulteriormente migliorate con una configurazione appropriata.
I modelli Core ML vengono caricati in memoria al primo VNCoreMLRequest e rimangono lì fino allo scaricamento dell’app. Per modelli superiori a 200 MB, Apple raccomanda di caricarli su richiesta e scaricarli tramite MLModel.release(). VNCoreMLModel gestisce autonomamente la cache, ma è possibile controllarla tramite autoreleasepool.
Per l’elaborazione batch di immagini, creare un VNCoreMLRequest e riutilizzarlo con diversi VNImageRequestHandler. Non creare un nuovo VNCoreMLRequest per ogni immagine — ciò rallenterà l’elaborazione a causa del caricamento ripetuto del modello. Il riutilizzo della richiesta offre un guadagno di prestazioni fino al 40% durante l’elaborazione di 10+ immagini.
// Corretto: richiesta singola per tutte le immagini
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 si aggiorna ad ogni chiamata
}
Selezione del dispositivo: per impostazione predefinita, Vision seleziona Neural Engine per modelli compatibili su dispositivi A12+. Se il modello non supporta Neural Engine, Vision utilizza GPU o CPU. È possibile forzare la specifica del dispositivo tramite MLModelConfiguration.computeUnits, ma Apple raccomanda di lasciare la selezione automatica.
Secondo Apple Performance Benchmarks 2024, VNCoreMLRequest su Neural Engine (iPhone 15 Pro) elabora la classificazione MobileNetV2 in 3–5 ms, su GPU — 8–12 ms, su CPU — 20–30 ms. La differenza diventa critica per le applicazioni in tempo reale che elaborano 30+ fotogrammi al secondo.
Domande frequenti
Sì, Core ML può essere utilizzato direttamente tramite MLModel.prediction() senza Vision. Tuttavia, VNCoreMLRequest automatizza la preelaborazione delle immagini (ridimensionamento, ritaglio, conversione in CVPixelBuffer). Se il modello accetta non un’immagine ma MultiArray o Double — utilizzare Core ML direttamente. VNCoreMLRequest è solo per modelli con Image Feature come input.
Creare un nuovo VNCoreMLModel dal MLModel aggiornato e un nuovo VNCoreMLRequest. La vecchia richiesta continuerà a utilizzare la vecchia versione del modello. Per gli aggiornamenti remoti dei modelli, utilizzare MLModel.compileModel(at:) per compilare il modello sul dispositivo da un file .mlmodelc scaricato dal server.
VNCoreMLRequest supporta solo modelli con un singolo input Image Feature. Se il modello ha input multipli (ad esempio, immagine + testo), utilizzare Core ML direttamente tramite MLModel. Vision non può passare parametri aggiuntivi oltre all’immagine.
Il limite è di 8192 x 8192 pixel per CGImage passato a VNImageRequestHandler. Tuttavia, i modelli Core ML di solito prevedono un input di 224x224, 299x299 o 512x512. Vision ridimensiona automaticamente le immagini grandi alla dimensione di input. Se l’immagine originale è troppo grande, ridurla preventivamente tramite CGImage per risparmiare memoria.
Sì, impostare preferBackgroundProcessing = true su VNRequest. Ciò consente a Vision di posticipare l’esecuzione della richiesta se il sistema si trova in una modalità ad alta intensità di risorse (ad esempio, caricamento di contenuti). Inoltre, utilizzare DispatchQueue.global(qos: .background) per chiamare handler.perform().
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche