Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

scikit-learn 이진 분류 모델 학습

Model Training 템플릿에서 UCI Breast Cancer Wisconsin (Diagnostic) 공개 데이터를 사용하여 이진 분류 모델을 학습합니다. 모델 연결을 설명하는 예제이며 실제 의료 판단을 위한 성능 검증을 대신하지 않습니다.

scikit-learn의 이 데이터는 0이 malignant(악성), 1이 benign(양성)입니다. prediction은 이 클래스 값이고 probability_0은 악성 클래스 확률, probability_1은 양성 클래스 확률입니다. 확률 열은 실제 model.classes_ 순서에 맞춰 기록합니다.

예제 의존성은 foundry-transforms-lib-python, pandas 1.5.3, scikit-learn 1.3.2와 dill 0.3.7입니다. palantir_models와 Model Training 템플릿도 준비합니다. CBAC 환경에서는 출력 리소스를 미리 생성합니다.

어댑터

src/main/model_adapters/adapter.py에 다음 코드를 둡니다. 30개 특성은 수치 입력이며 학습 때 공백을 밑줄로 바꾼 이름을 사용합니다. API에 float를 명시하여 표 열의 자료형을 정합니다.

import palantir_models as pm
from palantir_models.serializers import DillSerializer

class SklearnClassificationAdapter(pm.ModelAdapter):
    FEATURE_COLUMNS = [
        "mean_radius", "mean_texture", "mean_perimeter", "mean_area",
        "mean_smoothness", "mean_compactness", "mean_concavity",
        "mean_concave_points", "mean_symmetry", "mean_fractal_dimension",
        "radius_error", "texture_error", "perimeter_error", "area_error",
        "smoothness_error", "compactness_error", "concavity_error",
        "concave_points_error", "symmetry_error", "fractal_dimension_error",
        "worst_radius", "worst_texture", "worst_perimeter", "worst_area",
        "worst_smoothness", "worst_compactness", "worst_concavity",
        "worst_concave_points", "worst_symmetry", "worst_fractal_dimension",
    ]

    @pm.auto_serialize(model=DillSerializer())
    def __init__(self, model):
        self.model = model

    @classmethod
    def api(cls):
        columns = [(name, float) for name in cls.FEATURE_COLUMNS]
        return (
            {"df_in": pm.Pandas(columns=columns)},
            {"df_out": pm.Pandas(columns=columns + [
                ("prediction", int), ("probability_0", float), ("probability_1", float),
            ])},
        )

    def predict(self, df_in):
        features = df_in[self.FEATURE_COLUMNS]
        df_in["prediction"] = self.model.predict(features)
        probabilities = self.model.predict_proba(features)
        for index, label in enumerate(self.model.classes_):
            df_in[f"probability_{label}"] = probabilities[:, index]
        return df_in

입력에 정답 같은 추가 열이 있어도 학습한 특성만 모델에 전달하고 원래 표에는 추가 열을 유지합니다.

학습 변환

model_training/model_training.py에 다음 변환을 작성합니다. 라이브러리 데이터의 특성 이름에서 공백을 밑줄로 바꿉니다. 중앙값 대체 및 표준화 후 트리 50개, 최대 깊이 3인 RandomForestClassifier를 학습합니다. 출력 경로는 실제 모델 경로로 바꿉니다.

from transforms.api import transform
from palantir_models.transforms import ModelOutput
from main.model_adapters.adapter import SklearnClassificationAdapter
from sklearn.datasets import load_breast_cancer
from sklearn.compose import make_column_transformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier


@transform.using(
    model_output=ModelOutput("/path/to/model_asset"),
)
def compute(model_output):
    X_train, y_train = load_breast_cancer(as_frame=True, return_X_y=True)
    X_train.columns = X_train.columns.str.replace(' ', '_')
    columns = X_train.columns

    numeric_transformer = Pipeline(
        steps=[
            ("imputer", SimpleImputer(strategy="median")),
            ("scaler", StandardScaler())
        ]
    )

    preprocessor = make_column_transformer(
        (numeric_transformer, columns),
        remainder="passthrough"
    )

    model = Pipeline(
        steps=[
            ("preprocessor", preprocessor),
            ("classifier", RandomForestClassifier(n_estimators=50, max_depth=3))
        ]
    )
    model.fit(X_train, y_train)

    foundry_model = SklearnClassificationAdapter(model)
    model_output.publish(model_adapter=foundry_model)

배치 추론

model_training/run_inference.py에서 다음 변환을 빌드합니다. 표시된 모델 및 데이터셋 RID는 예시이므로 실제 리소스로 바꿉니다. 이 코드는 학습에 사용한 공개 데이터를 다시 읽어 추론 연결을 확인하며 별도 미학습 시험 집합의 성능 측정은 아닙니다.

from transforms.api import transform, Output, LightweightOutput
from palantir_models.transforms import ModelInput
from palantir_models import ModelAdapter
from sklearn.datasets import load_breast_cancer


@transform.using(
    model=ModelInput(
        "ri.models.main.model.cfc11519-28be-4f3e-9176-9afe91ecf3e1",
        # use_sidecar=True is recommended for models defined outside the current transform repository
        ),
    inference_output=Output("ri.foundry.main.dataset.5dd9907f-79bc-4ae9-a106-1fa87ff021c3"),
)
def compute(model: ModelAdapter, inference_output: LightweightOutput):
    X, y = load_breast_cancer(as_frame=True, return_X_y=True)
    X.columns = X.columns.str.replace(' ', '_')

    inference_results = model.transform(X)
    inference_output.write_pandas(inference_results.df_out)

다른 저장소에서 소비할 때에는 use_sidecar=True를 권장합니다. 경량 변환에서 sidecar를 사용하려면 palantir_models 0.2010.0 이상이 필요합니다. sidecar를 쓰지 않으면 현재 저장소에 어댑터 코드와 의존성이 있어야 합니다.

온라인 추론

모델을 Modeling Objective에 제출하여 릴리스한 뒤 온라인 배포를 생성합니다. 준비된 엔드포인트를 운영 앱에 연결할 수 있고 같은 제출물을 자동 평가와 배치 파이프라인에도 사용할 수 있습니다.

아래 값은 요청 형식을 설명하는 예시이며 실제 환자 자료나 판단 결과가 아닙니다. multi I/O v2 요청은 모델의 df_in 이름 아래 행 목록을 보냅니다.

{
  "df_in": [
    {
      "mean_radius": 15.09,
      "mean_texture": 23.71,
      "mean_perimeter": 92.65,
      "mean_area": 944.07,
      "mean_smoothness": 0.53,
      "mean_compactness": 0.21,
      "mean_concavity": 0.76,
      "mean_concave_points": 0.39,
      "mean_symmetry": 0.08,
      "mean_fractal_dimension": 0.14,
      "radius_error": 0.49,
      "texture_error": 0.82,
      "perimeter_error": 2.51,
      "area_error": 17.22,
      "smoothness_error": 0.07,
      "compactness_error": 0.01,
      "concavity_error": 0.05,
      "concave_points_error": 0.05,
      "symmetry_error": 0.01,
      "fractal_dimension_error": 0.08,
      "worst_radius": 12.95,
      "worst_texture": 20.66,
      "worst_perimeter": 185.41,
      "worst_area": 624.87,
      "worst_smoothness": 0.18,
      "worst_compactness": 0.26,
      "worst_concavity": 0.01,
      "worst_concave_points": 0.05,
      "worst_symmetry": 0.29,
      "worst_fractal_dimension": 0.05
    }
  ]
}

종료 예정인 기존 single I/O 엔드포인트를 사용하는 Modeling Objective 배포에서는 같은 행 목록을 requestData에 넣고 requestParams를 함께 전달합니다. 직접 모델 배포에는 이 기존 엔드포인트를 사용하지 않습니다. 온라인 요청과 배포의 엔드포인트 구분을 따릅니다.