VNCoreMLRequest — เป็นคลาสย่อยของ VNRequest ที่ช่วยให้สามารถเรียกใช้โมเดล Core ML ภายในไปป์ไลน์ของ Vision รวมข้อดีของตัวจับที่เตรียมพร้อมของ Vision (ใบหน้า ข้อความ วัตถุ) กับโมเดล ML ที่กำหนดเองสำหรับการจัดหมวดหมู่และการถดถอย โดยอัตโนมัติ 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: ตัวจัดการเสร็จสิ้น 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 (คอมไพล์ตอน build)
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 ซึ่งมีความสำคัญอย่างยิ่งสำหรับไปป์ไลน์: หลังจากการตรวจจับใบหน้า คุณจะส่งกรอบขอบเขตของมันเป็น 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 มิลลิวินาที ความแตกต่างนี้มีความสำคัญมากสำหรับแอปแบบเรียลไทม์ที่ประมวลผล 30+ เฟรมต่อวินาที
คำถามที่พบบ่อย
ได้ Core ML สามารถใช้งานโดยตรงผ่าน MLModel.prediction() โดยไม่ต้องใช้ Vision อย่างไรก็ตาม VNCoreMLRequest จะทำให้การประมวลผลภาพล่วงหน้า (การปรับขนาด การตัด การแปลงเป็น 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 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม