Update mlcmp doc
This commit is contained in:
parent
5ee5bad12c
commit
479115678c
1 changed files with 197 additions and 5 deletions
202
pages/mlcmp.md
202
pages/mlcmp.md
|
@ -1,5 +1,13 @@
|
||||||
# MLComponent
|
# MLComponent
|
||||||
|
|
||||||
|
- [Функция inference](#функция-inference)
|
||||||
|
- [Docstring](#docstring)
|
||||||
|
- [Логика функции inference](#логика-функции-inference)
|
||||||
|
- [Передача модели](#передача-модели)
|
||||||
|
- [Пример функции](#пример-функции)
|
||||||
|
- [Манифесты](#манифесты)
|
||||||
|
|
||||||
|
|
||||||
Компонент MLComponent позволяет создать сервис для синхронной обработки запросов пользователей.
|
Компонент MLComponent позволяет создать сервис для синхронной обработки запросов пользователей.
|
||||||
|
|
||||||
MLComponent подходит для быстрых вычислений, в частности запуска предобученной модели машинного обучения на небольшой выборке данных. Например, распознавание объекта на одном изображении, классификация таблицы текстовых данных. Если алгоритм работает за доли секунды, то он подходит как основа для MLComponent.
|
MLComponent подходит для быстрых вычислений, в частности запуска предобученной модели машинного обучения на небольшой выборке данных. Например, распознавание объекта на одном изображении, классификация таблицы текстовых данных. Если алгоритм работает за доли секунды, то он подходит как основа для MLComponent.
|
||||||
|
@ -32,13 +40,13 @@ def inference(parameters: List[Dict[str, Any]],
|
||||||
* `parameters` - список пар `[name, value]`, произвольных параметров примитивных типов.
|
* `parameters` - список пар `[name, value]`, произвольных параметров примитивных типов.
|
||||||
* `inputs` - список входных данных, где каждый элемент - это словарь. Ключи словаря:
|
* `inputs` - список входных данных, где каждый элемент - это словарь. Ключи словаря:
|
||||||
* `name` - название, произвольная строка, используется в коде модуля. Например, `"image"`.
|
* `name` - название, произвольная строка, используется в коде модуля. Например, `"image"`.
|
||||||
* `datatype` - тип входных данных, одна из строк `"FP32", "FP64", "INT32", "FILE", "str"`.
|
* `datatype` - тип входных данных, одна из строк `"FP32", "FP64", "INT32", "FILE", "str", "dict"`.
|
||||||
* `content_type` - тип содержимого файла, если тип входной переменной `datatype` - это `"FILE"`.
|
* `content_type` - тип содержимого файла, если тип входной переменной `datatype` - это `"FILE"`.
|
||||||
* `data` - строка с путём к входному файлу или одномерный список входных данных соответствующего типа.
|
* `data` - строка с путём к входному файлу или одномерный список входных данных соответствующего типа.
|
||||||
* `shape` - размерность входной переменной как массива, применимо даже к файлам (не размер файла в файловой системе).
|
* `shape` - размерность входной переменной как массива, применимо даже к файлам (не размер файла в файловой системе).
|
||||||
* `output_fields` - список выходных данных, где каждый элемент - это словарь. Ключи словаря:
|
* `output_fields` - список выходных данных, где каждый элемент - это словарь. Ключи словаря:
|
||||||
* `name` - название, произвольная строка, используется в коде модуля. Например, `"prediction"`.
|
* `name` - название, произвольная строка, используется в коде модуля. Например, `"prediction"`.
|
||||||
* `datatype` - тип выходных данных, одна из строк `"FP32", "FP64", "INT32", "FILE", "str"`.
|
* `datatype` - тип выходных данных, одна из строк `"FP32", "FP64", "INT32", "FILE", "str", "dict"`.
|
||||||
* `content_type` - тип содержимого файла, если тип выходной переменной `datatype` - это `"FILE"`.
|
* `content_type` - тип содержимого файла, если тип выходной переменной `datatype` - это `"FILE"`.
|
||||||
* `data` - строка с путём к выходному файлу или одномерный список выходных данных соответствующего типа.
|
* `data` - строка с путём к выходному файлу или одномерный список выходных данных соответствующего типа.
|
||||||
* `shape` - размерность выходной переменной как массива, применимо даже к файлам (не размер файла в файловой системе).
|
* `shape` - размерность выходной переменной как массива, применимо даже к файлам (не размер файла в файловой системе).
|
||||||
|
@ -49,23 +57,207 @@ def inference(parameters: List[Dict[str, Any]],
|
||||||
|
|
||||||
* список выходных данных, где каждый элемент - это словарь. Ключи словаря:
|
* список выходных данных, где каждый элемент - это словарь. Ключи словаря:
|
||||||
* `name` - название, произвольная строка, используется в коде модуля. Например, `"prediction"`.
|
* `name` - название, произвольная строка, используется в коде модуля. Например, `"prediction"`.
|
||||||
* `datatype` - тип выходных данных, одна из строк `"FP32", "FP64", "INT32", "FILE", "str"`.
|
* `datatype` - тип выходных данных, одна из строк `"FP32", "FP64", "INT32", "FILE", "str", "dict"`.
|
||||||
* `content_type` - тип содержимого файла, если тип выходной переменной `datatype` - это `"FILE"`.
|
* `content_type` - тип содержимого файла, если тип выходной переменной `datatype` - это `"FILE"`.
|
||||||
* `data` - строка с путём к выходному файлу или одномерный список выходных данных соответствующего типа.
|
* `data` - строка с путём к выходному файлу или одномерный список выходных данных соответствующего типа.
|
||||||
* `shape` - размерность выходной переменной как массива, применимо даже к файлам (не размер файла в файловой системе).
|
* `shape` - размерность выходной переменной как массива, применимо даже к файлам (не размер файла в файловой системе).
|
||||||
* объект модели, который можно передать в следующий вызов функции как аргумент `model`.
|
* объект модели, который можно передать в следующий вызов функции как аргумент `model`.
|
||||||
|
|
||||||
Формат самих входных данных, которые передаются в аргументе `inputs` при вызове функции, должен быть указан в docstring-спецификации.
|
|
||||||
|
|
||||||
|
### Docstring
|
||||||
|
|
||||||
```
|
Формат самих входных данных, которые передаются в аргументе `inputs` при вызове функции, и выходных данных, возвращаемых функцией, должен быть указан в docstring-спецификации.
|
||||||
|
|
||||||
|
Для каждой переменной нужно указать следующее:
|
||||||
|
|
||||||
|
1. Информация о переменной в формате `:param inputs.NAME: DESCRIPTION`
|
||||||
|
2. Информация о типе данных в формате `:type inputs.NAME: TYPE1 or TYPE2 or TYPE3[, optional]`
|
||||||
|
|
||||||
|
Здесь,
|
||||||
|
|
||||||
|
- `inputs` - тип переменной. Для входных это `inputs`, для выходных - `outputs`.
|
||||||
|
- `NAME` - имя переменной. Должно в точности соответствовать имени, которое передаётся через API.
|
||||||
|
- `DESCRIPTION` - описание переменной. Может содержать несколько строк текста. Используется в OpenAPI спецификации и каталоге.
|
||||||
|
- `TYPE1`, `TYPE2`, `TYPE3` - типы данных и типы содержимых, которые могут быть присвоены переменной.
|
||||||
|
- Возможные типы данных: `FP32, FP64, INT32, FILE, str, dict`.
|
||||||
|
- Типы содержимого (content_type) указываются так же, как типы данных - `FP32 or text/csv`.
|
||||||
|
- Если указано хотя бы один `content_type`, то тип `FILE` добавляется автоматически, даже если не указан - `:type inputs.mydata: text/csv`.
|
||||||
|
- Если не указан `content_type`, предполагается, что поддерживается любой.
|
||||||
|
- Если про тип переменной не указано ничего, предполагается, что поддерживается любой тип и любое содержимое.
|
||||||
|
- `[, optional]` в конце типа переменной может быть указано `, optional` (без квадратных скобок), что означает, что переменная опциональная, вызов функции должен работать и без неё.
|
||||||
|
|
||||||
|
Пример простой спецификации:
|
||||||
|
|
||||||
|
```python
|
||||||
def inference(parameters: List[Dict[str, Any]],
|
def inference(parameters: List[Dict[str, Any]],
|
||||||
inputs: List[Dict[str, Any]],
|
inputs: List[Dict[str, Any]],
|
||||||
output_fields: List[Dict[str, Any]],
|
output_fields: List[Dict[str, Any]],
|
||||||
model_key: str,
|
model_key: str,
|
||||||
model: Any = None) -> Tuple[List[Dict[str, Any]], Any]:
|
model: Any = None) -> Tuple[List[Dict[str, Any]], Any]:
|
||||||
|
"""
|
||||||
|
:param inputs.image: Изображение, на котором производится обнаружение объекта;
|
||||||
|
:type inputs.image: FILE or image/png or image/bmp or image/jpeg
|
||||||
|
|
||||||
|
:param outputs.detection: Словарь с результатом обнаружения.
|
||||||
|
Ключ "labels" содержит список меток
|
||||||
|
Ключ "scores" содержит список оценок 'уверенности' модели
|
||||||
|
Ключ "bboxes" содержит список кортежей [x1 y1 x2 y2] с координатами обнаруженного объекта
|
||||||
|
:type outputs.detection: dict
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Пример, иллюстрирующий синтаксис спецификации.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def example_inference_func(parameters: list,
|
||||||
|
inputs: list,
|
||||||
|
output_fields: set,
|
||||||
|
model_key: str,
|
||||||
|
model: Any = None) -> (list, Any):
|
||||||
|
"""
|
||||||
|
:param inputs.p: Параметр прогнозирования;
|
||||||
|
Если вход опциональный, то строка типа завершается ', optional',
|
||||||
|
это соответствует синтаксису sphinx rst
|
||||||
|
:type inputs.p: FP32, optional
|
||||||
|
|
||||||
|
:param inputs.X: Матрица экземпляров для классификации;
|
||||||
|
Если типов несколько, они перечисляются через 'or',
|
||||||
|
это соответствует синтаксису sphinx rst
|
||||||
|
:type inputs.X: FP64 or FP32 or FILE or text/csv
|
||||||
|
|
||||||
|
:param inputs.abc: Входной параметр;
|
||||||
|
Тип может быть не указан, тогда считается,
|
||||||
|
что поддерживаются все допустимые datatype и любые content-type
|
||||||
|
:type inputs.abc:
|
||||||
|
|
||||||
|
:param outputs.predict: Результат прогнозирования
|
||||||
|
:type outputs.predict: INT32 or 'FILE' or text/csv or application/json or BED
|
||||||
|
|
||||||
|
:param outputs.scores: Скоры прогнозирования;
|
||||||
|
Для этого выхода datatype 'FILE' будет добавлен, потому что указан content-type 'text/csv'
|
||||||
|
:type outputs.scores: FP32 or FP64 or text/csv
|
||||||
|
|
||||||
|
:param outputs.obj: Только объектный выход;
|
||||||
|
Для этого выхода тип только объектный
|
||||||
|
:type outputs.obj: INT32 or str, optional
|
||||||
|
|
||||||
|
:param model_parameters.mode: Режим модели;
|
||||||
|
Допустимые типы параметров модели - примитивные типы OpenAPI Spec
|
||||||
|
:type model_parameters.mode: number or integer or float
|
||||||
|
|
||||||
|
:param model_parameters.param1: Параметр работы модели
|
||||||
|
:type model_parameters.param1: string, optional
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример совмещения обычного docstring и спецификации выше для API.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def example_inference_func(parameters: list,
|
||||||
|
inputs: list,
|
||||||
|
output_fields: set,
|
||||||
|
model_key: str,
|
||||||
|
model: Any = None) -> (list, Any):
|
||||||
|
"""
|
||||||
|
Обычное описание функции, которое не будет частью спецификации.
|
||||||
|
|
||||||
|
Более подробное описание.
|
||||||
|
Подробное описание может продолжаться на несколько строк.
|
||||||
|
Подробное описание не может содержать docstring в форматах ReST, Google, Numpydoc-style и Epydoc,
|
||||||
|
так как это может конфликтовать со спецификацией для API.
|
||||||
|
|
||||||
|
:param inputs.X: Матрица экземпляров для классификации;
|
||||||
|
:type inputs.X: FP64 or FP32 or FILE or text/csv
|
||||||
|
|
||||||
|
:param outputs.predict: Результат прогнозирования
|
||||||
|
:type outputs.predict: INT32 or 'FILE' or text/csv or application/json
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Логика функции inference
|
||||||
|
|
||||||
|
|
||||||
|
Существует набор рекомендаций и особенностей реализации функции inference. Технически функция может быть реализована любым способом, который соответствует интерфейсу, но при возможности желательно следовать рекомендациям ниже.
|
||||||
|
|
||||||
|
#### Передача модели
|
||||||
|
|
||||||
|
За передачу модели в функцию отвечают два параметра: `model_key` и `model`.
|
||||||
|
|
||||||
|
- `model_key` - строка-ключ, позволяющая загрузить модель с диска или хранилища файлов. Обычно, это путь. Например, `/home/project/data/model_weights.pth` для загрузки файла или `/home/project/google-bert/bert-base-uncased` для загрузки модели из папки.
|
||||||
|
- `model` - уже загруженный объект модели. Этот же объект возвращается функцией в кортеже `outputs, model`.
|
||||||
|
|
||||||
|
Так как ML-компонент предназначен для быстрых вычислений, предполагается, что время выполнения одного запроса гораздо меньше времени загрузки модели или запуска контейнера. Поэтому один и тот же контейнер и один и тот же объект модели используется для множества запросов.
|
||||||
|
|
||||||
|
Если модель `model` не передана в функцию inference (например, это первый запрос к новому модулю), веса ИИ-модели загружаются с использованием ключа `model_key`. Эти загруженные веса возвращаются в конце работы функции и передаются в аргумент `model` при каждом следующем вызове.
|
||||||
|
|
||||||
|
Тип объекта `model` может быть любым, то есть это может быть и набор моделей, если это соответствует логике вычислений.
|
||||||
|
|
||||||
|
#### Пример функции
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
def inference(
|
||||||
|
parameters: list,
|
||||||
|
inputs: list,
|
||||||
|
output_fields: list,
|
||||||
|
model_key: str,
|
||||||
|
model: Any = None,
|
||||||
|
) -> (list, Any):
|
||||||
|
|
||||||
|
"""
|
||||||
|
:param inputs.X: Матрица экземпляров для классификации;
|
||||||
|
:type inputs.X: FP64 or FP32 or FILE or text/csv
|
||||||
|
|
||||||
|
:param outputs.predict: Результат прогнозирования;
|
||||||
|
:type outputs.predict: INT32 or 'FILE' or text/csv
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
outputs = []
|
||||||
|
if not model:
|
||||||
|
model = joblib.load(model_key)
|
||||||
|
|
||||||
|
|
||||||
|
for entry in inputs:
|
||||||
|
if entry["datatype"] == "FILE":
|
||||||
|
if entry["content_type"] == "text/csv":
|
||||||
|
input_table = load_csv(entry["data"])
|
||||||
|
else:
|
||||||
|
raise AttributeError(f'Not supported file type {entry["content_type"]}')
|
||||||
|
elif entry["datatype"] == "FP32":
|
||||||
|
input_table = load_array_fp32(entry["data"], entry["shape"])
|
||||||
|
else:
|
||||||
|
raise AttributeError(f'Not supported data type {entry["datatype"]}')
|
||||||
|
|
||||||
|
for output in output_fields:
|
||||||
|
if output["name"] == "predict":
|
||||||
|
y_pred = model.predict(input_table)
|
||||||
|
output_shape = y_pred.shape
|
||||||
|
if output["datatype"] == "FILE":
|
||||||
|
path = output["data"]
|
||||||
|
y_pred.tofile(path, sep=",")
|
||||||
|
output_data = path
|
||||||
|
elif output["datatype"] == "INT32":
|
||||||
|
output_data = y_pred.astype(int).flatten().tolist()
|
||||||
|
else:
|
||||||
|
raise AttributeError(f'Not supported datatype {output["datatype"]}')
|
||||||
|
|
||||||
|
output_data, output_shape = predict(output, model, model_inputs)
|
||||||
|
outputs.append(
|
||||||
|
dict(
|
||||||
|
name=output["name"],
|
||||||
|
datatype=output["datatype"],
|
||||||
|
shape=output_shape,
|
||||||
|
data=output_data,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return outputs, model
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Манифесты
|
## Манифесты
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue