CoreML для Swift: полное руководство с примерами
1. Что это и зачем нужна
CoreML — это фреймворк машинного обучения, разработанный компанией Apple для интеграции моделей машинного обучения непосредственно в приложения под iOS, macOS, watchOS и tvOS. В отличие от облачных решений, CoreML выполняет все вычисления на устройстве пользователя, что обеспечивает мгновенную обработку данных без задержек на передачу по сети и полную конфиденциальность пользовательских данных.
Зачем нужна CoreML? Во-первых, она позволяет разработчикам внедрять сложные функции ИИ (распознавание изображений, обработку естественного языка, анализ звука) без необходимости разбираться в тонкостях нейронных сетей. Во-вторых, работа на устройстве означает, что приложение может функционировать в офлайн-режиме, что критически важно для многих сценариев использования. В-третьих, Apple оптимизировала CoreML для работы с Neural Engine, GPU и CPU, что обеспечивает максимальную производительность на всех устройствах Apple.
CoreML поддерживает модели, созданные в популярных фреймворках (TensorFlow, PyTorch, scikit-learn), которые можно конвертировать в формат .mlmodel с помощью инструмента coremltools. Фреймворк также тесно интегрируется с Vision (для анализа изображений), Natural Language (для работы с текстом) и SoundAnalysis (для аудио).
2. Установка
CoreML является встроенным фреймворком Apple и не требует установки через менеджеры пакетов. Для его использования достаточно импортировать его в проект. Однако для конвертации моделей из других форматов вам понадобится Python-пакет coremltools.
Установка coremltools (Python):
pip install coremltools
Подключение CoreML в проекте Xcode:
import CoreML
Для работы с изображениями и видео дополнительно импортируйте Vision:
import Vision
3. Быстрый старт — минимальный рабочий пример
Создадим простое приложение, которое классифицирует изображение с помощью предобученной модели MobileNetV2. Сначала скачайте модель MobileNetV2.mlmodel из репозитория Apple или конвертируйте её с помощью coremltools.
Минимальный пример классификации изображения:
import CoreML
import Vision
import UIKit
// 1. Загружаем модель
guard let model = try? VNCoreMLModel(for: MobileNetV2().model) else {
fatalError("Не удалось загрузить модель")
}
// 2. Создаем запрос
let request = VNCoreMLRequest(model: model) { request, error in
guard let results = request.results as? [VNClassificationObservation],
let topResult = results.first else {
print("Не удалось классифицировать изображение")
return
}
print("Распознано: \(topResult.identifier) с вероятностью \(topResult.confidence)")
}
// 3. Загружаем изображение
guard let image = UIImage(named: "cat.jpg"),
let ciImage = CIImage(image: image) else {
fatalError("Не удалось загрузить изображение")
}
// 4. Выполняем запрос
let handler = VNImageRequestHandler(ciImage: ciImage)
try? handler.perform([request])
4. Основные методы/функции/классы
4.1. MLModel
Сигнатура: class MLModel
Что делает: Основной класс, представляющий загруженную модель машинного обучения. Позволяет выполнять предсказания и получать информацию о модели.
Пример:
// Загрузка модели из файла
guard let modelURL = Bundle.main.url(forResource: "MyModel", withExtension: "mlmodelc"),
let model = try? MLModel(contentsOf: modelURL) else {
fatalError("Не удалось загрузить модель")
}
// Получение метаданных модели
let description = model.modelDescription
print("Входные данные: \(description.inputDescriptionsByName)")
print("Выходные данные: \(description.outputDescriptionsByName)")
4.2. MLFeatureProvider
Сигнатура: protocol MLFeatureProvider
Что делает: Протокол, который определяет интерфейс для предоставления входных данных модели. Обычно используется через конкретные реализации, такие как MLDictionaryFeatureProvider.
Пример:
// Создание входных данных для модели
let inputFeatures: [String: MLFeatureValue] = [
"input": MLFeatureValue(double: 3.5),
"other_input": MLFeatureValue(string: "test")
]
guard let provider = try? MLDictionaryFeatureProvider(dictionary: inputFeatures) else {
fatalError("Не удалось создать provider")
}
// Использование с моделью
let output = try? model.prediction(from: provider)
4.3. MLMultiArray
Сигнатура: class MLMultiArray
Что делает: Представляет многомерный массив данных (тензор), который используется для передачи больших объемов числовых данных в модель и из нее.
Пример:
// Создание многомерного массива 3x3
let shape = [3, 3] as [NSNumber]
guard let array = try? MLMultiArray(shape: shape, dataType: .double) else {
fatalError("Не удалось создать MLMultiArray")
}
// Заполнение данными
for i in 0..<3 {
for j in 0..<3 {
let index = [i, j] as [NSNumber]
array[index] = NSNumber(value: Double(i * 3 + j))
}
}
// Чтение данных
let value = array[[1, 2] as [NSNumber]].doubleValue
print("Значение [1,2]: \(value)")
4.4. VNCoreMLModel
Сигнатура: class VNCoreMLModel
Что делает: Обертка для модели CoreML, которая позволяет использовать её с фреймворком Vision для обработки изображений и видео.
Пример:
// Создание Vision-модели из CoreML модели
guard let visionModel = try? VNCoreMLModel(for: MyImageClassifier().model) else {
fatalError("Не удалось создать VNCoreMLModel")
}
// Настройка запроса
let request = VNCoreMLRequest(model: visionModel) { request, error in
// Обработка результатов
}
request.imageCropAndScaleOption = .centerCrop
4.5. MLModelConfiguration
Сигнатура: class MLModelConfiguration
Что делает: Позволяет настроить параметры выполнения модели, такие как использование конкретного вычислительного устройства (CPU, GPU, Neural Engine) и политику вычислений.
Пример:
// Создание конфигурации
let config = MLModelConfiguration()
config.computeUnits = .all // Использовать все доступные вычислительные блоки
config.allowLowPrecisionAccumulationOnGPU = true
// Загрузка модели с конфигурацией
guard let model = try? MyModel(configuration: config) else {
fatalError("Не удалось загрузить модель с конфигурацией")
}
4.6. MLPredictionOptions
Сигнатура: class MLPredictionOptions
Что делает: Позволяет задать опции для выполнения предсказания, например, использовать ли кэширование результатов.
Пример:
// Создание опций предсказания
let options = MLPredictionOptions()
options.outputBackings = .default
// Выполнение предсказания с опциями
let output = try? model.prediction(from: inputProvider, options: options)
4.7. MLFeatureValue
Сигнатура: class MLFeatureValue
Что делает: Представляет одно значение признака (число, строка, изображение, многомерный массив и т.д.), которое может быть передано в модель.
Пример:
// Создание различных типов значений
let doubleValue = MLFeatureValue(double: 42.0)
let stringValue = MLFeatureValue(string: "hello")
let int64Value = MLFeatureValue(int64: 100)
// Создание значения из изображения
guard let image = UIImage(named: "photo"),
let pixelBuffer = image.pixelBuffer() else {
fatalError("Не удалось создать pixel buffer")
}
let imageValue = MLFeatureValue(pixelBuffer: pixelBuffer)
4.8. MLModelDescription
Сигнатура: class MLModelDescription
Что делает: Предоставляет метаданные о модели: имена и типы входных/выходных данных, информацию об авторе, версию и т.д.
Пример:
// Получение описания модели
let description = model.modelDescription
// Информация о входных данных
for (name, featureDescription) in description.inputDescriptionsByName {
print("Вход: \(name), тип: \(featureDescription.type), многозначный: \(featureDescription.isMultiArray)")
}
// Информация о выходных данных
for (name, featureDescription) in description.outputDescriptionsByName {
print("Выход: \(name), тип: \(featureDescription.type)")
}
// Метаданные
if let metadata = description.metadata {
print("Автор: \(metadata.author ?? "неизвестен")")
print("Описание: \(metadata.shortDescription ?? "нет описания")")
print("Версия: \(metadata.versionString ?? "не указана")")
}
4.9. MLBatchProvider
Сигнатура: protocol MLBatchProvider
Что делает: Позволяет выполнять пакетные предсказания для нескольких входных данных одновременно, что значительно ускоряет обработку.
Пример:
// Создание пакета входных данных
let inputs: [MLFeatureProvider] = [input1, input2, input3]
let batch = MLArrayBatchProvider(array: inputs)
// Выполнение пакетного предсказания
guard let batchOutput = try? model.predictions(fromBatch: batch) else {
fatalError("Ошибка пакетного предсказания")
}
// Обработка результатов
for i in 0..<batchOutput.count {
let output = batchOutput.features(at: i)
// Обработка каждого выхода
}
4.10. MLUpdateTask
Сигнатура: class MLUpdateTask
Что делает: Позволяет выполнять дообучение (fine-tuning) модели на устройстве с использованием новых данных. Доступно только для моделей, поддерживающих обновление.
Пример:
// Создание контекста для обновления
let updateContext = MLUpdateContext()
// Настройка параметров обучения
// Создание задачи обновления
let updateTask = try? MLUpdateTask(forModelAt: modelURL,
trainingData: trainingBatch,
configuration: config,
completionHandler: { context in
// Сохранение обновленной модели
try? context.model.write(to: updatedModelURL)
})
// Запуск обучения
updateTask?.resume()
5. Реальный практический пример (100-200 строк кода)
Создадим приложение для iOS, которое анализирует фотографии из библиотеки пользователя, определяет объекты на них и сохраняет результаты. Пример включает работу с CoreML, Vision и PhotoKit.
import UIKit
import CoreML
import Vision
import Photos
class PhotoAnalyzer {
private let model: VNCoreMLModel
private let request: VNCoreMLRequest
init() {
// Загружаем модель YOLOv3 для обнаружения объектов
guard let mlModel = try? YOLOv3(configuration: MLModelConfiguration()).model,
let visionModel = try? VNCoreMLModel(for: mlModel) else {
fatalError("Не удалось загрузить модель YOLOv3")
}
self.model = visionModel
// Создаем запрос с обработчиком результатов
self.request = VNCoreMLRequest(model: visionModel) { request, error in
guard let results = request.results as? [VNRecognizedObjectObservation] else {
print("Ошибка анализа: \(error?.localizedDescription ?? "неизвестная ошибка")")
return
}
// Обрабатываем результаты
for observation in results {
let labels = observation.labels
for label in labels where label.confidence > 0.5 {
print("Обнаружен: \(label.identifier) с вероятностью \(label.confidence)")
}
}
}
// Настройка параметров запроса
request.imageCropAndScaleOption = .scaleFill
request.usesCPUOnly = false
}
// Анализ одного изображения
func analyzeImage(_ image: UIImage, completion: @escaping ([String: Float]) -> Void) {
guard let ciImage = CIImage(image: image) else {
completion([:])
return
}
let handler = VNImageRequestHandler(ciImage: ciImage, orientation: .up)
DispatchQueue.global(qos: .userInitiated).async {
do {
try handler.perform([self.request])
guard let results = self.request.results as? [VNRecognizedObjectObservation] else {
DispatchQueue.main.async { completion([:]) }
return
}
var detectedObjects: [String: Float] = [:]
for observation in results {
if let topLabel = observation.labels.first {
let currentConfidence = detectedObjects[topLabel.identifier] ?? 0
if topLabel.confidence > currentConfidence {
detectedObjects[topLabel.identifier] = topLabel.confidence
}
}
}
DispatchQueue.main.async {
completion(detectedObjects)
}
} catch {
print("Ошибка выполнения запроса: \(error)")
DispatchQueue.main.async { completion([:]) }
}
}
}
// Пакетный анализ изображений из библиотеки
func analyzePhotoLibrary(limit: Int = 20) {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.fetchLimit = limit
let fetchResult = PHAsset.fetchAssets(with Также в библиотеке
Elasticsearch клиент для Kotlin: интеграция, примеры и возможности
Работа с изображениями в PHP: resize, crop и оптимизация с GD и Imagick
Mongoose для JavaScript (Node.js): полное руководство с примерами
Работа с Kafka в TypeScript: библиотека KafkaJS для Node.js