지난 포스팅에서는 Model Drift의 개념과 발생원인에 대해서 정리해보았다.
> Model Drift의 개념과 원인 (+ Data Drift, Label Drift, Concept Drift)
https://familia-89.tistory.com/69
잠깐 리마인드해보자면,
model drift가 발생했을때, 가장 대표적인 원인으로는 data drift, label drift, concept drift를 꼽을 수 있었다.
data drift는 학습당시의 데이터분포와 프로덕트단에서 input되는 데이터의 분포가 상이할 때 발생하는 성능 저하 현상이다.
label drift는 target데이터 분포가 학습당시와 프로덕트 단에서 차이가 있을 경우, 발생하는 성능 저하 현상이다.
마지막으로, concept drift는 feature와 target간의 관계가, 학습당시와 달라질 경우 발생할 수 있는 성능 저하 현상이다.
다만, 실제 프로덕트에서 위와 같이 model drift가 발생했을때, 원인을 정확히 정의하기 위해서는 그에 맞는 적절한 검증법을 통한
실험으로써 drift의 원인을 찾을 수 있다.
오늘은 Data Drift를 detection할 수 있는 검증방법들을 살펴보자.
Data/Label Drift Detection
Statistical Tests(통계적 검정)
: 학습데이터와 프로덕트단에서 input되는 데이터 집합간의 분포차이를 수치화하여 이상여부를 판단하는 방법이다.
1. Kolmogorov-Smirnov Test(이하 KS Test)
KS Test 검증법은 두 표본내의 각각의 원소(포인트)에 대한 누적분포를 계산한 후, 두 집합내의 동일한 포인트간의 누적분포 수치 차이를 구한 후, 그 중 '최대 누적분포 차이'를 통해, 두개의 표본이 같은 같은 분포를 가지는지를 검증하는 방법이다.
여기서 *누적분포에 대해서 잠시 알아보자.
- 표본 A : [1,2,3,4,5]
- 표본 B : [2,3,4,5,6]
위와 같은 두개의 표본이 있을때, 각 표본의 누적분포는 아래와 같이 구할 수 있다.
- 표본A의 누적분포
- 1이하의 값의 비율 : 1/5 = 0.2
- 2이하의 값의 비율 : 2/5 = 0.4
- 3이하의 값의 비율 : 3/5 = 0.6
- 4이하의 값의 비율 : 4/5 = 0.8
- 5이하의 값의 비율 : 5/5 = 1.0
- 따라서 표본A의 누적분포는 -> [0.2, 0.4, 0.6, 0.8, 1.0]으로 구할 수 있다.
- 동일한 방법으로 계산한 표본 B의 누적분포는 [0.2, 0.4, 0.6, 0.8, 1.0] 이다.
결국, 분포의 각 포인트별 누적분포를 비교했을때, '최대 누적분포'는 0이므로, 두 분포간의 차이는 없다고 판단할 수 있다.
python에서는 KS Test를 진행할 수 있는 라이브러리를 제공하고 있다.
import numpy as np
import scipy.stats as stats
# 샘플 데이터 생성
np.random.seed(0)
train_set = np.random.normal(0, 1, 1000) # 초기 데이터셋 (정규 분포)
product_set = np.random.normal(0.1, 1.1, 1000) # 새로운 데이터셋 (분포 약간 다르게)
ks_statistic, p_value = stats.ks_2samp(train_set, product_set)
print(f"KS Test Score: {ks_statistic}")
[output] KS Test Score: 0.086
Population Stability Index (PSI)
: PSI 또한 두 집단간 분포의 차이를 통해 계산하는 방식이라는 점은 위 KS Test와 동일하지만, 각 원소의 분포를 비교하는것이
아닌, 구간별 분포를 비교한다는 부분에 있어 차이점이 있다. 그리고 PSI는 데이터 구간내에서 '기대빈도'와 '실제빈도'사이의 차이를
비율로 표현하여 데이터 집단간의 분포차이를 수치화한다는 점이 특징이다.
아래 예시를 통해 확인해보자.
- 표본 A : [1,2,2,3,4]
- 표본 B : [2,3,3,4,5]
1단계) 데이터 구간 나누기
예를들어 위 표본을 아래와 같이 세 구간으로 나눈다.
- 구간1 : [1-2]
- 구간2 : [3-4]
- 구간3 : [5]
2단계) 구간별 데이터 비율 계산
표본 A와 표본B의 각 구간에서 데이터 비율을 계산한다.
- 표본 A
- 구간1 : 3/5 (원소 1,2,2가 여기 속한다)
- 구간2 : 2/5 (원소 3,5가 여기 속한다)
- 구간3 : 0/5 (해당하는 원소가 없다)
- 표본 B
- 구간1 : 1/5 (원소 2가 여기 속한다)
- 구간2 : 3/5 (원소 3,3,4가 여기 속한다)
- 구간3 : 1/5 (원소5가 여기 속한다)
3단계) PSI 계산
PSI는 다음 공식을 사용하여 계산된다.
위 예시 표본을 통해, PSI를 계산해보자.
- 구간 1: (0.2-0.6) x ln(0.2/0.6)
- 구간 2: (0.6-0.4) x ln(0.6/0.4)
- 구간 3: (0.2-0) x ln(0.2/(0+
import numpy as np
# 샘플 데이터 생성
np.random.seed(0)
train_set = np.random.normal(0, 1, 1000) # 초기 데이터셋 (정규 분포)
product_set = np.random.normal(0.1, 1.1, 1000) # 새로운 데이터셋 (분포 약간 다르게)
# PSI 계산 함수
def calculate_psi(train_set, product_set, buckets=10):
# 구간 분할
breakpoints = np.linspace(np.min([train_set.min(), product_set.min()]), np.max([train_set.max(), product_set.max()]), num=buckets + 1)
train_set_counts = np.histogram(train_set, breakpoints)[0]
product_set_counts = np.histogram(product_set, breakpoints)[0]
# 분포 비율 계산
train_set_ratios = train_set_counts / train_set_counts.sum()
product_set_ratios = product_set_counts / product_set_counts.sum()
# PSI 계산
psi_value = np.sum((product_set_ratios - train_set_ratios) * np.log((product_set_ratios + 1e-10) / (train_set_ratios + 1e-10)))
return psi_value
psi_value = calculate_psi(train_set, product_set)
print(f"PSI: {psi_value}")
[output] PSI: 0.10168885498870324
어느정도의 PSI 수치가 관찰되었을때, 주의가 필요하거나 데이터분포에 유의미한 변화가 있다고 가정할 수 있을지는
상황에 따라 경험적, 실험적인 판단이 필요하겠지만,
보통 0.1~0.2구간에서는 주의가 필요하며, 0.25이상의 차이가 관측될 경우 모델이나 데이터분포에 큰 변화가 있음을 의미하며
모델 또는 데이터 전략에 수정이 필요할 것으로 판단할 수 있다.
Visualization (시각화)
마지막으로, 데이터 분포의 변화를 시각화를 통해 직관적으로 파악하는 방법이다.
예를들어, 각 Feature의 최대값, 최소값, 평균값, 상관계수 등의 수치를 시간에 흐름에 따른 변화량을 관찰하는 방법이다.
가장 직관적이고 손쉽게 데이터의 변화 여부를 파악할 수 있다.
마치며
오늘은 여러 model drift의 원인 중 Data Drift 또는 Label Drift를 detection할 수 있는 여러 방법들을
정리해보았다. 간단하게는 feature별 분포의 변화를 통해 데이터 변화를 관측할 수 있었고,
PSI, KS Test를 통해 조금 더 객관적으로 기준데이터와 관찰데이터의 차이를 수치화할 수 있었다.
그리고, KS Test의 경우 표본 내 각 값들 사이의 분포를 비교한다면, PSI는 구간 내 데이터의 비교를 통해 차이를 관측하는 방법이므로,
목적과 상황에 따라 적절히 사용할 수 있도록 해야겠다.
다음에는 Concept Drift를 detction할 수 있는 검증방법에 대해 정리해보도록 하자.
Reference
1) Scipy document
https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ks_2samp.html
2) Blog
https://www.fiddler.ai/blog/measuring-data-drift-population-stability-index
https://roytravel.tistory.com/349
https://abluesnake.tistory.com/163
'DEVELOP_NOTE > MLOps' 카테고리의 다른 글
Drift를 감지하는 방법 (2) Concept Drift Detection (+ADWIN, Page-Hinkley Test, CUSUM, DDM) (0) | 2023.12.19 |
---|---|
Model Drift의 개념과 원인 (+ Data Drift, Label Drift, Concept Drift) (0) | 2023.12.16 |
MLOps란? (0) | 2023.12.14 |