Skip to content

構造化カスタムモデルの構築

DataRobotは、従来のターゲットタイプを使用するモデルを作成するために、さまざまなライブラリのビルトインサポートを提供します。 モデルがこれらのライブラリのいずれかに基づいている場合、DataRobotでは、モデルアーティファクトに一致するファイル拡張子があることが期待されます。

ライブラリ ファイル拡張子
Scikit-learn *.pkl sklean-regressor.pkl
Xgboost *.pkl xgboost-regressor.pkl
PyTorch *.pth torch-regressor.pth
tf.keras (tensorflow>=2.2.1) *.h5 keras-regressor.h5
ONNX *.onnx onnx-regressor.onnx
pmml *.pmml pmml-regressor.pmml
ライブラリ ファイル拡張子
Caret *.rds brnn-regressor.rds
ライブラリ ファイル拡張子
datarobot-prediction *.jar dr-regressor.jar
h2o-genmodel *.java GBM_model_python_1589382591366_1.java (pojo)
h2o-genmodel *.zip GBM_model_python_1589382591366_1.zip (mojo)
h2o-genmodel-ext-xgboost *.java XGBoost_2_AutoML_20,201,015_144158.java
h2o-genmodel-ext-xgboost *.zip XGBoost_2_AutoML_20,201,015_144158.zip
h2o-ext-mojo-pipeline *.mojo ...

備考

  • DRUMは、DataRobotで生成された「スコアリングコード」を含むモデルと、DataRobot-predictionライブラリIClassificationPredictorまたはIRegressionPredictorインターフェイスのいずれかを実装するモデルをサポートします。 モデルアーティファクトには、.jar拡張子が必要です。

  • DRUM_JAVA_XMX環境変数を定義し、JVMの最大ヒープメモリーサイズ(-Xmxjavaパラメーター):DRUM_JAVA_XMX=512mを設定できます。

  • H2OモデルをPOJOとしてエクスポートした場合、ファイル名は変更できません。ただし、MOJOとしてエクスポートされたモデルには、この制限は適用されません。任意の方法で名前を付けることができます。

  • h2o-ext-mojo-pipelineにはh2o driverless AIライセンスが必要です。

  • DAI Mojoパイプラインのサポートは、datarobot-drumの構築のテストには組み込まれていません。

モデルで以下のライブラリのいずれかが使用されていない場合は、 非構造化カスタムモデルを作成する必要があります。

以下の2つのタイプのカスタムモデルの特性と機能を比較します。

モデルタイプ 特性 機能
構造化
  • DataRobotに既知のターゲットタイプ(連続値、二値分類、多クラス、異常検知など)を使用します。
  • リクエスト/レスポンススキーマに準拠する必要があります。
  • 構造化入力および出力データを受け入れます。
  • 完全なデプロイ機能
  • デプロイ後に、トレーニングデータを受け入れます。
非構造化
  • DataRobotに知られていないカスタムターゲットタイプを使用します。
  • リクエスト/レスポンススキーマに準拠する必要はありません。
  • 非構造化入出力データを受け入れます。
  • デプロイ機能には制約があります。 データドリフトや精度統計、チャレンジャーモデル、信頼性ルールはサポートしません。
  • デプロイ後はトレーニングデータを受け付けません。

構造化カスタムモデルの要件

カスタムモデルでサポートされているライブラリのいずれかが使用されている場合は、次の要件を満たしていることを確認してください。

  • モデルに送信されたデータは、追加の前処理なしで予測に使用できる必要があります。
  • 連続値モデルは、予測データの行ごとに単一の浮動小数点を返す必要があります。
  • 二値分類モデルは、1つの1.0以下の浮動小数点値、または合計が1.0になる2つの浮動小数点値を、予測データの行ごとに返す必要があります。
    • 単一値の出力は、正のクラス確率と見なされます。
    • 多価の場合、最初の値は負のクラス確率で、2番目の値は正のクラス確率であると想定されます。
  • 単一のpkl/pth/h5ファイルが存在する必要があります。

データ形式

構造化モデルを操作する場合、DataRobotはcsvsparse、またはarrow形式のファイルとしてデータをサポートします。 DataRobotでは、欠損したまたは異常な(カッコ、スラッシュ、記号などを含む)列名はサニタイズされません。

構造化カスタムモデルフック

DataRobotのフレームワークを使用してカスタムモデルを定義するには、アーティファクトファイルには、モデルのトレーニング方法と新しいデータのスコアリング方法を定義するフック(または関数)が含まれている必要があります。 DataRobotは各フックを自動的に呼び出し、プロジェクトおよびブループリントの設定に基づいてパラメーターを渡します。 しかし、各フック内で実行するロジックを定義できる柔軟性があります。 必要に応じて、これらのフックを、Pythonモデルではcustom.py、またはRモデルではcustom.Rと呼ばれるファイル内のモデルフォルダーにモデルアーティファクトとともに含めることができます。

Include all required custom model code in hooks

Custom model hooks are callbacks passed to the custom model. All code required by the custom model must be in a custom model hook—the custom model can't access any code provided outside a defined custom model hook. In addition, you can't modify the input arguments of these hooks as they are predefined.

備考

トレーニングフックと推論フックは、同じファイルで定義できます。

次のセクションでは、例とともに各フックについて説明します。

フック署名でのタイプ注釈

次のフック署名は、Python 3タイプ注釈で記述されます。 Pythonタイプは以下のRタイプに一致します。

Pythonタイプ Rタイプ 説明
DataFrame data.frame numpy DataFrameまたはR data.frame
None NULL なし
str character 文字列
Any Rオブジェクト 非シリアル化モデル。
*args, **kwargs ... これらはタイプではなくキーワード引数であり、追加パラメーター用のプレースホルダーとして機能します。

init()

initフックは実行の開始時に1回だけ実行され、モデルが他のフックで使用するライブラリと追加のファイルをロードできるようにします。

init(**kwargs) -> None 

init() 入力

入力パラメーター 説明
**kwargs 追加のキーワード引数。 code_dirはモデルコードが保存されているパスです。

init()

def init(code_dir):
    global g_code_dir
    g_code_dir = code_dir 
init <- function() {
    library(brnn)
    library(glmnet)
} 

init() 出力

init()フックは何も返しません。


load_model()

load_model()フックは、複数のアーティファクトから1つ以上のトレーニング済みオブジェクトをロードするために、実行の開始時に1回だけ実行されます。 トレーニング済みのオブジェクトがサポートされていない形式を使用するアーティファクトに保存されている場合、または複数のアーティファクトが使用される場合にのみ必要です。 サポートされている形式の1つの形式のアーティファクトが1つだけある場合、load_model()フックは必要ありません。

  • Python:.pkl.pth.h5.joblib
  • Java: .mojo
  • R:.rds
load_model(code_dir: str) -> Any 

load_model() 入力

入力パラメーター 説明
code_dir 追加のキーワード引数。 code_dirはモデルコードが保存されているパスです。

load_model()

def load_model(code_dir):
    model_path = "model.pkl"
    model = joblib.load(os.path.join(code_dir, model_path)) 
load_model <- function(input_dir) {
    readRDS(file.path(input_dir, "model_name.rds"))
} 

load_model() 出力

load_model()フックは、トレーニング済みのオブジェクト(あらゆる型)を返します。


read_input_data()

read_input_dataフックは、モデルがデータを読み取る方法をカスタマイズします。例えば、エンコーディングや欠損値の処理などです。

read_input_data(input_binary_data: bytes) -> Any 

read_input_data()入力

入力パラメーター 説明
input_binary_data drum scoreモードで--inputパラメーターによって渡されたデータ、またはdrum server /predictエンドポイントに送信されたペイロード。

read_input_data()

def read_input_data(input_binary_data):
    global prediction_value
    prediction_value += 1
    return pd.read_csv(io.BytesIO(input_binary_data)) 
read_input_data <- function(input_binary_data) {
    input_text_data <- stri_conv(input_binary_data, "utf8")
    read.csv(text=gsub("\r","", input_text_data, fixed=TRUE))
} 

read_input_data()出力

read_input_data()フックは、pandas DataFrameまたはR data.frameを返すはずです。返さない場合は、独自のスコア方法を記述する必要があります。


transform()

transform()フックはカスタム変換の出力を定義し、変換されたデータを返します。 推定器モデルにこのフックを使用しないでください。 このフックは、トランスフォーマータスクと推定タスクの両方で使用できます。

  • トランスフォーマーの場合、このフックは提供されたデータに変換を適用し、下位のタスクに渡します。

  • 推定器の場合、このフックは予測を行う前に予測データに変換を適用します。

transform(data: DataFrame, model: Any) -> DataFrame 

transform() 入力

入力パラメーター 説明
data カスタムモデルが変換すべきデータを含むpandas DataFrame(Python)またはR data.frame。 欠損値は、read_input_dataフックによってオーバーライドされていない限り、PythonではNaN、およびRではNAで示されます。
model アーティファクト(通常、トレーニング済みのトランスフォーマー)からDataRobotがロードする、またはload_modelフックを介してロードされる、トレーニング済みのオブジェクト。

transform()

def transform(data, model):
    data = data.fillna(0)
    return data 
transform <- function(data, model) {
    data[is.na(data)] <- 0
    data
} 

transform() 出力

transform()フックは、データが変換されたpandas DataFrameまたはR data.frameを返します。


score()

score()フックは、カスタム推定器の出力を定義し、出力データに予測を返します。 変換モデルにこのフックは使用しないでください。

score(data: DataFrame, model: Any, **kwargs: Dict[str, Any]) -> DataFrame 

score() 入力

入力パラメーター 説明
data カスタムモデルがスコアリングするデータを含むPandasのDataFrame(Python)またはR data.frame。 transformフックが使用されている場合、dataは変換されたデータになります。
model DataRobotによってアーティファクトからロードされるか、またはload_modelフックを介してロードされるトレーニング済みオブジェクト。
**kwargs 追加のキーワード引数。 二値分類モデルの場合、正および負のクラスラベルを以下のキーとして含めます。
  • positive_class_label
  • negative_class_label

score()

def score(data: pd.DataFrame, model: Any, **kwargs: Dict[str, Any]) -> pd.DataFrame:
    predictions = model.predict(data)
    predictions_df = pd.DataFrame(predictions, columns=[kwargs["positive_class_label"]])
    predictions_df[kwargs["negative_class_label"]] = (
        1 - predictions_df[kwargs["positive_class_label"]]
    )

    return predictions_df 
score <- function(data, model, ){
    scores <- predict(model, newdata = data, type = "prob")
    names(scores) <- c('0', '1')
    return(scores)
} 

score() 出力

score()フックは、次の形式のpandas DataFrame(またはR data.frameまたはtibble)を返します。

  • 連続値または異常検知プロジェクトの場合、出力に予測というの数値列が必要です。

  • 二値または多クラスプロジェクトについては、出力にはクラスラベルごとに1つの列があり、クラス名を列名として使用する必要があります。 各セルには、それぞれのクラスの浮動小数点クラス確率を含んでいなければならず、各行の合計が1.0になる必要があります。

追加の出力列

本機能の提供について

カスタムモデルの予測レスポンスの追加出力は、デフォルトではオフになっています。 この機能を有効にする方法については、DataRobotの担当者または管理者にお問い合わせください。

機能フラグ:予測応答で追加のカスタムモデル出力を有効にする

score()フックは、stringintfloatbool、またはdatetime型のデータを含む追加の列を数に制限なく返すことができます。 追加の列がscore()メソッドによって返される場合、予測応答は次のようになります。

  • 表形式の応答(CSV)の場合、追加の列は応答テーブルまたはデータフレームの一部として返されます。
  • JSON応答の場合extraModelOutputキーが各行と一緒に返されます。 このキーは、行内の各追加列の値を含むディクショナリです。
例:余分な列を返す

さまざまなターゲットタイプの次のスコアフックは、予測データと共に追加の列(説明を目的としたランダムデータを含む)を返します。

連続値
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
def score(data, model, **kwargs):
    predictions = []
    int_extra_data = []
    str_extra_data = []

    for index in range(data.shape[0]):
        predictions.append(round(random(), 2))

        int_extra_data.append(randint(0,100))
        int_extra_data.append(f'str-{randint(0,100)}')


    return pd.DataFrame(
        {
            "Predictions": predictions,
            "Extra Integer": int_extra_data,
            "Extra String": str_extra_data,
        }
    ) 
多クラス分類
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def score(data: pd.DataFrame, model: Any, **kwargs: Dict[str, Any]) -> pd.DataFrame:
    positive_label = kwargs["positive_probabilities"]
    negative_label = kwargs["negative_probabilities"]

    positive_probabilities = []
    negative_probabilities = []
    int_extra_data = []
    str_extra_data = []
    for index in range(data.shape[0]):
        probability = round(random(), 2)

        positive_probabilities.append(probability)
        negative_probabilities.append(1 - probability)

        int_extra_data.append(randint(0,100))
        int_extra_data.append(f'str-{randint(0,100)}')


    return pd.DataFrame(
        {
            positive_label: positive_probabilities,
            negative_label: negative_probabilities,
            "Extra Integer": int_extra_data,
            "Extra String": str_extra_data,
        }
    ) 
Generative AI
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def score(data: pd.DataFrame, model, **kwargs):
    prompt_column_name = RuntimeParameters.get('PROMPT_COLUMN_NAME')
    target_column_name = os.environ['TARGET_NAME']

    target_data = []
    int_extra_data = []
    str_extra_data = []
    query_rows = data[prompt_column_name].tolist()
    for index, query in enumerate(query_rows):
        target_data.append(f'Answer {index} for query "{query}"')
        int_extra_data.append(randint(0,100))
        int_extra_data.append(f'str-{randint(0,100)}')

    return pd.DataFrame(
        {
            target_column_name: target_data,
            "Extra Integer": int_extra_data,
            "Extra String": str_extra_data,
        }
    ) 

chat()

chat()フックを使用すると、カスタムモデルにボルトオンのガバナンスAPIを実装して、チャット履歴やストリーミングレスポンスにアクセスできるようになります。 デプロイされたLLMブループリントでボルトオンのガバナンスAPIを使用する場合、modelパラメーターの推奨値については利用可能なLLMを参照してください。 あるいは、予約値 model="datarobot-deployed-llm" を指定して、LLMプロバイダーのサービスを呼び出すときに、LLMブループリントが関連するモデルIDを自動的に選択するようにします。

chat(completion_create_params: CompletionCreateParams, model: Any) -> ChatCompletion | Iterator[ChatCompletionChunk] 

ワークベンチで、chat関数を実装したデプロイ済みLLMを追加する場合、プレイグラウンドは優先通信手段としてボルトオンのガバナンスAPIを使用します。 LLMブループリントに関連付けられたチャットモデルIDを入力して、プレイグラウンドからデプロイされたLLMへのリクエストにmodelパラメーターを設定します。 あるいは、datarobot-deployed-llmを入力して、LLMプロバイダーのサービスを呼び出すときに、LLMブループリントが関連するモデルIDを自動的に選択するようにします。

chat() 入力

入力パラメーター 説明
completion_create_params チャット補完の作成に必要なすべてのパラメーターを含むオブジェクト。 詳細については、OpenAI Python APIライブラリで次の型を確認してください:CompletionCreateParamsChatCompletionChatCompletionChunk
model DRUMまたはload_model(指定した場合)によって読み込まれた逆シリアル化モデル。

chat()

def chat(completion_create_params, model):
    openai_client = model
    return openai_client.chat.completions.create(**completion_create_params) 

chat() 出力

chat()フックは、ストリーミングが無効な場合はChatCompletionオブジェクトを返し、ストリーミングが有効な場合はIterator[ChatCompletionChunk]を返します。 If there are prompt guards configured, the first chunk of the stream contains the prompt guard moderations information (accessible via datarobot_moderations on the chunk). For every response guard configured that can be applied to a chunk (all guards except faithfulness, NeMo, Rouge-1, Agent goal accuracy, and task adherence), each intermediate chunk (except the last chunk) has moderations information for those guards accessible via datarobot_moderations. For the last chunk, all response guards information is accessible via datarobot_moderations.

関連付けID

As of DRUM v1.16.16, every chat completion response automatically generates and returns an association ID (as datarobot_association_id). The same association ID gets passed to any other configured custom metrics for the deployed LLM. Note that the completion API does not support user-supplied association IDs, just those that are automatically generated.

Moderations

Moderation guardrails help your organization block prompt injection and hateful, toxic, or inappropriate prompts and responses. Moderation library now supports streaming response. In order for the chat() hook to return datarobot_moderations, the deployed LLM must be running in an execution environment that has the moderation library installed, and the custom model code directory must contain moderation_config.yaml to configure the moderations.

The example below shows what is present in ChatCompletion if streaming = False and in ChatCompletionChunk if streaming = True and moderation is enabled.

datarobot_moderations={
'Prompt tokens_latency': 0.20357584953308105,
'Prompts_token_count': 8,
'ROUGE-1_latency': 0.028343677520751953,
'Response tokens_latency': 0.0007507801055908203,
'Responses_rouge_1': 1.0,
'Responses_token_count': 1,
'action_promptText': '',
'action_resultText': '',
'association_id': '3d7d525b-9e99-42a4-a641-70254e924a76',
'blocked_promptText': False, 'blocked_resultText': False,
'datarobot_confidence_score': 1.0,
'datarobot_latency': 4.249604940414429,
'datarobot_token_count': 1,
'moderated_promptText': 'Now divide the result by 2.',
'replaced_promptText': False,
'replaced_resultText': False,
'reported_promptText': False,
'reported_resultText': False,
'unmoderated_resultText': '10'
}
引用

In order for the chat() hook to return citations, the deployed LLM must have a vector database associated with it. The chat() hook returns keys related to citations and accessible to custom models.

例:

citations=[
    {
        'content': 'ISS science results have Earth-based \napplications, including understanding our \nclimate, contributing to the treatment of \ndisease, improving existing materials, and \ninspiring the future generation of scientists, \nclinicians, technologists, engineers, \nmathematicians, artists, and explorers.\nBENEFITS\nFOR HUMANITY\nDISCOVERY\nEXPLORATION',
        'link': 'Space_Station_Annual_Highlights/iss_2020_highlights.pdf:10',
        'metadata':
        {
            'chunk_id': '953',
            'content': 'ISS science results have Earth-based \napplications, including understanding our \nclimate, contributing to the treatment of \ndisease, improving existing materials, and \ninspiring the future generation of scientists, \nclinicians, technologists, engineers, \nmathematicians, artists, and explorers.\nBENEFITS\nFOR HUMANITY\nDISCOVERY\nEXPLORATION',
            'page': 10,
            'similarity_score': 0.46,
            'source': 'Space_Station_Annual_Highlights/iss_2020_highlights.pdf'
        },
        'vector': None
    },
]

get_supported_llm_models()

DataRobot custom models support the OpenAI "List Models" API. To customize your model's response to this API, implement the get_supported_llm_models() hook in custom.py.

def get_supported_llm_models(model: Any)

get_supported_llm_models() input

入力パラメーター 説明
model オプションです。 A model ID to compare against.

get_supported_llm_models() example

def get_supported_llm_models(model: Any):
    _ = model
    return [
        Model(
            id="datarobot_llm_id",
            created=1744854432,
            object="model",
            owned_by="tester@datarobot.com",
        )
    ]

You can retrieve the supported models for a custom model using the OpenAI client or the DataRobot REST API:

from openai import OpenAI

API_KEY = '<datarobot API token>'
CHAT_API_URL = 'https://app.datarobot.com/api/v2/deployments/<id>/'

def list_models():
    openai_client = OpenAI(
        base_url=CHAT_API_URL,
        api_key=API_KEY,
        _strict_response_validation=False
    )
    response = openai_client.models.list()
    print("listing models...")
    print(response.to_dict())
$ curl "https://app.datarobot.com/api/v2/deployments/<id>/models" \
-H "Authorization: Bearer <datarobot API token>"

{"data":[{"created":1744854432,"id":"datarobot_llm_id","object":"model","owned_by":"tester@datarobot.com"}],"object":"list"}

In the DRUM repository, you can view a simple text generation model that supports the OpenAI API /chat and /models endpoints through the chat() and get_supported_llm_models() hooks.

get_supported_llm_models () output

If your custom.py does not implement get_supported_llm_models(), the custom model returns a one item list based on the LLM_ID runtime parameter, if it exists. Custom models exported from Playground blueprints have this parameter already set to the LLM you selected for the blueprint. If get_supported_llm_models() is not defined, and the LLM_ID runtime parameter is not defined, then the /models API returns an empty list. Support for /models is in DRUM 1.16.12 or later.


post_process()

post_processフックは、出力形式の期待値と一致しない場合にDataRobotまたはscoreフックによって返される予測データをフォーマットします。

post_process(predictions: DataFrame, model: Any) -> DataFrame

post_process()入力

入力パラメーター 説明
predictions DataRobotまたはscoreフックによって生成されたスコアリングデータを含むpandas DataFrame(Python)またはR data.frame。
model DataRobotによってアーティファクトからロードされるか、またはload_modelフックを介してロードされるトレーニング済みオブジェクト。

post_process()

def post_process(predictions, model):
    return predictions + 1 
post_process <- function(predictions, model) {
    names(predictions) <- c('0', '1')
} 

post_process()出力

post_processフックは、次の形式のpandas DataFrame(またはR data.frameまたはtibble)を返します。

  • 連続値または異常検知プロジェクトの場合、出力に予測という単一の数値列が必要です。

  • 二値または多クラスプロジェクトについては、出力にはクラスごとに1つの列があり、クラス名を列名として使用する必要があります。 各セルには各クラスの確率が含まれている必要があります。また、各行の合計が1.0になる必要があります。