Блог им. Replikant_mih
Придумал интересный подход. Мож кого натолкнет на интересные идеи какие-то.
Сейчас начал торговать ML модели. С практической стороны с моделями какая сложность – там есть процесс предобработки данных – генерация признаков в основном (если с точки зрения трейдинговых данных заходить), поэтому нельзя просто сохранить модель, в другом месте загрузить и она будет работать, надо сохранить, загрузить, предобработать исходные данные к тому виду, к которому приучена модель и только тогда она будет работать. К счастью тонна сопутствующих трудозатрат убирается такой классной штукой как пайплайн – сейчас моя модель это 2 пайплайна – один для предобработки данных, другой для предикта (сама модель). Т.е. я где-то что-то рисечу, дальше автоматика упаковывает в пайплайны (2 на модель, как сказал). Все, могу кинуть эти 2 файла в папку с моделями, откуда их забирает торгующий блок и, собственно, отторговывает. Красота. Всякие мета-данные – тикер там, время удержания позиции и прочие мета-логики упаковываю или в сам пайплайн или в название файла. Красота.
Но по сути, классические алгоритмы (обычные алго-стратегии) по факту можно так же упаковывать. Можно это делать по идее (хотя на практике ещё не пробовал – идея с пылу с жару только) даже с помощью той же библиотеки. Пайплайны как работают: на вход дата-фрейм (ну или дата-сет, если кто не знаком с пандасом), на выход дата-фрейм или вероятности или че хочешь. В этот контекст вполне можно вписать обычные логики стратегии, даешь на вход свечные (или какие используешь данные), в пайплайне зашиваешь логики стратегии, на выход сигнал, например, бинарно 0/1. Т.е. по факту пайплайн это код, это алгоритм, что для стратегии и нужно, собственно.
По идее, если унифицировать интерфейсы, то торгующий блок может не знать что в пайплайн упаковано – модель/алгоритм простой или что-то ещё, на вход идут данные, на выход предикт (например, бинарный). Все, состряпал стратегию, упаковываешь в пайплайн, кидаешь в папку, торгующий модуль на лету подхватывает, считывает мета-данные и торгует. Мета-данные инкапсулировать тоже очень удобно по-моему. Можно там настройки про риски зашивать в том числе, например, или что-то ещё. Торгующий блок может подгружая пайплайн считывать мета-данные и использовать их как ориентир, но при необходимости может их и не использовать. Например, получая модель первый раз давать ей «испытательный срок» месяц, гоняя с пониженными рисками, собирая стату, потом уже смотреть что там про риски говорит сам пайплайн и использовать эти данные уже, как вариант.
Обожаю автоматизацию.
И ему, торгующему модулю, должно быть совершенно по барабану, что там у вас происходит в модуле стратегий :). Пайплайны ли вы используете или функции одну за дргой вызываете.
Касательно МЛ, то тенсорфлов сделал tensorflow serving как раз именно для того что бы использовать модели в продакшене быстро и удобно. Однако там конечно не все так здорово и удобно )) без пол литра не разберешься.
CloseToAlgoTrading, Ну, путь к лучшим практикам может быть тернист)), до этого надо ещё дорасти, прийти к этому.
tensorflow serving — спасибо, глянул мельком, у меня нейросетевых моделей пока нету, но видимо что-то такое (tensorflow serving) буду использовать когда дело дойдет до практики.
Но если у вас крутится на одном языке и в одной коробочке, то это все не обязательно.
Так то «пайплайн» это просто обозначение конвеера выполнения задач, вы же его как то вызываете и данные на вход передаете. Вот этот момент можете обернуть в какой нить апи, и отделить полностью работу ваших стратегий, рекомендательных алгоритмов и тд, от остального приложения. Но только если вам это нужно.
зы. хотя возможно вы уже используете нечто подобное, :) говоря «сохраняю модель в пайплайн».
— обученную модель
— метаданные описывающие процесс генерации признаков и модели
— перечень инструментов и диапазон дат на которых было произведено обучение
— метрику качества
— полное время на генерацию при знаков и обучение модели
Я тоже просто делаю вызов сохрани модель — в результате получается грубо json с последовательностью шагов (имен функций) и параметров вызовов. Есть простая функция которая умеет загружать — берет json и делает вызовы соответствующих функций с соответствующими параметрами.
Если функции лежат в нужных модулях, то ничего больше делать не надо.
— что нужно сделать, чтобы сгенерировать признаки
— как и с какими параметрами строится обучающий алгоритм
— как и с какими параметрами осуществляется обучение.
— сохранить соответсвующий json
— загрузить json, обучить модель, сохранить обученную модель с указанием метаданных обучения — на каких инструментах и временных интервалах
— загрузить модель и часть json с описанием признаков и сделать предсказание для конкретной даты
Михаил, я в формате sklearn_pipeline это делаю.
Ну я понял, короч, у вас единое пространство, единый проект. У меня пространство для рисеча отдельное, более того, разный стек — рисеч это юпитер ноутбук, а торгует проект на питоне обычный.
По сути да, это одно и то же, только я как бы сами функции тоже упаковываю в пайплайн, а не ссылаюсь на них и параметры передаю.
Упаковываю это просто красивое слово — sklearn_pipeline за вас хранит ссылки на функции и параметры, и ничего он не упаковывает.
Внутри sklearn_pipeline хранит всего один атрибут — список кортежей (название шага, функция/класс шага, передаваемые параметры).
А основной метод по существу сводится к циклу — пройдись по списку вызови класс с соответсвующими аргументами, печатай в лог название шага.
Я этот цикл сам написал. Так как вы не лезете внутрь sklearn_pipeline, то видимо делаете pickle класса. Так как я имею доступ внутрь своего класса, мне легче список кортежей сохранить в виде json, но при желании могу сделать и pickle.
Просто pickle не удобен тем, что он бинарный и не понятный. Вот лежит он на диске, а чего там внутри. А json в человеко читаемом виде — собственно тот самый перечень шагов и параметров.
Плюс я не заперт в классах sklearn, а они не очень ложатся на сети.
Михаил, нуу да, возможно юпитер более склонен к хаосу), но усилием воли всегда можно разруливать, у меня в юпитере всякие надстройки стоят — как то сворачивание разделов и т.д. + я организацией кода играюсь — у меня все аккуратно щас получается довольно-таки), но да, иногда задумываюсь рисечить в IDE.
>> «Упаковываю это просто красивое слово — sklearn_pipeline за вас хранит ссылки на функции и параметры, и ничего он не упаковывает»
Ну окей, а гиде тогда сами функции?)) Я на другую машину переношу только пайплайны. Она знать не знает что я там нарисечил), единственное только надо обеспечить совместимость по версиям либ.
По поводы работы пайплайнов в sklern — имею представление как оно работает, имею представление как оттуда данные забрать какие мне нужно, как сохранить какие мне нужно, как в отдельные узлы и классы заходить, мне этой гибкости хватает более чем, инструмент не идеальный, но хороший.
>>«Просто pickle не удобен тем, что он бинарный и не понятный. Вот лежит он на диске, а чего там внутри. А json в человеко читаемом виде — собственно тот самы перечень шагов и параметров. „
Да, есть такое, ну я то что нужно в название упаковываю, а остальное после чтения файла уже можно вытащить.
Короче, не агитирую, но мне нравится).
Хотел для себя прояснить, потому, что звучит несколько странно
А как вы все-таки сохраняете пайплайн, потому что pickle надо иметь доступ к определениям всех типов для восстановления. В интернете народ тоже вроде жалуется, что не удается перетащить с кастомными функциями? Выскакивают ошибки из серии
На что рекомендуют:
Каким образом вы эту проблему обходите?
Михаил, Сохраняю через либу dill — это какая-то обертка над pickle.
Проблем при переносе при реализации было много, но все победил, из-за того что много — не помню, что конкретного делал, по ощущениям большая часть проблем была связана разницей версий библиотек и самого питона — все-таки виртуальная среда с одной стороны и анаконда с другой).
>>«AttributeError: module '__main__' has no attribute 'CustomTransformer'»
Что-то такое, вроде было, тоже победилось версиями либ вроде или чем-то аналогичным.
Хотя кастомные функции, не уверен, что я это использую, я вроде использую только переопределение стандартных методов fit и transform, но этого и хватает, функции нужны разве что для удобства. Да, чекнул — только эти использую.
Михаил, А где же: «дружище, копай в сторону этой архитектуры… и вот этой, ну ладно, я сегодня выпивши: и вот в сторону вот этой перспективной ещё копай»?)))
Похоже, действительно, заниматься дип-ленингом это сидеть вникать в такие вот научные работы на английском).
Михаил, Да, примерно такое впечатление о процессе и складывается. Пробовал вместо своих моделей на то же признаковое пространство применить нейросеть полносвязную — ничего конечно она интересней чем бустинг не нашла. Но конечно если там твиты анализировать, или паттерны графические распознавать или что-то такое — тут конечно только нейросети.
Пока нейросети побудут на правах фундаментальных исследований, а статистические классические модели — на правах прикладных), дальше как пойдет).
В сети лучше котировки напрямую пихать, что-то странное типа твитов.
Михаил, ага-ага. Как-то так.
А признаки да, люблю придумывать), творческий процесс).
2) сделать абстрагирующий интерфейс которому на вход данные, а на выход сигнал — это лежит на поверхности. Вопрос только в какой форме подавать данные вместе с историей.
У меня так: алгоритм может сериализоваться/десериализоваться вместе со своим внутреннем состоянием. Ну то есть если ему положим надо 20 последних баров, то он сам должен внутри держать буфер. При таком подходе алгоритму надо на вход только очередной бар чтобы он его «усвоил» и выдал результат. Время от времени сериализованное состояние скидывается в БД. Если приложение рестартует, то восстанавливает состояние из БД и докидывает бары до последнего известного.
Не универсально, но под специфику моих алгоритмов подходит идеально.
ivanovr, Не знаю насчет сумбурно, по-моему четко стройно и ново)). Но это с моей колокольни так, может потому что не разраб.
1) В смысле не алгоритм?) Из кубиков, которые каждый алгоритм складываем тоже алгоритм)), если не алгортим то что? — Данные + алгоритм?) — ну может, хотя самого дата-фрейма пайплайн не содержит пока не зафичен.
По поводу хранения состояний и т.д.: ну, у меня на вход серия нужной длины подается, длину извне задаю, но в принципе можно её в пайплайн зашивать, по хорошему так и надо. Состояниями у меня другие блоки заведуют, пайплайн у меня только получает датафрейм и выдает предикт, мне в этом подходе пока все нравится.
Про алгоритм: ясень что где там грань несколько размытая. Но сам пайплайн обычно это разновидность «орекстратора» задача которого в определенной последовательности вызвать собственно алгоритмы.