Section 14/201 menit

14. Privacy & Etika ML di iOS

14. Privacy & Etika ML di iOS

Prinsip Privacy by Design untuk ML

swift
1. On-device first: proses semua data sensitif di device, kirim hanya yang diperlukan
2. Data minimization: minta hanya permission yang benar-benar dibutuhkan
3. Transparency: jelaskan ke user data apa yang diproses
4. User control: berikan opsi untuk opt-out dari personalisasi
5. Ephemeral processing: jangan simpan data sensitif lebih lama dari diperlukan
swift
// Privacy: implementasi on-device processing dengan differential privacy

import CoreML
import CryptoKit

final class PrivacyPreservingAnalyzer {
    // Proses gambar on-device, hanya kirim hasil (bukan gambar)
    func analyzeImagePrivately(image: UIImage) async throws -> AnalysisSummary {
        // Semua inference terjadi on-device
        let classifications = try await imageClassifier.classify(image: image)
        let faces = try await visionAnalyzer.detectFaces(in: image)

        // Kembalikan hanya metadata, bukan data raw
        return AnalysisSummary(
            dominantCategory: classifications.first?.label ?? "unknown",
            faceCount: faces.count,
            // Jangan simpan atau kirim koordinat wajah
            containsFace: !faces.isEmpty
        )
    }

    // Anonymisasi sebelum logging untuk analytics
    func logEventAnonymously(_ event: UserEvent) {
        // Hash identifier agar tidak bisa dilacak ke individu
        let hashedId = SHA256.hash(data: Data(event.userId.utf8))
            .compactMap { String(format: "%02x", $0) }
            .joined()

        Analytics.log(event: event.name, userId: hashedId)
    }
}

struct AnalysisSummary {
    let dominantCategory: String
    let faceCount: Int
    let containsFace: Bool
}

struct UserEvent {
    let userId: String
    let name: String
    let timestamp: Date
}

Bias Detection dan Fairness

swift
// Testing: deteksi bias dalam model klasifikasi

import CoreML

struct FairnessEvaluator {
    let model: MLModel

    // Evaluasi akurasi per grup demografi
    func evaluateFairness(testData: [(input: MLFeatureProvider, label: String, group: String)]) -> FairnessReport {
        var groupResults: [String: (correct: Int, total: Int)] = [:]

        for sample in testData {
            guard let output = try? model.prediction(from: sample.input),
                  let predicted = output.featureValue(for: "classLabel")?.stringValue else {
                continue
            }

            var result = groupResults[sample.group] ?? (0, 0)
            result.total += 1
            if predicted == sample.label { result.correct += 1 }
            groupResults[sample.group] = result
        }

        let accuracies = groupResults.mapValues { Double($0.correct) / Double($0.total) }
        let minAccuracy = accuracies.values.min() ?? 0
        let maxAccuracy = accuracies.values.max() ?? 0

        return FairnessReport(
            perGroupAccuracy: accuracies,
            disparityRatio: minAccuracy / maxAccuracy,  // < 0.8 = potential bias
            isAcceptable: (maxAccuracy - minAccuracy) < 0.1
        )
    }
}

struct FairnessReport {
    let perGroupAccuracy: [String: Double]
    let disparityRatio: Double  // Idealnya > 0.8
    let isAcceptable: Bool
}