My Data Story

[군집] 활용 - 이미지 분할, 전처리, 준지도 학습 본문

Machine Learning/3. 비지도 학습 알고리즘

[군집] 활용 - 이미지 분할, 전처리, 준지도 학습

Hwasss 2023. 8. 19. 00:55
728x90

◈  '군집 활용' 목차 

1. 개요

2. 이미지 분할, 전처리, 준지도 학습

    사이킷런에서 군집을 활용해 이미지 분할, 데이터 전처리, 준지도 학습에 활용하는 방법에 대해 알아보자.

3. 이상치 탐지, 특이치 탐지


1. 군집을 사용한 이미지 분할

이미지 분할은 이미지를 세그먼트 여러 개로 분할하는 작업이다.

시맨틱 분할에서는 동일한 종류의 물체에 속한 모든 픽셀은 같은 세그먼트에 할당한다.

예를 들어 자율 주행 자동차의 비전 시스템에서 보행자 이미지를 구성하는 모든 픽셀을 '보행자' 세그먼트에 할당될 것이다.

이 경우 각 보행자는 다른 세그먼트가 될 수 있다. 

 

여기서는 훨씬 쉬운 작업인 색상 분할을 수행해보도록 하겠다.

 

from matplotlib.image import imread

image = imread(os.path.join('images', 'unsupervised_learning', 'ladybug.png'))
print(image.shape) #(533, 800, 3)

X = image.reshape(-1,3)
kmeans = KMneas(n_clusters=8).fit(X)
segmented_img = kmeans.cluster_centers_[kmeans.labels]
segmented_img =

 

 

2. 군집을 사용한 전처리

군집은 차원 축소에 효과적이다. 특히 지도 학습 알고리즘을 적용하기 전에 전처리 단계로 사용할 수 있다.

 

차원 축소에 군집을 사용하는 예를 위해 숫자 데이터 셋을 활용해 살펴보자.

 

숫자 이미지를 분류하는 모델을 만들기 전에, GridSearch를 통해 적절한 k개 선정하고, 군집을 활용해 각 특성을 k개의 클러스터까지의 거리로 바꾸는 전처리를 진행한 후 모델 훈련을 진행한다.

 

적절한 k개 선정할 때 실루엣 분석하거나 이너셔의 감소를 확인할 필요 없다.

적절한 k값은 교차 검증에서 가장 좋은 분류 성능을 내는 값이다.

 

from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.cluster import KMeans
from sklearn.linear_model import LogisticRegression

X_digits, y_digits = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X_digits, y_digits)

param_grid = dict(kmeans_n_cluster=range(2,100))

pipeline = Pipeline([
      ('kmeans', Kmeans(n_clusters=50)),
      ('log_reg', LogisticRegression())
  ])

grid_clf = GridSearchCV(pipeline, param_grid, cv=3, verbose=2)
grid_clf.fit(X_train, y_train)

print(grid_clf.best_params_)
print(grid_clf.score(X_test, y_test))

 

 

3. 군집을 사용한 준지도 학습

레이블이 없는 데이터가 많고 레이블이 있는 데이터가 적을 때 군집을 활용해 준지도 학습을 적용한다. 

 

숫자 데이터 셋에서 1~50 까지만 레이블 존재하는 상황에서 준지도 학습을 통해 모델 훈련시켜보자. 

 

 

step1

모든 훈련 세트를 50개의 클러스터로 모은다. (클러스터 갯수 = 레이블 개수)

 

 

step2

각 클러스터에서 센트로이드에 가장 가까운 이미지를 찾는다. 이런 이미지를 대표 이미지라 부른다.

 

k=50
kmeans = KMeans(n_cluster=50)
X_digit_dist = kmeans.fit_transform(X_train)
representative_digit_idx = np.argmin(X_digit_dist, axis=0)
X_representative_digits = X_train[representative_digit_idx]

 

 

step3

전문가가 직접 이미지를 보고 수동으로 레이블을 할당한다. 하지만 전문가가 수동으로 레이블을 할당하는 일은 비용이 많이 들므로 무작위 샘플 대신 대표 이미지에 대해서만 레이블을 할당하는 것도 좋다. 

y_representative_digits = np.array([4,8,0,6,8,3 ... ,7,6,2,3,1,1])

 

 

step4

이제 이 레이블(대표 이미지에 대해 전문가가 직접 할당한 레이블)을 동일한 클러스터에 있는 모든 샘플에 전파한다. 

 

y_train_propageted = np.empty(len(X_train), dtype=np.int32)

for i in range(k) : 
   #각 클러스터의 대표 이미지에 할당된 레이블을 같은 클러스터 내 샘플에도 레이블로 전파
   y_train_progaeted[kmeans.labels_ == i] = y_representative_digits[i]

 

 

step5

모델을 훈련하고 성능을 확인해본다. 

 

log_reg = LogisticRegression()
log_reg.fit(X_train, y_train_propagated)
print(log_reg.score(X_test, y_test))

 

 

step6

동일한 클러스터의 모든 샘플에 전파했기에, 클러스터 경계에 가깝게 위치한 샘플이 포함된 경우 잘못된 레이블을 부여했을 수도 있다. 이를 방지하기 위해 센트로이와 가까운 샘플 20%만 레이블을 전파할 수도 있다.

 

percenetile_closest = 20
X_clust_dist = X_digit_dist[np.arrange(len(X_train)), kmeans.labels_]
y_train_propageted = np.empty(len(X_train), dtype=np.int32)

for i in range(k) : 
   #특정 클러스터에 속하는 샘플만 추출하여, 센트로이드에서 가장 가까운 20% 위치 거리를 찾는다.
   in_cluster = (kmeans_labels==i)
   cluster_dist = X_cluster_dist[in_cluster]
 
   cutoff_distance = np.percentile(cluster_dist, percentile_closest)
   above_cutoff = (X_clust_dist > cutoff_distance)
   X_clust_dist[in_cluster & above_cutoff] = -1
   

partially_propagated = (X_cluster_dist!=-1)

X_train_partially_propagated = X_cluster_dist[partially_propagated]
y_train_partially_propagated = y_train_propagated[partially_propagated]

 

 

cf. 능동 학습

모델과 훈련 세트를 지속적으로 향상하기 위해 다음 단계로 능동 학습을 몇 번 반복할 수 있다. 이 방법은 전문가가 학습 알고리즘과 상호작용하여 알고리즘이 요청할 때 특정 샘플의 레이블을 제공해야 한다.  능동 학습의 전략 중 불확실성 샘플링이 가장 많이 사용된다. 

 

■ 전략1

모델이 가장 불확실하게 예측하는 샘플(추정 확률 낮은 샘플)을 전문가가 레이블을 제공한다. 

 

 전략2

모델을 가장 크게 바꾸는 샘플이나 모델의 검증 점수를 가장 크게 떨어뜨리는 샘플 또는 여러 알고리즘의 모델이 동일한 예측을 내지 않는 샘플에 대해 전문가가 레이블을 제공한다.