Мелкая питонячая радость #10: конечные автоматы и глубокое обучение в несколько строк
- пятница, 9 октября 2020 г. в 00:29:21
Конечно, самая большая радость этих дней — python 3.9. Но кроме этой радости кто-то должен ворошить github в поисках мелких приятностей, которые несут добро и свет тем, кто пишет на python.
Тем, кому приходилось писать реализацию какого-нибудь сложного информационного процесса, знает эту проблему.
У вас есть некий объект, который может находиться всегда только в одном состоянии.
Переходы между состояниями описываются диаграммой состояний — из какого в какое состояние объект может перейти, а из какого в какое — не может.
Например, пользователь у вас в системе может быть незарегистрированным, зарегистрированным, зарегистрированным и зааппрувленным, зарегистрированным, зааппрувленным и неактивным, зарегистрированным, зааппрувленным и заархивированным, заблокированным — ну и так далее. Понятно, что из незарегистрированного можно стать зарегистрированным, но из незарегистрированного нельзя стать заблокированным.
Программист посмотрит на все эти переходы, почешет репу — и нагородит кучу if-else условий для того, чтобы описать все возможные переходы между состояниями и запретить все невозможные. А хороший программист вспомнит (или нагуглит) абстракцию под названием “конечный автомат” и возьмет эту штуку для реализации своей задачи. И будет прав.
В python есть своя готовая реализация конечных автоматов, она называется transitions.
from transitions import Machine
# На этт объект будем вешать состояния
class Matter(object):
pass
lump = Matter()
# Полный список состояний
states=['solid', 'liquid', 'gas', 'plasma']
# Добавляем таблицу переходов — из какое в какое состояние мы можем попасть
transitions = [
{ 'trigger': 'melt', 'source': 'solid', 'dest': 'liquid' },
{ 'trigger': 'evaporate', 'source': 'liquid', 'dest': 'gas' },
{ 'trigger': 'sublimate', 'source': 'solid', 'dest': 'gas' },
{ 'trigger': 'ionize', 'source': 'gas', 'dest': 'plasma' }
]
# Инициализация машины
machine = Machine(lump, states=states, transitions=transitions, initial='liquid')
# Проверяем начальное состояние
lump.state
>>> 'liquid'
# И пробуем изменить состояние триггерами перехода
lump.evaporate()
lump.state
>>> 'gas'
lump.trigger('ionize')
lump.state
>>> 'plasma'
Несколько строк кода — мы получаем понятный механизм перехода ваших объектов из одного состояния в другое.
Вещь, которой некоторым из нас иногда приходится заниматься — правильно форматировать вывод различных валют. Да-да, для каждой валюты есть правила форматирования — где-то разряды нужно отделять точкой, а где-то — запятой. Иногда код валюты пишется перед суммой, а иногда — после. Помнить, гуглить или городить форматирование через locale каждый раз лень, поэтому мы будем пользоваться специализированной библиотекой для форматирования денежных сумм — money.
>>> from money import Money
>>> m = Money(amount='2.22', currency='EUR')
>>> m
EUR 2.22
Конечно же, объекты Money можно между собой еще и складывать/вычитать/умножать и делить.
Библиотек для глубокого обучения уже и так хватает — tensorflow, pytorch, keras и другие штуки поменьше успешно решат любую задачу по построению и обучению любой нейронной сети. Но тут появляется fastai и становится понятно, еще одна библиотека, в общем, не помешает и что с этой штукой жизнь стала приятней и веселей.
Fastai — высокоуровневая абстрактная нашлепка сверху на PyTorch, которая автоматизирует кучу всякой рутины, сокращает количество кода в ваших проектах и ускоряет процесс создания моделей машинного обучения.
Конечно, плюшек намного больше — смотрите документацию.
Наличие высокоуровневых абстракций сильно ускоряет написание кода.
# В одну строчку можно превратить папку с картинками в данные для обучения сети.
# Сразу же осуществляются все преобразования и присваиваются метки классов.
data = ImageDataBunch.from_name_re('./data', fnames, r'/([^/]+)_\d+.jpg$', ds_tfms=get_transforms(), size=224, bs=64).normalize(imagenet_stats)
# Еще одна строка грузит предобученную модель resnet34 и на ее основе создает нашу сеть,
# которую мы будем обучать на основе картинок из строчки выше.
learn = cnn_learner(data, models.resnet34, metrics=error_rate)
# Все, готово, обучили
learn.fit_one_cycle(4)
Конечно же, вы всегда можете опуститься на уровень ниже и обратиться непосредственно к PyTorch коду — например, для более тонкой настройки модели.
Если же вы понятия не имеете о том, как работать с нейронными сетями и глубоким обучением — авторы fastai сделали крутой и понятный курс, который позволит вам за пару недель научиться создавать модели машинного обучения под ваши задачи. На первом же занятии вы напишите детектор порд собак и кошек по фотографиям.
На сегодня все, прошлые питонячие радости смотрите по ссылке.