t-SNE 밑바닥부터 구현하기: 6차원의 덩어리가 어떻게 2D 지도로 풀려나가는가
요약
고차원 데이터를 2D로 시각화하는 차원 축소 알고리즘인 t-SNE의 작동 원리를 설명합니다. 가우시안 분포를 이용한 확률적 이웃 관계 설정과 밀집 문제를 해결하기 위한 스튜던트 t-분포 활용법을 다룹니다.
핵심 포인트
- t-SNE는 데이터 간의 국소적 유사성을 보존하며 차원을 축소함
- Perplexity 파라미터는 유효 이웃의 수를 결정하는 핵심 조절 장치임
- 스튜던트 t-분포를 사용하여 2D 공간의 밀집 문제(crowding problem)를 해결함
- 고차원의 거리를 확률 분포로 변환하여 최적화하는 과정을 거침
수십 또는 수백 개의 특징(feature)을 가진 데이터를 가지고 있고, 이를 직접 보고 싶다고 가정해 봅시다. 당신의 화면은 평면이므로, 문제는 다음과 같습니다: 고차원 공간(high-dim space)에 숨겨진 구조를 그림이 반영할 수 있도록 모든 점을 2D 지도 위에 어떻게 배치할 것인가? t-SNE는 바로 이 목적을 위해 만들어진 도구이며, 오늘 저는 브라우저에서 실행되는 모습을 직접 확인할 수 있는 작동 모델을 구현했습니다.
라이브 데모 (Run을 누르고 네 개의 클러스터가 분리되는 모습을 관찰하세요): https://dev48v.infy.uk/ml/day23-tsne.html
문제점: 고차원은 보이지 않는다
손글씨 숫자 이미지 데이터셋을 생각해 봅시다. 각 이미지는 784개의 숫자로 이루어져 있어, 이를 직접 눈으로 확인하는 것은 불가능합니다. 설상가상으로, 고차원 공간은 잔인한 속임수를 부립니다. 차원이 쌓일수록 거의 모든 점의 쌍이 대략 비슷한 거리에 놓이게 되어, 원시 거리(raw distances)는 약하고 흐릿한 신호가 되어버립니다. 모델이 아주 쉽게 찾아내는 클러스터(cluster)조차 당신의 눈에는 보이지 않게 됩니다.
차원 축소(Dimensionality reduction)는 데이터를 2D로 압축하여 당신이 말 그대로 데이터를 볼 수 있게 해줍니다. t-SNE (t-distributed Stochastic Neighbour Embedding)는 한 가지 명확한 절충(trade)을 통해 이를 수행합니다. 즉, _누가 누구와 가까운지_는 충실히 보존하되, 전역 기하학(global geometry)은 기꺼이 버리는 것입니다. 이 절충이 핵심이며, 이것이 바로 t-SNE 플롯을 매우 특정한 방식으로 해석해야 하는 이유입니다.
핵심 아이디어: 거리를 확률로 변환하기
t-SNE는 원시 거리를 최적화하지 않습니다. 각 점 $i$에 대해 다음과 같은 더 부드러운 질문을 던집니다: "만약 내가 거리에 따른 가우시안(Gaussian) 분포를 가중치로 두어 무작위로 이웃을 뽑는다면, $j$를 뽑을 확률은 얼마나 될까?" 가까운 점들은 높은 확률을 얻고, 먼 점들은 본질적으로 0에 가까운 확률을 얻습니다. 각 점의 답변은 해당 이웃들에 대한 확률 분포(probability distribution)를 형성합니다.
가우시안(Gaussian)의 너비는 고정되어 있지 않습니다. 분포가 사용자가 선택한 목표 "확산 정도(spread)"인 **perplexity (혼란도)**에 도달하도록 각 점마다 (이진 탐색을 통해) 조정됩니다. Perplexity는 대략 각 점이 주의를 기울이는 유효 이웃(effective number of neighbours)의 수이며, 일반적인 값은 5에서 50 사이입니다. 이는 가장 중요한 조절 장치입니다. 이 값이 너무 작으면 실제 클러스터가 종잇조각처럼 흩어져 버리고, 너무 크면 뚜렷한 그룹들이 서로 뭉개져 버립니다. 데모에서는 이 값을 드래그하며 레이아웃의 특성이 변하는 것을 관찰할 수 있습니다.
i가 j를 바라보는 관점과 j가 i를 바라보는 관점이 서로 다르기 때문에 (너비가 다르기 때문에), t-SNE는 이를 하나의 대칭적인 결합 행렬(symmetric joint matrix) P로 평균화하며, 모든 쌍의 합이 1이 되도록 정규화(normalise)합니다. 이 P가 2D 지도가 재현해야 할 고정된 목표입니다.
2D 측면, 그리고 이를 작동하게 만드는 한 가지 기묘한 트릭
2D 지도에서도 유사도(similarities)가 필요합니다. 여기서 t-SNE는 영리한 방식을 사용합니다. 또 다른 가우시안을 사용하는 대신, 자유도가 1인 스튜던트 t-분포 커널(Student-t kernel)인 1 / (1 + d²)을 사용합니다.
왜 그럴까요? 바로 crowding problem (밀집 문제) 때문입니다. 2D 공간은 고차원 공간보다 훨씬 더 좁기 때문에, 가우시안 지도를 사용하면 모든 것이 중앙의 더미로 압착됩니다. 스튜던트 t-분포의 두꺼운 꼬리(heavy tail)는 멀리 떨어진 쌍에 대해 천천히 감소하므로, 멀리 떨어진 점들이 큰 페널티 없이도 편안하게 멀리 떨어져 있을 수 있게 해줍니다. 이것이 바로 t-SNE가 임베딩 플롯에서 볼 수 있는 것처럼 선명하고 잘 분리된 섬(islands)들을 만들어내는 정확한 이유입니다.
목적 함수: KL divergence (KL 발산) 최소화
이제 두 개의 분포를 갖게 되었습니다: 고차원 목표인 P와 저차원 지도인 Q입니다. t-SNE는 Kullback–Leibler divergence (KL 발산), KL(P‖Q) = Σ Pᵢⱼ · log(Pᵢⱼ / Qᵢⱼ)를 사용하여 두 분포 사이의 불일치를 측정합니다. KL 발산은 비대칭적이기 때문에, P가 "가깝다"고 말한 곳에 지도상의 점들을 멀리 배치하는 것에 대해 그 반대의 경우보다 훨씬 더 큰 벌칙을 부여합니다. 따라서 t-SNE는 국소적 이웃(local neighbourhoods)을 격렬하게 보호하면서 전체적인 구조에 대해서는 느슨한 태도를 유지합니다.
최적의 레이아웃(layout)을 위한 폐쇄형 해(closed form)는 존재하지 않으므로, 우리는 경사 하강법 (gradient descent)을 통해 이를 찾아냅니다. 이 기울기 (gradient)에는 아주 멋진 스프링 해석이 가능합니다. 각 점은 P > Q인 쌍(더 가까워져야 하는 쌍)에는 끌리고 (attracted), Q > P인 쌍(더 멀어져야 하는 쌍)에서는 밀려납니다 (repelled). 이 힘은 Student-t 분자 값에 의해 스케일링됩니다. 모멘텀 (momentum)을 추가하고 매 단계마다 구름 (cloud)의 중심을 재설정하면, 점들이 제자리를 찾아 미끄러지듯 이동합니다.
6차원(4개의 가우시안 블롭 (Gaussian blobs))에서 80개의 점을 대상으로 시드(seed)를 설정하여 브라우저에서 실행해 본 결과, KL 발산 값은 500단계에 걸쳐 약 1.62에서 0.076으로 떨어졌습니다. 그리고 4개의 실제 클러스터 (clusters)는 구분이 불가능한 하나의 더미에서 조밀하고 잘 분리된 섬들로 변했습니다. 이때 클러스터 간/내 거리 비율 (between/within distance ratio)은 약 1에서 약 19로 급증했습니다. 데모의 색상은 결과를 판단할 수 있도록 실제 클러스터를 표시하지만, t-SNE는 레이블 (labels)을 전혀 보지 못합니다.
t-SNE 플롯에서 절대로 읽어서는 안 되는 것들
이 부분은 사람들이 자주 실수하는 지점이므로, 규칙으로서 명시합니다:
- 클러스터 간의 거리는 의미가 없습니다. 전역적 레이아웃 (global layout)은 의도적으로 희생되었습니다. 플롯에서 가깝게 위치한 두 클러스터가 멀리 떨어진 두 클러스터보다
대화형 버전 — perplexity (혼란도) 슬라이더, 실시간 KL readout (KL 판독값), step/run/reset (단계/실행/초기화), 실시간으로 분리되는 네 개의 클러스터 — 은 여기에서 확인할 수 있습니다: https://dev48v.infy.uk/ml/day23-tsne.html
내일 예고: UMAP — t-SNE보다 빠르고, 더 많은 전역적 구조 (global structure)를 유지하며, 새로운 데이터 포인트를 임베딩 (embedding)할 수 있습니다. UMAP은 이러한 플롯의 기본값 (default)으로 조용히 자리 잡았습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기