자습서: 텍스트 분류 모델 만들기, 평가 및 점수 매기기

이 자습서에서는 Microsoft Fabric에서 텍스트 분류 모델에 대한 Synapse 데이터 과학 워크플로의 엔드 투 엔드 예제를 제공합니다. 이 시나리오에서는 Spark에서 word2vec 및 로지스틱 회귀를 사용하여 책 제목에 따라 영국 도서관 책 데이터 세트에서 책의 장르를 결정합니다.

이 자습서에서는 다음 단계를 설명합니다.

  • 사용자 지정 라이브러리 설치
  • 데이터 로드
  • 예비 데이터 분석을 사용하여 데이터 이해 및 처리
  • word2vec 및 로지스틱 회귀를 사용하여 기계 학습 모델 학습 및 MLflow 및 패브릭 자동 로깅 기능을 사용하여 실험 추적
  • 점수 매기기 및 예측을 위한 기계 학습 모델 로드

필수 조건

  • Microsoft Fabric 구독가져옵니다. 또는 무료 Microsoft Fabric 평가판에 등록합니다.

  • Microsoft Fabric에 로그인합니다.

  • 홈페이지 왼쪽의 환경 전환기를 사용하여 Synapse 데이터 과학 환경으로 전환합니다.

    Screenshot of the experience switcher menu, showing where to select Data Science.

  • Microsoft Fabric 레이크하우스가 없는 경우 Microsoft Fabric에서 레이크하우스 만들기의 단계에 따라 만듭니다.

전자 필기장에서 팔로우

다음 옵션 중 하나를 선택하여 전자 필기장에서 따를 수 있습니다.

  • Synapse 데이터 과학 환경에서 기본 제공 Notebook 열기 및 실행
  • GitHub에서 Synapse 데이터 과학 환경으로 Notebook 업로드

기본 제공 Notebook 열기

샘플 타이틀 장르 분류 Notebook은 이 자습서와 함께 제공됩니다.

Synapse 데이터 과학 환경에서 자습서의 기본 제공 샘플 Notebook을 열려면 다음을 수행합니다.

  1. Synapse 데이터 과학 홈페이지로 이동합니다.

  2. 샘플 사용을 선택합니다.

  3. 해당 샘플을 선택합니다.

    • 기본 Python(엔드 투 엔드 워크플로) 탭에서 샘플이 Python 자습서용인 경우
    • R(엔드 투 엔드 워크플로) 탭에서 샘플이 R 자습서용인 경우
    • 빠른 자습서 탭에서 샘플이 빠른 자습서용인 경우
  4. 코드 실행을 시작하기 전에 Lakehouse를 Notebook 에 연결합니다.

GitHub에서 Notebook 가져오기

AIsample - 타이틀 장르 Classification.ipynb 은 이 자습서와 함께 제공되는 Notebook입니다.

이 자습서에 대해 함께 제공되는 Notebook을 열려면 데이터 과학 자습서를 위해 시스템 준비 자습서의 지침에 따라 Notebook을 작업 영역으로 가져옵니다.

이 페이지에서 코드를 복사하여 붙여 넣으면 새 Notebook을 만들 수 있습니다.

코드 실행을 시작하기 전에 Lakehouse를 Notebook에 연결해야 합니다.

1단계: 사용자 지정 라이브러리 설치

기계 학습 모델 개발 또는 임시 데이터 분석의 경우 Apache Spark 세션에 대한 사용자 지정 라이브러리를 신속하게 설치해야 할 수 있습니다. 라이브러리를 설치하는 두 가지 옵션이 있습니다.

  • 현재 Notebook에만 라이브러리를 설치하려면 Notebook의 인라인 설치 기능(%pip 또는 %conda)을 사용합니다.
  • 또는 패브릭 환경을 만들거나, 공용 원본에서 라이브러리를 설치하거나, 사용자 지정 라이브러리를 업로드한 다음, 작업 영역 관리자가 작업 영역의 기본값으로 환경을 연결할 수 있습니다. 그러면 환경의 모든 라이브러리를 작업 영역의 모든 Notebook 및 Spark 작업 정의에서 사용할 수 있게 됩니다. 환경에 대한 자세한 내용은 Microsoft Fabric에서 환경 만들기, 구성 및 사용을 참조 하세요.

분류 모델의 경우 라이브러리를 wordcloud 사용하여 단어의 크기가 해당 빈도를 나타내는 텍스트의 단어 빈도를 나타냅니다. 이 자습서에서는 Notebook에 설치 wordcloud 하는 데 사용합니다%pip install.

참고 항목

실행 후 %pip install PySpark 커널이 다시 시작됩니다. 다른 셀을 실행하기 전에 필요한 라이브러리를 설치합니다.

# Install wordcloud for text visualization by using pip
%pip install wordcloud

2단계: 데이터 로드

데이터 세트에는 라이브러리와 Microsoft 간의 공동 작업이 디지털화된 영국 도서관의 책에 대한 메타데이터가 있습니다. 메타데이터는 책이 소설인지 아니면 논픽션인지를 나타내는 분류 정보입니다. 이 데이터 세트를 사용하면 제목에 따라 책의 장르를 결정하는 분류 모델을 학습시키는 것이 목표입니다.

BL 레코드 ID 리소스 유형 이름 이름과 연결된 날짜 이름 유형 역할 모든 이름 타이틀 변형 제목 시리즈 제목 계열 내의 숫자 발행 국가 발행물의 장소 게시자 게시 날짜 버전 물리적 설명 듀이 분류 BL 선반 표시 토픽 장르 언어 주의 실제 리소스에 대한 BL 레코드 ID classification_id user_id created_at subject_ids annotator_date_pub annotator_normalised_date_pub annotator_edition_statement annotator_genre annotator_FAST_genre_terms annotator_FAST_subject_terms annotator_comments annotator_기본_language annotator_other_languages_summaries annotator_summaries_language annotator_translation annotator_original_language annotator_publisher annotator_place_pub annotator_country annotator_title 디지털화된 책 링크 주석
014602826 논문 Yearsley, Ann 1753-1806 person 더, 한나, 1745-1833 [사람]; Yearsley, Ann, 1753-1806 [person] 여러 번 시 [한나 모어에 의해 prefatory 편지와 함께.] 영국 런던 1786 네 번째 버전 원고 노트 Digital Store 11644.d.32 영어 003996603 False
014602830 논문 A, T. person 올덤, 존, 1653-1683 [사람]; A, T. [person] 베르투에 대한 사티르. (시: 타운 헥터에 의해 말해야한다 [존 올덤에 의해. 부호 있는 서문: T. A.]) 영국 런던 1679 15페이지(4°) Digital Store 11602.ee.10. (2.) 영어 000001143 False

다른 데이터 세트에 이 Notebook을 적용할 수 있도록 다음 매개 변수를 정의합니다.

IS_CUSTOM_DATA = False  # If True, the user must manually upload the dataset
DATA_FOLDER = "Files/title-genre-classification"
DATA_FILE = "blbooksgenre.csv"

# Data schema
TEXT_COL = "Title"
LABEL_COL = "annotator_genre"
LABELS = ["Fiction", "Non-fiction"]

EXPERIMENT_NAME = "sample-aisample-textclassification"  # MLflow experiment name

데이터 세트를 다운로드하고 레이크하우스에 업로드

이 코드는 공개적으로 사용 가능한 버전의 데이터 세트를 다운로드한 다음 Fabric Lakehouse에 저장합니다.

Important

실행하기 전에 Notebook에 Lakehouse 를 추가합니다. 이렇게 하지 않으면 오류가 발생합니다.

if not IS_CUSTOM_DATA:
    # Download demo data files into the lakehouse, if they don't exist
    import os, requests

    remote_url = "https://synapseaisolutionsa.blob.core.windows.net/public/Title_Genre_Classification"
    fname = "blbooksgenre.csv"
    download_path = f"/lakehouse/default/{DATA_FOLDER}/raw"

    if not os.path.exists("/lakehouse/default"):
        # Add a lakehouse, if no default lakehouse was added to the notebook
        # A new notebook won't link to any lakehouse by default
        raise FileNotFoundError(
            "Default lakehouse not found, please add a lakehouse and restart the session."
        )
    os.makedirs(download_path, exist_ok=True)
    if not os.path.exists(f"{download_path}/{fname}"):
        r = requests.get(f"{remote_url}/{fname}", timeout=30)
        with open(f"{download_path}/{fname}", "wb") as f:
            f.write(r.content)
    print("Downloaded demo data files into lakehouse.")

필수 라이브러리 가져오기

처리하기 전에 SparkSynapseML용 라이브러리를 포함하여 필요한 라이브러리를 가져와야 합니다.

import numpy as np
from itertools import chain

from wordcloud import WordCloud
import matplotlib.pyplot as plt
import seaborn as sns

import pyspark.sql.functions as F

from pyspark.ml import Pipeline
from pyspark.ml.feature import *
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import (
    BinaryClassificationEvaluator,
    MulticlassClassificationEvaluator,
)

from synapse.ml.stages import ClassBalancer
from synapse.ml.train import ComputeModelStatistics

import mlflow

하이퍼 매개 변수 정의

모델 학습을 위한 일부 하이퍼 매개 변수를 정의합니다.

Important

각 매개 변수를 이해하는 경우에만 이러한 하이퍼 매개 변수를 수정합니다.

# Hyperparameters 
word2vec_size = 128  # The length of the vector for each word
min_word_count = 3  # The minimum number of times that a word must appear to be considered
max_iter = 10  # The maximum number of training iterations
k_folds = 3  # The number of folds for cross-validation

이 Notebook을 실행하는 데 필요한 시간 기록을 시작합니다.

# Record the notebook running time
import time

ts = time.time()

MLflow 실험 추적 설정

자동 로깅은 MLflow 로깅 기능을 확장합니다. 자동 로깅은 학습할 때 기계 학습 모델의 입력 매개 변수 값 및 출력 메트릭을 자동으로 캡처합니다. 그런 다음 이 정보를 작업 영역에 기록합니다. 작업 영역에서 MLflow API 또는 해당 실험을 사용하여 작업 영역에서 정보에 액세스하고 시각화할 수 있습니다. 자동 로깅에 대한 자세한 내용은 Microsoft Fabric의 자동 로깅을 참조 하세요.

# Set up Mlflow for experiment tracking

mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True)  # Disable Mlflow autologging

Notebook 세션에서 Microsoft Fabric 자동 로깅을 사용하지 않도록 설정하려면 다음을 호출 mlflow.autolog() 하고 설정합니다 disable=True.

레이크하우스에서 원시 날짜 데이터 읽기

raw_df = spark.read.csv(f"{DATA_FOLDER}/raw/{DATA_FILE}", header=True, inferSchema=True)

3단계: 예비 데이터 분석 수행

명령을 사용하여 데이터 세트를 탐색하고, 데이터 세트 display 에 대한 상위 수준 통계를 보고, 차트 보기를 표시합니다.

display(raw_df.limit(20))

데이터 준비

중복 항목을 제거하여 데이터를 클린.

df = (
    raw_df.select([TEXT_COL, LABEL_COL])
    .where(F.col(LABEL_COL).isin(LABELS))
    .dropDuplicates([TEXT_COL])
    .cache()
)

display(df.limit(20))

클래스 분산을 적용하여 모든 바이어스 해결:

# Create a ClassBalancer instance, and set the input column to LABEL_COL
cb = ClassBalancer().setInputCol(LABEL_COL)

# Fit the ClassBalancer instance to the input DataFrame, and transform the DataFrame
df = cb.fit(df).transform(df)

# Display the first 20 rows of the transformed DataFrame
display(df.limit(20))

단락과 문장을 더 작은 단위로 분할하여 데이터 세트를 토큰화합니다. 이렇게 하면 의미를 더 쉽게 할당할 수 있습니다. 그런 다음 중지 단어를 제거하여 성능을 향상시킵니다. 중지 단어 제거에는 일반적으로 모음의 모든 문서에서 발생하는 단어가 제거됩니다. 중지 단어 제거는 NLP(자연어 처리) 애플리케이션에서 가장 일반적으로 사용되는 전처리 단계 중 하나입니다.

# Text transformer
tokenizer = Tokenizer(inputCol=TEXT_COL, outputCol="tokens")
stopwords_remover = StopWordsRemover(inputCol="tokens", outputCol="filtered_tokens")

# Build the pipeline
pipeline = Pipeline(stages=[tokenizer, stopwords_remover])

token_df = pipeline.fit(df).transform(df)

display(token_df.limit(20))

각 클래스에 대한 wordcloud 라이브러리를 표시합니다. wordcloud 라이브러리는 텍스트 데이터에 자주 나타나는 키워드(keyword) 시각적으로 눈에 띄는 프레젠테이션입니다. wordcloud 라이브러리는 키워드(keyword) 렌더링이 클라우드와 같은 색 그림을 형성하여 기본 텍스트 데이터를 한눈에 더 잘 캡처하기 때문에 효과적입니다. wordcloud에 대해 자세히 알아보세요.

# WordCloud
for label in LABELS:
    tokens = (
        token_df.where(F.col(LABEL_COL) == label)
        .select(F.explode("filtered_tokens").alias("token"))
        .where(F.col("token").rlike(r"^\w+$"))
    )

    top50_tokens = (
        tokens.groupBy("token").count().orderBy(F.desc("count")).limit(50).collect()
    )

    # Generate a wordcloud image
    wordcloud = WordCloud(
        scale=10,
        background_color="white",
        random_state=42,  # Make sure the output is always the same for the same input
    ).generate_from_frequencies(dict(top50_tokens))

    # Display the generated image by using matplotlib
    plt.figure(figsize=(10, 10))
    plt.title(label, fontsize=20)
    plt.axis("off")
    plt.imshow(wordcloud, interpolation="bilinear")

마지막으로 word2vec를 사용하여 텍스트를 벡터화합니다. word2vec 기술은 텍스트에 있는 각 단어의 벡터 표현을 만듭니다. 비슷한 컨텍스트에서 사용되거나 의미 체계 관계가 있는 단어는 벡터 공간에서의 근접성을 통해 효과적으로 캡처됩니다. 이 근접성은 유사한 단어에 유사한 단어 벡터가 있음을 나타냅니다.

# Label transformer
label_indexer = StringIndexer(inputCol=LABEL_COL, outputCol="labelIdx")
vectorizer = Word2Vec(
    vectorSize=word2vec_size,
    minCount=min_word_count,
    inputCol="filtered_tokens",
    outputCol="features",
)

# Build the pipeline
pipeline = Pipeline(stages=[label_indexer, vectorizer])
vec_df = (
    pipeline.fit(token_df)
    .transform(token_df)
    .select([TEXT_COL, LABEL_COL, "features", "labelIdx", "weight"])
)

display(vec_df.limit(20))

4단계: 모델 학습 및 평가

데이터가 있는 상태에서 모델을 정의합니다. 이 섹션에서는 로지스틱 회귀 모델을 학습시켜 벡터화된 텍스트를 분류합니다.

학습 및 테스트 데이터 세트 준비

# Split the dataset into training and testing
(train_df, test_df) = vec_df.randomSplit((0.8, 0.2), seed=42)

기계 학습 실험 추적

기계 학습 실험은 모든 관련 기계 학습 실행에 대한 조직 및 제어의 기본 단위입니다. 실행은 모델 코드의 단일 실행에 해당합니다.

기계 학습 실험 추적은 매개 변수, 메트릭, 모델 및 기타 아티팩트와 같은 모든 실험과 해당 구성 요소를 관리합니다. 추적을 사용하면 특정 기계 학습 실험의 모든 필수 구성 요소를 조직할 수 있습니다. 또한 저장된 실험을 사용하여 과거 결과를 쉽게 재현할 수 있습니다. Microsoft Fabric의 기계 학습 실험에 대해 자세히 알아봅니다.

# Build the logistic regression classifier
lr = (
    LogisticRegression()
    .setMaxIter(max_iter)
    .setFeaturesCol("features")
    .setLabelCol("labelIdx")
    .setWeightCol("weight")
)

hyperparameters 조정

하이퍼 매개 변수를 검색하는 매개 변수 그리드를 작성합니다. 그런 다음, 교차 평가기 추정기를 빌드하여 모델을 생성합니다.CrossValidator

# Build a grid search to select the best values for the training parameters
param_grid = (
    ParamGridBuilder()
    .addGrid(lr.regParam, [0.03, 0.1])
    .addGrid(lr.elasticNetParam, [0.0, 0.1])
    .build()
)

if len(LABELS) > 2:
    evaluator_cls = MulticlassClassificationEvaluator
    evaluator_metrics = ["f1", "accuracy"]
else:
    evaluator_cls = BinaryClassificationEvaluator
    evaluator_metrics = ["areaUnderROC", "areaUnderPR"]
evaluator = evaluator_cls(labelCol="labelIdx", weightCol="weight")

# Build a cross-evaluator estimator
crossval = CrossValidator(
    estimator=lr,
    estimatorParamMaps=param_grid,
    evaluator=evaluator,
    numFolds=k_folds,
    collectSubModels=True,
)

모델 평가

테스트 데이터 세트의 모델을 평가하여 비교할 수 있습니다. 잘 학습된 모델은 유효성 검사 및 테스트 데이터 세트에 대해 실행할 때 관련 메트릭에서 고성능을 보여 주어야 합니다.

def evaluate(model, df):
    log_metric = {}
    prediction = model.transform(df)
    for metric in evaluator_metrics:
        value = evaluator.evaluate(prediction, {evaluator.metricName: metric})
        log_metric[metric] = value
        print(f"{metric}: {value:.4f}")
    return prediction, log_metric

MLflow를 사용하여 실험 추적

학습 및 평가 프로세스를 시작합니다. MLflow를 사용하여 모든 실험 및 로그 매개 변수, 메트릭 및 모델을 추적합니다. 이 모든 정보는 작업 영역의 실험 이름 아래에 기록됩니다.

with mlflow.start_run(run_name="lr"):
    models = crossval.fit(train_df)
    best_metrics = {k: 0 for k in evaluator_metrics}
    best_index = 0
    for idx, model in enumerate(models.subModels[0]):
        with mlflow.start_run(nested=True, run_name=f"lr_{idx}") as run:
            print("\nEvaluating on test data:")
            print(f"subModel No. {idx + 1}")
            prediction, log_metric = evaluate(model, test_df)

            if log_metric[evaluator_metrics[0]] > best_metrics[evaluator_metrics[0]]:
                best_metrics = log_metric
                best_index = idx

            print("log model")
            mlflow.spark.log_model(
                model,
                f"{EXPERIMENT_NAME}-lrmodel",
                registered_model_name=f"{EXPERIMENT_NAME}-lrmodel",
                dfs_tmpdir="Files/spark",
            )

            print("log metrics")
            mlflow.log_metrics(log_metric)

            print("log parameters")
            mlflow.log_params(
                {
                    "word2vec_size": word2vec_size,
                    "min_word_count": min_word_count,
                    "max_iter": max_iter,
                    "k_folds": k_folds,
                    "DATA_FILE": DATA_FILE,
                }
            )

    # Log the best model and its relevant metrics and parameters to the parent run
    mlflow.spark.log_model(
        models.subModels[0][best_index],
        f"{EXPERIMENT_NAME}-lrmodel",
        registered_model_name=f"{EXPERIMENT_NAME}-lrmodel",
        dfs_tmpdir="Files/spark",
    )
    mlflow.log_metrics(best_metrics)
    mlflow.log_params(
        {
            "word2vec_size": word2vec_size,
            "min_word_count": min_word_count,
            "max_iter": max_iter,
            "k_folds": k_folds,
            "DATA_FILE": DATA_FILE,
        }
    )

실험을 보려면 다음을 수행합니다.

  1. 왼쪽 탐색에서 작업 영역 선택
  2. 실험 이름 찾기 및 선택 - 이 경우 sample_aisample-textclassification

Screenshot of an experiment.

5단계: 예측 결과 점수 매기기 및 저장

Microsoft Fabric을 사용하면 사용자가 확장 가능한 함수를 PREDICT 사용하여 기계 학습 모델을 운영할 수 있습니다. 이 함수는 모든 컴퓨팅 엔진에서 일괄 처리 채점(또는 일괄 처리 추론)을 지원합니다. 특정 모델의 Notebook 또는 항목 페이지에서 바로 일괄 처리 예측을 만들 수 있습니다. PREDICT 및 Fabric에서 사용하는 방법에 대한 자세한 내용은 Microsoft Fabric에서 PREDICT를 사용한 Machine Learning 모델 채점을 참조하세요.

위의 평가 결과에서 모델 1은 AUPRC(정밀도 회수 곡선) 아래의 영역과 AUC-ROC(곡선 수신기 작동 특성) 아래 영역 모두에 대해 가장 큰 메트릭을 가집니다. 따라서 예측에 모델 1을 사용해야 합니다.

AUC-ROC 측정값은 이진 분류자 성능을 측정하는 데 널리 사용됩니다. 그러나 때로는 AUPRC 측정값을 기반으로 분류자를 평가하는 것이 더 적절해집니다. AUC-ROC 차트는 TPR(참 긍정 비율)과 FPR(가양성 비율) 간의 절차를 시각화합니다. AUPRC 곡선은 단일 시각화에서 정밀도(양수 예측 값 또는 PPV) 및 회수(참 긍정 속도 또는 TPR)를 결합합니다.

# Load the best model
model_uri = f"models:/{EXPERIMENT_NAME}-lrmodel/1"
loaded_model = mlflow.spark.load_model(model_uri, dfs_tmpdir="Files/spark")

# Verify the loaded model
batch_predictions = loaded_model.transform(test_df)
batch_predictions.show(5)
# Code to save userRecs in the lakehouse
batch_predictions.write.format("delta").mode("overwrite").save(
    f"{DATA_FOLDER}/predictions/batch_predictions"
)
# Determine the entire runtime
print(f"Full run cost {int(time.time() - ts)} seconds.")