Хабр, привет! На связи Кравцов Кирилл и Суздалев Руслан из команды моделирования поведенческих сценариев Центра развития искусственного интеллекта СПАО «Ингосстрах»(далее — ЦРИИ). В статье поделимся решением, которое помогает нам быстрее обучать и интегрировать модели в компании.
С ростом компании и ЦРИИ, в частности, у нас появлялось все больше бизнес-заказчиков, которым нужны были ML-модели. Поэтому потребность росла, а ограниченность ресурсов не позволяла быстро обрабатывать задачи бизнеса и многое уходило в беклог.
Чтобы справиться с растущими потребностями, мы разработали несколько ключевых шагов, которые значительно упростили и ускорили процесс создания ML-моделей:
Шаг №1. Разработка моделей классического ML
Мы собрали команду специалистов разного уровня и обучили несколько ML-моделей, которые можно было использовать в различных сценариях, затем построили пайплайны на основе практик, которые показали себя лучше всего. Наличие готовых решений значительно ускорило процесс разработки.
Шаг №2. Выявление ошибок в процессе разработки
Мы провели анализ и выявили распространенные ошибки, которые могут возникать на различных этапах разработки моделей. Это включало как технические ошибки, так и проблемы, связанные с пониманием бизнес-требований. Такой подход позволил нам лучше подготовиться к возможным трудностям и снизить риск неудач.
Шаг №3. Оцифровка алгоритма работы Data Scientist
Мы оцифровали алгоритм работы Data Scientist, что позволило создать стандартизированный подход к разработке моделей. Это упрощает процесс как для новых членов команды, так и для опытных специалистов, обеспечивая единообразие в подходах и методах.
Шаг №4. Написание документации
Мы написали документацию по использованию AutoML, чтобы разработчики любого уровня могли использовать проект. Так же описали возможные проблемы, которые на данный момент не решены, и предостережения для безопасного пользования.
Шаг №5. Подготовка шаблона для запросов на разработку моделей
Мы разработали шаблон, который позволяет бизнес-подразделениям формулировать свои запросы на разработку моделей с помощью AutoML. Это значительно упрощает коммуникацию между бизнесом и командой разработчиков, т.к. теперь можно четко обозначить требования и ожидания от модели.
Шаг №6. Разработка AutoML
Наконец, мы разработали AutoML систему, которая теперь может обучает модели в сжатые сроки. AutoML позволяет автоматизировать многие рутинные процессы, что значительно ускоряет время от запроса до получения готовой модели.

А теперь будем разбираться более детально! Мы разработали модульную архитектуру, которая стала нашим спасательным кругом и представляет собой своего рода «конструктор», позволяющий легко работать с данными, моделями и процессами обучения. Она не только сэкономила нам массу времени, но и открыла новые горизонты для экспериментов, позволяя сосредоточиться на креативных аспектах разработки, а не на рутинных задачах. Давайте остановимся на основных компонентах нашего проекта, как они устроены и как взаимосвязаны между собой. Начнем на примере кейса как поменялся бизнес-процесс с одним из заказчиков ЦРИИ:


Основные компоненты архитектуры:

Хранилище данных
Хранилище данных обеспечивает унифицированный интерфейс для получения данных из различных источников (базы данных, файлы, API) и сохранения результатов. Это упрощает интеграцию новых источников данных без необходимости изменения основной логики проекта.
Ниже представлен код класса DataSource, который устанавливает интерфейс для получения и сохранения данных, позволяя создавать разные реализации под различные типы источников данных. Это особенно актуально, если у вас есть несколько источников или данные могут изменяться со временем.
from abc import ABC, abstractmethod
from typing import Dict
class DataSource(ABC):
"""Interface class for data sources providing methods to get and put data."""
def __init__(self, config: Dict):
self.config = config
@abstractmethod
def get_data(self, path: str) -> Any:
"""Retrieve data from the specified path."""
pass
@abstractmethod
def put_data(self, data: Any, path: str):
"""Store the given data at the specified path."""
pass
Модели
Обычно у Data Scientist’а есть любимый Jupyter Notebook на все случаи жизни, который он запускает с разными данными, а model factory, по сути, как раз и представляет собой этот самый ноутбук только автоматизированный.

Каждая модель реализована как класс, наследующийся от базового класса MLModel, обеспечивая единый интерфейс и общие атрибуты, в частности, такие методы как train, predict и valid должны быть реализованы в каждой модели. Например, CatBoostGridSearchClassifier включает в себя методы для настройки гиперпараметров.
Основные компоненты:
Инициализация: Конструктор класса принимает несколько параметров, таких как target, ids, preprocessor, features, output_channels_schema и т.д. Эти параметры позволяют настроить модель для конкретной задачи и обеспечить гибкость в использовании.
Схемы ввода и вывода: Свойства input_schema и output_schema определяют, какие столбцы данных используются для входа и выхода модели. Это важно для правильной обработки данных и формирования результатов.
Методы предсказания: Метод predict отвечает за создание таблиц с оценками для обученной модели. Он обрабатывает входные данные с помощью предварительного препроцессора и возвращает либо DataFrame с результатами, либо только оценки, в зависимости от параметра return_only_score.
Валидация модели: Метод valid позволяет проверить качество модели на отложенной выборке.
Обучение модели: Метод train отвечает за обучение модели на предоставленных данных. Он включает в себя предварительную обработку данных, настройку гиперпараметров с помощью класса CatBoostHyperparameterOptimizer, а также сам процесс обучения с использованием CatBoostClassifier. Важно отметить, что модель обучается на тренировочной выборке, а затем оценивается на валидационной.
from abc import ABC, abstractmethod
from typing import List
class MLModel(ABC):
"""Abstract base class for ML model prediction."""
def __init__(
self,
name: str,
features: List[str],
preprocessor,
id_cols: List[str],
target_col: str
):
self.name = name
self.features = features
self.preprocessor = preprocessor
self.id_columns = id_cols
self.target = target_col
@property
@abstractmethod
def input_schema(self):
"""Returns the schema of the input data."""
pass
@property
@abstractmethod
def output_schema(self):
"""Returns the schema of the output data."""
pass
@abstractmethod
def predict(self, data, return_only_score: bool = False):
"""Makes predictions based on the input data."""
pass
@abstractmethod
def train(self, data):
"""Trains the model using the provided data."""
pass
Конвейер моделей
Конвейер моделей управляет всем процессом: от получения данных из БД до обучения модели и получения предсказаний. Это позволяет настроить последовательность шагов и автоматизировать рутинные задачи.
from abc import ABC, abstractmethod
class ModelConveyor(ABC):
"""Abstract base class for managing training and prediction processes for ML models."""
@abstractmethod
def __init__(
self,
model_rep: ModelRepository,
feature_store: DataSource,
predictions_store: DataSource
):
self.model_rep = model_rep
self.feature_store = feature_store
self.predictions_store = predictions_store
self.model = None
self.data = None
self.predictions = None
@abstractmethod
def train(self, model: MLModel, query: str):
"""Trains the specified ML model using the provided query to fetch data."""
pass
@abstractmethod
def predict(self, model_name: str, query: str, target_table: str):
"""Makes predictions using the specified model and stores results in the target table."""
Pass
Несколько примеров конвейеров, которые у нас есть:
Базовый конвейер BasicModelConveyor: Этот класс реализует основные функции, такие как обучение модели, валидация и предсказание. Он использует хранилище моделей и источники данных для получения необходимых данных и сохранения результатов. Это позволяет легко управлять жизненным циклом модели;
Калиброванный конвейер CalibratedBasicModelConveyor: Этот класс расширяет функциональность базового конвейера, добавляя возможность калибровки модели. Калибровка позволяет улучшить точность предсказаний, особенно в задачах, где важно правильно оценить вероятности;
Многофункциональный конвейер MultiPredictConveyor: Этот класс позволяет выполнять предсказания с использованием нескольких моделей одновременно. Это полезно в сценариях, когда необходимо сравнить результаты различных моделей или использовать ансамблирование для повышения точности предсказаний.
Трансформеры
Трансформеры реализуют интерфейс Transformer, который определяет методы fit, transform и inverse_transform, тут по факту sklearn реализации. Это позволяет легко добавлять новые трансформеры и использовать их в конвейере.
Например, RemoveOutliers чистит данные от выбросов.
from sklearn.base import BaseEstimator, TransformerMixin
class Transformer(BaseEstimator, TransformerMixin):
"""
A custom transformer class that implements the Scikit-Learn BaseEstimator
and TransformerMixin interfaces.
"""
def fit(self, data):
"""
Fit the transformer to the input data.
"""
return self
@abstractmethod
def transform(self, data):
"""
Transform the input data.
"""
return data
def inverse_transform(self, data):
"""
Reverse the transformation on the input data.
"""
return data
SelectivePipeline позволяет выбирать, какие трансформеры и в какой последовательности применять на разных этапах: обучение, валидация или предсказание. Это помогает избежать лишних вычислений и ускоряет процесс.
Хранилище моделей
Класс ModelRepository отвечает за хранение и управление моделями. Он позволяет сохранять обученные модели на диск или в S3-хранилище и загружать их при необходимости, что упрощает процесс развертывания.
from abc import ABC, abstractmethod
from typing import Optional, Dict
class ModelRepository(ABC):
"""Abstract base class for managing machine learning models in a repository."""
def __init__(self, config: Optional[Dict] = None):
self.config = config
@abstractmethod
def get_model(self, model_name: str) -> MLModel:
"""Retrieves a machine learning model by its name."""
pass
@abstractmethod
def put_model(self, model: MLModel):
"""Stores a machine learning model in the repository."""
pass
Генерация отчетов
После того как модель обучилась нам нужно оценить её качество, для этого после обучения модели автоматически генерируется отчет с её характеристиками такими как: метрики, описание датасета, используемая модель и её гиперпараметры и т.д. Кроме того, такой отчет является отличным артефактом для представления бизнес-заказчику. Также к нему можно всегда вернуться спустя время, и, даже если сотрудник, который обучал модель ушёл, будет легко разобраться, что за модель, на чем обучалась и какое у неё качество.

Модуль генерации отчетов построен на основе гибкой и расширяемой архитектуры, которая позволяет добавлять новые блоки отчетов и настраивать их в зависимости от задач.
Основные компоненты кода включают классы Report, ReportBlock, и различные конкретные блоки отчетов, такие как ConfusionMatrixBlock, FeatureImportancesBlock и другие.
Описание функциональности классов:
Класс Report: отвечает за создание и управление отчетами. Он принимает список блоков отчётов и применяет их к методам модели.
Метод call: позволяет использовать класс как декоратор для модели, добавляя функциональность отчетов к методам модели. Метод report генерирует документ отчёта, добавляя в него все блоки отчетов.
Класс ReportBlock: это абстрактный базовый класс для всех блоков отчетов. Он определяет общие методы и атрибуты, которые должны быть реализованы в дочерних классах. Каждый блок может добавлять свои данные в документ и сохранять артефакты, связанные с выполнением методов модели.
from abc import ABC, abstractmethod
from typing import Union, List, Optional
import pandas as pd
class ReportBlock(ABC):
"""Abstract base class for report blocks."""
TYPE: ReportBlockType = ReportBlockType.PRE_EXECUTE
def __init__(self, methods: Union[str, List[str]]) -> None:
self.methods = methods
@abstractmethod
def add_block(self, document):
"""Adds the block to the document."""
pass
@abstractmethod
def save_artifacts(self, stage: Optional[str] = None, data: Optional[pd.DataFrame] = None, model: MLModel = None):
"""Saves the artifacts."""
pass
Типы блоков отчетов: ReportBlockType определяет два типа блоков: PRE_EXECUTE (выполняется перед методом) и POST_EXECUTE (выполняется после метода).
class ReportBlockType(Enum):
"""
Enumeration for the types of report blocks.
- PRE_EXECUTE: Block to be executed before the decorated method.
- POST_EXECUTE: Block to be executed after the decorated method.
"""
PRE_EXECUTE = 0
POST_EXECUTE = 1
Конкретные блоки отчетов:
в коде также определены конкретные блоки отчетов, такие как: ConfusionMatrixBlock, FeatureImportancesBlock и другие, которые реализуют методы для добавления информации в отчет и сохранения артефактов.
Списки блоков: CLF_CRM_MODEL_BLOCKS и REG_CRM_MODEL_BLOCKS содержат наборы блоков, которые могут быть использованы для различных типов моделей (например, для моделей классификации и регрессии).
Как может выглядеть последовательность блоков для задачи бинарной классификации:
InitDocument: Создает пустой документ.
DataPropertiesBlock: отображает основные свойства данных.
MetricsBlock: собирает и отображает метрики модели.
ConfusionMatrixBlock: создаёт матрицу ошибок.
FeaturesImportancesBlock: визуализирует важность признаков.
HyperparametersBlock: отображает гиперпараметры модели.
TargetDistributionBlock: показывает распределение целевой переменной.
Как работает модуль генерации отчетов:
Создание модели: Создайте класс модели, который будет содержать методы, для которых вы хотите генерировать отчеты.
Применение декоратора: Используйте класс Report как декоратор для вашей модели, передавая ему необходимые блоки отчетов.
@Report(CLF_CRM_MODEL_BLOCKS)
class MyModel(MLMo):
def train(self, data):
# Логика обучения модели
pass
def validate(self, data):
# Логика валидации модели
pass
Генерация отчета:
После выполнения методов модели, можно вызвать метод report для генерации отчета.
model = MyModel()
model.train(data)
model.validate(data)
report_path = model.report(folder_to_save='reports')
Какие (на наш взгляд) у модуля получились сильные стороны:
Модульность: использование блоков отчетов позволяет легко добавлять, удалять или изменять части отчета без изменения основной логики модели.
Повторное использование: блоки отчетов могут быть переиспользованы в различных моделях, что упрощает процесс создания отчетов для разных проектов.
Чистота кода: декораторы позволяют отделить логику отчетов от основной логики модели, что делает код более чистым и понятным.
Гибкость: возможность добавления различных типов блоков (например, для различных метрик или визуализаций) позволяет адаптировать систему отчетов под конкретные нужды.
Автоматизация: система автоматически сохраняет артефакты и генерирует отчеты, что экономит время и усилия разработчиков.
Логирование
Использование LoggerManager позволяет отслеживать все этапы обучения и предсказания, что упрощает диагностику и отладку. Логи могут включать информацию о: производительности моделей, предупреждения о проблемах с данными и результаты валидации.

P.S. Созданием паспорта и просмотров логов обучения, конечно же, все не ограничивается – жизненный цикл модели в Ингосстрахе гораздо длиннее: надо смотреть популяции, мониторить качество работы на проде и еще много чего. Но эта тема уже для отдельной статьи. =)
В итоге, пайплайн на обучение и инференсе работают так:


Ключевые особенности разработанной архитектуры:
Параллельное обучение: возможность запускать несколько моделей одновременно значительно ускоряет процесс обучения и позволяет экспериментировать с различными архитектурами и гиперпараметрами, не жертвуя временем. Это достигается за счет грамотного распределения задач между доступными вычислительными ресурсами.
Интерактивная настройка: в отличие от статических систем, наша архитектура поддерживает динамическое изменение параметров моделей и трансформеров во время обучения. Это позволяет оперативно реагировать на изменения данных или результаты промежуточных этапов, корректируя процесс обучения «на лету». Такая интерактивность дает беспрецедентную гибкость, позволяя исследователям экспериментировать и тонко настраивать модели для достижения оптимальных результатов.
Поддержка различных алгоритмов: архитектура спроектирована с учетом необходимости работы с разнообразными алгоритмами машинного обучения. Она легко адаптируется к новым алгоритмам, требуя минимальных изменений в коде. Это достигается за счет модульной архитектуры, где каждый алгоритм представлен как отдельный, легко заменяемый компонент. Это значительно упрощает интеграцию новых подходов и технологий.
Наши планы на будущее:
Пространства для улучшения в нашем проекте очень много. Всегда можно добавить в каскад моделей, какой-нибудь новый алгоритм, добавлять хитрые способы препроцессинга данных и т.д., Например сейчас, мы активно осваиваем GPU-кластер и интегрируем пред обученную на табличных данных нейронную сеть.
Также имеется много задач, связанных с уже существующим кодом. Рефакторинг, оптимизация по памяти и времени и подобные аспекты регулярно появляются в списке текущих задач.
Итого мы получаем следующее:
Разработанная архитектура — это не статичный продукт, а постоянно развивающаяся система, которая позволяет эффективно управлять процессами обучения моделей машинного обучения, обеспечивая гибкость, расширяемость и автоматизацию. Ее ключевые преимущества — параллельное обучение, интерактивная настройка и поддержка различных алгоритмов — делают её универсальным решением для широкого спектра задач. Постоянное развитие и совершенствование архитектуры, включающее интеграцию GPU‑кластера, усовершенствование препроцессинга и оптимизацию кода, позволят ей оставаться на переднем крае технологий машинного обучения.