Подключение пользовательского веб-сервиса к функциональности машинного обучения
Glossary Item Box
Общие сведения
Возможность подключения пользовательского веб-сервиса к функциональности машинного обучения доступна в Creatio версии 7.16.2 и выше.
Задачи машинного обучения (классификация, скоринг, числовая регрессия) или другие подобные задачи (например, прогнозирование оттока клиентов) можно реализовать с помощью веб-сервиса. Эта статья описывает процесс подключения к Creatio пользовательского веб-сервиса, реализующего задачу машинного обучения.
Основные принципы работы с сервисом машинного обучения описаны в статье "Сервис машинного обучения".
Общий порядок действий при подключении пользовательского веб-сервиса к сервису машинного обучения:
- Создайте веб-сервис — движок машинного обучения.
- Расширьте список задач сервиса машинного обучения.
- Реализуйте модель машинного обучения.
Создание веб-сервиса — движка машинного обучения
Пользовательский веб-сервис должен реализовать контракт для обучения и выполнения прогнозов по существующей модели. Пример контракта можно посмотреть через Swagger сервиса машинного обучения Creatio по адресу:
https://demo-ml.bpmonline.com/swagger/index.html#/MLService
Обязательные методы:
- /session/start — начало сессии обучения модели.
- /data/upload — передача данных в рамках открытой сессии обучения.
- /session/info/get — получение информации о состоянии сессии.
- <пользовательский метод начала обучения> — метод, который будет вызван Creatio по завершении процесса передачи данных. Процесс обучения модели не должен быть завершен до завершения выполнения этого метода. Процесс обучения может длиться произвольное количество времени (десятки минут и даже часы). Когда обучение завершено, метод /session/info/get должен будет вернуть состояние сессии обучения Done или Error в зависимости от результата обучения. Кроме этого, если модель успешно обучена, то необходимо вернуть информацию об экземпляре модели — ModelSummary: тип метрики, значение метрики, идентификатор экземпляра и другие.
- <пользовательский метод прогнозирования> — метод произвольной сигнатуры, который будет выполнять прогнозирование данных на основании идентификатора экземпляра обученной модели.
Процесс разработки веб-сервиса с использованием IDE Microsoft Visual Studio описан в статье "Разработка конфигурационного серверного кода в пользовательском проекте".
Расширение списка задач сервиса машинного обучения
Для расширения списка задач машинного обучения в Creatio необходимо дополнить справочник MLProblemType новой записью. Необходимо указать следующие параметры:
- Service endpoint Url — адрес работающего сервиса машинного обучения.
- Training endpoint — путь метода начала обучения.
- Prediction endpoint — путь метода прогнозирования.
Для дальнейшей работы необходимо знать идентификатор созданной записи. Посмотреть Id можно в таблице [dbo.MLProblemType] базы данных.
Реализация модели машинного обучения
Для настройки и отображения модели машинного обучения, возможно, потребуется расширить схему карточки MLModelPage.
Реализация IMLPredictor
Необходимо реализовать метод Predict, который на вход получит данные, выгруженные из системы по объекту (в виде Dictionary<string, object>, где key — название поля, а value — его значение), а на выход вернет результат прогноза. Метод может использовать прокси-класс, реализующий интерфейс IMLServiceProxy, который упростит вызов веб-сервиса.
Реализация IMLEntityPredictor
Необходимо инициализировать свойство ProblemTypeId идентификатором созданной записи в справочнике MLProblemType. Также необходимо реализовать следующие методы:
- SaveEntityPredictedValues — метод получает результат прогнозирования и должен сохранить его для объекта (entity) системы, для которого выполнялось прогнозирование. Если возвращаемое значение типа double или подобно результату классификации, можно воспользоваться методами вспомогательного класса PredictionSaver.
- SavePrediction (опционально) — метод сохраняет результат прогнозирования в привязке к экземпляру обученной модели и идентификатору объекта (entityId). Для базовых задач в системе существуют объекты MLPrediction и MLClassificationResult.
Расширение IMLServiceProxy и MLServiceProxy (опционально)
Можно расширить существующий интерфейс IMLServiceProxy и его реализацию методом прогнозирования для текущей задачи. В частности, класс MLServiceProxy содержит обобщенный метод Predict, который принимает контракты для входящих данных и результата прогнозирования.
Реализация IMLBatchPredictor
В слечае, если сервис вызывается с набором данных (500 шт.), следует реализовать интерфейс IMLBatchPredictor. Необходимо реализовать следующие методы:
- FormatValueForSaving — метод возвращает значение, преобразованное для сохранения результата прогноза в базе данных. В случае пакетного прогнозирования для ускорения операции сохранения запись обновляется в базе данных методом Update, а не через экземпляры Entity.
- SavePredictionResult — определяет, как будет сохраняться результат прогнозирования в системе для каждой записи. Для базовых задач в системе существуют объекты MLPrediction и MLClassificationResult.
Описание примера
Подключить к Creatio пользовательский аналог предиктивного скоринга.
Исходный код
Пакет с реализацией примера можно скачать по ссылке.
Алгоритм реализации примера
1. Создайте веб-сервис — движок машинного обучения
Пример реализации веб-сервиса машинного обучения для ASP.Net Core 3.1 можно скачать по ссылке.
Реализуйте веб-сервис машинного-обучения MLService.
Задайте обязательные методы:
- /session/start
- /data/upload
- /session/info/get
- /fakeScorer/beginTraining
- /fakeScorer/predict
Полностью исходный код представлен ниже.
namespace FakeScoring.Controllers { using System; using System.Collections.Generic; using System.Linq; using System.Net; using Microsoft.AspNetCore.Mvc; using Terrasoft.ML.Interfaces; using Terrasoft.ML.Interfaces.Requests; using Terrasoft.ML.Interfaces.Responses; [ApiController] [Route("")] public class MLService : Controller { public const string FakeModelInstanceUId = "{BFC0BD71-19B1-47B1-8BC4-D761D9172667}"; private List<ScoringOutput.FeatureContribution> GenerateFakeContributions(DatasetValue record) { var random = new Random(42); return record.Select(columnValue => new ScoringOutput.FeatureContribution { Name = columnValue.Key, Contribution = random.NextDouble(), Value = columnValue.Value.ToString() }).ToList(); } [HttpGet("ping")] public JsonResult Ping() { return new JsonResult("Ok"); } /// <summary> /// Handshake request to service with the purpose to start a model training session. /// </summary> /// <param name="request">Instance of <see cref="StartSessionRequest"/>.</param> /// <returns>Instance of <see cref="StartSessionResponse"/>.</returns> [HttpPost("session/start")] public StartSessionResponse StartSession(StartSessionRequest request) { return new StartSessionResponse { SessionId = Guid.NewGuid() }; } /// <summary> /// Uploads training data. /// </summary> /// <param name="request">The upload data request.</param> /// <returns>Instance of <see cref="JsonResult"/>.</returns> [HttpPost("data/upload")] public JsonResult UploadData(UploadDataRequest request) { return new JsonResult(string.Empty) { StatusCode = (int)HttpStatusCode.OK }; } /// <summary> /// Begins fake scorer training on uploaded data. /// </summary> /// <param name="request">The scorer training request.</param> /// <returns>Simple <see cref="JsonResult"/>.</returns> [HttpPost("fakeScorer/beginTraining")] public JsonResult BeginScorerTraining(BeginScorerTrainingRequest request) { // Start training work here. It doesn't have to be done by the end of this request. return new JsonResult(string.Empty) { StatusCode = (int)HttpStatusCode.OK }; } /// <summary> /// Returns current session state and model statistics, if training is complete. /// </summary> /// <param name="request">Instance of <see cref="GetSessionInfoRequest"/>.</param> /// <returns>Instance of <see cref="GetSessionInfoResponse"/> with detailed state info.</returns> [HttpPost("session/info/get")] public GetSessionInfoResponse GetSessionInfo(GetSessionInfoRequest request) { var response = new GetSessionInfoResponse { SessionState = TrainSessionState.Done, ModelSummary = new ModelSummary { DataSetSize = 100500, Metric = 0.79, MetricType = "Accuracy", TrainingTimeMinutes = 5, ModelInstanceUId = new Guid(FakeModelInstanceUId) } }; return response; } /// <summary> /// Performs fake scoring prediction. /// </summary> /// <param name="request">Request object.</param> /// <returns>Scoring rates.</returns> [HttpPost("fakeScorer/predict")] public ScoringResponse Predict(ExplainedScoringRequest request) { List<ScoringOutput> outputs = new List<ScoringOutput>(); var random = new Random(42); foreach (var record in request.PredictionParams.Data) { var output = new ScoringOutput { Score = random.NextDouble() }; if (request.PredictionParams.PredictContributions) { output.Bias = 0.03; output.Contributions = GenerateFakeContributions(record); } outputs.Add(output); } return new ScoringResponse { Outputs = outputs }; } } }
2. Расширьте список задач машинного обучения
Для расширения списка задач машинного обучения выполните следующие действия:
- Перейдите в дизайнер системы по кнопке . В блоке [Настройка системы] ([System setup]) перейдите по ссылке [Справочники] ([Lookups]).
- Выберите справочник [Задачи машинного обучения] ([ML problem types]).
- Создайте новую запись.
Для записи установите (рис. 1):
- [Название] ([Name]) — "Fake scoring";
- [Url сервиса] ([Service endpoint Url]) — "http://localhost:5000/";
- [Метод сервиса для обучения модели] ([Training endpoint]) — "/fakeScorer/beginTraining".
Рис. 1. — Настройка параметров задачи машинного обучения
Идентификатор созданной записи — 319c39fd-17a6-453a-bceb-57a398d52636.
3. Реализуйте модель машинного обучения
В разделе [Конфигурация] ([Configuration]) пользовательского пакета на вкладке [Схемы] ([Schemas]) выполните действие [Добавить] —> [Схема модели представления карточки] ([Add] —> [Schema of Edit Page View Model]). Созданный модуль должен наследовать функциональность базовой страницы модели машинного обучения MLModelPage, которая определена в пакете ML. Для этого укажите эту схему в качестве родительской для создаваемой схемы.
Для создаваемой схемы объекта установите (рис. 2):
- [Заголовок] ([Title]) — "FakeScoringMLModelPage";
- [Название] ([Name]) — "UsrMLModelPage".
- [Родительский объект] ([Parent object]) — выберите MLModelPage.
Рис. 2. — Настройка схемы модели представления карточки
Переопределите базовый метод getIsScoring, чтобы вид создаваемой карточки соответствовал карточке базового предиктивного скоринга. Полностью исходный код представлен ниже.
define("MLModelPage", [], function() { return { entitySchemaName: "MLModel", properties: { FakeScoringProblemTypeId: "319c39fd-17a6-453a-bceb-57a398d52636" }, methods: { getIsScoring: function() { const parentResult = this.callParent(arguments); return parentResult || this.getLookupValue("MLProblemType") === this.FakeScoringProblemTypeId; } } } });
После внесения изменений сохраните и опубликуйте схему.
В разделе [Конфигурация] ([Configuration]) пользовательского пакета на вкладке [Схемы] ([Schemas]) выполните действие [Добавить] —> [Исходный код] ([Add] —> [Source Code]). Процесс создания схемы типа [Исходный код] ([Source Code]) описан в статье "Создание схемы [Исходный код]".
Для создаваемой схемы объекта установите (рис. 3):
- [Заголовок] ([Title]) — "FakeScoringEntityPredictor";
- [Название] ([Name]) — "UsrFakeScoringEntityPredictor".
Рис. 3. — Настройка схемы объекта типа [Исходный код] ([Source Code])
Реализуйте метод Predict, который получает данные, выгруженные из системы по объекту, и возвращает результат прогноза. Метод использует прокси-класс, реализующий интерфейс IMLServiceProxy, который упрощает вызов веб-сервиса.
Инициализируйте свойство ProblemTypeId идентификатором созданной записи в справочнике MLProblemType и реализуйте методы SaveEntityPredictedValues и SavePrediction. Полностью исходный код представлен ниже.
namespace Terrasoft.Configuration.ML { using System; using System.Collections.Generic; using Core; using Core.Factories; using Terrasoft.ML.Interfaces; [DefaultBinding(typeof(IMLEntityPredictor), Name = "319C39FD-17A6-453A-BCEB-57A398D52636")] [DefaultBinding(typeof(IMLPredictor<ScoringOutput>), Name = "319C39FD-17A6-453A-BCEB-57A398D52636")] public class FakeScoringEntityPredictor: MLBaseEntityPredictor<ScoringOutput>, IMLEntityPredictor, IMLPredictor<ScoringOutput> { public FakeScoringEntityPredictor(UserConnection userConnection) : base(userConnection) { } protected override Guid ProblemTypeId => new Guid("319C39FD-17A6-453A-BCEB-57A398D52636"); protected override ScoringOutput Predict(IMLServiceProxy proxy, MLModelConfig model, Dictionary<string, object> data) { return proxy.FakeScore(model, data, true); } protected override List<ScoringOutput> Predict(MLModelConfig model, IList<Dictionary<string, object>> dataList, IMLServiceProxy proxy) { return proxy.FakeScore(model, dataList, true); } protected override void SaveEntityPredictedValues(MLModelConfig model, Guid entityId, ScoringOutput predictedResult) { var predictedValues = new Dictionary<MLModelConfig, double> { { model, predictedResult.Score } }; PredictionSaver.SaveEntityScoredValues(model.EntitySchemaId, entityId, predictedValues); } protected override void SavePrediction(MLModelConfig model, Guid entityId, ScoringOutput predictedResult) { PredictionSaver.SavePrediction(model.Id, model.ModelInstanceUId, entityId, predictedResult.Score); } } }
После внесения изменений сохраните и опубликуйте схему.
В разделе [Конфигурация] ([Configuration]) пользовательского пакета на вкладке [Схемы] ([Schemas]) выполните действие [Добавить] —> [Исходный код] ([Add] —> [Source Code]). Процесс создания схемы типа [Исходный код] ([Source Code]) описан в статье "Создание схемы [Исходный код]".
Для создаваемой схемы объекта установите (рис. 4):
- [Заголовок] ([Title]) — "FakeScoringProxy";
- [Название] ([Name]) — "UsrFakeScoringProxy".
Рис. 4. — Настройка схемы объекта типа [Исходный код] ([Source Code])
Расширьте существующий интерфейс IMLServiceProxy и его реализацию методом прогнозирования для текущей задачи. В частности класс MLServiceProxy содержит обобщенный метод Predict, который принимает контракты для входящих данных и результата прогнозирования.
Полностью исходный код представлен ниже.
namespace Terrasoft.Configuration.ML { using System; using System.Collections.Generic; using System.Linq; using Terrasoft.ML.Interfaces; using Terrasoft.ML.Interfaces.Requests; using Terrasoft.ML.Interfaces.Responses; public partial interface IMLServiceProxy { ScoringOutput FakeScore(MLModelConfig model, Dictionary<string, object> data, bool predictContributions); List<ScoringOutput> FakeScore(MLModelConfig model, IList<Dictionary<string, object>> dataList, bool predictContributions); } public partial class MLServiceProxy : IMLServiceProxy { public ScoringOutput FakeScore(MLModelConfig model, Dictionary<string, object> data, bool predictContributions) { ScoringResponse response = Predict<ExplainedScoringRequest, ScoringResponse>(model.ModelInstanceUId, new List<Dictionary<string, object>> { data }, model.PredictionEndpoint, 100, predictContributions); return response.Outputs.FirstOrDefault(); } public List<ScoringOutput> FakeScore(MLModelConfig model, IList<Dictionary<string, object>> dataList, bool predictContributions) { int count = Math.Min(1, dataList.Count); int timeout = Math.Max(ScoreTimeoutSec * count, BatchScoreTimeoutSec); ScoringResponse response = Predict<ScoringRequest, ScoringResponse>(model.ModelInstanceUId, dataList, model.PredictionEndpoint, timeout, predictContributions); return response.Outputs; } } }
После внесения изменений сохраните и опубликуйте схему.
В разделе [Конфигурация] ([Configuration]) пользовательского пакета на вкладке [Схемы] ([Schemas]) выполните действие [Добавить] —> [Исходный код] ([Add] —> [Source Code]). Процесс создания схемы типа [Исходный код] ([Source Code]) описан в статье "Создание схемы [Исходный код]".
Для создаваемой схемы объекта установите (рис. 5):
- [Заголовок] ([Title]) — "FakeBatchScorer";
- [Название] ([Name]) — "UsrFakeBatchScorer".
Рис. 5. — Настройка схемы объекта типа [Исходный код] ([Source Code])
Для использования функциональности пакетного прогнозирования реализуйте интерфейс IMLBatchPredictor, методы FormatValueForSaving и SavePredictionResult.
Полностью исходный код представлен ниже.
namespace Terrasoft.Configuration.ML { using System; using Core; using Terrasoft.Core.Factories; using Terrasoft.ML.Interfaces; [DefaultBinding(typeof(IMLBatchPredictor), Name = "319C39FD-17A6-453A-BCEB-57A398D52636")] public class FakeBatchScorer : MLBatchPredictor<ScoringOutput> { public FakeBatchScorer(UserConnection userConnection) : base(userConnection) { } protected override object FormatValueForSaving(ScoringOutput scoringOutput) { return Convert.ToInt32(scoringOutput.Score * 100); } protected override void SavePredictionResult(Guid modelId, Guid modelInstanceUId, Guid entityId, ScoringOutput value) { PredictionSaver.SavePrediction(modelId, modelInstanceUId, entityId, value); } } }
После внесения изменений сохраните и опубликуйте схему.