Section 9/161 menit
9. Asynchronous Prediction dengan Swift Concurrency
9. Asynchronous Prediction dengan Swift Concurrency
MLModel mendukung async prediction sejak iOS 15, memungkinkan inferensi tanpa blocking main thread.
Async/Await dengan Generated Class
swift
import CoreML
actor MLPredictionService {
private let model: ImageClassifier
init() throws {
let config = MLModelConfiguration()
config.computeUnits = .all
self.model = try ImageClassifier(configuration: config)
}
// prediction(from:) versi async tersedia di iOS 15+
func classify(image: UIImage) async throws -> ClassificationResult {
guard let cgImage = image.cgImage else {
throw ClassificationError.invalidImage
}
let input = try ImageClassifierInput(imageWith: cgImage)
// Async prediction — tidak block thread
let output = try await model.prediction(input: input)
return ClassificationResult(
label: output.classLabel,
confidence: output.classLabelProbs[output.classLabel] ?? 0
)
}
// Batch async
func classifyBatch(images: [UIImage]) async throws -> [ClassificationResult] {
return try await withThrowingTaskGroup(of: (Int, ClassificationResult).self) { group in
for (index, image) in images.enumerated() {
group.addTask {
let result = try await self.classify(image: image)
return (index, result)
}
}
var results = [(Int, ClassificationResult)]()
for try await result in group {
results.append(result)
}
return results.sorted { $0.0 < $1.0 }.map { $0.1 }
}
}
}
struct ClassificationResult {
let label: String
let confidence: Double
}
Streaming Prediction untuk Model Stateful (iOS 18+)
swift
// Stateful models: LLM, RNN, speech recognition
// Model menyimpan state antar prediction calls
class StatefulModelService {
private var model: MLModel?
private var state: MLState?
func loadModel() throws {
let url = Bundle.main.url(forResource: "StreamingASR", withExtension: "mlmodelc")!
model = try MLModel(contentsOf: url)
state = model?.makeState()
}
// Kirim audio chunk per chunk, model simpan konteks
func processAudioChunk(_ audioBuffer: MLMultiArray) throws -> String {
guard let model, let state else { throw ModelError.notLoaded }
let input = try MLDictionaryFeatureProvider(dictionary: [
"audio_chunk": MLFeatureValue(multiArray: audioBuffer)
])
// Prediction dengan state — hasil dipengaruhi chunk sebelumnya
let output = try model.prediction(from: input, using: state)
return output.featureValue(for: "transcript")?.stringValue ?? ""
}
func resetState() {
state = model?.makeState()
}
}