L2 정규화, 방향, 길이, classifier와 embedding
“방향이 뭔가?”, “길이는 세기인가?”, “C 방향이 강하면 C일 확률이 높은 것 아닌가?”에 대한 답변.
Q&A 열기Core Knowledge · 2026-05-19
이 문서는 “비슷해서 그렇다” 수준이 아니라, 모델이 실제로 어떤 숫자를 만들고, 그 숫자가 왜 그렇게 나오며, 우리가 무엇을 바꾸면 점수가 바뀌는지를 설명한다. 최초 작성 시 예시는 Sprint 1의 MobileCLIP2-S4/13-class 기준이었지만, 현재 개념 설명은 MobileCLIP2-S3/S4와 23-class 앱 후보에도 동일하게 적용한다.
Landmark Assistant의 이미지 검색 점수는 확률이 아니라 입력 이미지 embedding과 랜드마크 prototype embedding 사이의 cosine similarity다. 따라서 40%는 “정답 확률 40%”가 아니라 “대표 embedding과의 방향 유사도가 0.40”이라는 뜻이다.
사용자가 업로드한 이미지는 먼저 모델이 볼 수 있는 숫자 텐서로 바뀐다. 그 다음 MobileCLIP2 image encoder와 프로젝트용 embedding/projection layer를 지나 512차원 embedding이 되고, 이 embedding을 랜드마크별 대표 prototype과 비교한다.
모델은 JPG, PNG, WEBP 같은 파일을 그대로 이해하지 않는다. 이미지는 픽셀 숫자의 묶음으로 바뀌고, 그 숫자 묶음이 tensor 형태로 모델에 들어간다.
| 단계 | 무슨 일이 일어나는가 | 왜 필요한가 |
|---|---|---|
| RGB 변환 | 이미지를 3개 색 채널 Red, Green, Blue로 맞춘다. | 모델은 정해진 채널 순서를 기대한다. |
| Resize | 이미지 크기를 학습 때 사용한 입력 크기에 맞게 줄이거나 키운다. | 모델 내부 연산은 고정된 입력 크기를 기준으로 설계된다. |
| Center crop | 가운데 영역을 정사각형으로 잘라낸다. | 모델 입력을 (3, H, W) 형태로 맞춘다. |
| Normalize | 픽셀값에서 평균을 빼고 표준편차로 나눈다. | 학습 때 본 숫자 분포와 추론 때 숫자 분포를 맞춘다. |
입력 tensor 예시
shape: (batch, channel, height, width)
예: (1, 3, 224, 224) 또는 (1, 3, 256, 256)
dtype: float32
값: RGB 픽셀을 normalize한 숫자
MobileCLIP2는 기본적으로 이미지를 바로 “광화문”, “청계천”으로 분류하는 모델이 아니다. CLIP 계열 모델은 이미지와 텍스트를 같은 의미 공간의 vector로 바꾸는 dual encoder다.
우리 프로젝트는 여기에 랜드마크 분류 학습을 위해 classifier head를 붙였다. 학습 과정에서는 classifier처럼 학습했지만, 데모앱 검색 점수는 classifier 확률이 아니라 embedding 유사도 기반이다.
학습 시 구조
MobileCLIP2 image encoder
-> 프로젝트용 embedding layer
-> classifier head
-> landmark 분류 loss
데모 검색 시 주요 사용값
입력 이미지
-> 512차원 normalized embedding
-> landmark prototype과 cosine similarity 비교
Embedding은 이미지나 텍스트를 숫자 좌표로 바꾼 것이다. 우리 데모앱의 이미지 embedding은 보통 512개의 float 숫자로 구성된다.
예시: 실제 값은 매번 다름
[ 0.013, -0.042, 0.087, ..., -0.006 ]
shape: (512,)
meaning: 사람이 직접 이름 붙이기 어려운 512개의 의미 좌표
각 숫자가 “광화문 점수”, “청계천 점수”처럼 class에 직접 대응하는 것은 아니다. Embedding은 이미지를 의미 공간의 한 점 또는 한 방향으로 표현한 것이다.
Prototype은 특정 랜드마크를 대표하는 embedding이다. 예를 들어 광화문 이미지 여러 장을 embedding으로 바꾼 뒤 평균을 내면 광화문 prototype을 만들 수 있다.
검색 시에는 입력 이미지 embedding과 각 prototype embedding을 비교한다. 둘 다 L2 정규화되어 있으면 내적값이 곧 cosine similarity가 된다.
cosine similarity
= input_image_embedding · landmark_prototype_embedding
예:
입력 이미지 vs gwanghwamun prototype = 0.44
입력 이미지 vs naksan_park prototype = 0.10
입력 이미지 vs changgyeonggung prototype = 0.05
0.4는 확률이 아니라 embedding 유사도다. 그래서 0.4라는 절대값 하나만 보면 안 되고, Top-2와의 차이인 margin을 함께 봐야 한다.
| 결과 | 해석 | 권장 decision |
|---|---|---|
0.44 / 0.10 / 0.05 |
Top-1은 낮아 보여도 Top-2와 차이가 크다. | matched 가능 |
0.40 / 0.35 / 0.32 |
후보들이 붙어 있어 한 곳으로 확정하기 어렵다. | ambiguous |
0.23 / 0.20 / 0.18 |
전반적으로 낮고 붙어 있다. | out_of_scope 또는 ambiguous |
학습에 사용된 이미지라도 0.4가 나올 수 있다. 앱이 그 이미지를 자기 자신과 비교하는 것이 아니라, 여러 이미지를 평균낸 class prototype과 비교하기 때문이다.
유사도는 threshold 하나로 해결되지 않는다. 입력 전처리, embedding space, prototype 구성, score calibration을 함께 봐야 한다.
| 조절 지점 | 무엇을 바꾸는가 | 기대 효과 |
|---|---|---|
| 전처리 | resize, crop, mean/std, RGB 처리 | 학습 때 본 이미지 분포와 추론 때 분포를 맞춘다. |
| 학습 loss | ArcFace, contrastive, triplet, supervised contrastive | 같은 class는 당기고 다른 class는 멀리 보낸다. |
| Prototype | class당 1개가 아니라 viewpoint별 여러 prototype | 야간, 측면, 원거리 같은 class 내부 다양성을 표현한다. |
| Hard negative | 광화문 vs 근정문처럼 헷갈리는 쌍을 명시적으로 보강 | 비슷한 대상 사이의 구분력이 좋아진다. |
| Calibration | raw score만 보지 않고 margin, 품질, class별 분포 반영 | 사용자에게 더 신뢰할 수 있는 상태를 보여준다. |
모델은 “랜드마크의 본질”을 사람이 알려준 것처럼 이해하지 않는다. 학습 데이터와 라벨을 통해 어떤 이미지들을 같은 class로 당기고, 어떤 이미지들을 다른 class로 밀어낼지 배운다.
| 라벨링 품질 | 모델에 생기는 효과 |
|---|---|
| 정확한 class 라벨 | 올바른 class 방향으로 embedding이 당겨진다. |
| 잘못된 class 라벨 | embedding space가 오염되어 혼동이 늘어난다. |
| 다양한 view 라벨 | 정면, 측면, 야간, 원거리 같은 실제 입력 변화에 강해진다. |
| Hard negative 라벨 | 비슷한 랜드마크끼리의 차이를 더 잘 배운다. |
| 한/영 caption과 query example | 자연어 검색에서 사용자의 표현과 landmark 의미가 더 잘 연결된다. |
0.4대 점수가 정상 scale인지, 아니면 artifact나 preprocessing 문제가 있는지 보려면 아래 검증이 먼저 필요하다.
best.pt, prototype_index.json, ONNX artifact가 같은 모델 버전인지 확인한다.이 Core 문서를 읽다가 나온 후속 질문은 별도 Q&A 문서로 정리한다. 이후 새 질문이 생기면 여기에 링크를 계속 추가한다.
아래 자료는 이 문서의 배경지식을 더 깊게 확인할 때 참고하기 좋다. 먼저 CLIP 개념을 보고, 그 다음 MobileCLIP2와 PyTorch 정규화/유사도 문서를 보면 흐름이 자연스럽다.
| 주제 | 자료 | 왜 보면 좋은가 |
|---|---|---|
| CLIP 기본 개념 | Learning Transferable Visual Models From Natural Language Supervision | 이미지 encoder와 텍스트 encoder를 같은 embedding space에 놓고 비교하는 원리를 설명한 원 논문. |
| CLIP 쉬운 소개 | OpenAI CLIP: Connecting text and images | CLIP이 왜 text-image pair를 비교할 수 있는지 직관적으로 이해하기 좋다. |
| MobileCLIP2 | MobileCLIP2: Improving Multi-Modal Reinforced Training | MobileCLIP2-S4가 어떤 계열의 모델인지, 왜 mobile-friendly CLIP 모델인지 확인할 수 있다. |
| MobileCLIP2-S4 모델 페이지 | timm/MobileCLIP2-S4-OpenCLIP | 우리가 사용하는 모델 이름과 OpenCLIP 호환 모델 정보를 확인하는 데 유용하다. |
| OpenCLIP 구현 | mlfoundations/open_clip | 데모앱에서 사용하는 open_clip 계열 API와 tokenizer/model loading 흐름을 확인할 수 있다. |
| L2 정규화 | PyTorch torch.nn.functional.normalize | embedding vector를 길이 1로 맞추는 함수가 실제 라이브러리에서 어떻게 정의되는지 확인할 수 있다. |
| Cosine similarity | PyTorch torch.nn.functional.cosine_similarity | L2 정규화된 vector의 내적이 cosine similarity로 해석되는 이유를 구현 관점에서 확인할 수 있다. |