Русский
Русский
English
Статистика
Реклама

Coreml

Перевод Реализуем машинное обучение на iOS устройстве с использованием Core ML, Swift и Neural Engine

30.07.2020 18:15:54 | Автор: admin
Привет, хабр! В преддверии старта продвинутого курса Разработчик iOS, мы традиционно подготовили для вас перевод полезного материала.





Введение


Core ML это библиотека машинного обучения, выпущенная в свет Apple на WWDC 2017.

Она позволяет iOS разработчикам добавлять в свои приложения персонализированный опыт в режиме реального времени с использованием передовых локальных моделей машинного обучения с помощью Neural Engine.

Обзор чипа A11 Bionic



Начинка чипа A11 Bionic
Количество транзисторов: 4.3 миллиарда
Количество ядер: 6 ядер ARM (64 бита) 2 высокочастотных (2.4 ГГц) 4 с низким энергопотреблением
Количество графических процессоров: 3
Neural Engine 600 базовых операций в секунду

12 сентября 2017 Apple представила миру чип A11 Bionic с Neural Engine. Это нейросетевое аппаратное обеспечение может выполнять до 600 базовых операций в секунду (BOPS) и используется для FaceID, Animoji и других задач машинного обучения. Разработчики могут использовать Neural Engine с помощью Core ML API.

Core ML оптимизирует производительность на устройстве за счет использования ресурсов центрального процессора, графического процессора и Neural Engine, минимизируя объем памяти и энергопотребление.

Запуск модели локально на устройстве пользователя устраняет необходимость в сетевом подключении, что помогает сохранять конфиденциальность данных пользователя и улучшает отклик вашего приложения.

Core ML является основой для фреймворков и функционала данной предметной области. Core ML поддерживает Vision для анализа изображений, Natural Language для обработки текста, Speech для преобразования звука в текст и Sound Analysis для идентификации звуков в аудио.


Core ML API
Мы можем легко автоматизировать задачу построения моделей машинного обучения, что включают в себя обучение и тестирование модели, используя Playground, и интегрировать полученный файл модели в наш iOS проект.

Совет для новичков: Выделяйте отдельные метки для задач классификации.



Общая блок-схема Core ML

Ладно. Что мы будем создавать?


В этом уроке я покажу вам, как построить модель классификатора изображений с использованием Core ML, который может классифицировать изображения апельсинов (Orange) и клубники (Strawberry), и добавить эту модель в наше iOS приложение.


Модель классификатора изображений.

Подсказка для новичков: Классификация изображений относится к задачам обучения с учителем, в которых мы используем помеченные данные (в нашем случае метка (label) название изображения).




Необходимый минимум:


  • Знание языка Swift
  • Основы iOS разработки
  • Понимание концепций объектно-ориентированного программирования


Прикладные программы:

  • X-code 10 или более поздняя версия
  • iOS SDK 11.0+
  • macOS 10.13+


Сбор данных




При сборе данных для классификации изображений следуйте следующим рекомендациям Apple.

  • Используйте минимум 10 изображений на категорию чем больше, тем лучше.
  • Избегайте сильно несбалансированных наборов данных, подготовив примерно равное количество изображений на каждую категорию.
  • Сделайте вашу модель более надежной, включив параметры Create ML UIs Augmentation: Crop, Rotate, Blur, Expose, Noise и Flip.
  • Не брезгуйте избыточностью для своих тренировочных наборов: снимайте много изображений под разными углами, с разным фоном и в разных условиях освещения. Имитируйте реальные условия съемки, включая шум и размытость изображения.
  • Сфотографируйте образцы объектов в ваших руках, чтобы имитировать реальных пользователей, которые пытаются классифицировать объекты в своих руках.
  • Исключайте из поля зрения другие объекты, особенно те, которые вы хотите классифицировать по-другому.


После того как вы собрали ваш набор данных (Data Set), разделите его на обучающий (Train) и проверочный (Test) наборы и поместите их в соответствующие папки



ВАЖНОЕ ПРИМЕЧАНИЕ : Убедитесь что вы распределили изображения по соответствующим папкам внутри папки test. Потому что имя папки служит меткой для наших изображений.



В нашем случае у нас есть две папки, в каждой из которых лежат соответствующие изображения.

Создание модели




Не паникуйте! Apple значительно упростила эту задачу, автоматизировав основные этапы.

С Core ML вы можете использовать уже обученную модель для классификации входных данных или создать свою собственную. Для применения моделей классификации к изображениям и предварительной обработки этих изображений, и чтобы сделать задачи машинного обучения более простыми и надежными, с Core ML уже работает фреймворк Vision.

Просто следуйте этим шагам.

ШАГ 1: Откройте ваш X-code.
ШАГ 2: Создайте чистую Swift Playground.
ШАГ 3: Удалите код сгенерированный по умолчанию, добавьте следующую программу и запустите playground.

   import CreateMLUI //Импортируем нужный модуль     let builder = MLImageClassifierBuilder() //Создаем инстанс MLImageClassifierBuilder    builder.showInLiveView() //Показывает интерфейс редактора Xcode Model builder


Описание:
Здесь мы открываем интерфейс билдера модели по умолчанию предоставленного XCode.

ШАГ 4: Перетащите папку с обучающей выборкой в область обучения.

Поместите папку с обучающей выборкой в область обучения, обозначенную пунктирными линиями.

Совет для новичков : Мы также можем указать произвольное имя для нашей модели, щелкнув стрелку вниз в области обучения.


Шаг 5: Xcode автоматически обработает изображение и начнет процесс обучения. По умолчанию на обучение модели уходит 10 итераций, в зависимости от характеристик вашего Mac и размера набора данных. Вы можете наблюдать за ходом обучения в окне терминала Playground.


Жду пока происходит обучение модели.

ШАГ 6: После завершения обучения вы можете проверить свою модель, перетащив папку Test в область тестирования. Xcode автоматически протестирует вашу модель и отобразит результат.


Как вы можете заметить, наша модель точно классифицировала изображения .

ШАГ 7: Сохраните вашу модель.




Интеграция в iOS приложение:

ШАГ 1: Откройте ваш X-code.
ШАГ 2: Создайте Single Page iOS приложение.
ШАГ 3: Откройте навигатор проекта.
ШАГ 4: Перетащите обученную модель в навигатор проекта.


Поместите вашу модель в навигатор проекта.

ШАГ 5: Откройте Main.storyboard и создайте простой интерфейс, как показано ниже, добавьте IBOutlets и IBActions для соответствующих представлений.


Добавьте UIImageView, UIButtons и UILabels.

ШАГ 6: Откройте файл ViewController.swift и добавьте следующий код в качестве расширения.

  extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {          func getimage() {             let imagePicker = UIImagePickerController()//Создайте объект UIImagePickerController()            imagePicker.delegate = self //Установите контекст делегата            imagePicker.sourceType = .photoLibrary  //Выбирете библиотеку фотографий пользователя в качестве источника             imagePicker.allowsEditing = true  //Разрешите пользователю обрезать изображение            present(imagePicker, animated: true)  //Всплывающее окно UIPickerView        }         func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo С: [UIImagePickerController.InfoKey: Any]) {             let fimage = info[.editedImage] as!UIImage //Получает выбранное пользователем изображение с ключом .editedImage из словаря info             //Приведение типа изображения к UIImage            fruitImageView.image = fimage  //Установите выбранное изображение в UIImageView            dismiss(animated: true, completion: nil)  //Закрывает окно выбора изображений, когда пользователь выбрал изображение        }         func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {             dismiss(animated: true, completion: nil)  //Если пользователь не хочет выбирать изображение, закрывает представление средства выбора изображений        }     } 


Описание: Здесь мы создаем расширение для нашего класса ViewController и реализуем UINavigationControllerDelegate и UIImagePickerControllerDelegate, чтобы отобразить UIImagePickerView когда пользователь нажимает PickImage UIButton. Убедитесь, что вы установили контекст делегата.



Шаги связанные с доступом к модели Core ML в iOS приложении




ШАГ 1: Убедитесь, что вы импортировали следующие библиотеки.

import CoreML  import Vision


ШАГ 2: Создайте экземпляр нашего класса Core ML модели.

let modelobj = ImageClassifier()


ШАГ 3: Чтобы заставить Core ML произвести классификацию, мы должны сначала сформировать запрос типа VNCoreMLRequest (VN обозначает Vision)

var myrequest: VNCoreMLRequest? //Создает экземпляр VNCoreMLRequest myrequest = VNCoreMLRequest(model: fruitmodel, completionHandler: { (request, error) in    //Инстанцируется посредством передачи объекта модели                //Этот обработчик вызывается, когда запрос был выполнен Core ML                self.handleResult(request: request, error: error)//Вызов пользовательской функции                                                      })


ШАГ 4: Убедитесь, что вы обрезали изображение так, чтобы оно было совместимо с моделью Core ML.

myrequest!.imageCropAndScaleOption = .centerCrop

ШАГ 5: Поместите вышеуказанный код в пользовательскую функцию, которая возвращает объект запроса.

 func mlrequest() - > VNCoreMLRequest {         var myrequest: VNCoreMLRequest ?             let modelobj = ImageClassifier()         do {             let fruitmodel =                 try VNCoreMLModel(                     for: modelobj.model)             myrequest = VNCoreMLRequest(model: fruitmodel, completionHandler: {                   (request, error) in self.handleResult(request: request, error: error)                      })         } catch {            print("Unable to create a request")         }         myrequest!.imageCropAndScaleOption = .centerCrop         return myrequest!     } 


ШАГ 6: Теперь мы должны преобразовать наш UIImage в CIImage (CI:CoreImage), чтобы его можно было использовать в качестве входных данных для нашей Core ML модели. Это можно легко сделать, создав экземпляр CIImage, передав UIImage в конструкторе.

guard  let ciImage = CIImage(image: image)  else {        return     } 


ШАГ 7: Теперь мы можем обработать наш VNCoreMLRequest, создав обработчик запроса и передав ciImage.

let handler = VNImageRequestHandler(ciImage: ciImage)


ШАГ 8: Запрос может быть выполнен с помощью вызова метода perform() и передачи в качестве параметра VNCoreMLRequest.

DispatchQueue.global(qos: .userInitiated).async {        let handler = VNImageRequestHandler(ciImage: ciImage)        do {            try handler.perform([self.mlrequest()])        } catch {             print("Failed to get the description")         }     } 


Описание: DispatchQueue это объект, который управляет выполнением задач последовательно (или одновременно) в основном (или фоновом) потоке вашего приложения.

ШАГ 10: Поместите вышеуказанный код в пользовательскую функцию, как показано ниже.

func excecuteRequest(image: UIImage) {              guard             let ciImage = CIImage(image: image)             else {                 return             }             DispatchQueue.global(qos: .userInitiated).async {                 let handler = VNImageRequestHandler(ciImage: ciImage)                 do {                     try handler.perform([self.mlrequest()])                 } catch {                     print("Failed to get the description")                 }             } 


ШАГ 11: Создайте пользовательскую функцию с именем handleResult(), которая принимает объект VNRequest и объект ошибки в качестве параметров. Эта функция будет вызываться после завершения VNCoreMLRequest.

func handleResult(request: VNRequest, error: Error ? ) {         if let classificationresult = request.results as ? [VNClassificationObservation] {// Приведение типа запроса к массиву VNClassificationObservation            DispatchQueue.main.async {                self.fruitnamelbl.text = classificationresult.first!.identifier//Обновление UILabel идентификатором первого элемента в массиве путем доступа к тексту prperty                print(classificationresult.first!.identifier)            }         }         else {             print("Unable to get the results")         }     }  


Примечание: DispatchQueue.main.async используется для обновления объектов UIKit (в нашем случае это UILabel) с использованием UI Thread или Main Thread, поскольку все задачи классификации выполняются в фоновом потоке (background thread).




Листинг ViewController.Swift



import UIKit     import CoreML     import Vision     class ViewController: UIViewController {         var name: String = ""         @IBOutlet weak         var fruitnamelbl: UILabel!@IBOutlet weak         var fruitImageView: UIImageView!override func viewDidLoad() {             super.viewDidLoad()             // Выполняйте любую дополнительную настройку после загрузки представления.          }         @IBAction func classifybtnclicked(_ sender: Any) {             excecuteRequest(image: fruitImageView.image!)         }         @IBAction func piclimage(_ sender: Any) {             getimage()         }         func mlrequest() - > VNCoreMLRequest {             var myrequest: VNCoreMLRequest ?                 let modelobj = ImageClassifier()            do {                 let fruitmodel =                     try VNCoreMLModel(                         for: modelobj.model)                 myrequest = VNCoreMLRequest(model: fruitmodel, completionHandler: {                     (request, error) in self.handleResult(request: request, error: error)                 })             } catch {                 print("Unable to create a request")             }             myrequest!.imageCropAndScaleOption = .centerCrop             return myrequest!         }         func excecuteRequest(image: UIImage) {             guard             let ciImage = CIImage(image: image)             else {                 return             }             DispatchQueue.global(qos: .userInitiated).async {                 let handler = VNImageRequestHandler(ciImage: ciImage)                 do {                     try handler.perform([self.mlrequest()])                 } catch {                     print("Failed to get the description")                 }             }         }         func handleResult(request: VNRequest, error: Error ? ) {             if let classificationresult = request.results as ? [VNClassificationObservation] {                 DispatchQueue.main.async {                     self.fruitnamelbl.text = classificationresult.first!.identifier                     print(classificationresult.first!.identifier)                 }             }             else {                 print("Unable to get the results")             }         }     }     extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {         func getimage() {             let imagePicker = UIImagePickerController()             imagePicker.delegate = self             imagePicker.sourceType = .photoLibrary             imagePicker.allowsEditing = true             present(imagePicker, animated: true)         }         func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {             let fimage = info[.editedImage] as!UIImage             fruitImageView.image = fimage             dismiss(animated: true, completion: nil)         }         func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {             dismiss(animated: true, completion: nil)         }     }


Все готово!




Теперь запустите ваш Simulator и протестируйте приложение.

Примечание: Убедитесь что в библиотеке фотографий вашего Simulator у вас есть фото апельсинов и клубники.



Нажмите кнопку Pick Image


Выберите любое изображение


Нажмите кнопку Classify


Выберите другую картинку и нажмите Classify

Ура:


Вы создали свое первое IOS приложение с использованием Core ML.

Еще:


Подробнее..

Перевод Построители результатов в Swift описание и примеры кода

05.05.2021 12:08:12 | Автор: admin

Перевод подготовлен в рамках набора на курс "iOS Developer. Professional".

Всех желающих приглашаем на открытый демо-урок Machine Learning в iOS с помощью CoreML и CreateML: изображения, текст, звук. На занятии обсудим:

1. Основные архитектуры нейронных сетей и их оптимизированные версии под мобильные устройства;
2. Возможности CoreML 3 и 4, обучение на iOS устройстве;
3. Самостоятельное обучение классификатора изображений с помощью CreateML и использование его с Vision;
4. Использование обученных моделей для работы с текстом и звуком в iOS.


Построители результатов (result builders) в Swift позволяют получать результирующее значение из последовательности компонентов выставленных друг за другом строительных блоков. Они появились в Swift5.4 и доступны в Xcode12.5 и более поздних версиях. Ранее эти средства были известны как function builders (построители функций). Вам, вероятно, уже приходилось использовать их при создании стеков представлений в SwiftUI.

Должен признаться: поначалу я думал, что это некая узкоспециализированная возможность Swift, которую я никогда не стану применять для организации своего кода. Однако стоило мне в ней разобраться и написать небольшое решение для создания ограничений представления в UIKit, как я обнаружил, что раньше просто не понимал всю мощь построителей результатов.

Что такое построители результатов?

Построитель результата можно рассматривать как встроенный предметно-ориентированный язык (DSL), описывающий объединение неких частей в окончательный результат. В простых объявлениях представлений SwiftUI за кадром используется атрибут @ViewBuilder, который представляет собой реализацию построителя результата:

struct ContentView: View {     var body: some View {         // This is inside a result builder         VStack {             Text("Hello World!") // VStack and Text are 'build blocks'         }     } }

Все дочерние представления (в данном случае VStack, содержащий Text) будут объединены в одно представление View. Другими словами, строительные блоки View встраиваются в результат View. Это важно понять, поскольку именно так работают построители результатов.

Если рассмотреть объявление протокола View в SwiftUI, можно заметить, что переменная body определяется с использованием атрибута @ViewBuilder:

@ViewBuilder var body: Self.Body { get }

Именно так можно использовать собственный построитель результата в качестве атрибута функции, переменной или сабскрипта.

Создание собственного построителя результата

Способ определения кастомного построителя результата я покажу на примере, который использовал сам. При разработке авторазметки посредством кода я обычно реализую логику следующего вида:

var constraints: [NSLayoutConstraint] = [     // Single constraint     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor) ] // Boolean check if alignLogoTop {     constraints.append(swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)) } else {     constraints.append(swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor)) } // Unwrap an optional if let fixedLogoSize = fixedLogoSize {     constraints.append(contentsOf: [         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width),         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)     ]) } // Add a collection of constraints constraints.append(contentsOf: label.constraintsForAnchoringTo(boundsOf: view)) // Returns an array // Activate NSLayoutConstraint.activate(constraints)

Как видите, здесь довольно много условных ограничений. В сложных представлениях прочитать их все может быть весьма непросто.

В этом случае построители результатов это отличное решение. Они позволяют переписать приведенный выше пример кода следующим образом:

 @AutolayoutBuilder var constraints: [NSLayoutConstraint] {     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor) // Single constraint          if alignLogoTop {         swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)     } else {         swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor) // Single constraint     }          if let fixedLogoSize = fixedLogoSize {         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)     }          label.constraintsForAnchoringTo(boundsOf: view) // Returns an array } 

Здорово, не правда ли?

Итак, рассмотрим способ создания такого решения.

Определение построителя для авторазметки

Начинаем с определения собственной структуры AutolayoutBuilder и добавляем атрибут @resultBuilder, чтобы пометить ее как построитель результата:

@resultBuilder struct AutolayoutBuilder {          // .. Handle different cases, like unwrapping and collections  } 

Чтобы объединить все строительные блоки и получить результат, нам нужно настроить обработчики для каждого случая, в частности для обработки опционалов и коллекций. Но для начала реализуем обработку случая с единственным ограничением.

Это делается с помощью следующего метода:

 @resultBuilder struct AutolayoutBuilder {          static func buildBlock(_ components: NSLayoutConstraint...) -> [NSLayoutConstraint] {         return components     }  }

Этот метод принимает на вход вариативный параметр components (тоесть параметр с переменным числом возможных значений). Это означает, что может существовать одно или несколько ограничений. Нам нужно вернуть коллекцию ограничений, то есть в этом случае мы можем напрямую вернуть входные компоненты.

Теперь мы можем определить коллекцию ограничений следующим образом:

@AutolayoutBuilder var constraints: [NSLayoutConstraint] {     // Single constraint     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor) } 

Обработка коллекции строительных блоков

Следующим шагом будет обработка коллекции элементов как одного элемента. В первом примере кода мы использовали удобный метод constraintsForAnchoringTo(boundsOf:), который возвращает множество ограничений в виде коллекции. Если бы мы применили его в этом случае, мы получили бы следующую ошибку:

Поначалу кастомный построитель результата не может обрабатывать коллекции компонентов.Поначалу кастомный построитель результата не может обрабатывать коллекции компонентов.

Описание ошибки отлично объясняет происходящее:

Cannot pass array of type [NSLayoutConstraint] as variadic arguments of type NSLayoutConstraint Невозможно передать массив типа [NSLayoutConstraint] как вариативные аргументы типа NSLayoutConstraint

Как ни странно, в Swift нельзя передавать массив в качестве вариативных параметров. Вместо этого нужно определить собственный метод для обработки коллекции в качестве входных компонентов. На первый взгляд может показаться, что нам нужен следующий доступный метод:

Список доступных методов в определении кастомного построителя результата.Список доступных методов в определении кастомного построителя результата.

К сожалению, как указано в описании метода, он обеспечивает поддержку только циклов, которые объединяют несколько результатов в один. Мы здесь используем не итератор, а удобный метод для прямого возврата коллекции, поэтому нам потребуется написать еще немного собственного кода.

Можно решить эту проблему, определив новый протокол, который реализуется как с использованием одного NSLayoutConstraint, так и с использованием коллекции ограничений:

 protocol LayoutGroup {     var constraints: [NSLayoutConstraint] { get } } extension NSLayoutConstraint: LayoutGroup {     var constraints: [NSLayoutConstraint] { [self] } } extension Array: LayoutGroup where Element == NSLayoutConstraint {     var constraints: [NSLayoutConstraint] { self } } 

Этот протокол позволит нам преобразовывать как отдельные ограничения, так и коллекцию ограничений в массив ограничений. Другими словами, мы можем объединить оба типа в один [NSLayoutConstraint].

Теперь мы можем переписать наш построитель результата так, чтобы он принимал наш протокол LayoutGroup:

 @resultBuilder struct AutolayoutBuilder {          static func buildBlock(_ components: LayoutGroup...) -> [NSLayoutConstraint] {         return components.flatMap { $0.constraints }     } } 

Для получения единой коллекции ограничений здесь используется метод flatMap. Если вы не знаете, для чего нужен метод flatMap или почему мы использовали его вместо compactMap, почитайте мою статью Методы compactMap и flatMap:в чем разница?

Наконец, мы можем обновить наше решение, чтобы задействовать новый обработчик коллекции строительных блоков:

@AutolayoutBuilder var constraints: [NSLayoutConstraint] {     // Single constraint     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)          label.constraintsForAnchoringTo(boundsOf: view) // Returns an array } 

Разворачивание опционалов

Другой случай, который необходимо рассмотреть, это разворачивание опционалов. Этот механизм позволит добавлять ограничения, если существует определенное значение.

Добавим метод buildOptional(..) к нашему построителю результата:

 @resultBuilder struct AutolayoutBuilder {          static func buildBlock(_ components: LayoutGroup...) -> [NSLayoutConstraint] {         return components.flatMap { $0.constraints }     }          static func buildOptional(_ component: [LayoutGroup]?) -> [NSLayoutConstraint] {         return component?.flatMap { $0.constraints } ?? []     } } 

Метод пытается преобразовать результат в коллекцию ограничений или возвращает пустую коллекцию, если данного значения не существует.

Теперь мы можем развернуть опционал в нашем определении строительных блоков:

@AutolayoutBuilder var constraints: [NSLayoutConstraint] {     // Single constraint     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)          label.constraintsForAnchoringTo(boundsOf: view) // Returns an array          // Unwrapping an optional     if let fixedLogoSize = fixedLogoSize {         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)     } } 

Обработка условных операторов

Еще один распространенный случай условные операторы. В зависимости от логического значения может потребоваться добавить то или иное ограничение. Этот обработчик может обрабатывать первый или второй компонент в проверке условия:

 @AutolayoutBuilder var constraints: [NSLayoutConstraint] {     // Single constraint     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)          label.constraintsForAnchoringTo(boundsOf: view) // Returns an array          // Unwrapping an optional     if let fixedLogoSize = fixedLogoSize {         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)     }          // Conditional check     if alignLogoTop {         // Handle either the first component:         swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)     } else {         // Or the second component:         swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor)     } } 

В наш построитель результата надо добавить еще пару обработчиков строительных блоков:

 @resultBuilder struct AutolayoutBuilder {          static func buildBlock(_ components: LayoutGroup...) -> [NSLayoutConstraint] {         return components.flatMap { $0.constraints }     }          static func buildOptional(_ component: [LayoutGroup]?) -> [NSLayoutConstraint] {         return component?.flatMap { $0.constraints } ?? []     }          static func buildEither(first component: [LayoutGroup]) -> [NSLayoutConstraint] {         return component.flatMap { $0.constraints }     }      static func buildEither(second component: [LayoutGroup]) -> [NSLayoutConstraint] {         return component.flatMap { $0.constraints }     } } 

В обоих обработчиках buildEither для получения ограничений и их возвращения в виде плоской структуры используется все тот же протокол LayoutGroup.

Это были последние два обработчика, необходимые для работы нашего примера. Ура!

Однако мы еще не закончили. Мы можем немного усовершенствовать этот код, используя построители результатов внутри функций.

Использование построителей результатов в качестве параметров функций

Отличный способ использовать построитель результата определить его как параметр функции. Так мы действительно получим пользу от нашего кастомного AutolayoutBuilder.

Например, можно добавить такое расширение к NSLayoutConstraint, чтобы немного упростить активацию ограничений:

extension NSLayoutConstraint {     /// Activate the layouts defined in the result builder parameter `constraints`.     static func activate(@AutolayoutBuilder constraints: () -> [NSLayoutConstraint]) {         activate(constraints())     } 

Применяться расширение будет вот так:

NSLayoutConstraint.activate {     // Single constraint     swiftLeeLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor)          label.constraintsForAnchoringTo(boundsOf: view) // Returns an array          // Unwrapping an optional     if let fixedLogoSize = fixedLogoSize {         swiftLeeLogo.widthAnchor.constraint(equalToConstant: fixedLogoSize.width)         swiftLeeLogo.heightAnchor.constraint(equalToConstant: fixedLogoSize.height)     }          // Conditional check     if alignLogoTop {         // Handle either the first component:         swiftLeeLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)     } else {         // Or the second component:         swiftLeeLogo.centerYAnchor.constraint(equalTo: view.centerYAnchor)     } } 

Теперь, реализовав данный метод, мы также можем создать удобный метод в UIView для непосредственного добавления субпредставления с ограничениями:

 protocol SubviewContaining { } extension UIView: SubviewContaining { } extension SubviewContaining where Self == UIView {          /// Add a child subview and directly activate the given constraints.     func addSubview<View: UIView>(_ view: View, @AutolayoutBuilder constraints: (Self, View) -> [NSLayoutConstraint]) {         addSubview(view)         NSLayoutConstraint.activate(constraints(self, view))     } } 

Это можно использовать следующим образом:

 let containerView = UIView() containerView.addSubview(label) { containerView, label in          if label.numberOfLines == 1 {         // Conditional constraints     }          // Or just use an array:     label.constraintsForAnchoringTo(boundsOf: containerView)      } 

Поскольку мы используем дженерики, мы можем выполнять проверку условий на основе входного типа UIView. В этом случае можно добавить различные ограничения, если метка label будет содержать только одну строку текста.

Как разработать собственное решение с построителем результата?

Вы, наверняка, думаете: как же определить, будет ли построитель результата полезен в том или ином фрагменте кода?

Каждый раз, когда вам встречается фрагмент кода, состоящий из нескольких условных элементов и преобразуемый в одиночный элемент возвращаемого типа, вы можете задуматься о написании построителя результата. Однако делать это стоит лишь в случае, если вы уверены, что вам придется писать этот фрагмент часто.

Когда мы пишем ограничения для разработки авторазметки посредством кода, мы повторяем одни и те же инструкции по нескольку раз, поэтому в данном случае стоит написать кастомный построитель результата. Сами ограничения тоже состоят из множества строительных блоков, если рассматривать каждую коллекцию ограничений (одиночную или нет) как отдельный такой блок.

Наконец, я хотел бы сослаться на репозиторий с примерами построителей функций (которые теперь называются построителями результатов).

Заключение

Построители результатов это очень мощное дополнение к Swift5.4. Они позволяют писать код на собственном предметно-ориентированном языке, за счет чего можно усовершенствовать свой подход к написанию кода. Я надеюсь, что эта статья немного прояснит для вас понятие кастомных построителей результатов, которые помогают упрощать код на организационном уровне.


Узнать подробнее о курсе "iOS Developer. Professional"

Смотреть вебинар Machine Learning в iOS с помощью CoreML и CreateML: изображения, текст, звук

Подробнее..

Перевод Запускаем модель машинного обучения на iPhone

18.04.2021 18:19:42 | Автор: admin

Чего уж только на Хабре не было, и DOOM на осциллографе, тесте на беременности и калькуляторе запускали, даже сервер Minecraftна зеркалке Canon 200D поднимали. Сегодня же, специально к старту нового потока курса по Machine Learning и углубленного Machine Learning и Deep Learning, попробуем описать кратчайший путь от обучения модели машинного обучения на Python до доказательства концепции iOS-приложения, которое можно развернуть на iPhone. Цель статьи дать базовый скаффолдинг, оставляя место для дальнейшей настройки, подходящей для конкретного случая использования.


Для простоты мы пропустим некоторые задачи, такие как проверка модели и создание полностью отшлифованного пользовательского интерфейса (UI). К концу этого туториала у вас будет обученная модель, работающая на iOS, которую вы сможете продемонстрировать как прототип и загрузить на своё устройство.

Шаг 1. Настройка среды

Во-первых, давайте создадим виртуальную среду Python под названием .core_ml_demo, а затем установим необходимые библиотеки: pandas, scikit-learn и coremltools. Чтобы создать виртуальную среду, выполните в терминале эти команды:

python3 -m venv ~/.core_ml_demosource  ~/.core_ml_demo/bin/activatepython3 -m pip install \pandas==1.1.1 \scikit-learn==0.19.2 \coremltools==4.0

Далее установим Xcode. XCode это инструментарий разработки для продуктов Apple. Обратите внимание, что Xcode довольно большой (больше 10 ГБ). Я бы порекомендовал выпить чашку кофе или запустить установку на ночь.

Примечание: в этом туториале используется Xcode 12.3 (12C33) на MacOS Catalina 10.15.5.

Шаг 2. Обучение модели

Мы будем использовать набор данных Boston Housing Price от scikit-learn для обучения модели линейной регрессии и прогнозирования цен на жильё на основе свойств и социально-экономических атрибутов.

Поскольку мы стремимся к простоте, ограничим пространство признаков тремя предикторами и как целевую переменную будем использовать цену дома.

import pandas as pdfrom sklearn.linear_model import LinearRegressionfrom sklearn.datasets import load_boston# Load databoston = load_boston()boston_df = pd.DataFrame(boston["data"])boston_df.columns = boston["feature_names"]boston_df["PRICE"]= boston["target"]y = boston_df["PRICE"]X = boston_df.loc[:,["RM", "AGE", "PTRATIO"]]# Train a modellm = LinearRegression()lm.fit(X, y)

Шаг 3. Преобразование модели в Core ML

Apple предоставляет два способа разработки моделей для iOS. Первый, Create ML, позволяет создавать модели полностью в рамках экосистемы Apple. Второй, Core ML, позволяет интегрировать модели от третьих лиц в платформу Apple, преобразовав их в формат Core ML. Поскольку мы заинтересованы в запуске обученной модели на iOS, воспользуемся вторым способом.

Перед импортом в Xcode мы преобразуем нашу модель sklearn в формат Core ML (.mlmodel) с помощью пакета python coremltool; coremltools позволяет назначать метаданные объекту модели, такие как информация об авторстве, описание функций модели и результатов.

# Convert sklearn model to CoreMLimport coremltools as cmlmodel = cml.converters.sklearn. \convert(lm,        ["RM", "AGE", "PTRATIO"],        "PRICE")# Assign model metadatamodel.author = "Medium Author"model.license = "MIT"model.short_description = \"Predicts house price in Boston"# Assign feature descriptionsmodel.input_description["RM"] = \"Number of bedrooms"model.input_description["AGE"] = \"Proportion of units built pre 1940"model.input_description["PTRATIO"] = \"Pupil-teacher ratio by town"# Assign the output descriptionmodel.output_description["PRICE"] = \"Median Value in 1k (USD)"# Save modelmodel.save('bhousing.mlmodel')

Шаг 4. Создание нового проекта в Xcode

С Python мы закончили. Теперь можно завершить прототип приложения при помощи только Xcode и Swift. Это можно сделать так:

  1. Откройте Xcode и создайте новый проект.

  2. Выберите iOS как тип мультиплатформы.

  3. Выберите тип приложения App.

Создание нового проекта Xcode для iOSСоздание нового проекта Xcode для iOS

4. Дайте проекту название и выберите интерфейс SwiftUI.

Конфигурация проектаКонфигурация проекта

Теперь просто перетащите созданный на третьем шаге файл модели .ml в каталог Xcode. Xcode автоматически сгенерирует класс Swift для вашей модели, как показано в редакторе ниже. Если вы посмотрите на класс, то заметите, что он содержит детали, которые мы ввели при сохранении нашей модели на Python с помощью coremltools, такие как описания объектов и целевых полей. Это удобно при управлении моделью.

Импорт файла .coreml в проект XcodeИмпорт файла .coreml в проект Xcode

Шаг 5. Создание UI модели

Далее создадим базовый пользовательский интерфейс, изменив файл contentView.swift. Приведённый ниже код на Swift отображает пользовательский интерфейс, который позволяет пользователям настраивать атрибуты дома, а затем прогнозировать его цену. Есть несколько элементов, которые мы можем здесь рассмотреть.

NavigationView содержит необходимый пользовательский интерфейс. Он включает:

  • Степпер (строки 1930) для каждой из наших трёх функций, который позволяет пользователям изменять значения функций. Степперы это в основном виджеты, которые изменяют @State атрибутных переменных нашего дома (строки 68).

  • Кнопку на панели навигации (строки 3140) для вызова нашей модели из функции predictPrice (строка 46). На экране появится предупреждающее сообщение с прогнозируемой ценой.

За пределами NavigationView у нас есть функция predictPrice (строки 4662). Она создаёт экземпляр класса Swift Core ML model и генерирует прогноз в соответствии с хранящимися в состояниях объектов значениями.

import SwiftUIimport CoreMLimport Foundationstruct ContentView: View {  @State private var rm = 6.5  @State private var age = 84.0  @State private var ptratio = 16.5      @State private var alertTitle = ""  @State private var alertMessage = ""  @State private var showingAlert = false      var body: some View {      NavigationView {        VStack {        Text("House Attributes")            .font(.title)        Stepper(value: $rm, in: 1...10,                step: 0.5) {            Text("Rooms: \(rm)")          }          Stepper(value: $age, in: 1...100,              step: 0.5) {          Text("Age: \(age)")          }          Stepper(value: $ptratio, in: 12...22,              step: 0.5) {          Text("Pupil-teacher ratio: \(ptratio)")          }          .navigationBarTitle("Price Predictor")          .navigationBarItems(trailing:              Button(action: predictPrice) {                  Text("Predict Price")              }          )          .alert(isPresented: $showingAlert) {              Alert(title: Text(alertTitle),                    message: Text(alertMessage),              dismissButton: .default(Text("OK")))          }        }      }  }            func predictPrice() {    let model = bhousing()    do { let p = try      model.prediction(          RM: Double(rm),          AGE: Double(age),          PTRATIO: Double(ptratio))        alertMessage = "$\(String((p.PRICE * 1000)))"      alertTitle = "The predicted price is:"  } catch {    alertTitle = "Error"    alertMessage = "Please retry."  }    showingAlert = true}}struct ContentView_Previews: PreviewProvider {    static var previews: some View {        ContentView()    }}

И, наконец, самое интересное: мы можем создать и запустить симуляцию приложения в Xcode, чтобы увидеть нашу модель в действии. В приведённом ниже примере я создал симуляцию с помощью iPhone 12.

Симуляция модели работает на iOS.Симуляция модели работает на iOS.

Заключение

И это всё. Первый прототип завершён. Здесь есть что добавить, например валидацию модели, тесты для подтверждения ожидаемой производительности после импорта в iOS и более гладкий/дружественный пользовательский интерфейс. Тем не менее я надеюсь, что статья послужит полезным справочником по развёртыванию машинного обучения на мобильном устройстве.

Новые и усовершенствованные инструменты продолжают делать поиски в мобильной разработке более доступными для сообщества Data Science, и в мобильном мире есть большое пространство для творчества. Поскольку мобильная техника мультимедийная по своей сути, она даёт богатство типов данных (например, аудио, видео, движение и местоположение) наряду с уникальными вариантами применения приложений для расширения инструментария Data Science.

Если вы кодите на Python и столкнулись в работе с задачами машинного обучения обратите внимание на наш курс Machine Learning, на котором вы сможете систематизировать и углубить полученные самостоятельно знания, пообщаться с профессионалами и применить модели Machine Learning на практике. Даже можно будет ворваться на хакатоны Kaggle.

Если же есть намерение сменить сферу деятельности и погрузиться в ML более плотно то можно посмотреть на продвинутый курс Machine Learning и Deep Learning, на котором вы освоите основные алгоритмы машинного обучения, обучите рекомендательную систему и создадите несколько нейронных сетей.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Перевод Новости о машинном обучении Apple в 2020 году

27.07.2020 12:16:39 | Автор: admin

В 2020 году машинное обучение на мобильных платформах перестало быть революционным новшеством. Интеграция интеллектуальных функций в приложения стала стандартной практикой.

К счастью, это вовсе не означает, что Apple прекратила разрабатывать инновационные технологии.

В этой публикации я кратко расскажу о новостях в отношении платформы Core ML и других технологий искусственного интеллекта и машинного обучения в экосистеме Apple.

Core ML


В прошлом году платформа Core ML серьёзно обновилась. В этом году всё гораздо скромнее: добавлено несколько новых типов слоёв, поддержка моделей шифрования и возможность размещать обновления модели в CloudKit.

Похоже, было принято решение отказаться от номеров версий. После прошлогоднего обновления платформа стала именоваться Core ML 3, однако сейчас для неё используется название Core ML без номера версии. Тем не менее, пакет coremltools всё-таки был обновлён до версии 4.

Примечание. Внутренняя спецификация mlmodel теперь имеет номер версии 5, а значит, новые модели будут отображаться в Netron с именем Core ML v5.

Новые типы слоёв в Core ML


Добавлены следующие слои:

  • Convolution3DLayer, Pooling3DLayer, GlobalPooling3DLayer: эти слои особенно полезны для обработки видеоданных теперь для этого можно использовать платформу Vision (в Core ML по-прежнему отсутствует прямая поддержка одномерных свёрточных слоёв, хотя для этого можно использовать обычные двумерные свёрточные слои).
  • OneHotLayer: обеспечивает прямое унитарное кодирование входных данных.
  • ClampedReLULayer: обеспечивает активацию ReLU с максимальным значением (удобно использовать для создания ReLU6).
  • ArgSortLayer: обеспечивает сортировку для входного тензора. При этом вместо фактически отсортированных значений возвращаются отсортированные индексы. Обычный слой сортировки не предусмотрен, однако можно использовать GatherLayer, чтобы переупорядочить элементы из выходных данных argsort.
  • CumSumLayer: вычисляет нарастающий итог для входного тензора.
  • SliceBySizeLayer: в Core ML уже доступно несколько типов слоёв разбиения. Этот слой позволяет передать тензор, содержащий индекс, с которого будет начинаться разбиение. При этом размер сектора всегда остаётся фиксированным.

Такие типы слоёв можно использовать, начиная с версии 5, то есть в iOS 14 и macOS 11.0 или более поздних версиях.

Ещё одно полезное усовершенствование: 8-битовые квантованные операции для следующих слоёв:

  • InnerProductLayer
  • BatchedMatMulLayer

В предыдущих версиях Core ML допускалось квантование весовых коэффициентов, однако после загрузки модели они преобразовывались обратно в формат с плавающей запятой. Новая функция int8DynamicQuantize позволяет сохранять весовые коэффициенты в виде 8-битовых целочисленных значений и выполнять фактические вычисления также с использованием целых чисел.

Вычисления с использованием INT8 могут выполняться гораздо быстрее, чем операции с плавающей запятой. Это предоставляет ЦП определённые преимущества, но нет уверенности в том, повысится ли производительность графических процессоров, поскольку для них операции с плавающей запятой весьма эффективны. Возможно, в будущем обновлении Neural Engine будет реализована встроенная поддержка операций INT8 (всё-таки компания Apple не так давно приобрела Xnor.ai).

Что касается ЦП, на них Core ML теперь также может использовать 16-битовые операции с плавающей запятой вместо 32-битовых (на A11 Bionic и выше). Как мы уже говорили в видеоролике Explore numerical computing in Swift (Изучаем численные расчёты в Swift), Float16 сегодня стал типом данных Swift первого класса. Благодаря встроенной поддержке 16-битовых операций с плавающей запятой скорость работы Core ML может увеличиться вдвое!

Примечание. В Core ML тип данных Float16 уже использовался на графических процессорах и Neural Engine, так что различия будут заметны только при использовании на ЦП.

Остальные (незначительные) изменения:

  • UpsampleLayer теперь поддерживает дробный коэффициент масштабирования. В режиме BILINEAR доступны новые параметры дискретизации точек сетки (метод align-corners). В принципе, это должно решать большинство проблем, которые описывает данная публикация в блоге.
  • Для ReorganizeDataLayerParams добавлен режим PIXEL_SHUFFLE. Это ещё один метод, позволяющий выполнить повышающую дискретизацию. Ранее для перетасовки пикселей можно было использовать несколько слоёв перестановки и изменения формы, однако встроенная функция делает этот процесс значительно более удобным.
  • Для слоёв SliceStaticLayer и SliceDynamicLayer добавлено свойство squeezeMasks, которое повышает удобство и эффективность разбиения.
  • Слой TileLayer принимает второй входной тензор, благодаря чему можно динамически задавать количество повторов.

Изменений в отношении локального обучения на устройствах, похоже, нет: по-прежнему поддерживаются только полносвязные и свёрточные слои. Класс MLParameterKey в CoreML.framework теперь содержит параметр конфигурации для оптимизатора RMSprop, однако это усовершенствование пока не включено в NeuralNetwork.proto. Возможно, оно будет добавлено в следующей бета-версии.

Добавлены следующие новые типы моделей:
VisionFeaturePrint.Object блок выделения признаков, оптимизированный для распознавания объектов.

SerializedModel. Не знаю точно, для чего это нужно. Это частное определение, которое может быть изменено без предварительного уведомления и какой-либо ответственности. Может быть, таким образом Apple встраивает патентованные форматы моделей в mlmodel?

Размещение обновлений модели в CloudKit



Этот новый компонент Core ML позволяет обновлять модели отдельно от приложения.

Вместо обновления всего приложения, можно просто загрузить в развёрнутые экземпляры новую версию файла mlmodel. Честно говоря, эта идея не нова, и некоторые сторонние поставщики уже разработали соответствующие пакеты SDK. Кроме того, несложно создать такой пакет самостоятельно. Преимущество решения Apple в данном случае заключается в возможности размещать модели в облаке Apple Cloud.

Поскольку в приложении может быть несколько моделей, новая концепция коллекции моделей позволяет объединить модели в одном пакете, чтобы приложение смогло обновить их все одновременно. Такие коллекции можно создавать с помощью панели управления CloudKit.

Для загрузки обновления моделей и управления ими приложение использует класс MLModelCollection. В видеоролике WWDC показаны фрагменты кода для выполнения этой задачи.

Для подготовки модели Core ML к развёртыванию теперь доступна кнопка Create Model Archive (Создать архив модели) в Xcode. По нажатию на неё выполняется запись в файл .mlarchive. Такую версию модели можно отправить на панель управления CloudKit, а затем добавить её в коллекцию моделей (mlarchive выглядит как обычный ZIP-архив, в который добавлено содержимое папки mlmodelc).

Очень удобно, что можно выполнить развёртывание различных коллекций моделей для разных пользователей. Например, камера iPhone отличается от камеры iPad, поэтому может потребоваться создать две версии модели и отправить одну из них пользователям iPhone, а вторую пользователям iPad.

Можно определить правила настройки под различные классы устройств (iPhone, iPad, TV, Watch), различные операционные системы и их версии, коды региона, языковые коды и версии приложения.

Кажется, не предусмотрен механизм, позволяющий разделить пользователей на группы по другим критериям, например, для A/B-тестирования обновлений модели или настройки под конкретные типы устройств iPhone X или более ранней версии. Однако это по-прежнему можно сделать вручную, создав коллекции с разными именами, а затем явным образом запросив у MLModelCollection предоставление соответствующей коллекции по заданному имени в среде выполнения.

Развёртывание новой версии модели не всегда выполняется быстро. В определённый момент приложение обнаруживает новую доступную модель и автоматически загружает и размещает её в тестовой среде приложения. Однако вам не предоставляется возможность определять, где и как это произойдёт: Core ML может выполнять загрузку в фоновом режиме, например, пока вы не пользуетесь телефоном.

Из-за этого рекомендуется во всех случаях добавлять в приложение встроенную модель как резервный вариант например, универсальную модель, которая поддерживает как iPhone, так и iPad.

Несмотря на то, что это удобное решение позволяет пользователям не беспокоиться о самостоятельном размещении моделей, следует иметь в виду, что теперь ваше приложение использует CloudKit. Как я понимаю, коллекции моделей учитываются в общей квоте системы хранения данных, а загрузка моделей учитывается в квотах сетевого трафика.

См. также:


Примечание. Новую возможность обновления с использованием CloudKit, к сожалению, довольно трудно совместить с локальной персонализацией модели. Не предусмотрено никаких простых способов передать знания, полученные персонализированной моделью, в новую модель или каким-то образом объединить их.

Шифрование модели


До настоящего момента любой злоумышленник мог с лёгкостью выкрасть вашу модель Core ML и интегрировать её в собственное приложение. Начиная с версии iOS 14/macOS 11.0, Core ML поддерживает автоматическое шифрование и дешифрование моделей, ограничивая доступ злоумышленников к вашим папкам mlmodelc. Шифрование можно использовать в сочетании с новой функцией развёртывания через CloudKit или отдельно.


Xcode шифрует скомпилированные модели (mlmodelc), а не исходный файл mlmodel. Модель всегда сохраняется на пользовательском устройстве в зашифрованном виде. И только когда приложение создаёт экземпляр модели, Core ML автоматически выполняет её дешифрование. Дешифрованная версия модели существует только в памяти, но не хранится в виде файла.

Во-первых, теперь вам потребуется ключ шифрования. Хорошая новость: вам не придётся управлять этим ключом самостоятельно! В средстве просмотра моделей Core ML Xcode теперь доступна кнопка Create Encryption Key (Создать ключ шифрования). По нажатию на эту кнопку Xcode создаёт новый ключ шифрования и связывает его с учётной записью вашей команды разработчиков Apple. Вам не придётся иметь дело с запросами на подпись сертификатов и физическими ключами доступа.

В ходе этой процедуры создаётся новый файл .mlmodelkey. Ключ хранится на серверах Apple, однако вы также получаете локальную копию для шифрования моделей в Xcode. Вам не потребуется встраивать этот ключ шифрования в приложение, тем более что этого и не следует делать!

Для шифрования модели Core ML можно добавить флаг компилятора --encrypt YourModel.mlmodelkey для этой модели. А если вы планируете развёртывать модель с помощью CloudKit, потребуется указать ключ шифрования при создании архива модели.

Чтобы дешифровать модель после того, как приложение создаст её экземпляр, Core ML потребуется по сети получить с серверов Apple ключ шифрования. Для этого, разумеется, необходимо подключение к сети. Core ML выполняет эту процедуру только при первом использовании модели.

Если сетевое соединение отсутствует и ключ шифрования ещё не загружен, приложение не сможет создать экземпляр модели Core ML. По этой причине рекомендуется использовать новую функцию YourModel.load(). Она содержит завершающий обработчик, который позволяет реагировать на ошибки загрузки. Например, код ошибки modelKeyFetch сообщает о том, что Core ML не удалось загрузить ключ шифрования с серверов Apple.

Это очень полезная функция, если вы беспокоитесь о том, что кто-то похитит вашу патентованную технологию. К тому же её легко интегрировать в приложение.

См. также:


Примечание. Согласно информации, приведённой в этом сообщении на форуме разработчиков, зашифрованные модели не поддерживают локальную персонализацию. Звучит разумно.

CoreML.framework


API-интерфейс iOS, предназначенный для работы с моделями Core ML, не особенно сильно изменился. И всё же хочется отметить пару интересных моментов.

Единственный новый класс здесь MLModelCollection, который предназначен для развёртывания с помощью CloudKit.

Как вы уже знаете, при добавлении файла mlmodel в свой проект Xcode автоматически генерирует исходный файл Swift или Objective-C, который содержит классы, упрощающие работу с моделью. В этих сгенерированных классах можно заметить пару изменений:

  • Стандартный метод init() признан устаревшим. Поэтому, запись let model = YourModel() вызовет предупреждение компилятора. Вместо устаревшего можно использовать метод YourModel(configuration:) или новый метод YourModel.load(), который позволяет обрабатывать ошибки при загрузке (например, если не удаётся дешифровать зашифрованную модель).
  • Если в модели используются изображения, то вместо обработки объектов CVPixelBuffer можно создать объект YourModelInput, используя для этого класс CGImage или URL-адрес, указывающий на локальный PNG- или JPG-файл, и составить прогноз на основе этих данных. Тем не менее, при этом не будет возможности применить метод cropAndScale или cropRect. То есть, если нужны дополнительные инструменты контроля за изменением размера изображений, вряд ли эти новые методы будут полезны.

В документации по MLModel появилось новое предупреждение:

Используйте экземпляр MLModel только в одном потоке или в одной очереди отправки. Для этого можно сериализовать вызовы метода к модели или создать отдельный экземпляр модели для каждого потока и очереди отправки.

Ой, прошу прощения. Мне казалось, что внутри MLModel использовалась последовательная очередь для обработки запросов, однако я мог ошибаться или же что-то изменилось. В любом случае, лучше придерживаться этой рекомендации в будущем.

В MLMultiArray реализован новый инициализатор init(concatenating:axis:dataType:), который создаёт новый мульти-массив путём объединения нескольких существующих мульти-массивов. Все они должны иметь одинаковую форму за исключением заданной оси, вдоль которой выполняется объединение. Похоже, эта функция добавлена специально для формирования прогнозов по видеоданным, как в новых моделях классификатора действий в Create ML. Удобно!

Примечание. Перечисление MLMultiArrayDataType теперь содержит статические свойства .float и .float64. Не знаю точно, для чего они нужны, ведь это перечисление уже имеет свойства .float32 и .double. Ошибка бета-версии?

Средство просмотра моделей Xcode


В Xcode теперь отображается гораздо больше информации о моделях, например, метки классов и все добавленные пользовательские метаданные. Кроме того, выводятся статистические данные о типах слоёв в модели.



Это удобное средство интерактивного просмотра, с помощью которого можно вносить изменения в модель в тестовом режиме, не запуская приложение. В это окно предварительного просмотра можно перетаскивать изображения, видеоролики или текст и сразу же просматривать прогнозы модели. Отличное обновление!

Кроме того, теперь можно использовать модели Core ML в интерактивной среде. Xcode автоматически генерирует для этого класс, который можно использовать в обычном порядке. Это ещё один способ интерактивного тестирования моделей до их добавления в приложение.

coremltools 4


Создавать собственные модели для простых проектов удобно с помощью Create ML, однако гораздо чаще для обучения используются TensorFlow и PyTorch. Чтобы использовать такую модель в Core ML, необходимо сначала конвертировать её в формат mlmodel. Именно для этого используется набор инструментов coremltools.

Отличные новости: документация стала значительно лучше. Рекомендую ознакомиться с ней. Будем надеяться, что руководство для пользователя будет регулярно обновляться, потому что раньше документация не всегда была актуальной.

Примечание. К сожалению, исчезли образцы блокнотов Jupyter. Теперь они включены в руководство для пользователя, но уже не как блокноты.

Серьёзно изменился способ преобразования моделей. Используемые ранее конвертеры нейросетей устарели, и их заменили более новые и гибкие версии.

На сегодняшний день доступно три типа конвертеров:

  • Современные конвертеры для TensorFlow (как 1.x, так и 2.x), tf.keras и PyTorch. Все эти конвертеры созданы на основе одних и тех же технологий и используют так называемый промежуточный язык модели (MIL). Для таких моделей больше не нужно использовать tfcoreml или onnx-coreml.
  • Старые конвертеры для нейросетей Keras 1.x, Caffe и ONNX. Для каждой из них предусмотрен специализированный конвертер. Их дальнейшая разработка прекращена, в будущем планируется выпускать только исправления. Для преобразования моделей PyTorch больше не рекомендуется использовать ONNX.
  • Конвертеры для моделей не на основе нейросетей, таких как scikit-learn и XGBoost.

Для преобразования моделей TensorFlow 1.x, 2.x, PyTorch или tf.keras используется новый единый API-интерфейс преобразования. Он применяется следующим образом:

import coremltools as ct class_labels = [ "cat", "dog" ] image_input = ct.ImageType(shape=(1, 224, 224, 3),                           bias=[-1, -1, -1],                           scale=2/255.) model = ct.convert(    keras_model,     inputs=[ image_input ],    classifier_config=ct.ClassifierConfig(class_labels)) model.save("YourModel.mlmodel")

Функция ct.convert() проверяет файл модели, чтобы определить её формат, а затем автоматически выбирает соответствующий конвертер. Аргументы несколько отличаются от тех, что использовались прежде: аргументы предварительной обработки передаются с помощью объекта ImageType, метки классификатора с помощью объекта ClassifierConfig и так далее.

Новый API-интерфейс преобразования конвертирует модель в промежуточное представление т. н. MIL. На сегодняшний день доступны конвертеры для преобразования моделей TensorFlow 1.x в MIL, TensorFlow 2.x в MIL (в том числе tf.keras) и PyTorch в MIL. Если наберёт популярность новая платформа глубокого обучения, она получит собственный конвертер в MIL.



После конвертации модели в формат MIL её можно оптимизировать согласно общим правилам, например, изъять ненужные операции или объединить несколько разных слоёв. Затем модель преобразовывается из MIL в формат mlmodel.


Я ещё не изучил всё это подробно, однако новый подход даёт возможность надеяться, что coremtools 4 сможет создавать более эффективные файлы mlmodel, чем раньше особенно для графов TF 2.x.

В MIL мне особенно нравится возможность настроить для конвертера способ обработки тех слоёв, которые он ещё не проанализировал. Если ваша модель содержит слой, который не поддерживается в Core ML напрямую, может потребоваться разделить его на более простые операции MIL, такие как матричное умножение или другие арифметические действия.

После этого конвертер сможет использовать так называемые составные операции для всех слоёв такого типа. Это намного проще, чем добавлять неподдерживаемые операции с помощью пользовательских слоёв, хотя и это возможно. В документации приведён хороший пример использования таких составных операций.

См. также:


Другие платформы Apple, использующие машинное обучение


Несколько других высокоуровневых платформ в пакетах SDK для iOS и macOS также используются для задач, связанных с машинным обучением. Давайте посмотрим, что нового в этой сфере.

Vision


Платформа компьютерного зрения Vision получила ряд новых функций.

На платформе Vision уже использовались модели распознавания лиц, отличительных черт и человеческих тел. В новой версии добавлены следующие функции:

Распознавание положения рук (VNDetectHumanHandPoseRequest)
Распознавание поз нескольких человек (VNDetectHumanBodyPoseRequest)

Очень здорово, что Apple включила функции распознавания поз в ОС. Эту функцию поддерживают несколько моделей с открытым исходным кодом, однако они далеко не так эффективны или быстры. Коммерческие же решения отличаются высокой стоимостью. Теперь качественные инструменты распознавания поз доступны бесплатно!

Сейчас, в отличие от рассматривания статических изображений, больше внимания уделяется распознаванию объектов на видеозаписи как в автономном режиме, так и в реальном времени. Для удобства можно задействовать объекты CMSampleBuffer непосредственно с камеры, используя для этого обработчики запросов.

Также в класс VNImageBasedRequest добавлен подкласс VNStatefulRequest, который отвечает за оперативное подтверждение обнаружения искомого объекта. В отличие от стандартного класса VNImageBasedRequest здесь повторно используется запрос с отслеживанием состояния, охватывающий несколько кадров. Такой запрос выполняет анализ через каждые N кадров видеозаписи.

После обнаружения искомого объекта вызывается завершающий обработчик, содержащий объект VNObservation, который теперь имеет свойство timeRange, указывающее время начала и прекращения наблюдения в видеозаписи.

Напрямую класс VNStatefulRequest не используется. Это абстрактный базовый класс, который в настоящее время делится на подклассы только посредством запроса VNDetectTrajectoriesRequest для целей распознавания траектории. Это позволяет распознавать формы, движущиеся вдоль параболической траектории, например, при броске мяча или ударе по нему ногой (кажется, в настоящее время это единственная встроенная задача, связанная с видео).

Для анализа видеозаписей в автономном режиме можно использовать VNVideoProcessor. Этот объект добавляет URL-адрес в локальную видеозапись и выполняет один или несколько запросов Vision через каждые N кадров или N секунд.

Одним из важнейших традиционных приёмов компьютерного зрения для анализа видеозаписей является оптический поток. В Vision теперь доступен запрос VNGenerateOpticalFlowRequest, который вычисляет направление, в котором каждый пиксель перемещается из одного кадра в другой (плотный оптический поток). В результате создаётся объект VNPixelBufferObservation, содержащий новое изображение, в котором каждому пикселю соответствуют два 32-битовых или 16-битовых значения с плавающей запятой.

Кроме того, добавлен новый запрос VNDetectContoursRequest для распознавания контуров объектов в изображении. Такие контуры возвращаются в виде векторных контуров. VNGeometryUtils предоставляет вспомогательные инструменты для последующей обработки распознанных контуров, например, их упрощения до базовых геометрических фигур.

И последнее нововведение в Vision новая версия встроенного блока выделения признаков VisionFeaturePrint. В iOS уже реализован блок VisionFeaturePrint.Scene, который особенно удобен для создания классификаторов изображений. Кроме того, теперь доступна новая модель VisionFeaturePrint.Object, которая оптимизирована для выделения признаков, используемых при распознавании объектов.

Эта модель поддерживает входные изображения 299299 и возвращает два мульти-массива формы (288, 35, 35) и (768, 17, 17), соответственно. Это ещё не четкие ограничивающие рамки, а лишь необработанные признаки. Для полноценного распознавания объектов потребуется добавить логику, которая преобразует эти признаки в ограничивающие рамки и метки классов. Эту задачу выполняет Create ML, если обучение инструмента распознавания объектов выполняется с использованием переноса обучения.

См. также:


Обработка естественного языка


Для задач обработки естественного языка можно использовать платформу Natural Language. Она активно применяет модели, обученные в Create ML.

В этом году добавлено совсем немного новых функций:

  • NLTagger и NLModel теперь находят несколько тегов и предсказывают их достоверность. Раньше достоверность тега определялась только набранным количеством баллов.
  • Вставка предложений. Вставку слов можно было использовать и раньше, однако теперь NLEmbedding поддерживает целые предложения.


При вставке предложений используется встроенная нейросеть для кодирования всего предложения в 512-мерный вектор. Это позволяет получить контекст, в котором слова используются в предложении (вставка слов такую функцию не поддерживает).

См. также:


Анализ речи и звуков


В этой области изменений не было.

Обучение моделей


Обучение моделей с помощью API-интерфейсов Apple впервые стало доступно в iOS 11.3 и на платформе Metal Performance Shaders. За предыдущие несколько лет добавлено множество новых API для обучения, и этот год тоже не стал исключением: по моим подсчётам, нам теперь доступно целых 7 различных API для обучения нейросетей на платформах iOS и macOS!



В настоящее время для обучения моделей машинного обучения в частности, нейросетей в iOS и macOS можно использовать следующие API-интерфейсы Apple:

  • Локальное обучение в Core ML.
  • Create ML: этот интерфейс может быть известен вам в виде приложения, однако это также платформа, доступная в macOS.
  • Metal Performance Shaders: API для формирования логического вывода и обучения на графическом процессоре. По сути это два разных API, довольно сложных в использовании, если вы плохо знакомы с Metal. Кроме того, также доступна новая платформа Metal Performance Shaders Graph, которая, похоже, заменит эти устаревшие API.
  • BNNS: часть платформы Accelerate. Ранее в BNNS были доступны только процедуры логического вывода, однако в этом году добавлена также поддержка обучения.
  • ML Compute: принципиально новая платформа, которая выглядит весьма многообещающе.
  • Turi Create: фактически это версия Create ML для Python. В последнее время её создатели о ней подзабыли, хотя поддержка платформы пока не прекращена.

Рассмотрим нововведения в этих API подробнее.

Локальное обучение в Core ML


По сути, никаких масштабных изменений здесь нет. Могла быть добавлена поддержка обновлений ещё для нескольких типов слоёв, но документации по этому вопросу я пока не видел.

Одно из важных нововведений, которого стоит ожидать в будущей бета-версии оптимизатор RMSprop. В текущую бета-версию он не входит.

Create ML


Платформу Create ML изначально можно было использовать только под управлением macOS. Её можно запустить в среде Swift Playground, чтобы использовать для обучения моделей всего пару строк кода.



В прошлом году Create ML была преобразована в приложение с достаточно ограниченным функционалом, и я с удовольствием отмечаю значительные усовершенствования в этом году. При этом Create ML остаётся платформой, которую всё ещё можно использовать из кодовой части. Фактически приложение представляет собой просто удобный графический интерфейс для работы с платформой.

В предыдущей версии приложения Create ML можно было обучить модель всего один раз. Чтобы что-то изменить, приходилось обучать её повторно с нуля, а это занимало немало времени.

Новая версия Xcode 12 позволяет приостанавливать обучение и возобновлять его позднее, сохранять контрольные точки модели (моментальные снимки) и просматривать предварительные результаты обучения модели. Теперь в нашем распоряжении значительно больше инструментов для управления процессом обучения. Благодаря этому обновлению приложение Create ML действительно становится полезным!

На платформе CreateML.framework также доступны новые API для настройки сеансов обучения, обработки контрольных точек модели и т. д. Я полагаю, большинство специалистов просто будет использовать приложение Create ML, но всё равно приятно видеть, что эта функция теперь доступна и на платформе.

Новые функции Create ML (как на платформе, так и в приложении):

  • Перенос стиля для изображений и видеозаписей
  • Классификация действий людей в видеозаписях
  • Перенос обучения для распознавания объектов
  • Перенос обучения с тегированием слов и динамической вставкой слов

Давайте подробнее рассмотрим новую модель классификации действий. Она использует модель распознавания поз, доступную на платформе Vision. Классификатор действий представляет собой нейросеть, которая в качестве входных данных принимает форму (window_size, 3, 18), при этом первое значение представляет длительность видеофрагмента, указанную в количестве кадров (обычно используются фрагменты около 2 секунд), а (3, 18) представляют ключевые точки позы.

Вместо повторяющихся слоёв нейросеть использует одномерные свёртки. Скорее всего, это вариация свёрточной сети с пространственно-временными графами (STGCN) тип модели, специально предназначенный для прогнозирования временных рядов. Эти детали не должны вас волновать при использовании таких моделей в приложении. Однако мне всегда хочется узнать, как всё это работает.

Что касается моделей распознавания объектов, можно выбрать обучение всей сети на основе TinyYOLOv2 или же использовать новый режим переноса обучения, в рамках которого задействован новый блок выделения признаков VisionFeaturePrint.Object. Остальная часть модели по-прежнему напоминает YOLO и SSD, однако благодаря переносу её обучение будет гораздо более быстрым, чем обучение всей модели на основе YOLO.

См. также:


Metal Performance Shaders


Metal Performance Shaders (MPS) платформа на базе производительных вычислительных ядер Metal, которая в основном используется для обработки изображений, но с 2016 года предлагает также поддержку нейросетей. Я уже много писал об этом в блоге.

Сегодня большинство пользователей выберут Core ML, а не MPS. Конечно, Core ML всё равно использует возможности MPS при выполнении моделей на графическом процессоре. Однако MPS также можно использовать напрямую, особенно если пользователь планирует проводить обучение самостоятельно (кстати, теперь доступна новая платформа ML Compute, которую рекомендуется использовать вместо MPS. Её описание приведено ниже).

В этом году в MPSCNN мало новых функций, но усовершенствовано несколько существующих.

Добавлены новые классы MPSImageCanny для распознавания контуров и MPSImageEDLines для распознавания линейных сегментов. Они очень полезны при работе над задачами компьютерного зрения.

Стоит также отметить и ряд других изменений:

  • В MPSCNNConvolutionDataSource добавлено новое свойство kernelWeightsDataType, которое позволяет использовать для весовых коэффициентов тип данных, отличный от того, что применяется при свёртке. Что интересно, весовые коэффициенты не могут относиться к типу данных INT8, даже несмотря на то, что Core ML позволяет использовать этот тип данных для отдельных слоёв.
  • Если kernelWeightsDataType возвращает значение .float32, свёрточные и полносвязные слои выполняются с использованием 32-битовых операций с плавающей запятой вместо 16-битовых. Ранее поддерживались только 16-битовые.
  • Функции потерь теперь могут использовать параметр reduceAcrossBatch.

По-прежнему можно использовать MPSCNN, если Metal вас не пугает. Однако теперь доступна новая платформа, которая значительно упрощает создание и выполнение таких графов: MPS Graph.

Примечание. В видеоролике WWDC указывается, что MPSNDArray новый API, но на самом деле он появился ещё в прошлом году. Это гораздо более гибкая структура данных, чем MPSImage, поскольку не все тензоры в вашей модели могут быть изображениями.

Новое: Metal Performance Shaders Graph



В MPS давно доступен API MPSNNGraph, однако такие графы, по сути, описывают только нейросети. Однако далеко не все графы обязательно должны быть нейросетями, и именно в этом случае будет полезна платформа Metal Performance Shaders Graph.

Эту новую платформу можно использовать для создания универсальных графов вычислительных операций графического процессора. Платформа MPS Graph не зависит от Metal Performance Shaders, хотя и создавалась на её основе.

В предыдущей версии устаревшего API MPSNNGraph в граф невозможно было добавить пользовательские операции. Новая платформа в этом отношении гораздо более гибкая. Впрочем, добавлять собственные вычислительные ядра Metal нельзя. Потребуется выражать все вычисления с помощью существующих примитивов.

К счастью, компилятор MPSGraph поддерживает объединение таких примитивов в единое вычислительное ядро, что обеспечивает его максимально эффективную работу на графическом процессоре. Тем не менее, эта схема не сработает, если для какой-то операции невозможно или затруднительно использовать предоставленные примитивы. Я просто не понимаю, почему Apple, создавая новый API вроде этого, никогда не предусматривает возможность создания полноценных пользовательских функций! Но ничего не поделаешь.

Новая платформа MPSGraph представляет собой достаточно простую и логичную структуру, описывающую связь между операциями в наборе MPSGraphOperations посредством тензоров MPSGraphTensors, содержащих результаты операций. Кроме того, можно определить управляющие зависимости, чтобы принудительно запускать отдельные узлы раньше других. После настройки графа, его необходимо выполнить или передать в командный буфер, а затем дождаться результата.

MPSGraph предоставляет целый набор методов экземпляра, которые позволяют добавлять в граф любые математические операции или операции нейросети.

Кроме того, поддерживается обучение, которое предполагает добавление в граф операции обработки потерь и последующее выполнение операций градиента для всех слоёв в обратном порядке как и в устаревшем MPSNNGraph. Для удобства доступен также режим автоматической дифференциации, в рамках которого MPSGraph автоматически выполняет операции градиента для графа. Это позволяет сэкономить много усилий.

Мне нравится, что для создания таких вычислительных графов теперь есть новый, простой и понятный API. Он гораздо удобнее в использовании, чем предыдущие версии. И для работы с ним не нужно быть экспертом по Metal. Кстати, он во многом похож на графы TensorFlow 1.x, но при этом имеет большое преимущество в плане оптимизации, что позволяет максимально сократить издержки. И всё-таки не хватает возможности добавлять в граф произвольные вычислительные ядра.

См. также:


BNNS (Basic Neural Network Subroutines)


Если Core ML выполняется на ЦП, то она использует подпрограммы BNSS, которые являются частью платформы Accelerate. Я уже писал о BNNS в этой статье. Поддержка этих функций BNNS на сегодняшний день по большей части прекращена, и они заменены новым набором функций.

Ранее поддерживались только полносвязные слои, функции свёртки, группирования и активации. Это обновление добавляет в BNNS поддержку n-мерных массивов, практически всех типов слоёв Core ML, а также версии обратной совместимости таких слоёв для обучения (включая слои, которые в настоящее время не поддерживают обучение Core ML, например, LSTM).

Стоит также отметить наличие слоя множественного внимания. Такие слои часто используются в моделях Transformer, например, BERT. Ещё один интересный момент свёртывания тензоров.

Возможно, вы не будете самостоятельно использовать эти функции BNNS точно так же, как не станете использовать MPS для обучения на графическом процессоре. Вместо этого теперь доступна платформа более высокого уровня ML Compute, которая абстрагирует используемый процессор. В основу ML Compute положены BNNS и MPS, но разработчикам не придётся беспокоиться о таких мелочах.

См. также: документация по платформе BNNS

Новое: ML Compute


ML Compute представляет собой принципиально новую платформу для обучения нейросетей на ЦП или графических процессорах (но, видимо, не на процессорах Neural Engine). На Mac Pro с несколькими графическими процессорами эта платформа может автоматически использовать для обучения их все сразу.

Меня слегка удивило наличие ещё одной платформы для обучения, однако эта платформа действительно всё упрощает, потому что позволяет скрывать низкоуровневые компоненты из BNNS и MPS, а в будущем, может быть, и из Neural Engine.

Что самое интересное, ML Compute также поддерживается системами iOS, а не только на Mac. Забавно, что нигде не упоминается Core ML. ML Compute как будто бы создавалась совершенно отдельно. Эту платформу нельзя использовать для создания моделей Core ML.

По своему опыту могу сказать, что задача ML Compute, в первую очередь, ускорить работу сторонних инструментов глубокого обучения. Вам не придётся писать код, чтобы работать напрямую с ML Compute. Похоже, предполагается (ну или разработчики надеются на это), что такие инструменты, как TensorFlow, начнут использовать эту платформу, чтобы реализовать в Mac поддержку обучения с аппаратным ускорением.

Доступен примерно тот же набор слоёв, что и в BNNS. Слои необходимо добавить в граф, а затем выполнить его (здесь режим напряжённого ожидания не используется).

Чтобы создать граф, необходимо сначала создать экземпляр объекта MLCGraph и добавить в него узлы. Узел это подкласс MLCLayer. Узлы соединяются между собой посредством объектов MLCTensor, которые содержат выходные данные других слоёв.

Что интересно, операции разделения, конкатенации, переформатирования и переноса представляют собой не отдельные типы слоёв, а операции непосредственно на графе.

Отличная функция отладки summarizedDOTDescription. Она возвращает описание DOT для графа, на основе которого затем можно создать график с помощью, например, программы Graphviz или OmniGraffle (кстати, Keras генерирует графики моделей именно так).

ML Compute различает графы логического вывода и графы обучения. Последний содержит дополнительные узлы, например, слой потерь и оптимизатор.

Похоже, способов создания пользовательских слоёв здесь не предусмотрено, поэтому придётся обойтись только типами, доступными в ML Compute.

Странно, что по этой новой платформе не было сессий в рамках WWDC, и документация тоже достаточно разрозненная. Как бы там ни было, я продолжу следить за её развитием, потому что, кажется, это именно тот API, который лучше всего подходит для обучения моделей на устройствах Apple.

См. также: документация по платформе ML Compute

Заключение


В Core ML добавлен ряд новых полезных функций, например, автоматическое обновление моделей и шифрование. Новые типы слоёв на самом деле не очень нужны, потому что слои, добавленные в прошлом году, позволяют решить практически любые задачи. В целом это обновление мне нравится.

В coremltools 4 добавлены важные усовершенствования новая архитектура конвертера и встроенная поддержка TensorFlow 2 и PyTorch. Я рад, что нам больше не придётся использовать ONNX для преобразования моделей PyTorch.

В Vision добавлено множество новых удобных функций. И мне нравится, что компания Apple добавила функцию анализа видеозаписей. Хотя системы машинного обучения и можно применять для отдельных кадров видеозаписи, в этом случае не учитывается время. Поскольку сегодня мобильные устройства стали достаточно быстрыми, чтобы выполнять машинное обучение на основе видеоданных в реальном времени, я полагаю, в ближайшем будущем видео будет играть более важную роль в разработках технологий компьютерного зрения.

Что касается обучения не уверен, что нам нужны семь разных API для этой задачи. Полагаю, Apple просто не захотела выводить из обращения устаревшие интерфейсы, пока новые не будут полностью доработаны. О платформе ML Compute пока известно мало. Однако на момент написания этой статьи вышла только первая бета-версия. Кто знает, что нас ждёт впереди

В докладной картинке использована иконка Freepik с flaticon.com.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru