얼굴 이미지는 픽셀을 일렬로 펼치면 차원이 매우 커집니다(수천~수만 차원).
PCA로 “얼굴들이 주로 변하는 방향(주성분)”만 남겨 저차원 표현(=eigenface 계수)을 만들고, 그 공간에서 SVM으로 사람을 분류합니다.
fetch_lfw_people: LFW 얼굴 데이터 로더PCA: 주성분 분석SVC: RBF SVM 분류기StandardScaler: 스케일/표준화RandomizedSearchCV, loguniform: (C, γ) 하이퍼파라미터 탐색classification_report, ConfusionMatrixDisplay: 정량 평가/시각화이렇게 나누는 이유
fetch_lfw_people(min_faces_per_person=70, resize=0.4)핵심 파라미터:
min_faces_per_person=70
한 사람(클래스)당 최소 70장 이상 있는 사람만 남깁니다.
resize=0.4
이미지를 원본 대비 0.4배로 줄여 특징 수(n_features)를 크게 줄입니다.
데이터는 다음처럼 다룹니다.
lfw_people.images는 (n_samples, h, w) 형태의 이미지 텐서lfw_people.data는 (n_samples, n_features) 형태의 flatten된 벡터Total dataset size:
n_samples: 1288
n_features: 1850
n_classes: 7
→ 즉, 0.4 리사이즈 후에도 한 장이 1850차원(픽셀)로 꽤 큽니다.
train_test_split(test_size=0.25, random_state=42)test_size=0.25: 데이터의 25%를 테스트로 사용 random_state=42: 재현성(같은 분할 유지)예제에서는 1288장의 25%인 약 322장을 테스트로 쓰고, 나머지 966장으로 학습합니다.
StandardScaler()픽셀(feature)마다 분산이 다를 수 있고, 조명/명암으로 전체 값 범위가 흔들릴 수 있습니다.
StandardScaler는 각 feature에 대해
로 변환합니다.
Why Need
제가 실제로 경험해본 ML에서는
StandardScaler와whiten=True는 “둘 다 스케일링”이지만 대상이 다릅니다.
- StandardScaler: 픽셀(feature) 단위로 분산을 1로
- whitening: 주성분(component) 단위로 분산을 1로
둘을 동시에 쓰면 “픽셀 스케일 불균형”과 “주성분 스케일 불균형”을 모두 줄인다는 의도가 됩니다.
PCA(n_components=150, svd_solver="randomized", whiten=True)핵심 파라미터 3개를 분해해서 이해하면 됩니다.
n_components=150의 의미PCA는 공분산 의 고유값/고유벡터를 구해, 분산이 큰 순서대로 축을 정렬합니다.
상위 150개 성분만 남기면,
로 근사합니다.
왜 150?
예제 출력:
Extracting the top 150 eigenfaces from 966 faces
done in 0.087s
Projecting the input data on the eigenfaces orthonormal basis
done in 0.006s
svd_solver="randomized"의 의미randomized는 “상위 일부 성분만” 필요할 때 근사적으로 빠르게 구하는 알고리즘 계열입니다.whiten=True의 의미(수학/직관)PCA 변환 결과 는 성분 간 상관은 0이지만(대각 공분산), 각 성분의 분산은 로 다릅니다.
Whitening은
로 스케일링하여 모든 성분의 분산을 1로 맞춥니다.
장점: RBF SVM처럼 거리 기반 모델에서 “특정 주성분(큰 분산)”이 거리를 지배하는 현상을 줄여 등방성(isotropic)에 가깝게 만듭니다.
단점: 상대적 분산 정보(“어느 방향이 더 중요했는지”)를 일부 버리고, 작은 방향을 과증폭하여 노이즈를 키울 수도 있습니다.
pca.components_.reshape((n_components, h, w))pca.components_는 각 주성분 벡터 (길이 n_features)를 담습니다.핵심은 이 부분입니다.
모델: SVC(kernel="rbf", class_weight="balanced")
rbf는
형태의 커널을 씁니다.
class_weight="balanced"는 클래스별 샘플 수 차이를 보정해, 적은 클래스가 무시되지 않게 합니다.
탐색: RandomizedSearchCV(..., n_iter=10)
C ~ loguniform(1e3, 1e5)gamma ~ loguniform(1e-4, 1e-1)n_iter=10은 “예제 수준에서 시간 제한”을 고려한 단순한 예제를 보여주기 위함인 것 같습니다.예제 출력:
Fitting the classifier to the training set
done in 6.049s
Best estimator found by grid search:
SVC(C=..., class_weight='balanced', gamma=...)
classification_report: precision/recall/F1 등 지표ConfusionMatrixDisplay.from_estimator(..., display_labels=..., xticks_rotation="vertical")예제에서는 전체 정확도 약 0.84로 보입니다(테스트 322장 기준).
또한 Bush/Blair/Powell 등 인물이 상대적으로 잘 맞고, Chavez 같은 상대적으로 샘플이 적거나 변동이 큰 인물은 recall이 낮게 나올 수 있습니다.
plot_gallery(images, titles, h, w, n_row=3, n_col=4)figsize=(1.8*n_col, 2.4*n_row)는 12장(3×4)을 보기 좋게 배치하는 휴리스틱subplots_adjust로 여백/간격 조정title(...) 함수는 예측/정답 이름의 마지막 성(surname)만 뽑아 표시합니다(rsplit(" ", 1)).1) 차원 축소(속도/메모리)
픽셀을 펼친 특징은 매우 고차원입니다. RBF SVM 같은 모델은 입력 차원이 크면 학습이 느려지고 과적합 위험이 커집니다.
2) 노이즈/중복 제거(통계적 효율)
얼굴 이미지는 픽셀 간 상관이 큽니다(인접 픽셀 밝기 비슷). PCA는 상관 구조를 요약해 중복 정보를 압축합니다.
3) 샘플 수 < 차원(“small n, large p”) 문제 완화
얼굴 데이터는 보통 “사람 수/이미지 수”가 픽셀 차원보다 작기 쉬워 공분산 추정이 불안정합니다. PCA는 효과적인 저차원 표현을 제공합니다.
평균 얼굴 를 뺀 얼굴 벡터들의 공분산 에 대해
를 만족하는 고유벡터 를 이미지 모양으로 reshape한 것이 eigenface입니다.
직관: “데이터셋 전체에서 가장 자주 나타나는 변화 방향”을 얼굴 이미지 형태로 보여줌.
PCA가 버리는 것은 “작은 분산 방향”입니다. 구체적으로는:
1) 미세한 디테일/고주파 성분
고유값이 작은 성분은 데이터셋에서 덜 흔한 변화인데, 종종 미세한 구분 정보(점, 주름, 작은 윤곽)를 포함할 수 있습니다.
2) 분류에 유용하지만 분산이 작은 방향
PCA는 분산 최대화가 목적이지, 클래스 분리 최대화가 목적이 아닙니다.
→ “분류에는 중요하지만 전체 분산은 작다”면 잘릴 수 있습니다.
3) (예제의 전처리 자체가) 공간적 위치 관계
이미지를 벡터로 펼치므로 “눈-코-입의 상대 위치”라는 2D 구조적 제약은 모델이 직접 사용하지 못합니다.
PCA를 거친 좌표를 라고 하면:
선형 SVM이면:
로 표현되고, 결정경계는 PCA 공간에서 “평면(초평면)”입니다.
마진은 로, PCA 공간에서의 유클리드 거리 기준 최대 마진을 찾습니다.
RBF SVM이면:
결정함수는
형태로, PCA 공간에서 지원 벡터 주변에 방사형으로 영향이 퍼지는 비선형 경계가 만들어집니다.
Whitening이 켜져 있으면
가 사실상 원공간에서의 마할라노비스 거리와 유사한 의미를 갖습니다(각 주성분 분산을 1로 맞췄기 때문).
즉, “큰 분산 축만 과대평가하지 않는 거리”로 RBF가 작동합니다.
n_components를 바꾸면?k를 줄이면: 근사에서 더 많은 성분이 누락 → 재구성 오차 증가
k를 늘리면: 근사 오차 감소, 하지만 노이즈/희귀 변동까지 포함 가능
resize를 바꾸면?해상도는 곧 n_features입니다.
whiten을 끄면?해당 코드에서 가져가는 구조는 표준화, PCA, SVM을 load_digits 으로 실행하고 있습니다.
그래서, 동일한 구조(표준화→PCA→SVM)를 load_digits로 실행해 “전처리 차이가 결과에 어떤 영향을 주는지”를 확인했습니다.
열심히 해석해 본 결과:
노이즈가 섞인 이미지 를
PCA 또는 KernelPCA로 저차원 표현으로 투영한 뒤 다시 복원하여 성분을 줄입니다.
fetch_openml(data_id=41082) + MinMaxScaler()왜 MinMaxScaler로 [0,1]?
scale=0.25 같은 값은 입력 스케일에 민감합니다.gamma도 거리 스케일에 매우 민감하므로, 스케일을 고정하는 것이 중요합니다.train_size=1000, test_size=100, stratify=y, random_state=0
가우시안 노이즈:
noise ~ Normal(0, 0.25^2)MSE가 왜 약 0.06인가?
노이즈만 생각하면, 각 픽셀에 대해 이므로
이고 예제에서 보고되는 0.06과 비슷해집니다(표본 오차).
plot_digits: 10x10 그리드로 100장 시각화plt.subplots(nrows=10, ncols=10, figsize=(8,8))img.reshape((16,16)) 해서 16x16 이미지로 복원해 보여줌왜 16x16?
n_components=32n_components=400kernel="rbf"gamma=1e-3fit_inverse_transform=Truealpha=5e-3핵심 포인트는 KernelPCA는 inverse_transform이 “학습된 근사 함수”라는 점입니다.
fit_inverse_transform=True이면, “특징공간(커널 공간)에서의 저차원 좌표 → 원공간 이미지”로 되돌리는 함수를 추정합니다.
PCA:
KernelPCA:
inverse_transform이 바로 이 근사 복원을 수행Noisy test images: MSE ≈ 0.06
PCA reconstruction: MSE ≈ 0.01
Kernel PCA reconstruction: MSE ≈ 0.03
원문은 “PCA의 MSE가 더 낮지만, KernelPCA는 배경 노이즈를 더 없애 더 부드럽게 보일 수 있다”는 정성 분석을 함께 제공합니다.
전제가 하나 있습니다: 신호는 저차원 구조(상관됨), 노이즈는 대체로 등방성(비상관)이고 분산이 작다.
즉, 디노이징은
라는 저랭크 근사(low-rank approximation)로 이해할 수 있습니다.
단, 복원(inverse)은 PCA처럼 닫힌형이 아니라 “근사”이므로, 파라미터(γ, α 등)에 따라 성능이 크게 달라집니다.
KernelPCA에서 투영은 특징공간 에서 이루어집니다.
즉,
에서 마지막 역함수 가 없거나 계산 불가능한 상황이 pre-image problem입니다.
scikit-learn은 fit_inverse_transform=True에서 추정 문제(회귀)로 이를 근사해 해결합니다(예제는 “Learning to find pre-images”를 참고로 듭니다).
(질문 문장 자체는 “둘 다 좋아짐”이라 모순은 없지만, 실제로는 아래 두 현상이 모두 가능합니다.)
1) MSE와 시각 품질이 같이 좋아지는 경우
KernelPCA가 매니폴드 구조를 잘 잡아 “진짜 숫자 모양”을 더 잘 복원하면
2) MSE는 낮은데, 시각적으로는 별로인 경우(혹은 반대)
KernelPCA의 기하학은 “특징공간에서의 PCA”입니다.
1) 커널 정의:
2) 훈련 샘플로 커널 행렬 구성 후 중심화(center)
3) 고유분해:
4) 새로운 점의 j번째 좌표는
즉, 원공간에서 보면 비선형으로 휘어진 좌표계를 학습해 저차원으로 펼치는 것과 같습니다.
RBF 커널은 특히 “가까운 점들”의 관계를 강조하는 국소적(로컬) 기하를 만듭니다.
핵심 차이 3가지:
1) 선형 PCA는 보통 ‘적은 성분’으로도 큰 분산을 설명
숫자 이미지는 상관이 커서 상위 32개 PC만으로도 꽤 많은 구조를 담을 수 있습니다.
2) KernelPCA의 성분은 ‘샘플 수’에 의해 제한
KernelPCA는 (n_samples × n_samples) 커널 행렬의 고유벡터를 쓰므로, 성분 수는 최대 n_samples입니다.
예제는 train이 1000이므로 400을 택해 “비선형 표현력을 충분히” 확보합니다.
3) inverse_transform이 근사라서 성분 수가 너무 적으면 복원이 급격히 나빠질 수 있음
KernelPCA는 “좌표→원공간” 복원을 회귀로 근사하는데, 좌표 자체가 지나치게 압축되면 원공간 복원이 불안정합니다.
fit_inverse_transform=True일 때, scikit-learn은 inverse mapping을 ridge regression(L2 정규화)로 학습합니다.USPS 대신 load_digits(8×8=64차원)를 사용해 같은 절차를 실행해 보았습니다.
→ KernelPCA가 더 낮은 MSE로 복원한 사례(매니폴드/비선형성 이점).
그러니까 γ는 “너무 작아도/커도” 망가지고, 데이터 스케일에 맞는 적정 폭이 필요합니다.
성분 수를 늘리면 복원력은 좋아지지만(오차 감소), 너무 늘리면 노이즈까지 복원될 수 있어 “적정점”을 찾아야 합니다.
1) Eigenfaces는 “얼굴 데이터의 주된 변동 패턴”을 저차원 기저로 만든 것이며, 분류기는 그 좌표(계수) 공간에서 학습됩니다.
2) PCA는 차원 축소 + 노이즈 억제 + 상관 제거로 고차원 이미지 문제를 전통 ML 모델이 다룰 수 있게 만듭니다.
3) Whitening은 거리 기반 모델의 등방성 가정에 도움을 줄 수 있지만, 항상 이득이 아니며 데이터/노이즈 구조에 따라 성능을 깎을 수도 있습니다.
4) 디노이징에서 KernelPCA는 비선형 매니폴드를 더 잘 따라가 복원이 좋아질 수 있지만, inverse_transform이 pre-image 근사 문제이므로 (γ, α, n_components) 튜닝이 성능을 좌우합니다.
보고서작성할 때 읽은 닥스들입니다.
scikit-learn Eigenfaces example:
https://scikit-learn.org/stable/auto_examples/applications/plot_face_recognition.html
scikit-learn Denoising using kernel PCA example:
https://scikit-learn.org/stable/auto_examples/applications/plot_digits_denoising.html
PCA API:
https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html
KernelPCA API:
https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.KernelPCA.html