VNCoreMLRequest — 개요, iOS Core ML에 대한 Vision 요청

저자: IT Sectr 게시일: 2026-07-20 읽는 시간: 8 분

VNCoreMLRequest — VNRequest의 하위 클래스로, Vision 파이프라인 내에서 Core ML 모델을 실행할 수 있도록 하며, Vision의 기존 검출기(얼굴, 텍스트, 물체)의 장점과 분류 및 회귀를 위한 사용자 정의 ML 모델을 결합합니다. Apple Machine Learning Documentation (2024)에 따르면, VNCoreMLRequest는 Core ML 모델의 요구사항에 따라 이미지 전처리(스케일링, 크롭, 색공간 변환)를 자동으로 처리합니다.

주요 요점

  • VNCoreMLRequest — Core ML과 Vision 사이의 구동루: ML 모델이 Vision 요청으로 작동합니다.
  • 자동 이미지 전처리: 모델 요구사항에 따른 스케일링, 크롭 및 색교정.
  • 파이프라인 구축을 위한 단일 perform()에서 다른 VNRequest와 결합가능.
  • VNCoreMLModel 지원 — 이미지 및 FeatureValue 작업을 위한 MLModel 래퍼.
  • 최대 성능을 위해 Neural Engine 및 GPU에서 실행.

VNCoreMLRequest란?

VNCoreMLRequest VNRequest의 하위 클래스로, iOS 11에서 Vision과 함께 추가되었으며, Vision의 문맥에서 Core ML 모델을 실행할 수 있도록 합니다. Core ML 모델이 필요로 하는 모든 이미지 전처리(크기 조정, 크롭, 정규화 및 색공간 변환)를 처리합니다.

VNCoreMLRequest가 없으면, 개발자는 UIImage/CGImage를 필요한 크기의 MultiArray(MLMultiArray) 또는 PixelBuffer(CVPixelBuffer)로 직접 변환해야 합니다. VNCoreMLRequest는 이 과정을 자동화합니다: VNImageRequestHandler를 통해 CGImage를 전달하면, VNCoreMLRequest가 모델 입력으로 더크기를 맞게 조정합니다.

VNCoreMLRequest는 모든 VNRequest 기능을 상속받습니다: completion handler, regionOfInterest, 여러 요청을 동시에 실행하는 기능, VNImageRequestHandler 및 VNSequenceRequestHandler 지원.

swift
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로 변환합니다. 다른 입력 데이터 타입의 경우, Vision 없이 Core ML을 직접 사용해야 합니다.

Apple WWDC 2023에 따르면, VNCoreMLRequest는 이미지 처리를 위해 Core ML을 사용하는 모든 iOS 앱의 40%에서 사용됩니다. 이것은 iOS 앱에 ML 모델을 통합하는 가장 인기 있는 방법입니다.

VNCoreMLModel: Core ML 모델 래퍼

VNCoreMLModel은 Core ML 모델(MLModel)을 Vision에서 사용할 수 있도록 적응시키는 래퍼입니다. 모델의 입력 및 출력 데이터를 Vision이 이해할 수 있는 형식으로 변환합니다: 이미지 → CVPixelBuffer, 결과 → VNObservation.

VNCoreMLModel 초기화는 모델과 Vision의 호환성을 확인합니다: 모델은 입력으로 이미지(Image Feature)를 받아들이고 분류(MLMultiArray 또는 Dictionary)를 반환해야 합니다. 모델이 호환되지 않으면, 초기화자가 오류를 발생시킵니다.

swift
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은 첫 로드 후 메모리에 모델을 캐시합니다. 동일한 모델을 다시 로드하면 캐시된 인스턴스가 반환되어 후속 요청이 빠말니다. 그러나 모델이 100MB를 초과하면, 리소스가 부족할 때 iOS가 메모리에서 언로드할 수 있습니다 — 이 경우 VNCoreMLModel이 자동으로 모델을 다시 로드합니다.

Create ML에서 학습된 모델의 경우, VNCoreMLModel은 추가 구성 없이 작동합니다. Create ML은 Vision이 자동으로 인식하는 올바른 메타데이터와 함께 모델을 내보냅니다 — VNCoreMLModel(model:)에 모델을 전달하기만 하면 됩니다.

imageCropAndScaleOption 구성

imageCropAndScaleOption은 VNCoreMLRequest의 주요 속성으로, Vision이 원본 이미지를 Core ML 모델 입력 크기에 맞게 변환하는 방법을 결정합니다. 올바른 옵션을 선택하는 것이 분류 정확도에 직접 영향을 미칩니다.

.centerCrop은 이미지를 중앙에서 정사각형으로 잘라낸 후 모델 입력 크기로 크기를 조정합니다. 중앙에 위치한 물체로 학습된 모델에 적합합니다(대부분의 ImageNet 분류기). .scaleFill은 비율을 유지하지 않고 이미지를 입력 크기로 단순 확장합니다. 빠르지만 기하학적 이슈가 발생합니다. .scaleFit은 비율을 유지하면서 크기를 조정하고, 테두리에 letterbox(검은 막대)를 추가합니다.

swift
import Vision

let request = VNCoreMLRequest(model: model)

// .centerCrop — 중앙 물체용 (기본)
request.imageCropAndScaleOption = .centerCrop

// .scaleFill — 균일 텍스처용 (왼곡 없음)
request.imageCropAndScaleOption = .scaleFill

// .scaleFit — 물체 비율이 중요할 때
request.imageCropAndScaleOption = .scaleFit

권장: 대부분의 분류 모델에는 .centerCrop을 사용하세요 — 이것이 정확도와 성능의 가장 좋은 균형을 제공합니다. 모델이 비율이 유지된 이미지(예: 문서 사진의 이상 감지)로 학습된 경우, letterbox가 있는 .scaleFit을 선택하세요.

Apple Developer Documentation 2024에 따르면, imageCropAndScaleOption의 올바르지 않은 선택은 모델 정확도를 15–25% 감소시킬 수 있습니다. 예를 들어, 프레임 가장자리에 있는 얼굴에 .scaleFill을 사용하면, .centerCrop에서 그 일부가 잘라나거나 .scaleFill에서 비율이 일어난 수 있습니다.

다른 VNRequest와의 결합

VNCoreMLRequest의 주요 장점은 단일 perform() 호출에서 다른 VNRequest와 결합할 수 있다는 점입니다. 이를 통해 파이프라인을 구축할 수 있습니다: 먼저 얼굴을 감지하고(VNDetectFaceRectanglesRequest), 그 다음에 커스텀 Core ML 모델(VNCoreMLRequest)을 통해 각 얼굴을 분류합니다.

VNCoreMLRequest는 regionOfInterest도 지원합니다 — 이 영역을 설정하면, Vision은 Core ML 모델에 전달하기 전에 이미지를 지정된 직사각형으로 잘라냅니다. 이것은 파이프라인에 필수적입니다: 얼굴 감지 후, VNCoreMLRequest의 regionOfInterest로 해당 경계 상자를 전달합니다.

swift
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])
    // 감정 분류 결과 처리
}

제한: VNCoreMLRequest에 대한 regionOfInterest는 모델이 동일한 크기와 비율의 이미지로 학습된 경우에만 의미가 있습니다. 모델이 엄격한 정사각형 입력(224x224)을 기대하는 경우, regionOfInterest가 있는 .centerCrop이 가장 좋은 결과를 제공합니다.

Apple ML Research에 따르면, regionOfInterest를 통한 “감지 → 분류” 파이프라인은 전체 이미지 분류에 비해 20–30% 정확도 향상을 제공합니다. 그 이유는 ML 모델이 배경 잡음 없이 관련 영역만을 수신하기 때문입니다.

파이프라인 유형요청 1(감지)요청 2(ML)
얼굴 → 감정VNDetectFaceRectanglesRequestVNCoreMLRequest기분 감지
물체 → 브랜드VNDetectObjectAtPointRequestVNCoreMLRequest로고 인식
텍스트 → 언어VNRecognizeTextRequestVNCoreMLRequest텍스트 언어 분류
장면 → 설명VNClassifyImageRequestVNCoreMLRequest태그 생성

VNCoreMLRequest 결과 처리

VNCoreMLRequest는 결과를 VNClassificationObservation(분류 모델의 경우) 또는 VNCoreMLFeatureValueObservation(회귀 및 다른 유형의 경우)로 반환합니다. 결과 유형은 Core ML 모델의 출력 데이터에 따라 달라집니다.

VNClassificationObservation에는 identifier(클래스 이름)와 confidence가 있습니다. softmax 출력이 있는 모델은 confidence 내림차순으로 정렬된 해당 관찰 배열을 반환합니다. VNCoreMLFeatureValueObservation에는 임의의 MLFeatureValue가 포함됩니다 — MultiArray, Double, String 또는 Dictionary가 된 수 있습니다.

swift
// 분류 모델용
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”)과 일치합니다. 이를 통해 여러 출력이 있는 모델을 처리할 수 있습니다 — 각 출력은 고유한 featureName을 가진 별도의 관찰로 표시됩니다.

최고의 실무 및 성능

VNCoreMLRequest는 Neural Engine (A12+), GPU 및 CPU에서 작동하도록 최적화되어 있습니다. Vision은 모델의 유형과 크기에 따라 실행에 가장 적합한 장치를 자동으로 선택합니다. 그러나 적절한 구성을 통해 성능을 더욱 향상시킬 수 있습니다.

메모리 관리

Core ML 모델은 첫 VNCoreMLRequest에서 메모리에 로드되고 앱이 언로드될 때까지 그래에 남아 있습니다. 200MB를 초과하는 모델의 경우, Apple은 필요에 따라 로드하고 MLModel.release()를 통해 언로드할 것을 권장합니다. VNCoreMLModel이 캐시를 자체 관리하지만, autoreleasepool을 통해 제어할 수 있습니다.

일괄 처리

일괄 처리를 위해 하나의 VNCoreMLRequest를 생성하고 다른 VNImageRequestHandler와 재사용하세요. 이미지 마다 새 VNCoreMLRequest를 생성하지 마세요 — 반복적인 모델 로드로 인해 처리가 늘어집니다. 10+ 이미지를 처리할 때 요청 재사용은 새로 생성하는 것에 비해 40% 까지 성능 향상을 제공합니다.

swift
// 올바름: 모든 이미지에 단일 요청
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은 A12+ 장치에서 호환되는 모델에 대한 Neural Engine을 선택합니다. 모델이 Neural Engine을 지원하지 않는 경우, Vision은 GPU 또는 CPU를 사용합니다. MLModelConfiguration.computeUnits를 통해 강제로 장치를 지정할 수 있지만, Apple은 자동 선택을 권장합니다.

Apple Performance Benchmarks 2024에 따르면, Neural Engine(iPhone 15 Pro)에서 VNCoreMLRequest는 MobileNetV2 분류를 3–5ms에 처리하고, GPU에서는 8–12ms, CPU에서는 20–30ms입니다. 이 차이는 30+ 프레임/초를 처리하는 실시간 앱에 중요합니다.

자주 묻는 질문

VNCoreMLRequest를 Vision 없이 Core ML과 직접 사용할 수 있습니까?

네, Core ML은 Vision 없이 MLModel.prediction()을 통해 직접 사용할 수 있습니다. 그러나 VNCoreMLRequest는 이미지 전처리(스케일링, 크롭, CVPixelBuffer 변환)를 자동화합니다. 모델이 이미지 대신 MultiArray 또는 Double을 받는 경우, Core ML을 직접 사용하세요. VNCoreMLRequest는 입력으로 Image Feature가 있는 모델에 대해서만 사용합니다.

모델의 새 버전이 출시되었을 때 VNCoreMLRequest를 어떻게 업데이트하나요?

업데이트된 MLModel에서 새 VNCoreMLModel 과 새 VNCoreMLRequest를 생성하세요. 이전 요청은 계속 이전 버전의 모델을 사용합니다. 원격 모델 업데이트를 위해, 서버에서 다운로드한 .mlmodelc 파일로부터 장치에서 모델을 컴파일하려면 MLModel.compileModel(at:)을 사용하세요.

VNCoreMLRequest는 여러 입력이 있는 모델을 지원합니까?

VNCoreMLRequest는 단일 Image Feature 입력이 있는 모델만 지원합니다. 모델에 여러 입력(예: 이미지 + 텍스트)이 있는 경우, MLModel을 통해 Core ML을 직접 사용하세요. Vision은 이미지 외에 추가 매개변수를 전달할 수 없습니다.

VNCoreMLRequest에 대한 최대 이미지 크기는 얼마인가요?

VNImageRequestHandler에 전달된 CGImage의 한계는 8192 x 8192 픽셀입니다. 그러나 Core ML 모델은 보통 224x224, 299x299 또는 512x512 입력을 기대합니다. Vision은 크 이미지를 입력 크기로 자동 조정합니다. 원본 이미지가 너무 크면, 메모리 절약을 위해 CGImage를 통해 미리 축소하세요.

VNCoreMLRequest를 백그라운드에서 실행할 수 있습니까?

네, VNRequest에 preferBackgroundProcessing = true를 설정하세요. 이를 통해 시스템이 리소스 집중적인 모드(예: 콘텐츠 로딩)에 있을 때 Vision이 요청 실행을 지연할 수 있습니다. 또한 handler.perform()을 호출하려면 DispatchQueue.global(qos: .background)를 꼭 사용하세요.

요약

  • VNCoreMLRequest — 자동 이미지 전처리를 통한 Vision 파이프라인에서 Core ML 모델을 실행하기 위한 VNRequest의 하위 클래스.
  • VNCoreMLModel은 Vision을 위해 MLModel를 래핑하고, CGImage를 필요한 크기와 색공간의 CVPixelBuffer로 자동 변환합니다.
  • imageCropAndScaleOption(centerCrop, scaleFill, scaleFit)은 크기 조정 전략을 결정하고 모델 정확도에 15–25% 영향을 미칩니다.
  • VNDetectFaceRectanglesRequest 및 다른 VNRequest와의 결합으로 regionOfInterest를 통한 “감지 → 분류” 파이프라인을 구축할 수 있습니다.
  • 결과는 VNClassificationObservation(분류의 경우) 또는 VNCoreMLFeatureValueObservation(회귀/다른 유형의 경우)로 반환됩니다.
  • 일괄 처리를 위한 하나의 VNCoreMLRequest 재사용은 이미지마다 새로 생성하는 것보다 40% 까지 성능 향상을 제공합니다.
  • Neural Engine(MobileNetV2에서 3–5ms)에서의 성능은 CPU보다 4–6배 높으며, 실시간 앱에 중요합니다.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기