Creatio development guide
PDF
Это документация Creatio версии 7.16.0. Мы рекомендуем использовать новую версию документации.

Подключение пользовательского веб-сервиса к функциональности машинного обучения

Glossary Item Box

Общие сведения

Возможность подключения пользовательского веб-сервиса к функциональности машинного обучения доступна в Creatio версии 7.16.2 и выше.

Задачи машинного обучения (классификация, скоринг, числовая регрессия) или другие подобные задачи (например, прогнозирование оттока клиентов) можно реализовать с помощью веб-сервиса. Эта статья описывает процесс подключения к Creatio пользовательского веб-сервиса, реализующего задачу машинного обучения.

Основные принципы работы с сервисом машинного обучения описаны в статье "Сервис машинного обучения".

Общий порядок действий при подключении пользовательского веб-сервиса к сервису машинного обучения:

  1. Создайте веб-сервис — движок машинного обучения.
  2. Расширьте список задач сервиса машинного обучения.
  3. Реализуйте модель машинного обучения.

Создание веб-сервиса — движка машинного обучения

Пользовательский веб-сервис должен реализовать контракт для обучения и выполнения прогнозов по существующей модели. Пример контракта можно посмотреть через 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. Расширьте список задач машинного обучения

Для расширения списка задач машинного обучения выполните следующие действия:

  1. Перейдите в дизайнер системы по кнопке . В блоке [Настройка системы] ([System setup]) перейдите по ссылке [Справочники] ([Lookups]).
  2. Выберите справочник [Задачи машинного обучения] ([ML problem types]).
  3. Создайте новую запись.

Для записи установите (рис. 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);
        }

    }

}

После внесения изменений сохраните и опубликуйте схему.

© Terrasoft 2002-2020.

Был ли данный материал полезен?

Как можно улучшить эту статью?