본문 바로가기
딥러닝 with Python

[딥러닝 with Python] LIME이란? (Local Interpretable Model-Agnostic Explanations) / Google Colab으로 LIME 구현해보기

by CodeCrafter 2025. 6. 7.
반응형

 

1. LIME이란?

- LIME은 Local Interpretable Model Agnostic Explanations의 줄임말로, 복잡한 인공지능 모델의 Black box문제를 해결하고 입력과 출력의 관계에 집중하여 모델의 결과에 대한 해석력을 제공하는 모델입니다.

 

- 현대의 딥러닝, 앙상블 모델 등 높은 정확도를 얻기 위해서는 모델이 점차 더 복잡해지고 이러 인해 설명가능성이 부족해지고 있습니다. 

 

- 이러한 설명가능성의 부재는 모델에 대한 신뢰도 / 수용 가능성 등에 문제를 일으키게 되는데요.

- 특히, 모델이 제시하는 결과물은 복잡한 행렬연산과 미분의 상호작용에 따른 결과물이기에 사람이 이해하기에는 어렵습니다. 

 

- 이로 인해 제안된 방법이 LIME 입니다.

 

-LIME의 핵심 아이디어는 다음과 같습니다.

 " 복잡한 모델의 전체를 설명하려 하지 말고, 관심 있는 특정 입력 데이터 주변에서만 그 모델의 행동을 근사하여 이해하자" 입니다.

 

즉, 설명하려는 대상 x를 기준으로

 * 그 주변에 있는 데이터를 생성(perturbation)하고

 * 원래 모델 f에 대한 예측값을 얻은 후

 * 그 결과를 바탕으로 간단한 모델인 g(선형회귀 등)에 로컬로 근사하는 것입니다.

 

 

- LIME에 대한 알고리즘을 정리하면 다음과 같은 순서입니다.

 

 1) 설명하고자하는 인스턴스 x를 선택

 ex. 이 환자는 왜 악성으로 분류되었지?

 

 2) x 주변이 데이터 포인트인 z를 생성

 * 입력 공간에서 feature를 무작위로 제거하거나 변경하여 perturbated 샘플을 생성

 

 3) 원래 모델인 f로 각 z에 대한 예측값이 f(z)를 계산

 * 복잡한 모델을 직접 사용 (XGBoost, Random Forest 등 실제 예측에 활용한 복잡한 모델 / 설명하고자 하는 모델)

 

4) 각 z에 대해 원래 x와의 거리인 phi_x(z)를 계산합니다.

 * 일반적으로 RBF 가우시안 커널을 사용하여 아래와 같은 식으로 거리가 계산됩니다.

 

5) 로컬 Surrorgate 모델인 g를 학습 (예: Lasso 선형 회귀 등)

 * 입력

* 목적 : 가중 회귀로 g를 학습하여 f를 근사

 

6) g이 계수 해석 후 설명

 ex) concave points mean 값이 0.14 이상이면 악성일 가능성이 증가

 

 

이 과정을 수학적 공식으로 정리해보면 아래와 같습니다.

 

- LIME의 장점과 한계는 아래와 같습니다.

 1) 장점

  * 해석 용이한 설명을 제공

  * 모든 모델에 적용 가능

  * 로컬 설명 제공

 2) 단점

  * perturbation 방식이 임의적일 수있음

  * 입력공간에 따라 설명 일관성이 낮을 수 있음

  * Global behavior에 대한 설명은 불가능 

 

 

 

2. LIME Python을 활용해 구현해보기

 

이번에는  실제 Python 코딩을 활용해 LIME을 구현해보고 그 결과를 시각화 해보겠습니다.

 

구현 환경은 Google Colab입니다.

 

1) 먼저 데이터를 불러오겠습니다. 데이터는 breast cancer 데이터이고 양성 또는 악성의 이진 분류 문제입니다.

# 1. 필요한 패키지 임포트
from sklearn.datasets import load_breast_cancer
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 2. 데이터 불러오기
data = load_breast_cancer()
X = data.data
y = data.target
feature_names = data.feature_names

# 3. DataFrame으로 변환
df = pd.DataFrame(X, columns=feature_names)
df['target'] = y

# 클래스 분포 확인
print(df['target'].value_counts())

 

총 569개 데이터 중 양성은 357개 악성은 212개 입니다.

데이터의 feature 들간의 상관관계를 시각화 해보면 아래와 같습니다.

 

2) 이제 데이터를 train과 test로 분할하고 분할된 결과의 클래스별 비율을 시각화해보겠습니다.

from sklearn.model_selection import train_test_split

# 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, stratify=y)

# 클래스 비율 시각화 함수
def plot_split_ratio(y_train, y_test):
    fig, axes = plt.subplots(1, 2, figsize=(10, 4))

    sns.countplot(x=y_train, ax=axes[0])
    axes[0].set_title("Train Class Distribution")
    axes[0].set_xlabel("Class")
    axes[0].set_ylabel("Count")

    sns.countplot(x=y_test, ax=axes[1])
    axes[1].set_title("Test Class Distribution")
    axes[1].set_xlabel("Class")
    axes[1].set_ylabel("Count")

    plt.tight_layout()
    plt.show()

# 시각화 실행
plot_split_ratio(y_train, y_test)

 

3) 이제 모델을 학습시키고 그 결과를 확인해보겠습니다. 모델은 앙상블 모델의 대표격인 RandomForest이고, 예측은 Accuracy로 test 데이터에 대해 진행했습니다.

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# 모델 학습
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# 예측 및 정확도
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"✅ Random Forest Test Accuracy: {accuracy:.4f}")

 

결과는 95.8%의 분류 정확도를 보입니다.

 

4) 이제 해석을 위 결과에 따른 feature importance를 시각화해봅니다.

 

import numpy as np

# 중요도 추출 및 시각화
importances = model.feature_importances_
indices = np.argsort(importances)[::-1][:10]  # 상위 10개 feature만 표시

plt.figure(figsize=(10, 5))
sns.barplot(x=importances[indices], y=feature_names[indices])
plt.title("Top 10 Feature Importances from Random Forest")
plt.xlabel("Importance")
plt.ylabel("Feature")
plt.tight_layout()
plt.show()

 

worst area가 가장 높은 영향도를 줌을 알 수 있습니다.

 

5) 이제 LIME으로 보다 정확한 해석을 해보겠습니다. 먼저 LIME package를 설치해줍니다.

 

!pip install lime

 

그리고 특정 샘플(idx=12)에 대해 왜 양성 또는 악성으로 예측되었는지를 feature 단위로 시각적으로 보여주었습니다.

import lime
import lime.lime_tabular

# LIME Explainer 생성
explainer = lime.lime_tabular.LimeTabularExplainer(
    training_data=X_train,
    feature_names=feature_names,
    class_names=data.target_names,
    mode='classification'
)

# 설명할 샘플 선택
idx = 12
sample = X_test[idx]

# LIME 설명 생성
exp = explainer.explain_instance(
    data_row=sample,
    predict_fn=model.predict_proba,
    num_features=8
)

# 설명 결과 시각화
exp.show_in_notebook()

 

 

예측 결과는 악성(malignant)이고, 예측확률은 94%입니다. 

이 샘플은 worst area, worst radius, worst perimeter, concave points 등이 모두 높은 편이며, 이에 기반해 모델은 악성 종양일 가능성이 높다고 판단한 것입니다.

 

6) 설명된 feature 및 weight를 추출해서 더 자세히 알아보겠습니다.

 

# 설명된 feature 및 weight 추출
local_weights = dict(exp.as_list())

# 시각화
import seaborn as sns
plt.figure(figsize=(8, 4))
sns.barplot(x=list(local_weights.values()), y=list(local_weights.keys()))
plt.title("LIME Explanation (Local Feature Weights)")
plt.xlabel("Weight")
plt.ylabel("Feature")
plt.tight_layout()
plt.show()

 

X축은 각 feature의 LIME weight인 기여도

Y축은 해당 샘플의 feature 조건 (임계값 기준) 이며

 

음수방향은 해당 feature의 조건이 malignant(악성)쪽으로 기여함을 의미하며, 양수방향은 bening(양성)쪽으로 기여하는 feature를 의미하는데 이 그래프에는 없습니다.

 

이를 통해 해석을 내려보면

 

이 샘플은 전반적으로 크기(radius, area, perimeter)가 매우 큰 종양이며, 

외곽형태가 불규칙(concave points가 높음)하기 때문에 모델이 이 샘플을 악성 (malignant) 종양으로 강하게 판단한 것입니다.

 

 

반응형

댓글