Section 6/161 menit
6. Menjalankan Inferensi di Device
6. Menjalankan Inferensi di Device
Synchronous Prediction (Paling Sederhana)
swift
import CoreML
import UIKit
// Generated class dari Xcode setelah drag .mlmodel
// Xcode generate: ImageClassifier.swift, ImageClassifierInput.swift, ImageClassifierOutput.swift
func classifyImage(_ image: UIImage) throws -> String {
// 1. Pastikan model di-cache — jangan init per-request
let model = try ImageClassifier(configuration: MLModelConfiguration())
// 2. Siapkan input — ImageClassifier butuh CVPixelBuffer
guard let cgImage = image.cgImage else {
throw ClassificationError.invalidImage
}
let input = try ImageClassifierInput(imageWith: cgImage)
// 3. Jalankan prediksi
let output = try model.prediction(input: input)
// 4. Baca hasil
return output.classLabel
}
// Contoh dengan probabilitas
func classifyImageWithProbs(_ image: UIImage) throws -> [(label: String, confidence: Double)] {
let model = try ImageClassifier(configuration: MLModelConfiguration())
guard let cgImage = image.cgImage else {
throw ClassificationError.invalidImage
}
let input = try ImageClassifierInput(imageWith: cgImage)
let output = try model.prediction(input: input)
// classLabelProbs: [String: Double]
let sorted = output.classLabelProbs
.sorted { $0.value > $1.value }
.prefix(5)
.map { (label: $0.key, confidence: $0.value) }
return Array(sorted)
}
Batch Prediction untuk Multiple Inputs
swift
func classifyBatch(images: [UIImage]) throws -> [String] {
let model = try ImageClassifier(configuration: MLModelConfiguration())
// Buat array input
let inputs: [ImageClassifierInput] = try images.compactMap { image in
guard let cgImage = image.cgImage else { return nil }
return try ImageClassifierInput(imageWith: cgImage)
}
// Batch prediction — lebih efisien daripada loop satu-satu
let batchProvider = MLArrayBatchProvider(array: inputs)
let outputProvider = try model.predictions(fromBatch: batchProvider)
return (0..<outputProvider.count).map { i in
let output = outputProvider.features(at: i)
return output.featureValue(for: "classLabel")!.stringValue
}
}
Manual MLFeatureProvider (Untuk Model Tanpa Code Generation)
swift
// Ketika model tidak di-generate (misal: model di-download runtime)
func predictWithFeatureProvider(modelURL: URL, inputData: MLMultiArray) throws -> String {
let model = try MLModel(contentsOf: modelURL)
// Buat input manual
let inputFeatures = try MLDictionaryFeatureProvider(dictionary: [
"input": MLFeatureValue(multiArray: inputData)
])
let outputFeatures = try model.prediction(from: inputFeatures)
guard let labelValue = outputFeatures.featureValue(for: "classLabel") else {
throw PredictionError.missingOutput
}
return labelValue.stringValue
}
Membuat CVPixelBuffer dari UIImage Secara Manual
swift
// Beberapa model membutuhkan CVPixelBuffer, bukan CGImage
extension UIImage {
func toCVPixelBuffer(size: CGSize) -> CVPixelBuffer? {
let attributes: [CFString: Any] = [
kCVPixelBufferCGImageCompatibilityKey: true,
kCVPixelBufferCGBitmapContextCompatibilityKey: true
]
var pixelBuffer: CVPixelBuffer?
let status = CVPixelBufferCreate(
kCFAllocatorDefault,
Int(size.width),
Int(size.height),
kCVPixelFormatType_32ARGB,
attributes as CFDictionary,
&pixelBuffer
)
guard status == kCVReturnSuccess, let buffer = pixelBuffer else { return nil }
CVPixelBufferLockBaseAddress(buffer, [])
defer { CVPixelBufferUnlockBaseAddress(buffer, []) }
let context = CGContext(
data: CVPixelBufferGetBaseAddress(buffer),
width: Int(size.width),
height: Int(size.height),
bitsPerComponent: 8,
bytesPerRow: CVPixelBufferGetBytesPerRow(buffer),
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
)
context?.draw(cgImage!, in: CGRect(origin: .zero, size: size))
return buffer
}
}