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()
    }
}