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
}