Section 4/201 menit

4. Core ML: Fondasi ML di iOS

4. Core ML: Fondasi ML di iOS

Anatomy MLModel

swift
// Core ML: anatomy dasar inference pipeline

import CoreML
import Vision

final class ImageClassifier {
    private let model: VNCoreMLModel

    init() throws {
        // .mlpackage dikompilasi menjadi .mlmodelc oleh Xcode
        let config = MLModelConfiguration()
        config.computeUnits = .all  // Neural Engine + GPU + CPU

        let coreMLModel = try FoodClassifier(configuration: config).model
        self.model = try VNCoreMLModel(for: coreMLModel)
    }

    func classify(image: UIImage) async throws -> [Classification] {
        guard let cgImage = image.cgImage else {
            throw MLError.invalidInput("UIImage tidak memiliki CGImage")
        }

        return try await withCheckedThrowingContinuation { continuation in
            let request = VNCoreMLRequest(model: model) { request, error in
                if let error {
                    continuation.resume(throwing: error)
                    return
                }

                let results = request.results as? [VNClassificationObservation] ?? []
                let classifications = results
                    .filter { $0.confidence > 0.1 }  // Filter noise
                    .map { Classification(label: $0.identifier, confidence: $0.confidence) }

                continuation.resume(returning: classifications)
            }

            request.imageCropAndScaleOption = .centerCrop

            let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
            do {
                try handler.perform([request])
            } catch {
                continuation.resume(throwing: error)
            }
        }
    }
}

struct Classification {
    let label: String
    let confidence: Float  // 0.0 - 1.0
}

enum MLError: Error {
    case invalidInput(String)
    case modelNotFound
    case inferenceFailure(String)
}

MLFeatureProvider untuk Input Custom

Beberapa model butuh input yang lebih kompleks dari gambar — gunakan MLFeatureProvider:

swift
// Core ML: custom feature provider untuk model tabular/multi-input

import CoreML

final class LoanApprovalPredictor {
    private let model: LoanApprovalModel

    init() throws {
        let config = MLModelConfiguration()
        config.computeUnits = .cpuAndNeuralEngine
        self.model = try LoanApprovalModel(configuration: config)
    }

    func predict(applicant: LoanApplicant) throws -> LoanDecision {
        // Buat input menggunakan generated Swift interface dari .mlpackage
        let input = LoanApprovalModelInput(
            age: Double(applicant.age),
            income: applicant.annualIncome,
            creditScore: Double(applicant.creditScore),
            existingDebt: applicant.existingDebt,
            loanAmount: applicant.requestedAmount,
            employmentYears: Double(applicant.yearsEmployed)
        )

        let output = try model.prediction(input: input)

        return LoanDecision(
            approved: output.approved == "yes",
            confidence: output.approvedProbability["yes"] ?? 0,
            reason: output.explanation
        )
    }

    // Batch prediction untuk multiple applicants
    func predictBatch(applicants: [LoanApplicant]) throws -> [LoanDecision] {
        let inputs = applicants.map { applicant in
            LoanApprovalModelInput(
                age: Double(applicant.age),
                income: applicant.annualIncome,
                creditScore: Double(applicant.creditScore),
                existingDebt: applicant.existingDebt,
                loanAmount: applicant.requestedAmount,
                employmentYears: Double(applicant.yearsEmployed)
            )
        }

        let options = MLPredictionOptions()
        options.usesCPUOnly = false

        let outputs = try model.predictions(inputs: inputs, options: options)
        return outputs.map { output in
            LoanDecision(
                approved: output.approved == "yes",
                confidence: output.approvedProbability["yes"] ?? 0,
                reason: output.explanation
            )
        }
    }
}

struct LoanApplicant {
    let age: Int
    let annualIncome: Double
    let creditScore: Int
    let existingDebt: Double
    let requestedAmount: Double
    let yearsEmployed: Int
}

struct LoanDecision {
    let approved: Bool
    let confidence: Double
    let reason: String
}