🧠 Core ML 완전정복
온디바이스 머신러닝으로 이미지 분류, 객체 탐지, 텍스트 분석까지! 모든 처리가 기기 내에서.
⭐ 난이도: ⭐⭐⭐⭐
⏱️ 예상 시간: 3-4h
📂 App Services
✨ Core ML이란?
Core ML은 Apple의 머신러닝 프레임워크입니다. TensorFlow, PyTorch 모델을 변환하여 iPhone에서 실행할 수 있습니다. 모든 처리가 기기 내에서 이루어져 프라이버시가 보장됩니다.
📦 모델 추가하기
모델 가져오기
1. Core ML 모델 다운로드
- Apple 제공 모델: https://developer.apple.com/machine-learning/models/
- MobileNet, ResNet, SqueezeNet 등
2. Xcode 프로젝트에 .mlmodel 파일 드래그
3. 자동으로 Swift 코드 생성됨
- MyModel.swift (자동 생성, 수정 금지)🖼️ 이미지 분류 (Image Classification)
ImageClassifier.swift
import CoreML import Vision import UIKit class ImageClassifier { // MobileNet 모델 로드 (Apple 제공) func classifyImage(_ image: UIImage) async throws -> String { // 1. 모델 로드 let model = try VNCoreMLModel(for: MobileNet().model) // 2. 요청 생성 let request = VNCoreMLRequest(model: model) // 3. 이미지 처리 guard let cgImage = image.cgImage else { throw NSError(domain: "Image Error", code: 0) } let handler = VNImageRequestHandler(cgImage: cgImage) try handler.perform([request]) // 4. 결과 처리 guard let results = request.results as? [VNClassificationObservation], let topResult = results.first else { return "분류 실패" } return "\(topResult.identifier) (\(Int(topResult.confidence * 100))%)" } } // 사용 예시 let classifier = ImageClassifier() let image = UIImage(named: "dog.jpg")! let result = try await classifier.classifyImage(image) print(result) // "golden retriever (92%)"
📱 SwiftUI 통합
ClassifierView.swift
import SwiftUI import PhotosUI struct ImageClassifierView: View { @State private var selectedItem: PhotosPickerItem? @State private var selectedImage: UIImage? @State private var result: String = "" @State private var isProcessing = false let classifier = ImageClassifier() var body: some View { VStack(spacing: 20) { if let image = selectedImage { Image(uiImage: image) .resizable() .scaledToFit() .frame(height: 300) .cornerRadius(12) } if isProcessing { ProgressView("분석 중...") } else if !result.isEmpty { Text(result) .font(.title2) .bold() } PhotosPicker(selection: $selectedItem, matching: .images) { Label("사진 선택", systemImage: "photo") } .buttonStyle(.borderedProminent) } .padding() .onChange(of: selectedItem) { Task { if let data = try? await selectedItem?.loadTransferable(type: Data.self), let image = UIImage(data: data) { selectedImage = image await classify(image) } } } } func classify(_ image: UIImage) async { isProcessing = true defer { isProcessing = false } result = (try? await classifier.classifyImage(image)) ?? "오류" } }
🎯 객체 탐지 (Object Detection)
ObjectDetector.swift
import Vision func detectObjects(_ image: UIImage) async throws -> [VNRecognizedObjectObservation] { // YOLO 모델 사용 (프로젝트에 추가 필요) let model = try VNCoreMLModel(for: YOLOv3().model) let request = VNCoreMLRequest(model: model) guard let cgImage = image.cgImage else { throw NSError(domain: "Image Error", code: 0) } let handler = VNImageRequestHandler(cgImage: cgImage) try handler.perform([request]) guard let results = request.results as? [VNRecognizedObjectObservation] else { return [] } return results } // 결과 그리기 func drawBoxes(on image: UIImage, results: [VNRecognizedObjectObservation]) -> UIImage { let renderer = UIGraphicsImageRenderer(size: image.size) return renderer.image { context in image.draw(at: .zero) UIColor.red.setStroke() context.cgContext.setLineWidth(3) for observation in results { // Vision 좌표계 변환 (왼쪽 하단 = 0,0) let boundingBox = observation.boundingBox let rect = CGRect( x: boundingBox.origin.x * image.size.width, y: (1 - boundingBox.origin.y - boundingBox.height) * image.size.height, width: boundingBox.width * image.size.width, height: boundingBox.height * image.size.height ) context.cgContext.stroke(rect) // 라벨 표시 if let label = observation.labels.first { let text = "\(label.identifier) \(Int(label.confidence * 100))%" let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont.boldSystemFont(ofSize: 16), .foregroundColor: UIColor.red ] text.draw(at: rect.origin, withAttributes: attributes) } } } }
📝 텍스트 분석 (Sentiment Analysis)
SentimentAnalysis.swift
import NaturalLanguage func analyzeSentiment(_ text: String) -> String { let tagger = NLTagger(tagSchemes: [.sentimentScore]) tagger.string = text let (sentiment, _) = tagger.tag( at: text.startIndex, unit: .paragraph, scheme: .sentimentScore ) guard let sentimentValue = sentiment, let score = Double(sentimentValue.rawValue) else { return "중립" } if score > 0.3 { return "😊 긍정적 (\(Int(score * 100))%)" } else if score < -0.3 { return "😢 부정적 (\(Int(abs(score) * 100))%)" } else { return "😐 중립적" } } // 사용 예시 let text1 = "이 영화 정말 재미있었어요!" print(analyzeSentiment(text1)) // "😊 긍정적" let text2 = "최악의 서비스였습니다." print(analyzeSentiment(text2)) // "😢 부정적"
🎤 음성 인식 통합
SpeechToML.swift
import Speech func transcribeAndClassify(audioURL: URL) async throws -> (String, String) { // 1. 음성 인식 let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "ko-KR"))! let request = SFSpeechURLRecognitionRequest(url: audioURL) let result = try await recognizer.recognitionTask(with: request).bestTranscription let text = result.formattedString // 2. 감정 분석 let sentiment = analyzeSentiment(text) return (text, sentiment) }
🔄 모델 업데이트 (On-Device Training)
OnDeviceTraining.swift
import CoreML import CreateML // Updatable 모델만 가능 (Create ML로 생성 시 활성화) func updateModel(with newData: [MLDataTable]) throws { // 1. 기존 모델 로드 let modelURL = Bundle.main.url(forResource: "MyModel", withExtension: "mlmodelc")! let model = try MLModel(contentsOf: modelURL) // 2. 업데이트 설정 let configuration = MLModelConfiguration() configuration.computeUnits = .all // 3. 학습 (온디바이스) let updateTask = try MLUpdateTask( forModelAt: modelURL, trainingData: newData, configuration: configuration ) updateTask.resume() // 4. 완료 핸들러 // updateTask.completionHandler = { context in ... } }
⚡ 성능 최적화
Performance.swift
import CoreML // 1. Compute Unit 설정 let config = MLModelConfiguration() config.computeUnits = .all // CPU + GPU + Neural Engine config.computeUnits = .cpuAndGPU // Neural Engine 제외 config.computeUnits = .cpuAndNeuralEngine // GPU 제외 config.computeUnits = .cpuOnly // CPU만 let model = try MobileNet(configuration: config) // 2. 배치 처리 (여러 이미지 동시 처리) let images: [CVPixelBuffer] = /* ... */ let batch = MLArrayBatchProvider(array: images.map { image in try! MLFeatureProvider(image: image) }) let results = try model.predictions(from: batch) // 3. 모델 재사용 (인스턴스 캐싱) class ModelManager { static let shared = ModelManager() let model: MobileNet private init() { model = try! MobileNet(configuration: MLModelConfiguration()) } }
🔧 Create ML로 모델 만들기
Training.swift
// Create ML 앱 사용 (GUI) 1. Xcode > Open Developer Tool > Create ML 2. 새 프로젝트 생성 3. 학습 데이터 추가 4. Train 클릭 5. .mlmodel 파일 export // 코드로 학습 (Swift Playgrounds) import CreateML let trainingData = try MLImageClassifier.DataSource.labeledDirectories(at: trainingDataURL) let testData = try MLImageClassifier.DataSource.labeledDirectories(at: testDataURL) let model = try MLImageClassifier( trainingData: trainingData, validationData: testData ) try model.write(to: URL(fileURLWithPath: "/tmp/MyModel.mlmodel"))
🐍 Python 모델 변환
convert.py
# TensorFlow/PyTorch → Core ML 변환 import coremltools as ct # TensorFlow 모델 변환 import tensorflow as tf model = tf.keras.models.load_model('model.h5') coreml_model = ct.convert(model) coreml_model.save('MyModel.mlmodel') # PyTorch 모델 변환 import torch model = torch.load('model.pth') traced_model = torch.jit.trace(model, example_input) coreml_model = ct.convert(traced_model) coreml_model.save('MyModel.mlmodel')
💡 Core ML 장점
✅ 프라이버시 보장 (모든 처리가 기기 내)
✅ 오프라인 작동
✅ 낮은 지연시간
✅ Neural Engine 활용 (A11 이상)
✅ 배터리 효율적