Section 12/201 menit
12. Optimasi Performa: Compute Units & Batching
12. Optimasi Performa: Compute Units & Batching
Memilih Compute Units yang Tepat
swift
// Core ML: benchmark compute units untuk model specific
import CoreML
final class ComputeUnitBenchmark {
static func benchmark(modelURL: URL, input: MLFeatureProvider) async {
let configurations: [(String, MLComputeUnits)] = [
("CPU Only", .cpuOnly),
("CPU + GPU", .cpuAndGPU),
("CPU + Neural Engine", .cpuAndNeuralEngine),
("All (Auto)", .all)
]
for (name, units) in configurations {
let config = MLModelConfiguration()
config.computeUnits = units
do {
let model = try MLModel(contentsOf: modelURL, configuration: config)
let iterations = 50
let start = CFAbsoluteTimeGetCurrent()
for _ in 0..<iterations {
_ = try model.prediction(from: input)
}
let elapsed = (CFAbsoluteTimeGetCurrent() - start) / Double(iterations) * 1000
print("\(name): \(String(format: "%.2f", elapsed))ms per inference")
} catch {
print("\(name): Error — \(error)")
}
}
}
}
// Gunakan MLComputePlan untuk analisis lebih detail (iOS 17+)
func analyzeComputePlan(modelURL: URL) async throws {
let config = MLModelConfiguration()
config.computeUnits = .all
let plan = try await MLComputePlan.load(contentsOf: modelURL, configuration: config)
for (layer, deviceUsage) in plan.deviceUsage {
print("Layer: \(layer), Device: \(deviceUsage)")
}
}
Batch Processing untuk Throughput Tinggi
swift
// Core ML: batch prediction untuk throughput optimal
import CoreML
final class BatchImageClassifier {
private let model: MLModel
init(modelURL: URL) throws {
let config = MLModelConfiguration()
config.computeUnits = .all
self.model = try MLModel(contentsOf: modelURL, configuration: config)
}
func classifyBatch(images: [UIImage]) async throws -> [String] {
let BATCH_SIZE = 32 // Sesuaikan dengan memory budget
var allResults: [String] = []
// Proses dalam chunks untuk kontrol memory
for chunk in images.chunked(into: BATCH_SIZE) {
let providers: [MLFeatureProvider] = chunk.compactMap { image in
guard let cgImage = image.cgImage,
let pixelBuffer = cgImage.toPixelBuffer(size: CGSize(width: 224, height: 224)) else {
return nil
}
return try? MLDictionaryFeatureProvider(dictionary: [
"image": MLFeatureValue(pixelBuffer: pixelBuffer)
])
}
let batchProvider = MLArrayBatchProvider(array: providers)
let options = MLPredictionOptions()
options.usesCPUOnly = false
let results = try model.predictions(from: batchProvider, options: options)
for i in 0..<results.count {
let output = results.features(at: i)
if let label = output.featureValue(for: "classLabel")?.stringValue {
allResults.append(label)
}
}
}
return allResults
}
}
extension Array {
func chunked(into size: Int) -> [[Element]] {
stride(from: 0, to: count, by: size).map {
Array(self[$0..<Swift.min($0 + size, count)])
}
}
}