Метод тестирования Core ML моделей
На сайте https://developer.apple.com/machine-learning/build-run-models/
опубликован перечень Core ML моделей, готовых к применению в приложениях пользователей.
Но какая модель лучше подходит для конкретной задачи?
Неплохо бы предварительно протестировать различные модели, например, на задаче классификации неподвижных изображений. Выбирая модель и проверяя ее на тестовых множествах, можно получить оптимальный результат.
Да, но тестовые множества могут содержать сотни и тысячи фотографий.
Похоже, что нужна программа, которая позволит выбрать модель, альбом с фотографиями, а затем автоматически выполнит классификацию и группировку по принадлежности каждой фотографии в альбоме,
сформирует результат в виде таблицы.
Ниже предлагается вариант такой программы.
Программа разработана на аппаратных и программных средствах компании Apple. Язык программирования – Swift 4. Операционная система на устройстве тестирования - IOS 11.2.
При разработке программы использовались модифицированные фрагменты текста из примеров "SamplePhotosApp" и "Vision + ML Example" компании Apple.
Эти примеры позволили значительно сократить время разработки. Спасибо авторам.
Идея программы и реализация принадлежит автору статьи.
1. Работа с программой.
Снимки для статьи подготовлены при работе программы на симуляторе.
1.1. Пользователь может выбрать любую из предустановленных в программе моделей: Inceptionv3, MobileNet, SequeezeNet, Resnet50, GoogLeNetPlaces. Выглядит это так: Отмечу, что потенциально в программу может быть включено такое количество моделей, какое позволяют ресурсы устройства тестирования.
1.2. Затем необходимо выбрать альбом с фотографиями, в котором находится тестовое множество.
В данной версии программы предлагаются альбомы на локальном устройстве, однако, ничто не мешает загружать фотографии с Web сервера или iCloud.
1.3. Пользователь может открыть содержимое любого альбома и просмотреть фотографии.
Кнопка Flow предназначена для запуска потоковой классификации фотографий в альбоме. Нажатие на Image запустит процесс только для выбранной ячейки.
1.4. При нажатии на кнопку Flow программа в автоматическом режиме последовательно классифицирует каждую фотографии из указанного альбома и отправит ее Asset в группу по принадлежности. Вот так выглядит экран после окончания классификации последней фотографии
Кнопка List Result предназначена для вывода на экран результатов классификации и группировки.
1.5. При нажатии на кнопку List Result пользователь получит на экране устройства таблицу с именами групп распознанных объектов и количеством фотографий в каждой группе.
1.6. Можно открыть любую строку таблицы и увидеть все изображения для данной группы. Ну и конечно, выбрав любое изображение, можно получить его увеличенный вариант в UIImageView.
2. Результат классификации.
Результат работы программы представлен в виде таблицы. При анализе каждой группы выявляются ошибки классификации.
Соотнося общее количество элементов в тестовом множестве и число ошибок, можно получить численные характеристики эффективности той или иной модели.
3. Организация цикла просмотра.
Определим транзакцию так: загрузка фотографии + классификация + группировка. Транзакция требует значительной вычислительной работы. Например, на устройстве IPhone SE с моделью MobileNet для альбома с 200 фотографиями потребуется около 15 секунд, чтобы выполнить задачу. С моделью Inceptionv3 потребуется уже почти в два раза больше времени. Естественно, что возникает вопрос, как лучше организовать такую работу. Простое решение организовать цикл перебора в DispatchQueue.main.async приведет к тому, что устройство перестанет отвечать на действия пользователя до завершения задачи. Если перенести цикл перебора в DispatchQueue.global(qos: .userInitiated).async , то на альбомах, содержащих небольшое количество фотографий задача успешно выполняется, а интерфейс программы откликается.
Однако, если запустить задачу на большом количестве фотографий, она потерпит крах. В чем причина? Анализ ситуации указывает на бесконтрольное нарастание потоков вплоть до исчерпания ресурсов системы, транзакции, запущенные на выполнение не успевают выполняться до запуска новых. С учетом указанных причин в программе применен метод семафоров – новая транзакция не запускается до завершения предыдущей. Каждая транзакция использует как фоновый так и главный потоки. Другой вариант организации перебора фотографий в альбоме можно реализовать с помощью таймера. Этот вариант проверен - он нормально работает. Таймер работает по прерыванию и снимает часть нагрузки c процессора. 4. Группировка классифицированных изображений.
Переменная типа:
var assetDictonary = [String : [PHAsseet!]]
используется в качестве основной структуры для накопления и группировки распознанных объектов. В качестве ключа в этом словаре используется первое имя классифицированного объекта. Процент вероятности и второе имя в этой версии программы не учитываются. В качестве значения для ключа принимается массив типа [PHAsset], в котором хранятся Asset фотографий.
Принцип работы со словарем таков: каждой классифицированной фотографии ставится в соответствие имя (key) изображенного объекта, затем проверяется, есть ли такое имя в словаре. Если имени нет – добавляется новая строка:
self.assetDictonary[key] = [self.asset]
Если такое имя уже есть, то к существующему ключу в качестве значения в массив добавляется Asset фотографии:
self.assetDictonary[key]!.append(self.asset)
Таким образом, по окончании цикла перебора выбранного пользователем альбома, мы получим заполненный словарь, который, затем выводится на экран пользователя в классе ResultClassificationTable.
5. Свойство lazy var request: VNCoreMLRequest.
На первый взгляд непонятно, почему данное свойство в примере Apple объявлено как lazy. Я переписал это свойство в виде функции func request() -> VNCoreMLRequest { …}.
Запустил и протестировал программу в режиме Flow. Посмотрел и вернул все обратно. Что оказалось не так? Дело в том, что время работы программы увеличилось почти в два раза - вот вам и lazy!
Евгений Вересов.
27.03.2018 года.
|