
На WWDC 2017 Apple представила ML kit, який став одним з основних кроків вперед у сучасному мобільному програмному забезпеченні і був створений для досягнення суттєвих змін у досвіді користувачів iOS. Більше того, Apple не лише дозволила користувачам по-новому відчути свої пристрої, але й спростила програмістам впровадження складних алгоритмів машинного навчання у своїх застосунках.
Отже, що таке машинне навчання? Сьогодні ми чуємо про це багато, але чи справді розуміємо, що це таке? Якщо коротко, це спосіб використання складної статистики та математики для досягнення ефекту «навчання» машини, що приймає рішення без фактичного програмування на це. Чесно кажучи, сьогодні вся сфера штучного інтелекту (AI) не є чимось іншим, як ML. Зазвичай вирішення проблем за допомогою ML складається з двох етапів — навчання моделі за допомогою датасету (набору специфічних даних, зібраних експертами) та використання цієї моделі для вирішення подібних проблем.
Складність машинного навчання полягає в тому, що воно вимагає багато обчислювальної потужності, якої зазвичай не вистачає на мобільних пристроях. Насправді ніхто не буде використовувати застосунок, який споживає занадто багато батареї чи трафіку, навіть якщо він корисний і надає новий досвід. Більше того, ніхто не хоче ділитися своїми даними, які можуть бути досить особистими, з обчислювальним хмарним сервісом.
Отже, як Apple вдалося впоратися з цими викликами?
По-перше, це питання конфіденційності. ML kit не надсилає жодних даних у хмару, тому всі обчислення виконуються безпосередньо на пристрої. По-друге, це питання оптимізації. Apple також вирішила цю проблему. По-третє, ви не навчаєте модель на пристрої, а лише використовуєте її для вирішення проблем користувача.
Згідно з документацією Apple, фреймворк Core ML базується на металевих шейдерах продуктивності, що надає можливість отримати максимум продуктивності від апаратного забезпечення пристрою, accelerate — бібліотека для високооптимізованого виконання складних математичних обчислень, та BNNS (базові підпрограми нейронних мереж), які надають базові інструменти, що зазвичай використовуються в ML.
Щоб краще зрозуміти BNNS, давайте заглибимося трохи глибше і розглянемо конкретну проблему (нехай це буде розпізнавання зображень) і як вона вирішується за кулісами. Насправді процес розпізнавання є досить простим: потрібно надіслати початкове зображення через ланцюг фільтрів, які модифікують його певним чином, і порівняти вихідне зображення з шаблонами, збереженими в моделі. Отже, BNNS надає можливість працювати з цими фільтрами, хоча наразі доступні лише три їхні типи.
Існує три основні проблеми, які легко вирішити за допомогою ML kit і інтегрувати у вашому застосунку: зір (розпізнавання шаблонів), розуміння природної мови (наприклад, пояснення фрази) та налаштування ігрового процесу відповідно до досвіду користувача за допомогою GameplayKit.
Давайте ближче ознайомимося з фреймворком vision, щоб краще зрозуміти, як його можна використовувати «в реальному житті». Для цього я підготував невеликий демонстраційний застосунок Prizma, який дозволяє розпізнавати деякі об'єкти навколо за допомогою камери iPhone. Він дозволяє розпізнавати обличчя, прямокутники, штрих-коди та текстові мітки з їхньою позицією «з коробки» і класифікувати інші об'єкти, використовуючи деякі кастомні ML моделі.
Виявлення будь-яких з об'єктів «з коробки» таке ж просте, як створення запиту на візію та вказівка обробки для нього.
> lazy var rectangleDetectionRequest: VNDetectRectanglesRequest ={ let rectDetectRequest = VNDetectRectanglesRequest(completionHandler: self.handleDetectedRectangles) rectDetectRequest.maximumObservations =8 rectDetectRequest.minimumConfidence =0.6 rectDetectRequest.minimumAspectRatio =0.3return rectDetectRequest }()>
У запиті ми можемо вказати максимальну кількість об'єктів, виявлених одночасно, мінімальну впевненість у виявленні (від 0 до 1), необхідну для активації обробника, та мінімальне співвідношення сторін для розпізнавання прямокутника. Досить гнучко, чи не так? У цьому конкретному застосунку обробка виявлення означає малювання його на шарі поверх камери.
> fileprivate func handleDetectedRectangles(request: VNRequest?, error: Error?){if let nsError = error as NSError? { self.presentAlert("Помилка виявлення прямокутників", error: nsError)return} DispatchQueue.main.async { guard let drawLayer = self.cameraView?.layer, let results = request?.results as? [VNRectangleObservation]else{return} self.draw(rectangles: results, onImageWithBounds: drawLayer.bounds) drawLayer.setNeedsDisplay()}} >
Потім для кожного кадру, захопленого камерою, ми просто викликаємо метод для виконання наших запитів.
> fileprivate func performVisionRequest(image: CGImage, orientation: CGImagePropertyOrientation){ var requests =[VNImageBasedRequest]()if Settings.provider.facesSelected { requests.append(faceLandmarkRequest); requests.append(faceDetectionRequest)}if Settings.provider.rectsSelected { requests.append(rectangleDetectionRequest)}if Settings.provider.textSelected { requests.append(textDetectionRequest)}if Settings.provider.barcodeSelected { requests.append(barcodeDetectionRequest)} let imageRequestHandler = VNImageRequestHandler(cgImage: image, orientation: orientation, options:[:]) DispatchQueue.global(qos: .userInitiated).async {do{ try imageRequestHandler.perform(requests)} catch let error as NSError{ self.presentAlert("Запит зображення не вдався", error: error)return}}} >
Тепер ви бачите, що використання ML kit є декларативним і досить простим.
Давайте перейдемо до другої частини застосунку — використання кастомних моделей. Ви можете вибрати, чи навчати свою кастомну модель, чи використовувати модель когось іншого. На сайті документації Apple ви можете знайти деякі базові моделі. Якщо чесно, вони не зовсім точні. Ви також можете пошукати в інтернеті, щоб знайти деякі моделі з відкритим кодом. З моменту випуску Xcode 10.0 стало ще простіше створювати свої власні моделі. Навчання моделі вимагає наявності набору даних і перетягування його до Xcode. Більше інформації про це ви можете знайти тут.
Щоб виконати класифікацію, нам потрібно створити запит, вказавши модель для використання. На даний момент неможливо створити чи завантажити модель і використовувати її на льоту, тому нам потрібно заздалегідь підготувати моделі, які ми хочемо використовувати.
> guard let visionModel:VNCoreMLModel = Settings.provider.currentModel.model else{return} let classificationRequest = VNCoreMLRequest(model: visionModel, completionHandler: handleClassification) classificationRequest.imageCropAndScaleOption = .centerCrop do{ try self.visionSequenceHandler.perform([classificationRequest], on: pixelBuffer)} catch { print("Throws: \(error)")}>
Під час створення запиту ми можемо вказати мінімальну (максимальну) впевненість, так само як і в попередній частині. Результат класифікації — це масив міток класифікації та впевненостей. Щоб обробити це, ми просто відображаємо ці дані на етикетці.
> func updateClassificationLabel(labelString: String){ DispatchQueue.main.async { self.resultLabel?.text = labelString }} func handleClassification(request: VNRequest, error: Error?){ guard let observations = request.results else{ updateClassificationLabel(labelString:"")return} let classifications = observations[0...min(3, (observations.count -1))] .compactMap({ $0 as? VNClassificationObservation}) .filter({ $0.confidence > 0.2}) .map(self.textForClassification) if(classifications.count > 0){ updateClassificationLabel(labelString:"\(classifications.joined(separator: "\n"))")}else{ updateClassificationLabel(labelString:"")}} func textForClassification(classification: VNClassificationObservation)-> String { let pc = Int(classification.confidence *100)return"\(classification.identifier)\nConfidence: \(pc)%"} >
Весь вихідний код цього демонстраційного застосунку можна знайти тут.
У нашій компанії з розробки програмного забезпечення ми бачимо, що, незважаючи на те, що ML є досить складною галуззю комп'ютерних наук, Apple за допомогою ML kit надала нам можливість легко використовувати його в декларативний спосіб, дозволяючи користувачам насолоджуватися високою продуктивністю своїх пристроїв і поважаючи їхню конфіденційність.