Updated:

πŸ”­Β Overview

μ‹œμž‘ν•˜κΈ° μ•žμ„œ, λ³Έ λ…Όλ¬Έ 리뷰λ₯Ό μˆ˜μ›”ν•˜κ²Œ 읽으렀면 Transformer 에 λŒ€ν•œ 선이해가 ν•„μˆ˜μ μ΄λ‹€. 아직 Transformer 에 λŒ€ν•΄μ„œ 잘 λͺ¨λ₯Έλ‹€λ©΄ ν•„μžκ°€ μž‘μ„±ν•œ 포슀트λ₯Ό 읽고 였길 ꢌμž₯ν•œλ‹€. λ˜ν•œ λ³Έλ¬Έ λ‚΄μš©μ„ μž‘μ„±ν•˜λ©΄μ„œ μ°Έκ³ ν•œ λ…Όλ¬Έκ³Ό μ—¬λŸ¬ 포슀트의 링크λ₯Ό 맨 λ°‘ ν•˜λ‹¨μ— μ²¨λΆ€ν–ˆμœΌλ‹ˆ μ°Έκ³  λ°”λž€λ‹€. μ‹œκ°„μ΄ μ—†μœΌμ‹  뢄듀은 μ€‘κ°„μ˜ μ½”λ“œ κ΅¬ν˜„λΆ€λ₯Ό μƒλž΅ν•˜κ³  Insight λΆ€ν„° 읽기λ₯Ό ꢌμž₯ν•œλ‹€.

Vision Transformer(μ΄ν•˜ ViT)λŠ” 2020λ…„ 10μ›” Googleμ—μ„œ λ°œν‘œν•œ 컴퓨터 λΉ„μ „μš© λͺ¨λΈμ΄λ‹€. μžμ—°μ–΄ μ²˜λ¦¬μ—μ„œ λŒ€μ„±κ³΅μ„ κ±°λ‘” 트렌슀포머 ꡬ쑰와 기법을 거의 κ·ΈλŒ€λ‘œ λΉ„μ „ 뢄야에 μ΄μ‹ν–ˆλ‹€λŠ” μ μ—μ„œ 큰 μ˜μ˜κ°€ 있으며, 이후 컴퓨터 λΉ„μ „ λΆ„μ•Όμ˜ 트렌슀포머 μ „μ„±μ‹œλŒ€κ°€ μ—΄λ¦¬κ²Œ 된 κ³„κΈ°λ‘œ μž‘μš©ν•œλ‹€.

ν•œνŽΈ, ViT 의 섀계 철학은 λ°”λ‘œ scalability(λ²”μš©μ„±)이닀. 신경망 μ„€κ³„μ—μ„œ λ²”μš©μ„±μ΄λž€, λͺ¨λΈμ˜ ν™•μž₯ κ°€λŠ₯성을 λ§ν•œλ‹€. 예λ₯Ό λ“€λ©΄ ν•™μŠ΅ 데이터보닀 더 크고 λ³΅μž‘ν•œ 데이터 μ„ΈνŠΈλ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜ λͺ¨λΈμ˜ νŒŒλΌλ―Έν„°λ₯Ό 늘렀 μ‚¬μ΄μ¦ˆλ₯Ό ν‚€μ›Œλ„ μ—¬μ „νžˆ μœ νš¨ν•œ μΆ”λ‘  κ²°κ³Όλ₯Ό λ„μΆœν•˜κ±°λ‚˜ 더 λ‚˜μ€ μ„±λŠ₯을 보여주고 λ‚˜μ•„κ°€ κ°œμ„ μ˜ 여지가 μ—¬μ „νžˆ λ‚¨μ•„μžˆμ„ λ•Œ β€œν™•μž₯성이 높닀” 라고 ν‘œν˜„ν•œλ‹€. μ €μžλ“€μ€ λ…Όλ¬Έ μ΄ˆλ°˜μ— 콕 μ°μ–΄μ„œ 컴퓨터 λΉ„μ „ λΆ„μ•Όμ˜ scalability λ†’μ΄λŠ” 것이 이번 λͺ¨λΈ μ„€κ³„μ˜ λͺ©ν‘œμ˜€λ‹€κ³  밝히고 μžˆλ‹€. λ²”μš©μ„±μ€ 신경망 λͺ¨λΈ μ„€κ³„μ—μ„œ κ°€μž₯ 큰 화두가 λ˜λŠ”λ° λ„λ©”μΈλ§ˆλ‹€ μ •μ˜ν•˜λŠ” μ˜λ―Έμ— 차이가 λ―Έμ„Έν•˜κ²Œ μ‘΄μž¬ν•œλ‹€. λ”°λΌμ„œ ViT의 μ €μžλ“€μ΄ λ§ν•˜λŠ” λ²”μš©μ„±μ΄ 무엇을 μ˜λ―Έν•˜λŠ”μ§€ μ•Œμ•„λ³΄λŠ” 것은 ꡬ체적인 λͺ¨λΈ ꡬ쑰λ₯Ό μ΄ν•΄ν•˜λŠ”λ° 큰 도움이 될 것이닀.

🧠 Scalability in ViT

λ…Όλ¬Έ μ΄ˆλ°˜λΆ€μ—μ„œ λ‹€μŒκ³Ό 같은 λ¬Έμž₯이 μ„œμˆ  λ˜μ–΄μžˆλ‹€.

β€œOur Vision Transformer (ViT) attains excellent results when pre-trained at sufficient scale and transferred to tasks with fewer datapoints"

이 ꡬ문이 ViT 의 Scalabilityλ₯Ό κ°€μž₯ 잘 μ„€λͺ…ν•˜κ³  μžˆλ‹€κ³  μƒκ°ν•œλ‹€. μ €μžλ“€μ΄ λ§ν•˜λŠ” λ²”μš©μ„±μ€ κ²°κ΅­ backbone ꡬ쑰의 ν™œμš©μ„ μ˜λ―Έν•œλ‹€. μžμ—°μ–΄ μ²˜λ¦¬μ— μ΅μˆ™ν•œ λ…μžλΌλ©΄ μ‰½κ²Œ 이해가 κ°€λŠ₯ν•  것이닀. Transformer, GPT, BERT의 λ“±μž₯ 이후, μžμ—°μ–΄ μ²˜λ¦¬λŠ” λ²”μš©μ„±μ„ κ°–λŠ” 데이터 μ„ΈνŠΈλ‘œ 사전 ν›ˆλ ¨ν•œ λͺ¨λΈμ„ ν™œμš©ν•΄ Task-Agnosticν•˜κ²Œ ν•˜λ‚˜μ˜ backbone으둜 거의 λͺ¨λ“  Taskλ₯Ό μˆ˜ν–‰ν•  수 있으며, μž‘μ€ μ‚¬μ΄μ¦ˆμ˜ 데이터라도 μƒλ‹Ήνžˆ 높은 μˆ˜μ€€μ˜ μΆ”λ‘  μ„±λŠ₯을 λ‚Ό 수 μžˆμ—ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ‹Ήμ‹œ 컴퓨터 λΉ„μ „μ˜ λ©”μΈμ΄μ—ˆλ˜ Conv 기반 λͺ¨λΈλ“€μ€ νŒŒμΈνŠœλ‹ν•΄λ„ 데이터 크기가 μž‘μœΌλ©΄ μΌλ°˜ν™” μ„±λŠ₯이 맀우 떨어지고, Task에 λ”°λΌμ„œ λ‹€λ₯Έ μ•„ν‚€ν…μ²˜λ₯Ό κ°–λŠ” λͺ¨λΈμ„ μƒˆλ‘­κ²Œ μ •μ˜ν•˜κ±°λ‚˜ λΆˆλŸ¬μ™€ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” λ²ˆκ±°λ‘œμ›€μ΄ μžˆμ—ˆλ‹€. 예λ₯Ό λ“€λ©΄ Image Classfication μ—λŠ” ResNet, Segmentation μ—λŠ” U-Net, Object Detection 은 YOLO λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμ²˜λŸΌ 말이닀. 반면 μžμ—°μ–΄ μ²˜λ¦¬λŠ” 사전 ν•™μŠ΅λœ λͺ¨λΈ ν•˜λ‚˜λ‘œ λͺ¨λ“  NLU, μ‹¬μ§€μ–΄λŠ” NLG Task도 μˆ˜ν–‰ν•  수 μžˆλ‹€. μ €μžλ“€μ€ μ΄λŸ¬ν•œ λ²”μš©μ„±μ„ 컴퓨터 비전에도 이식 μ‹œν‚€κ³  μ‹Άμ—ˆλ˜ 것 κ°™λ‹€. κ·Έλ ‡λ‹€λ©΄ λ¨Όμ € μžμ—°μ–΄ μ²˜λ¦¬μ—μ„œ 트랜슀포머 계열이 λ²”μš©μ„±μ„ κ°€μ§ˆ 수 μžˆμ—ˆλ˜ μ΄μœ λŠ” 무엇인지 κ°„λ‹¨νžˆ μ‚΄νŽ΄λ³΄μž.

μ €μžλ“€μ€ self-attention(내적)의 νš¨μœ¨μ„±, λͺ¨λΈμ˜ ꡬ쑰적 탁월성 그리고 self-supervised task의 쑴재λ₯Ό κΌ½λŠ”λ‹€. 그럼 이것듀이 μ™œ λ²”μš©μ„±μ„ λ†’μ΄λŠ”λ° 도움이 될까??

self-attention(내적)은 ν–‰λ ¬ κ°„ κ³±μ…‰μœΌλ‘œ μ •μ˜ λ˜μ–΄ 섀계가 맀우 κ°„νŽΈν•˜κ³  λ³‘λ ¬λ‘œ ν•œλ²ˆμ— μ²˜λ¦¬ν•˜λŠ” 것이 κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— 효율적으둜 전체 데이터λ₯Ό λͺ¨λ‘ κ³ λ €ν•œ μ—°μ‚° κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€.

Multi-Head Attention κ΅¬μ‘°λŠ” μ—¬λŸ¬ μ°¨μ›μ˜ 의미 관계λ₯Ό λ™μ‹œμ— ν¬μ°©ν•˜κ³  그것을 μ•™μƒλΈ”ν•œ 것과 같은(μ‹€μ œλ‘œλŠ” MLP) κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€λŠ” μ μ—μ„œ ꡬ쑰적으둜 νƒμ›”ν•˜λ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ MLM, Auto-Regression(LM) TaskλŠ” 데이터 μ„ΈνŠΈμ— λ³„λ„μ˜ μΈκ°„μ˜ κ°œμž…(라벨링)이 ν•„μš”ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— κ°€μ„±λΉ„ 있게 데이터와 λͺ¨λΈμ˜ μ‚¬μ΄μ¦ˆλ₯Ό 늘릴 수 있게 λœλ‹€.
이제 λ…Όλ¬Έμ—μ„œ 트랜슀포머 계열이 가진 λ²”μš©μ„±μ„ μ–΄λ–»κ²Œ λΉ„μ „ 뢄야에 μ μš©ν–ˆλŠ”μ§€ μ£Όλͺ©ν•˜λ©΄μ„œ λͺ¨λΈ ꡬ쑰λ₯Ό ν•˜λ‚˜ ν•˜λ‚˜ μ‚΄νŽ΄λ³΄μž.

🌟 Modeling

ViT Model Structure ViT Model Structure

  • 1) Transfer Scalability from pure Transformer to Computer Vision
    • Overcome reliance on Convolution(Inductive Bias) in Computer Vision
    • Apply Self-Attention & Architecture from vanilla NLP Transformers as closely as possible
    • Treat Image as sequence of text token
    • Make $P$ sub-patches from whole image, playing same role as token in NLP Transformer

μ €μžλ“€μ€ λ¨Όμ € Conv 에 λŒ€ν•œ μ˜μ‘΄μ„ 버릴 것을 μ£Όμž₯ν•œλ‹€. Convκ°€ 가진 Inductive Bias λ•Œλ¬Έμ— νŒŒμΈνŠœλ‹ λ ˆλ²¨μ—μ„œ 데이터 크기가 μž‘μœΌλ©΄ μΌλ°˜ν™” μ„±λŠ₯이 λ–¨μ–΄μ§€λŠ” 것이라고 μ„€λͺ…ν•˜κ³  μžˆλ‹€. 이 말을 μ΄ν•΄ν•˜λ €λ©΄ Inductive Bias에 λŒ€ν•΄μ„œ λ¨Όμ € μ•Œμ•„μ•Ό ν•œλ‹€. Inductive Biasλž€, 주어진 λ°μ΄ν„°λ‘œλΆ€ν„° μΌλ°˜ν™” μ„±λŠ₯을 높이기 μœ„ν•΄ β€˜μž…λ ₯λ˜λŠ” λ°μ΄ν„°λŠ” ~ ν•  것이닀’, β€˜μ΄λŸ° νŠΉμ§•μ„ κ°–κ³  μžˆμ„ 것이닀’와 같은 κ°€μ •, κ°€μ€‘μΉ˜, κ°€μ„€ 등을 κΈ°κ³„ν•™μŠ΅ μ•Œκ³ λ¦¬μ¦˜μ— μ μš©ν•˜λŠ” 것을 λ§ν•œλ‹€.

Conv μ—°μ‚° 자체 (κ°€μ€‘μΉ˜ 곡유, 풀링 μžˆλŠ” Conv Block이 Invariance)의 κΈ°λ³Έ 가정은 translation equivariance, locality이닀. 사싀 μ €μžμ˜ μ£Όμž₯을 μ΄ν•΄ν•˜λŠ”λ° equivariance와 locality의 뜻이 무엇인지 νŒŒμ•…ν•˜λŠ” 것은 크게 μ˜λ―Έκ°€ μ—†λ‹€ (equivariance와 invariance에 λŒ€ν•΄μ„œλŠ” λ‹€λ₯Έ ν¬μŠ€νŒ…μ—μ„œ μžμ„Ένžˆ μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜κ² λ‹€). μ€‘μš”ν•œ 것은 μž…λ ₯ 데이터에 가정을 λ”ν•œλ‹€λŠ” 점이닀. λ§Œμ•½ 주어진 μž…λ ₯이 미리 κ°€μ •ν•œ Inductive Bias 에 λ²—μ–΄λ‚œλ‹€λ©΄ μ–΄λ–»κ²Œ 될까??

μ•„λ§ˆ μ˜€λ²„ν”ΌνŒ… λ˜κ±°λ‚˜ λͺ¨λΈ ν•™μŠ΅μ΄ μˆ˜λ ΄μ„±μ„ 갖지 λͺ»ν•˜κ²Œ 될 것이닀. 이미지 데이터도 Task에 따라 ν•„μš”ν•œ Inductive Biasκ°€ 달라진닀. 예λ₯Ό λ“€μ–΄ Segmentation, Detection 의 κ²½μš°λŠ” 이미지 속 객체의 μœ„μΉ˜, ν”½μ…€ μ‚¬μ΄μ˜ spatial variance 정보가 맀우 μ€‘μš”ν•˜λ‹€. ν•œνŽΈ, Classification은 spatial invarianceκ°€ μ€‘μš”ν•˜λ‹€. λͺ©ν‘œ 객체의 μœ„μΉ˜μ™€ μ£Όλ³€ νŠΉμ§•λ³΄λ‹€ νƒ€κ²Ÿ 자체λ₯Ό 신경망이 μΈμ‹ν•˜λŠ” 것이 μ€‘μš”ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. λ”°λΌμ„œ ViT μ €μžλ“€μ€ μ–΄λ–€ Bias던 상관없이 편ν–₯을 κ°–κ³  데이터λ₯Ό λ³Έλ‹€λŠ” 것 μžμ²΄μ— μ˜λ¬Έμ„ ν‘œν•˜λ©°, 이미지 μ—­μ‹œ Inductive Biasμ—μ„œ λ²—μ–΄λ‚˜, 주어진 데이터 전체 νŠΉμ§•(패치) μ‚¬μ΄μ˜ 관계λ₯Ό νŒŒμ•…ν•˜λŠ” κ³Όμ •μ—μ„œ scalabilityλ₯Ό νšλ“ν•  수 μžˆλ‹€κ³  μ£Όμž₯ν•œλ‹€.

κ·Έλž˜μ„œ Conv의 λŒ€μ•ˆμœΌλ‘œ μƒλŒ€μ μœΌλ‘œ Inductive Bias κ°€ λΆ€μ‘±ν•œ Self-Attention, Transformer Architectureλ₯Ό μ‚¬μš©ν•œλ‹€. λ‘κ°€μ§€μ˜ νš¨μš©μ„±μ— λŒ€ν•΄μ„œλŠ” 이미 μœ„μ—μ„œ μ–ΈκΈ‰ν–ˆκΈ° λ•Œλ¬Έμ— μƒλž΅ν•˜κ³ , μ—¬κΈ°μ„œ 짚고 λ„˜μ–΄κ°€μ•Όν•  점은 Self-Attention이 Conv λŒ€λΉ„ Inductive Biasκ°€ μ λ‹€λŠ” 점이닀. Self-Attention κ³Όμ •μ—λŠ” μ—¬λŸ¬ μ—°μ‚°, μŠ€μΌ€μΌ 쑰정값듀이 ν¬ν•¨λ˜μ§€λ§Œ 본질적으둜 β€œλ‚΄μ β€ 이 쀑심이닀. 내적은 κ·Έ μ–΄λ–€ 편ν–₯ (Conv와 λŒ€μ‘°ν•˜λ €κ³  μ΄λ ‡κ²Œ μ„œμˆ ν–ˆμ§€λ§Œ 사싀 Position Embedding λ”ν•˜λŠ” 것도 μΌμ’…μ˜ μ•½ν•œ Inductive Bias)이 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€. 일단 주어진 λͺ¨λ“  데이터에 λŒ€ν•΄μ„œ 내적값을 μ‚°μΆœν•˜κ³  κ·Έ λ‹€μŒμ— 관계가 μžˆλ‹€κ³  μƒκ°λ˜λŠ” 정보λ₯Ό 좔리기 λ•Œλ¬Έμ΄λ‹€. Conv λ•Œμ™€ 달리 β€˜μž…λ ₯λ˜λŠ” λ°μ΄ν„°λŠ” ~ ν•  것이닀’, β€˜μ΄λŸ° νŠΉμ§•μ„ κ°–κ³  μžˆμ„ 것이닀’ λΌλŠ” 가정이 μ—†λ‹€. 이번 ν¬μŠ€νŒ…μ˜ λ§ˆμ§€λ§‰ μ―€μ—μ„œ λ‹€μ‹œ λ‹€λ£¨κ² μ§€λ§Œ κ·Έλž˜μ„œ ViTλŠ” μΈμŠ€ν„΄μŠ€ μ‚¬μ΄μ˜ λͺ¨λ“  관계λ₯Ό λ½‘μ•„λ³΄λŠ” Self-Attention(내적) 을 기반으둜 λ§Œλ“€μ–΄μ‘ŒκΈ° λ•Œλ¬Έμ— μ΄λ―Έμ§€μ˜ Global Information을 ν¬μ°©ν•˜λŠ”λ° νƒμ›”ν•œ μ„±λŠ₯을 보이고, Conv λŠ” β€œμ€‘μš”ν•œ μ •λ³΄λŠ” 근처 픽셀에 λͺ°λ €μžˆλ‹€λΌλŠ”” Inductive Bias 덕뢄에 Local Information을 ν¬μ°©ν•˜λŠ”λ° νƒμ›”ν•œ μ„±λŠ₯을 λ‚Έλ‹€.

κ·Έλ ‡λ‹€λ©΄ ν”½μ…€ ν•˜λ‚˜ ν•˜λ‚˜λΌλ¦¬ λ‚΄μ ν•΄μ€€λ‹€λŠ” κ²ƒμΌκΉŒ?? μ•„λ‹ˆλ‹€ μ—¬κΈ°μ„œ λ…Όλ¬Έμ˜ 제λͺ©μ΄ An Image Is Worth 16x16 Words 인 μ΄μœ κ°€ λ“œλŸ¬λ‚œλ‹€. 일단 ν”½μ…€ ν•˜λ‚˜ ν•˜λ‚˜λΌλ¦¬ μœ μ‚¬λ„λ₯Ό μΈ‘μ •ν•˜λŠ” 것이 μœ μ˜λ―Έν• κΉŒ μƒκ°ν•΄λ³΄μž. μžμ—°μ–΄μ˜ 토큰과 달리 μ΄λ―Έμ§€μ˜ 단일 ν”½μ…€ ν•œ κ°œλŠ” 큰 μΈμ‚¬μ΄νŠΈλ₯Ό μ–»κΈ° νž˜λ“€λ‹€. 픽셀은 말 κ·ΈλŒ€λ‘œ 점 ν•˜λ‚˜μΌ 뿐이닀. 픽셀을 μ—¬λŸ¬ 개 λ¬Άμ–΄ 패치 λ‹¨μœ„λ‘œ λ¬ΆλŠ”λ‹€λ©΄ μ΄μ•ΌκΈ°λŠ” 달라진닀. 일정 크기 μ΄μƒμ˜ 패치라면 μžμ—°μ–΄μ˜ ν† ν°μ²˜λŸΌ κ·Έ 자체둜 μ–΄λ–€ 의미λ₯Ό 담을 수 μžˆλ‹€. λ”°λΌμ„œ μ €μžλŠ” 전체 이미지λ₯Ό μ—¬λŸ¬ 개의 16x16 ν˜Ήμ€ 14x14 μ‚¬μ΄μ¦ˆ 패치둜 λ‚˜λˆ„μ–΄ ν•˜λ‚˜ ν•˜λ‚˜λ₯Ό ν† ν°μœΌλ‘œ κ°„μ£Όν•΄ 이미지 μ‹œν€€μŠ€λ₯Ό λ§Œλ“€κ³  그것을 λͺ¨λΈμ˜ Input으둜 μ‚¬μš©ν•œλ‹€.

Class Diagram Class Diagram

λͺ¨λΈ ꡬ쑰의 λΌˆλŒ€κ°€ λ˜λŠ” λ‚΄μš©λ“€μ„ λͺ¨λ‘ μ‚΄νŽ΄λ³΄μ•˜κ³ , μœ„μ—μ„œ μ„œμˆ ν•œ λ‚΄μš©μ„ κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ μ–΄λ–€ 블둝듀을 μ‚¬μš©ν–ˆλŠ”μ§€ ν•„μžκ°€ 직접 논문을 보고 따라 κ΅¬ν˜„ν•œ μ½”λ“œμ™€ ν•¨κ»˜ μ•Œμ•„λ³΄λ„λ‘ ν•˜μž. μœ„μ— μ²¨λΆ€ν•œ λͺ¨λΈ λͺ¨μ‹λ„에 λ‚˜μ™€ μžˆλŠ” 블둝듀 ν•˜λ‚˜ ν•˜λ‚˜ μ‚΄νŽ΄λ³Ό μ˜ˆμ •μ΄λ‹€. μ—¬λ‹΄μœΌλ‘œ Google Research의 Official Repo μ—­μ‹œ ν•¨κ»˜ μ°Έκ³ ν–ˆλŠ”λ°, μ½”λ“œκ°€ λͺ¨λ‘ ꡬ글이 μš”μƒˆ μƒˆλ‘­κ²Œ λ―ΈλŠ” Jax, Flax 둜 κ΅¬ν˜„ λ˜μ–΄ μžˆμ—ˆλ‹€. νŒŒμ΄ν† μΉ˜λ‚˜ μ’€ 써본 ν•„μž μž…μž₯μ—μ„œλŠ” 정말 … 지μ˜₯λΆˆμ„ κ²½ν—˜ν–ˆλ‹€. μ˜€λŠ˜λ„ λ‹€μ‹œ ν•œ 번 페이슀뢁 νŒŒμ΄ν† μΉ˜ κ°œλ°œνŒ€μ— 큰절 λ“œλ¦¬κ³  μ‹Άλ‹€.

πŸ”¬Β Linear Projection of Flattened Patches

\[x_p \in R^{N * (P^2β€’C)}\] \[z_{0} = [x_{class}; x_p^1E;x_p^2E;x_p^3E....x_p^NE]\] \[N = \frac{H*W}{P*P}\]

ViT의 μž…λ ₯ μž„λ² λ”©μ„ μƒμ„±ν•˜λŠ” 역할을 ν•œλ‹€. ViTλŠ” $x \in R^{H * W * C}$(H: height, W: width, C: channel)의 ν˜•μƒμ„ κ°–λŠ” 이미지λ₯Ό μž…λ ₯으둜 λ°›μ•„ κ°€λ‘œ μ„Έλ‘œ 길이가 $P$, 채널 개수 $C$인 $N$개의 패치둜 reshape ν•œλ‹€. ν•„μžκ°€ μ½”λ“œ κ΅¬ν˜„ 쀑 κ°€μž₯ ν˜Όλ™ν•œ 뢀뢄이 λ°”λ‘œ 패치 개수 $N$μ΄μ—ˆλ‹€. μ§κ΄€μ μœΌλ‘œ 패치 개수라고 ν•˜λ©΄, 전체 이미지 μ‚¬μ΄μ¦ˆμ—μ„œ 패치 크기λ₯Ό λ‚˜λˆˆ 값이라고 μƒκ°ν•˜κΈ° 쉽기 λ•Œλ¬Έμ΄λ‹€. 예λ₯Ό λ“€λ©΄ 512x512짜리 이미지λ₯Ό 16x16 μ‚¬μ΄μ¦ˆμ˜ 패치둜 λ‚˜λˆˆλ‹€κ³  ν•΄λ³΄μž. ν•„μžλŠ” λ‹¨μˆœνžˆ 512/16=32 λΌλŠ” κ²°κ³Όλ₯Ό μ΄μš©ν•΄ $N=32$둜 μ„€μ •ν•˜κ³  μ‹€ν—˜μ„ μ§„ν–‰ν•˜λ‹€κ°€ ν…μ„œ 차원이 λ§žμ§€ μ•Šμ•„ λ°œμƒν•˜λŠ” μ—λŸ¬ 둜그λ₯Ό λ§ˆμ£Όν–ˆμ—ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ…Όλ¬Έ 속 μˆ˜μ‹μ„ 확인해보면, $H * W / P^2$이 λ°”λ‘œ 패치 개수$N$으둜 μ •μ˜λœλ‹€. κ·Έλž˜μ„œ λ§Œμ•½ 512x512 μ‚¬μ΄μ¦ˆμ˜ RGB 이미지 10μž₯을 ViT μž…λ ₯ μž„λ² λ”©μ— 맞게 차원 λ³€ν™˜ν•œλ‹€λ©΄ κ²°κ³ΌλŠ” [10, 3, 1024, 768] 이 될 것이닀. (이 μ˜ˆμ‹œλ₯Ό μ•žμœΌλ‘œ 계속 μ΄μš©ν•˜κ² λ‹€)

μ΄λ ‡κ²Œ 차원을 λ°”κΏ”μ€€ 이미지λ₯Ό nn.Linear((channels * patch_size**2), dim_model) λ₯Ό 톡해 ViT의 μž„λ² λ”© λ ˆμ΄μ–΄μ— μ„ ν˜• νˆ¬μ˜ν•΄μ€€λ‹€. μ—¬κΈ°μ„œ μžμ—°μ–΄ μ²˜λ¦¬μ™€ νŒŒμ΄ν† μΉ˜λ₯Ό 자주 μ‚¬μš©ν•˜μ‹œλŠ” λ…μžλΌλ©΄ μ™œ nn.Embedding을 μ‚¬μš©ν•˜μ§€ μ•Šμ•˜λŠ”κ°€ μ˜λ¬Έμ„ κ°€μ§ˆ 수 μžˆλ‹€.

μžμ—°μ–΄ μ²˜λ¦¬μ—μ„œ μž…λ ₯ μž„λ² λ”©μ„ λ§Œλ“€λ•ŒλŠ” λͺ¨λΈμ˜ ν† ν¬λ‚˜μ΄μ €μ— μ˜ν•΄ 사전 μ •μ˜λœ vocab의 μ‚¬μ΄μ¦ˆκ°€ μž…λ ₯ λ¬Έμž₯에 μ†ν•œ 토큰 κ°œμˆ˜λ³΄λ‹€ 훨씬 크기 λ•Œλ¬Έμ— 데이터 룩업 ν…Œμ΄λΈ” λ°©μ‹μ˜ nn.Embedding 을 μ‚¬μš©ν•˜κ²Œ λœλ‹€. 이게 무슨 말이냐면, ν† ν¬λ‚˜μ΄μ €μ— μ˜ν•΄ 사전에 μ •μ˜λœ vocab 전체가 nn.Embedding(vocab_size, dim_model)둜 투영 λ˜μ–΄ κ°€λ‘œλŠ” vocab μ‚¬μ΄μ¦ˆ, μ„Έλ‘œλŠ” λͺ¨λΈμ˜ 차원 크기에 ν•΄λ‹Ήν•˜λŠ” 룩업 ν…Œμ΄λΈ”μ΄ μƒμ„±λ˜κ³ , λ‚΄κ°€ μž…λ ₯ν•œ 토큰듀은 전체 vocab의 μΌλΆ€λΆ„μΌν…Œλ‹ˆ 전체 μž„λ² λ”© 룩업 ν…Œμ΄λΈ”μ—μ„œ λ‚΄κ°€ μž„λ² λ”©ν•˜κ³  싢은 ν† ν°λ“€μ˜ 인덱슀만 μ•Œμ•„λ‚Έλ‹€λŠ” 것이닀.

κ·Έλž˜μ„œ nn.Embedding 에 μ •μ˜λœ 차원과 μ‹€μ œ μž…λ ₯ λ°μ΄ν„°μ˜ 차원이 λ§žμ§€ μ•Šμ•„λ„ ν•¨μˆ˜κ°€ λ™μž‘ν•˜κ²Œ λ˜λŠ” 것이닀. κ·ΈλŸ¬λ‚˜ λΉ„μ „μ˜ 경우, 사전에 μ •μ˜λœ vocabμ΄λΌλŠ” κ°œλ…μ΄ μ „ν˜€ μ—†κ³  μž…λ ₯ 이미지 μ—­μ‹œ 항상 κ³ μ •λœ 크기의 μ°¨μ›μœΌλ‘œ λ“€μ–΄μ˜€κΈ° λ•Œλ¬Έμ— nn.Embedding이 μ•„λ‹Œ nn.Linear 을 μ‚¬μš©ν•΄ κ³§λ°”λ‘œ μ„ ν˜• νˆ¬μ˜μ„ κ΅¬ν˜„ν•œ 것이닀. 두 λ©”μ„œλ“œμ— λŒ€ν•œ μžμ„Έν•œ λΉ„κ΅λŠ” νŒŒμ΄ν† μΉ˜ κ΄€λ ¨ ν¬μŠ€νŠΈμ—μ„œ λ‹€μ‹œ ν•œ 번 μžμ„Ένžˆ 닀루도둝 ν•˜κ² λ‹€.

ν•œνŽΈ, Position Embedding을 λ”ν•˜κΈ° μ „, Input Embedding의 차원은 [10, 1024, 1024] 이 λœλ‹€. μ§€κΈˆκΉŒμ§€ μ„€λͺ…ν•œ λΆ€λΆ„(Linear Projection of Flattened Patches )을 νŒŒμ΄ν† μΉ˜ μ½”λ“œλ‘œ κ΅¬ν˜„ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

class VisionTransformer(nn.Module):
    ...
    μ€‘λž΅
    ...
    self.num_patches = int(image_size / patch_size)**2
    self.input_embedding = nn.Linear((channels * patch_size**2), dim_model) # Projection Layer for Input Embedding
    ...
    μ€‘λž΅
    ...  
    def forward(self, inputs: Tensor) -> any:
        """ For cls pooling """
        assert inputs.ndim != 4, f"Input shape should be [BS, CHANNEL, IMAGE_SIZE, IMAGE_SIZE], but got {inputs.shape}"
        x = inputs 
        x = self.input_embedding(
            x.reshape(x.shape[0], self.num_patches, (self.patch_size**2 * x.shape[1])) # Projection Layer for Input Embedding
        )
        cls_token = torch.zeros(x.shape[0], 1, x.shape[2])  # can change init method
        x = torch.cat([cls_token, x], dim=1)
    ...

μž„λ² λ”© λ ˆμ΄μ–΄λ₯Ό 객체둜 λ”°λ‘œ κ΅¬ν˜„ν•΄λ„ λ˜μ§€λ§Œ, ν•„μžλŠ” ꡳ이 좔상화가 ν•„μš”ν•˜μ§€ μ•Šλ‹€κ³  생각해 ViT의 μ΅œμƒμœ„ 클래슀인 VisionTransformer의 forward λ©”μ„œλ“œ 맨 μ΄ˆλ°˜λΆ€μ— κ΅¬ν˜„ν•˜κ²Œ λ˜μ—ˆλ‹€. μž…λ ₯ 받은 이미지 ν…μ„œλ₯Ό torch.reshape 을 톡해 [패치 개수, ν”½μ…€κ°œμˆ˜*μ±„λ„κ°œμˆ˜] 둜 λ°”κΎΌ λ’€, 미리 μ •μ˜ν•΄λ‘” self.input_embedding 에 λ§€κ°œλ³€μˆ˜λ‘œ 전달해 β€œμœ„μΉ˜ μž„λ² λ”©β€ 값이 더해지기 μ „ Input Embedding을 λ§Œλ“ λ‹€.

ν•œνŽΈ, CLS Pooling을 μœ„ν•΄ λ§ˆμ§€λ§‰μ— [batch, 1, image_size] 의 차원을 κ°–λŠ” cls_token 을 μ •μ˜ν•΄ 패치 μ‹œν€€μŠ€μ™€ concat (맨 μ•žμ—)ν•΄μ€€λ‹€. 이 λ•Œ 논문에 μ œμ‹œλœ μˆ˜μ‹ 상, CLS Token은 μ„ ν˜• νˆ¬μ˜ν•˜μ§€ μ•ŠμœΌλ©°, 패치 μ‹œν€€μŠ€μ— μ„ ν˜• 투영이 이뀄지고 λ‚œ 뒀에 맨 μ•žμ— Concat ν•˜κ²Œ λœλ‹€.

CLS TokenκΉŒμ§€ λ”ν•œ μ΅œμ’… Input Embedding 의 ν…μ„œ 차원은 [10, 1025, 1024] κ°€ λœλ‹€.

πŸ”’Β Positional Embedding

\[E_{pos} \in R^{(N+1)*D}\]

이미지λ₯Ό 패치 λ‹¨μœ„μ˜ μž„λ² λ”©μœΌλ‘œ λ§Œλ“€μ—ˆλ‹€λ©΄ 이제 μœ„μΉ˜ μž„λ² λ”©μ„ μ •μ˜ν•΄μ„œ 더해주면 λͺ¨μ‹λ„ 속 Embedded Patches , 즉 인코더에 λ“€μ–΄κ°ˆ μ΅œμ’… Patch Embedding 이 μ™„μ„± λœλ‹€. μœ„μΉ˜ μž„λ² λ”©μ„ λ§Œλ“œλŠ” 방식은 κΈ°μ‘΄ Transformer, BERT 와 λ™μΌν•˜λ‹€. μ•„λž˜ VisionEncoder 클래슀λ₯Ό κ΅¬ν˜„ν•œ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄μž.

 class VisionEncoder(nn.Module):
    ...
    μ€‘λž΅
    ...
    self.positional_embedding = nn.Embedding((self.num_patches + 1), dim_model)  # add 1 for cls token
    ...
    μ€‘λž΅
    ...
    def forward(self, inputs: Tensor) -> tuple[Tensor, Tensor]:
        layer_output = []
        pos_x = torch.arange(self.num_patches + 1).repeat(inputs.shape[0]).to(inputs)  # inputs.shape[0] = Batch Size of Input
        x = self.dropout(
            inputs + self.positional_embedding(pos_x)
        )
    ...

Input Embeddingκ³Ό λ‹€λ₯΄κ²Œ μœ„μΉ˜ μž„λ² λ”©μ€ nn.Embedding으둜 κ΅¬ν˜„ν–ˆλŠ”λ°, μ—¬κΈ°μ„œλ„ 사싀 nn.Linearλ₯Ό μ‚¬μš©ν•΄λ„ λ¬΄λ°©ν•˜λ‹€. 그것보닀 nn.Embedding의 μž…λ ₯ 차원인 self.num_patches + 1 에 μ£Όλͺ©ν•΄λ³΄μž. μ™œ 1을 더해쀀 값을 μ‚¬μš©ν–ˆμ„κΉŒ??

ViTλŠ” BERT의 CLS Token Pooling 을 μ°¨μš©ν•˜κΈ° μœ„ν•΄ 패치 μ‹œν€€μŠ€ 맨 μ•žμ— CLS 토큰을 μΆ”κ°€ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. μ΄λ ‡κ²Œ μΆ”κ°€λœ CLS Token은 인코더λ₯Ό 거쳐 μ΅œμ’… MLP Head에 ν˜λŸ¬λ“€μ–΄κ°€ λ‘œμ§“μœΌλ‘œ λ³€ν™˜λœλ‹€. λ§Œμ•½ λ…μžκ»˜μ„œ CLS Token Pooling λŒ€μ‹  λ‹€λ₯Έ 풀링 방식을 μ‚¬μš©ν• κ±°λΌλ©΄ 1을 좔가해쀄 ν•„μš”λŠ” μ—†λ‹€.

μ• μ΄ˆμ— 객체 μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™” λ‹Ήμ‹œμ— CLS Token 을 μΆ”κ°€λ₯Ό λ°˜μ˜ν•œ 값을 μ „λ‹¬ν•˜λ©΄ λ˜μ§€ μ•ŠλŠ”κ°€ν•˜λŠ” 의문이 λ“€ μˆ˜λ„ μžˆλ‹€. ν•˜μ§€λ§Œ VisionEncoder 객체 μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™” λ‹Ήμ‹œμ—λŠ” num_patches κ°’μœΌλ‘œ CLS Token이 μΆ”κ°€λ˜κΈ° 이전 κ°’(+1 반영이 μ•ˆλ˜μ–΄ 있음)을 μ „λ‹¬ν•˜λ„λ‘ 섀계 λ˜μ–΄ μžˆμ–΄μ„œ CLS Pooling을 μ‚¬μš©ν• κ±°λΌλ©΄ 1 μΆ”κ°€λ₯Ό κΌ­ ν•΄μ€˜μ•Ό ν•œλ‹€.

Performance Table by making Position Embedding method Performance Table by making Position Embedding method

ν•œνŽΈ μ €μžλŠ” 2D Postion Embedding, Relative Position Embedding 방식도 μ μš©ν•΄λ΄€μ§€λ§Œ, κ΅¬ν˜„ λ³΅μž‘λ„ & μ—°μ‚°λŸ‰ λŒ€λΉ„ μ„±λŠ₯ ν–₯상 폭이 맀우 λ―Έλ―Έν•΄ 일반적인 1D Position Embedding을 μ‚¬μš©ν•  것을 μΆ”μ²œν•˜κ³  μžˆλ‹€.

πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦ Multi-Head Attention

\[z_t^{'} = MSA(LN(z_{t-1}) + z_{t-1})\] \[MSA(z) = [SA_1();SA_2();SA_3()...SA_k()]*U_{msa}, \ \ U_{msa} \in R^{(k*D_h)*D} \\\]

트랜슀포머 계열 λͺ¨λΈμ˜ 핡심 Multi-Head Self-Attention λͺ¨λ“ˆμ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μž. 사싀 κΈ°μ‘΄ μžμ—°μ–΄ 처리 Transformer, BERT λ“±μ˜ λ™μž‘ 방식과 μ™„μ „νžˆ λ™μΌν•˜λ©°, μ½”λ“œλ‘œ κ΅¬ν˜„ν•  λ•Œ μ—­μ‹œ λ™μΌν•˜κ²Œ λ§Œλ“€μ–΄μ£Όλ©΄ λœλ‹€. μžμ„Έν•œ 원리와 λ™μž‘ 방식은 Attention Is All You Need 리뷰 ν¬μŠ€νŠΈμ—μ„œ μ„€λͺ…ν–ˆκΈ° λ•Œλ¬Έμ— μƒλž΅ν•˜κ³  λ„˜μ–΄κ°€κ² λ‹€. ν•œνŽΈ νŒŒμ΄ν† μΉ˜λ‘œ κ΅¬ν˜„ν•œ Multi-Head Self-Attention λΈ”λŸ­μ— λŒ€ν•œ μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

def scaled_dot_product_attention(q: Tensor, k: Tensor, v: Tensor, dot_scale: Tensor) -> Tensor:
    """
    Scaled Dot-Product Attention
    Args:
        q: query matrix, shape (batch_size, seq_len, dim_head)
        k: key matrix, shape (batch_size, seq_len, dim_head)
        v: value matrix, shape (batch_size, seq_len, dim_head)
        dot_scale: scale factor for Qβ€’K^T result, same as pure transformer
    Math:
        A = softmax(qβ€’k^t/sqrt(D_h)), SA(z) = Av
    """
    attention_dist = F.softmax(
        torch.matmul(q, k.transpose(-1, -2)) / dot_scale,
        dim=-1
    )
    attention_matrix = torch.matmul(attention_dist, v)
    return attention_matrix

class AttentionHead(nn.Module):
    """
    In this class, we implement workflow of single attention head
    Args:
        dim_model: dimension of model's latent vector space, default 1024 from official paper
        dim_head: dimension of each attention head, default 64 from official paper (1024 / 16)
        dropout: dropout rate, default 0.1
    Math:
        [q,k,v]=zβ€’U_qkv, A = softmax(qβ€’k^t/sqrt(D_h)), SA(z) = Av
    """
    def __init__(self, dim_model: int =  1024, dim_head: int = 64, dropout: float = 0.1) -> None:
        super(AttentionHead, self).__init__()
        self.dim_model = dim_model
        self.dim_head = dim_head
        self.dropout = dropout
        self.dot_scale = torch.sqrt(torch.tensor(self.dim_head))
        self.fc_q = nn.Linear(self.dim_model, self.dim_head)
        self.fc_k = nn.Linear(self.dim_model, self.dim_head)
        self.fc_v = nn.Linear(self.dim_model, self.dim_head)

    def forward(self, x: Tensor) -> Tensor:
        attention_matrix = scaled_dot_product_attention(
            self.fc_q(x),
            self.fc_k(x),
            self.fc_v(x),
            self.dot_scale
        )
        return attention_matrix

class MultiHeadAttention(nn.Module):
    """
    In this class, we implement workflow of Multi-Head Self-Attention
    Args:
        dim_model: dimension of model's latent vector space, default 1024 from official paper
        num_heads: number of heads in MHSA, default 16 from official paper for ViT-Large
        dim_head: dimension of each attention head, default 64 from official paper (1024 / 16)
        dropout: dropout rate, default 0.1
    Math:
        MSA(z) = [SA1(z); SA2(z); Β· Β· Β· ; SAk(z)]β€’Umsa
    Reference:
        https://arxiv.org/abs/2010.11929
        https://arxiv.org/abs/1706.03762
    """
    def __init__(self, dim_model: int = 1024, num_heads: int = 8, dim_head: int = 64, dropout: float = 0.1) -> None:
        super(MultiHeadAttention, self).__init__()
        self.dim_model = dim_model
        self.num_heads = num_heads
        self.dim_head = dim_head
        self.dropout = dropout
        self.attention_heads = nn.ModuleList(
            [AttentionHead(self.dim_model, self.dim_head, self.dropout) for _ in range(self.num_heads)]
        )
        self.fc_concat = nn.Linear(self.dim_model, self.dim_model)

    def forward(self, x: Tensor) -> Tensor:
        """ x is already passed nn.Layernorm """
        assert x.ndim == 3, f'Expected (batch, seq, hidden) got {x.shape}'
        attention_output = self.fc_concat(
            torch.cat([head(x) for head in self.attention_heads], dim=-1)  # concat all dim_head = num_heads * dim_head
        )
        return attention_output

MultiHeadAttention을 κ°€μž₯ μ΅œμƒμœ„ 객체둜 두고, ν•˜μœ„μ— AttentionHead객체λ₯Ό λ”°λ‘œ κ΅¬ν˜„ν–ˆλ‹€. μ΄λ ‡κ²Œ κ΅¬ν˜„ν•˜λ©΄, μ–΄ν…μ…˜ ν•΄λ“œλ³„λ‘œ 쿼리, ν‚€, 벨λ₯˜ μ„ μ˜ 투영 ν–‰λ ¬(nn.Linear)을 λ”°λ‘œ κ΅¬ν˜„ν•΄μ€„ ν•„μš”κ°€ 없어지며, nn.ModuleList λ₯Ό 톡해 κ°œλ³„ ν•΄λ“œλ₯Ό ν•œ λ²ˆμ— κ·Έλ£Ήν•‘ν•˜κ³  loop λ₯Ό 톡해 좜λ ₯ κ²°κ³Όλ₯Ό concat 해쀄 수 μžˆμ–΄ λ³΅μž‘ν•˜κ³  λ§Žμ€ μ—λŸ¬λ₯Ό μœ λ°œν•˜λŠ” ν…μ„œ 차원 μ‘°μž‘μ„ ν”Όν•  수 있으며, μ½”λ“œμ˜ 가독성이 μ˜¬λΌκ°€λŠ” νš¨κ³Όκ°€ μžˆλ‹€.

πŸ—³οΈ MLP

\[z_{t} = MLP(LN(z_{t}^{'}) + z_{t}^{'})\]

μ΄λ¦„λ§Œ MLP둜 λ°”λ€Œμ—ˆμ„ 뿐, κΈ°μ‘΄ 트랜슀포머의 ν”Όλ“œ ν¬μ›Œλ“œ λΈ”λŸ­κ³Ό λ™μΌν•œ 역할을 ν•œλ‹€. μ—­μ‹œ μžμ„Έν•œ λ™μž‘ 방식은 μ—¬κΈ° ν¬μŠ€νŠΈμ—μ„œ ν™•μΈν•˜μž. νŒŒμ΄ν† μΉ˜λ‘œ κ΅¬ν˜„ν•œ μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

class MLP(nn.Module):
    """
    Class for MLP module in ViT-Large
    Args:
        dim_model: dimension of model's latent vector space, default 512
        dim_mlp: dimension of FFN's hidden layer, default 2048 from official paper
        dropout: dropout rate, default 0.1
    Math:
        MLP(x) = MLP(LN(x))+x
    """
    def __init__(self, dim_model: int = 1024, dim_mlp: int = 4096, dropout: float = 0.1) -> None:
        super(MLP, self).__init__()
        self.mlp = nn.Sequential(
            nn.Linear(dim_model, dim_mlp),
            nn.GELU(),
            nn.Dropout(p=dropout),
            nn.Linear(dim_mlp, dim_model),
            nn.Dropout(p=dropout),
        )

    def forward(self, x: Tensor) -> Tensor:
        return self.mlp(x)

νŠΉμ΄ν•œ 점은 Activation Function으둜 GELUλ₯Ό μ‚¬μš©(κΈ°μ‘΄ νŠΈλžœμŠ€ν¬λ¨ΈλŠ” RELU)ν–ˆλ‹€λŠ” 점이닀.

πŸ“˜ Vision Encoder Layer

ViT 인코더 λΈ”λŸ­ 1κ°œμ— ν•΄λ‹Ήν•˜λŠ” ν•˜μœ„ λͺ¨λ“ˆκ³Ό λ™μž‘μ„ κ΅¬ν˜„ν•œ 객체이닀. κ΅¬ν˜„ν•œ μ½”λ“œλŠ” μ•„λž˜μ™€ κ°™λ‹€.

class VisionEncoderLayer(nn.Module):
    """
    Class for encoder_model module in ViT-Large
    In this class, we stack each encoder_model module (Multi-Head Attention, Residual-Connection, Layer Normalization, MLP)
    """
    def __init__(self, dim_model: int = 1024, num_heads: int = 16, dim_mlp: int = 4096, dropout: float = 0.1) -> None:
        super(VisionEncoderLayer, self).__init__()
        self.self_attention = MultiHeadAttention(
            dim_model,
            num_heads,
            int(dim_model / num_heads),
            dropout,
        )
        self.layer_norm1 = nn.LayerNorm(dim_model)
        self.layer_norm2 = nn.LayerNorm(dim_model)
        self.dropout = nn.Dropout(p=dropout)
        self.mlp = MLP(
            dim_model,
            dim_mlp,
            dropout,
        )

    def forward(self, x: Tensor) -> Tensor:
        ln_x = self.layer_norm1(x)
        residual_x = self.dropout(self.self_attention(ln_x)) + x

        ln_x = self.layer_norm2(residual_x)
        fx = self.mlp(ln_x) + residual_x  # from official paper & code by Google Research
        return fx

νŠΉμ΄μ μ€ λ§ˆμ§€λ§‰ MLP Layer와 Residual κ²°κ³Όλ₯Ό λ”ν•œ λ’€, λ‹€μŒ 인코더 블둝에 μ „λ‹¬ν•˜κΈ° 전에 μΈ΅ μ •κ·œν™”λ₯Ό ν•œ 번 더 μ μš©ν•œλ‹€λŠ” 것이닀. λͺ¨λΈ λͺ¨μ‹λ„μ—λŠ” λ‚˜μ™€ μžˆμ§€ μ•Šμ§€λ§Œ, 본문에 ν•΄λ‹Ή λ‚΄μš©μ΄ μ‹€λ € μžˆλ‹€. λ§ˆμ§€λ§‰ μΈμ½”λ”μ˜ 좜λ ₯κ°’μ—λ§Œ ν•œλ²ˆ 더 layernorm을 μ μš©ν•œλ‹€.

πŸ“š VisionEncoder

μž…λ ₯ 이미지λ₯Ό Patch Embedding으둜 인코딩 ν•˜κ³  N개의 VisionEncoderLayerλ₯Ό μŒ“κΈ° μœ„ν•΄ κ΅¬ν˜„λœ 객체이닀. Patch Embedding을 λ§Œλ“œλŠ” 뢀뢄은 이미 μœ„μ—μ„œ μ„€λͺ…ν–ˆκΈ° λ•Œλ¬Έμ— λ„˜μ–΄κ°€κ³ , 인코더 λΈ”λŸ­μ„ N개 μŒ“λŠ” 방법은 μ—­μ‹œλ‚˜ nn.ModuleList λ₯Ό μ‚¬μš©ν•˜λ©΄ κ°„νŽΈν•˜κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€. μ•„λž˜ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄μž.

class VisionEncoder(nn.Module):
    """
    In this class, encode input sequence(Image) and then we stack N VisionEncoderLayer
    This model is implemented by cls pooling method for classification
    First, we define "positional embedding" and then add to input embedding for making patch embedding
    Second, forward patch embedding to N EncoderLayer and then get output embedding
    Args:
        num_patches: number of patches in input image => (image_size / patch_size)**2
        N: number of EncoderLayer, default 24 for large model
    """

    def __init__(self, num_patches: int, N: int = 24, dim_model: int = 1024, num_heads: int = 16, dim_mlp: int = 4096, dropout: float = 0.1) -> None:
        super(VisionEncoder, self).__init__()
        self.num_patches = num_patches
        self.positional_embedding = nn.Embedding((self.num_patches + 1), dim_model)  # add 1 for cls token
        self.num_layers = N
        self.dim_model = dim_model
        self.num_heads = num_heads
        self.dim_mlp = dim_mlp
        self.dropout = nn.Dropout(p=dropout)
        self.encoder_layers = nn.ModuleList(
            [VisionEncoderLayer(dim_model, num_heads, dim_mlp, dropout) for _ in range(self.num_layers)]
        )
        self.layer_norm = nn.LayerNorm(dim_model)

    def forward(self, inputs: Tensor) -> tuple[Tensor, Tensor]:
        layer_output = []
        pos_x = torch.arange(self.num_patches + 1).repeat(inputs.shape[0]).to(inputs)
        x = self.dropout(
            inputs + self.positional_embedding(pos_x)
        )
        for layer in self.encoder_layers:
            x = layer(x)
            layer_output.append(x)
        encoded_x = self.layer_norm(x)  # from official paper & code by Google Research
        layer_output = torch.stack(layer_output, dim=0).to(x.device)  # For Weighted Layer Pool: [N, BS, SEQ_LEN, DIM]
        return encoded_x, layer_output

λ§ˆμ§€λ§‰ 측의 인코더 좜λ ₯κ°’μ—λŠ” layernorm을 μ μš©ν•΄μ€˜μ•Ό 함을 μžŠμ§€ 말자. ν•œνŽΈ, layer_outputλŠ” λ ˆμ΄μ–΄ 별 μ–΄ν…μ…˜ κ²°κ³Όλ₯Ό μ‹œκ°ν™” ν•˜κ±°λ‚˜ λ‚˜μ€‘μ— WeightedLayerPool에 μ‚¬μš©ν•˜λ €κ³  λ§Œλ“€μ—ˆλ‹€.

πŸ€– VisionTransformer

ViT Model Variant ViT Model Variant

ViT λͺ¨λΈμ˜ κ°€μž₯ μ΅œμƒμœ„ 객체둜, μ•žμ—μ„œ μ„€λͺ…ν•œ λͺ¨λ“  λͺ¨λ“ˆλ“€μ˜ λ™μž‘μ΄ μ΄λ€„μ§€λŠ” 곳이닀. μ‚¬μš©μžλ‘œλΆ€ν„° ν•˜μ΄νΌνŒŒλΌλ―Έν„°λ₯Ό μž…λ ₯ λ°›μ•„ λͺ¨λΈμ˜ 크기, 깊이, 패치 크기, 이미지 μž„λ² λ”© μΆ”μΆœ 방식을 μ§€μ •ν•œλ‹€. 그리고 μž…λ ₯ 이미지λ₯Ό 전달받아 μž„λ² λ”©μ„ λ§Œλ“€κ³  인코더에 μ „λ‹¬ν•œ λ’€, MLP Head λ₯Ό 톡해 μ΅œμ’… 예츑 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜λŠ” 역할을 ν•œλ‹€.

이미지 μž„λ² λ”© μΆ”μΆœ 방식은 Linear Projectionκ³Ό Convolution이 μžˆλ‹€. μ „μžκ°€ λ…Όλ¬Έμ—μ„œ λ§ν•˜λŠ” 일반적인 ViTλ₯Ό λ§ν•˜λ©° ν›„μžλŠ” μ €μžκ°€ Hybrid ViT라고 λ”°λ‘œ λͺ…λͺ…ν•˜λŠ” λͺ¨λΈμ΄λ‹€. μž„λ² λ”© μΆ”μΆœ 방식 이외에 λ‹€λ₯Έ μ°¨μ΄λŠ” μ „ν˜€ μ—†λ‹€. extractor λ§€κ°œλ³€μˆ˜λ₯Ό 톡해 μž„λ² λ”© μΆ”μΆœ 방식을 지정할 수 μžˆμœΌλ‹ˆ μ•„λž˜ μ½”λ“œλ₯Ό ν™•μΈν•΄λ³΄μž.

class VisionTransformer(nn.Module):
    """
    Main class for ViT of cls pooling, Pytorch implementation
    We implement pure ViT, Not hybrid version which is using CNN for extracting patch embedding
    input must be [BS, CHANNEL, IMAGE_SIZE, IMAGE_SIZE]
    In NLP, input_sequence is always smaller than vocab size
    But in vision, input_sequence is always same as image size, not concept of vocab in vision
    So, ViT use nn.Linear instead of nn.Embedding for input_embedding
    Args:
        num_classes: number of classes for classification task
        image_size: size of input image, default 512
        patch_size: size of patch, default 16 from official paper for ViT-Large
        extractor: option for feature extractor, default 'base' which is crop & just flatten
                   if you want to use Convolution for feature extractor, set extractor='cnn' named hybrid ver in paper
        classifier: option for pooling method, default token meaning that do cls pooling
                    if you want to use mean pooling, set classifier='mean'
        mode: option for train type, default fine-tune, if you want pretrain, set mode='pretrain'
              In official paper & code by Google Research, they use different classifier head for pretrain, fine-tune
    Math:
        image2sequence: [batch, channel, image_size, image_size] -> [batch, patch, patch_size^2*channel]
        input_embedding: R^(P^2 Β·C)Γ—D
    Reference:
        https://arxiv.org/abs/2010.11929
        https://arxiv.org/abs/1706.03762
        https://github.com/google-research/vision_transformer/blob/main/vit_jax/models_vit.py#L184
    """
    def __init__(
            self,
            num_classes: int,
            channels: int = 3,
            image_size: int = 512,
            patch_size: int = 16,
            num_layers: int = 24,
            dim_model: int = 1024,
            num_heads: int = 16,
            dim_mlp: int = 4096,
            dropout: float = 0.1,
            extractor: str = 'base',
            classifier: str = 'token',
            mode: str = 'fine_tune',
    ) -> None:
        super(VisionTransformer, self).__init__()
        self.num_patches = int(image_size / patch_size)**2
        self.num_layers = num_layers
        self.patch_size = patch_size
        self.dim_model = dim_model
        self.num_heads = num_heads
        self.dim_mlp = dim_mlp
        self.dropout = nn.Dropout(p=dropout)

        # Input Embedding
        self.extractor = extractor
        self.input_embedding = nn.Linear((channels * patch_size**2), dim_model)
        self.conv = nn.Conv2d(
            in_channels=channels,
            out_channels=self.dim_model,
            kernel_size=self.patch_size,
            stride=self.patch_size
        )

        # Encoder Multi-Head Self-Attention
        self.encoder = VisionEncoder(
            self.num_patches,
            self.num_layers,
            self.dim_model,
            self.num_heads,
            self.dim_mlp,
            dropout,
        )
        self.classifier = classifier
        self.pretrain_classifier = nn.Sequential(
            nn.Linear(self.dim_model, self.dim_model),
            nn.Tanh(),
        )
        self.fine_tune_classifier = nn.Linear(self.dim_model, num_classes)
        self.mode = mode

    def forward(self, inputs: Tensor) -> any:
        """ For cls pooling """
        assert inputs.ndim != 4, f"Input shape should be [BS, CHANNEL, IMAGE_SIZE, IMAGE_SIZE], but got {inputs.shape}"
        x = inputs

        if self.extractor == 'cnn':
            # self.conv(x).shape == [batch, dim, image_size/patch_size, image_size/patch_size]
            x = self.conv(x).reshape(x.shape[0], self.dim_model, self.num_patches**2).transpose(-1, -2)
        else:
            # self.extractor == 'base':
            x = self.input_embedding(
                x.reshape(x.shape[0], self.num_patches, (self.patch_size**2 * x.shape[1]))
            )
        cls_token = torch.zeros(x.shape[0], 1, x.shape[2])  # can change init method
        x = torch.cat([cls_token, x], dim=1)

        x, layer_output = self.encoder(x)  # output

        # classification
        x = x[:, 0, :]  # select cls token, which is position 0 in sequence
        if self.mode == 'fine_tune':
            x = self.fine_tune_classifier(x)

        if self.mode == 'pretrain':
            x = self.fine_tune_classifier(self.pretrain_classifier(x))
        return x

ν•œνŽΈ, μ½”λ“œμ—μ„œ λˆˆμ—¬κ²¨λ΄μ•Ό ν•  점은 MLP Head둜, μ €μžλŠ” pre-train μ‹œμ κ³Ό fine-tune μ‹œμ μ— μ„œλ‘œ λ‹€λ₯Έ Classifier Headλ₯Ό μ‚¬μš©ν•œλ‹€. μ „μžμ—λŠ” Activation Function 1κ°œμ™€ 두 개의 MLP Layerλ₯Ό μ‚¬μš©ν•˜κ³ , ν›„μžμ—λŠ” 1개의 MLP Layerλ₯Ό μ‚¬μš©ν•œλ‹€.

λ‹€λ§Œ, pretrain_classifier의 μž…μΆœλ ₯ 차원에 λŒ€ν•œ μ •ν™•ν•œ 수치λ₯Ό λ…Όλ¬Έμ΄λ‚˜ official repo codeλ₯Ό 확인해도 찾을 수 μ—†μ—ˆλ‹€, κ·Έλž˜μ„œ μž„μ‹œλ‘œ λͺ¨λΈμ˜ 차원과 λ˜‘κ°™μ΄ μ„ΈνŒ…ν•˜κ²Œ λ˜μ—ˆλ‹€.

λ˜ν•œ μ €μžλŠ” CLS Poolingκ³Ό λ”λΆˆμ–΄ GAP 방식도 μ œμ‹œν•˜λŠ”λ°, GAP 방식은 좔후에 λ”°λ‘œ μΆ”κ°€κ°€ ν•„μš”ν•˜λ‹€. 그리고 사전 ν›ˆλ ¨κ³Ό 파인 νŠœλ‹ λͺ¨λ‘ λΆ„λ₯˜ ν…ŒμŠ€ν¬λ₯Ό μˆ˜ν–‰ν–ˆλŠ”λ° (심지어 같은 데이터 μ„ΈνŠΈλ₯Ό μ‚¬μš©ν•¨) μ™œ ꡳ이 μ„œλ‘œ λ‹€λ₯Έ Classifier Headλ₯Ό μ •μ˜ν–ˆλŠ”μ§€ μ˜λ„λ₯Ό μ•Œ 수 μ—†μ–΄ 논문을 λ‹€μ‹œ μ½μ–΄λ΄€μ§€λ§Œ, μ΄μœ μ— λŒ€ν•΄μ„œ μƒμ„Ένžˆ μ–ΈκΈ‰ν•˜λŠ” 뢀뢄이 μ—†μ—ˆλ‹€.

ViTλŠ” μž…λ ₯ μž„λ² λ”©μ„ μ •μ˜ν•˜λŠ” 뢀뢄을 μ œμ™Έν•˜λ©΄ μ €μžμ˜ μ˜λ„λŒ€λ‘œ κΈ°μ‘΄ νŠΈλžœμŠ€ν¬λ¨Έμ™€ λ™μΌν•œ λͺ¨λΈ ꡬ쑰λ₯Ό κ°€μ‘Œλ‹€. μ™„μ „νžˆ λ‹€λ₯Έ 데이터인 이미지와 ν…μŠ€νŠΈμ— 같은 ꡬ쑰의 λͺ¨λΈμ„ μ μš©ν•œλ‹€λŠ” 것이 정말 쉽지 μ•Šμ•„ λ³΄μ˜€λŠ”λ°, 패치 κ°œλ…μ„ λ§Œλ“€μ–΄ μžμ—°μ–΄μ˜ ν† ν°μ²˜λŸΌ κ°„μ£Όν•˜κ³  μ‚¬μš©ν•œ 것이 μ˜λ„λŒ€λ‘œ κ΅¬ν˜„ν•˜λŠ”λ° μ§κ΄€μ μ΄λ©΄μ„œλ„ 정말 νš¨κ³Όμ μ΄μ—ˆλ‹€κ³  μƒκ°ν•œλ‹€. 이제 μ΄λ ‡κ²Œ λ§Œλ“€μ–΄μ§„ λͺ¨λΈμ„ 톡해 μ§„ν–‰ν•œ μ—¬λŸ¬ μ‹€ν—˜ 결과에 μ–΄λ–€ μΈμ‚¬μ΄νŠΈκ°€ 담겨 μžˆλŠ”μ§€ μ•Œμ•„λ³΄μž.

πŸ”¬Β Insight from Experiment

πŸ’‘Β Insight 1. ViT의 Scalability 증λͺ…

  • Pre-Train에 μ‚¬μš©λ˜λŠ” 이미지 데이터 μ„ΈνŠΈμ˜ 크기가 컀질수둝 Fine-Tune Stageμ—μ„œ ViTκ°€ CNN보닀 높은 μ„±λŠ₯
  • 같은 μ„±λŠ₯이라면 ViTκ°€ μƒλŒ€μ μœΌλ‘œ 적은 μ—°μ‚°λŸ‰μ„ 기둝

Performance per Dataset Scale Performance per Dataset Scale

μœ„ λ„ν‘œλŠ” Pre-Train Stage에 μ‚¬μš©λœ 이미지 데이터 μ„ΈνŠΈμ— λ”°λ₯Έ λͺ¨λΈμ˜ Fine-Tune μ„±λŠ₯ 좔이λ₯Ό λ‚˜νƒ€λ‚Έ μžλ£Œλ‹€. 사전 ν›ˆλ ¨ 데이터 μŠ€μΌ€μΌμ΄ 크지 μ•Šμ„ λ•ŒλŠ” Conv 기반의 ResNet μ‹œλ¦¬μ¦ˆκ°€ ViT μ‹œλ¦¬μ¦ˆλ₯Ό μ••λ„ν•˜λŠ” λͺ¨μŠ΅μ„ 보여쀀닀. ν•˜μ§€λ§Œ 데이터 μ„ΈνŠΈμ˜ 크기가 컀질수둝 점점 ViT μ‹œλ¦¬μ¦ˆμ˜ μ„±λŠ₯이 ResNet을 λŠ₯κ°€ν•˜λŠ” κ²°κ³Όλ₯Ό λ³Ό 수 μžˆλ‹€.

ν•œνŽΈ, ViT & ResNet μ„±λŠ₯ κ²°κ³Ό λͺ¨λ‘ ImageNetκ³Ό JFT-Image둜 사전 ν›ˆλ ¨ 및 파인 νŠœλ‹μ„ 거쳐 λ‚˜μ™”λ‹€κ³  ν•˜λ‹ˆ μ°Έκ³ ν•˜μž. μΆ”κ°€λ‘œ 파인 νŠœλ‹ κ³Όμ •μ—μ„œ 사전 ν›ˆλ ¨ λ•Œλ³΄λ‹€ 이미지 μ‚¬μ΄μ¦ˆλ₯Ό ν‚€μ›Œμ„œ ν›ˆλ ¨μ„ μ‹œμΌ°λ‹€κ³  λ…Όλ¬Έμ—μ„œ 밝히고 μžˆλŠ”λ°, μ΄λŠ” μ €μžμ˜ μ‹€ν—˜ 결과에 κΈ°μΈν•œ 것이닀. 논문에 λ”°λ₯΄λ©΄ 파인 νŠœλ‹ λ•Œ 사전 ν›ˆλ ¨ λ‹Ήμ‹œλ³΄λ‹€ 더 높은 ν•΄μƒλ„μ˜ 이미지λ₯Ό μ‚¬μš©ν•˜λ©΄ μ„±λŠ₯이 ν–₯상 λœλ‹€κ³  ν•˜λ‹ˆ κΈ°μ–΅ν–ˆλ‹€κ°€ μ¨λ¨Ήμ–΄λ³΄μž.

Performance per FLOPs Scale Performance per FLOPs

μœ„ λ„ν‘œλŠ” μ—°μ‚°λŸ‰ 변화에 λ”°λ₯Έ λͺ¨λΈμ˜ μ„±λŠ₯ 좔이λ₯Ό λ‚˜νƒ€λ‚Έ 그림이닀. 두 μ§€ν‘œ λͺ¨λ‘ 같은 점수라면 ViT μ‹œλ¦¬μ¦ˆμ˜ μ—°μ‚°λŸ‰μ΄ ν˜„μ €νžˆ μ μŒμ„ μ•Œ 수 μžˆλ‹€. λ˜ν•œ 정확도 95% μ΄ν•˜ κ΅¬κ°„μ—μ„œ 같은 μ„±λŠ₯이라면 ViT의 Hybrid 버전 λͺ¨λΈμ˜ μ—°μ‚°λŸ‰μ΄ 일반 ViT 버전보닀 ν˜„μ €νžˆ μ μŒμ„ 확인할 수 μžˆλ‹€. μ΄λŸ¬ν•œ 사싀은 좔후에 Swin-Transformer 섀계에 μ˜κ°μ„ μ€€λ‹€.

두 개의 μ‹€ν—˜ κ²°κ³Όλ₯Ό μ’…ν•©ν–ˆμ„ λ•Œ, ViTκ°€ ResNet보닀 μΌλ°˜ν™” μ„±λŠ₯이 더 λ†’μœΌλ©°(λ„ν‘œ 1) λͺ¨λΈμ˜ Saturation ν˜„μƒμ΄ λ‘λ“œλŸ¬μ§€μ§€ μ•Šμ•„ μ„±λŠ₯의 ν•œκ³„μΉ˜(λ„ν‘œ 2) μ—­μ‹œ 더 λ†’λ‹€κ³  λ³Ό 수 μžˆλ‹€. λ”°λΌμ„œ κΈ°μ‘΄ 트랜슀포머의 연산‒ꡬ쑰적 μΈ‘λ©΄μ—μ„œ Scalabilityλ₯Ό μ„±κ³΅μ μœΌλ‘œ μ΄μ‹ν–ˆλ‹€κ³  평가할 수 μžˆκ² λ‹€.

πŸ’‘Β Insight 2. Pure Self-Attention은 쒋은 이미지 ν”Όμ²˜λ₯Ό μΆ”μΆœν•˜κΈ°μ— μΆ©λΆ„ν•˜λ‹€

  • Patch Embedding Layer의 PCA κ²°κ³Ό, 패치의 κΈ°μ €κ°€ λ˜λŠ” 차원과 μœ μ‚¬ν•œ λͺ¨μ–‘을 μΆ”μΆœ
    • Convolution 없이 Self-Attentionλ§ŒμœΌλ‘œλ„ μΆ©λΆ„νžˆ μ΄λ―Έμ§€μ˜ 쒋은 ν”Όμ²˜λ₯Ό μΆ”μΆœν•˜λŠ” 것이 κ°€λŠ₯
    • Visionμ—μ„œ Convolution에 λŒ€ν•œ reliance νƒˆν”Ό κ°€λŠ₯

Patch Embedding Layer’s Filter Patch Embedding Layer’s Filter

μœ„ μžλ£ŒλŠ” μΆ©λΆ„ν•œ ν•™μŠ΅μ„ 거치고 λ‚œ ViT의 Patch Embedding Layer의 ν•„ν„°λ₯Ό PCAν•œ κ²°κ³Ό μ€‘μ—μ„œ νŠΉμž‡κ°’μ΄ 높은 μƒμœ„ 28개의 ν”Όμ²˜λ₯Ό λ‚˜μ—΄ν•œ 그림이닀. μ΄λ―Έμ§€μ˜ κΈ°λ³Έ λΌˆλŒ€κ°€ λ˜κΈ°μ— 적합해 λ³΄μ΄λŠ” ν”Όμ²˜λ“€μ΄ μΆ”μΆœλœ λͺ¨μŠ΅μ„ λ³Ό 수 μžˆλ‹€.

λ”°λΌμ„œ Inductive Bias 없이, 단일 Self-Attention만으둜 μ΄λ―Έμ§€μ˜ ν”Όμ²˜λ₯Ό μΆ”μΆœν•˜λŠ” 것이 μΆ©λΆ„νžˆ κ°€λŠ₯ν•˜λ‹€. λΉ„μ „ 뢄야에 λ§Œμ—°ν•œ Convolution μ˜μ‘΄μ—μ„œ λ²—μ–΄λ‚˜ μƒˆλ‘œμš΄ μ•„ν‚€ν…μ²˜μ˜ λ„μž…μ΄ κ°€λŠ₯함을 μ‹œμ‚¬ν•œ 뢀뢄이라고 ν•  수 μžˆκ² λ‹€.

πŸ’‘Β Insight 3. Bottom2General Information, Top2Specific Information

  • μž…λ ₯κ³Ό κ°€κΉŒμš΄ μΈμ½”λ”μΌμˆ˜λ‘ Global & Generalν•œ Information을 포착
  • 좜λ ₯κ³Ό κ°€κΉŒμš΄ μΈμ½”λ”μΌμˆ˜λ‘ Local & Specificν•œ Information을 포착

Multi-Head Attention Distance per Network Depth Multi-Head Attention Distance per Network Depth

λ‹€μŒ μžλ£ŒλŠ” μΈμ½”λ”μ˜ 개수 변화에 λ”°λ₯Έ κ°œλ³„ μ–΄ν…μ…˜ ν•΄λ“œμ˜ μ–΄ν…μ…˜ 거리 λ³€ν™” 좔이λ₯Ό λ‚˜νƒ€λ‚Έ 그림이닀. μ—¬κΈ°μ„œ μ–΄ν…μ…˜ κ±°λ¦¬λž€, ν•΄λ“œκ°€ μ–Όλ§ˆλ‚˜ 멀리 떨어진 패치λ₯Ό μ–΄ν…μ…˜ν–ˆλŠ”μ§€ ν”½μ…€ λ‹¨μœ„λ‘œ ν‘œν˜„ν•œ μ§€ν‘œλ‹€. ν•΄λ‹Ή 값이 λ†’μ„μˆ˜λ‘ 거리상 멀리 떨어진 νŒ¨μΉ˜μ™€ μ–΄ν…μ…˜μ„, μž‘μ„μˆ˜λ‘ κ°€κΉŒμš΄ νŒ¨μΉ˜μ™€ μ–΄ν…μ…˜ ν–ˆλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. λ‹€μ‹œ λ„ν‘œλ₯Ό μ‚΄νŽ΄λ³΄μž. μž…λ ₯κ³Ό κ°€κΉŒμš΄ μΈμ½”λ”μΌμˆ˜λ‘(Depth 0) ν•΄λ“œλ³„ μ–΄ν…μ…˜ 거리의 뢄산이 컀지고, 좜λ ₯κ³Ό κ°€κΉŒμš΄ μΈμ½”λ”μΌμˆ˜λ‘(Depth 23) 뢄산이 점자 쀄어듀닀가 거의 ν•œ 점에 μˆ˜λ ΄ν•˜λŠ”λ“―ν•œ 양상을 보여쀀닀. λ‹€μ‹œ 말해, μž…λ ₯κ³Ό κ°€κΉŒμš΄ Bottom EncoderλŠ” 멀리 떨어진 νŒ¨μΉ˜λΆ€ν„° κ°€κΉŒμš΄ νŒ¨μΉ˜κΉŒμ§€ λͺ¨λ‘ 전역적(Global)으둜 μ–΄ν…μ…˜μ„ μˆ˜ν–‰ν•΄ General ν•œ 정보λ₯Ό ν¬μ°©ν•˜κ²Œ 되고 좜λ ₯κ³Ό κ°€κΉŒμš΄ Top EncoderλŠ” κ°œλ³„ ν•΄λ“œλ“€μ΄ λͺ¨λ‘ λΉ„μŠ·ν•œ 거리에 μœ„μΉ˜ν•œ 패치(Local)에 μ–΄ν…μ…˜μ„ μˆ˜ν–‰ν•΄ Specific ν•œ 정보λ₯Ό ν¬μ°©ν•˜κ²Œ λœλ‹€.

이 λ•Œ Globalκ³Ό Localμ΄λΌλŠ” μš©μ–΄ λ•Œλ¬Έμ— Bottom Encoder λŠ” 멀리 떨어진 νŒ¨μΉ˜μ™€ μ–΄ν…μ…˜ν•˜κ³ , Top EncoderλŠ” κ°€κΉŒμš΄ νŒ¨μΉ˜μ™€ μ–΄ν…μ…˜ν•œλ‹€κ³  μ°©κ°ν•˜κΈ° 쉽닀. κ·ΈλŸ¬λ‚˜ κ°œλ³„ ν•΄λ“œλ“€μ˜ μ–΄ν…μ…˜ 거리가 μ–Όλ§ˆλ‚˜ λΆ„μ‚°λ˜μ–΄ μžˆλŠ”κ°€κ°€ λ°”λ‘œ Global, Local을 κ΅¬λΆ„ν•˜λŠ” 기쀀이 λœλ‹€. μž…λ ₯뢀에 κ°€κΉŒμš΄ λ ˆμ΄μ–΄λ“€μ€ ν—€λ“œλ“€μ˜ μ–΄ν…μ…˜ 거리 뢄산이 맀우 큰 편인데, 이것을 이패치 μ €νŒ¨μΉ˜ λͺ¨λ‘ μ–΄ν…μ…˜ 해보고 비ꡐ해본닀고 ν•΄μ„ν•΄μ„œ Global이라고 λΆ€λ₯΄κ³ , 좜λ ₯뢀에 κ°€κΉŒμš΄ λ ˆμ΄μ–΄λŠ” ν—€λ“œλ“€μ˜ μ–΄ν…μ…˜ 거리 뢄산이 맀우 μž‘μ€ 편인데, 이게 λ°”λ‘œ 각각의 ν—€λ“œλ“€μ΄ μ–΄λ–€ 정보에 μ£Όλͺ©ν•΄μ•Όν• μ§€(λΆ„λ₯˜ 손싀이 κ°€μž₯ μž‘μ•„μ§€λŠ” 패치) λ²”μœ„λ₯Ό μΆ©λΆ„νžˆ 쒁힌 μƒνƒœμ—μ„œ νŠΉμ • λΆ€λΆ„μ—λ§Œ μ§‘μ€‘ν•œλ‹€λŠ” 의미둜 해석해 Local 이라고 λΆ€λ₯΄κ²Œ λ˜μ—ˆλ‹€.

<Revisiting Few-sample BERT Fine-tuning>도 μœ„μ™€ λΉ„μŠ·ν•œ λ§₯락의 사싀에 λŒ€ν•΄ μ–ΈκΈ‰ν•˜κ³  μžˆμœΌλ‹ˆ μ°Έκ³ ν•΄λ³΄μž. μ΄λŸ¬ν•œ 사싀은 트랜슀포머 인코더 계열 λͺ¨λΈμ„ νŠœλ‹ν•  λ•Œ Depth λ³„λ‘œ λ‹€λ₯Έ Learning Rate을 μ μš©ν•˜λŠ” Layerwise Learning Rate Decay 의 μ΄ˆμ„μ΄ λ˜κΈ°λ„ ν•œλ‹€. Layerwise Learning Rate Decay 에 λŒ€ν•΄μ„œλŠ” μ—¬κΈ° 포슀트λ₯Ό μ°Έκ³ ν•˜λ„λ‘ ν•˜μž.

Output from Last Encoder Output from Last Encoder

ν•œνŽΈ λ…Όλ¬Έμ—λŠ” μ–ΈκΈ‰λ˜μ§€ μ•Šμ€, ν•„μžμ˜ λ‡Œν”Όμ…œμ— κ°€κΉμ§€λ§Œ, 좜λ ₯에 κ°€κΉŒμš΄ μΈμ½”λ”λ“€μ˜ ν•΄λ“œκ°€ 가진 Attention Distance이 λͺ¨λ‘ λΉ„μŠ·ν•˜λ‹€λŠ” μ‚¬μ‹€λ‘œ 이미지 λΆ„λ₯˜μ— 결정적인 역할을 ν•˜λŠ” ν”Όμ²˜κ°€ μ΄λ―Έμ§€μ˜ νŠΉμ • ꡬ역에 λͺ¨μ—¬ 있으며, κ·Έ μŠ€νŒŸμ€ μ΄λ―Έμ§€μ˜ 쀑앙 뢀근일 κ°€λŠ₯성이 λ†’λ‹€κ³  μΆ”μΈ‘ ν•΄λ³Ό 수 μžˆλ‹€. λͺ¨λ“  ν•΄λ“œμ˜ ν”½μ…€ 거리가 μ„œλ‘œ λΉ„μŠ·ν•˜λ €λ©΄ 일단 λΉ„μŠ·ν•œ μœ„μΉ˜μ˜ νŒ¨μΉ˜μ— μ–΄ν…μ…˜μ„ ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— λΆ„λ₯˜ 손싀값을 μ΅œμ†Œλ‘œ μ€„μ—¬μ£ΌλŠ” ν”Όμ²˜λŠ” 보톡 ν•œ ꡬ역(패치)에 λͺ°λ € μžˆμ„ 것이라고 μœ μΆ”κ°€ κ°€λŠ₯ν•˜λ‹€. λ˜ν•œ νŠΉμ • 슀팟이 쀑앙에 μœ„μΉ˜ν• μˆ˜λ‘ μ–΄ν…μ…˜ 거리의 뢄산이 쀄어듀것이라고 생각 ν•΄λ³Ό μˆ˜λ„ μžˆμ—ˆλ‹€. μ €μžλŠ” Attention Rolloutμ΄λΌλŠ” κ°œλ…μ„ 톡해 Attention Distance을 μ‚°μΆœν–ˆλ‹€κ³  μ–ΈκΈ‰ν•˜λŠ”λ°, μžμ„Έν•œ λ‚΄μš©μ€ μ˜†μ— 두 링크λ₯Ό μ°Έκ³ ν•΄λ³΄μž(ν•œκ΅­μ–΄ μ„€λͺ… λΈ”λ‘œκ·Έ, 원논문). μ΄λŸ¬ν•œ ν•„μžμ˜ 가섀이 λ§žλ‹€λ©΄, Convolution 의 Inductive Bias 쀑 Locality 의 νš¨κ³Όμ„±μ„ Self-Attention을 톡해 μž…μ¦μ΄ κ°€λŠ₯ν•˜λ©°, λ°˜λŒ€λ‘œ Convolution에 λŒ€ν•œ μ˜μ‘΄μ—μ„œ λ²—μ–΄λ‚˜ 단일 Self-Attention μœΌλ‘œλ„ 같은 효과λ₯Ό λ‚Ό 수 μžˆλ‹€λŠ” 증거 쀑 ν•˜λ‚˜κ°€ 될 것이닀.

πŸ’‘Β Insight 4. ViTλŠ” CLS Pooling μ‚¬μš©ν•˜λŠ”κ²Œ 효율적

  • CLS Pooling은 GAP 보닀 2λ°° 이상 큰 ν•™μŠ΅λ₯ μ„ μ‚¬μš©ν•΄λ„ λΉ„μŠ·ν•œ μ„±λŠ₯을 기둝
    • ν•™μŠ΅ μ†λ„λŠ” 더 λΉ λ₯΄λ˜ μ„±λŠ₯이 λΉ„μŠ·ν•˜κΈ° λ•Œλ¬Έμ— CLS Pooling 이 더 효율적

Performance Trend by Pooling Method with LR Performance Trend by Pooling Method with LR

λ‹€μŒ λ„ν‘œλŠ” 풀링 방식과 ν•™μŠ΅λ₯ μ˜ 변동에 λ”°λ₯Έ 정확도 λ³€ν™” 좔이λ₯Ό λ‚˜νƒ€λ‚Έ 그림이닀. λΉ„μŠ·ν•œ μ„±λŠ₯이라면 CLS Pooling이 GAP보닀 2λ°° 이상 큰 ν•™μŠ΅λ₯ μ„ μ‚¬μš©ν–ˆλ‹€. ν•™μŠ΅λ₯ μ΄ 크면 λͺ¨λΈμ˜ 수렴 속도가 빨라져 ν•™μŠ΅ 속도가 λΉ¨λΌμ§€λŠ” μž₯점이 μžˆλ‹€. 그런데 μ„±λŠ₯κΉŒμ§€ λΉ„μŠ·ν•˜λ‹€λ©΄ ViTλŠ” CLS Pooling을 μ‚¬μš©ν•˜λŠ” 것이 더 효율적이라고 ν•  수 μžˆκ² λ‹€.

λ‚˜μ€‘μ— μ‹œκ°„μ΄ λœλ‹€λ©΄ λ‹€λ₯Έ 풀링 방식, 예λ₯Ό λ“€λ©΄ Weighted Layer Pooling, GeM Pooling, Attention Pooling 같은 것을 μ μš©ν•΄ μ‹€ν—˜ν•΄λ³΄κ² λ‹€.

πŸ’‘Β Insight 5. ViTλŠ” Absolute 1D-Position Embedding μ‚¬μš©ν•˜λŠ”κ²Œ κ°€μž₯ 효율적

  • μ–΄λ–€ ν˜•νƒœλ‘œλ“  μœ„μΉ˜ μž„λ² λ”© 값을 μ •μ˜ν•΄μ€€λ‹€λ©΄, ν˜•νƒœμ™€ μ’…λ₯˜μ— 상관없이 거의 λΉ„μŠ·ν•œ μ„±λŠ₯을 λ³΄μž„
  • μ„±λŠ₯이 λΉ„μŠ·ν•˜λ©΄, 직관적이고 κ΅¬ν˜„μ΄ κ°„νŽΈν•œ Absolute 1D-Position Embedding 방법을 μ‚¬μš©ν•˜λŠ” 것이 κ°€μž₯ 효율적
  • ViTλŠ” Patch-Level μ‚¬μš©ν•΄, Pixel-Level보닀 μƒλŒ€μ μœΌλ‘œ μ‹œν€€μŠ€ 길이가 짧아 μœ„μΉ˜β€’κ³΅κ°„ 정보λ₯Ό μΈμ½”λ”©ν•˜λŠ” 방식에 영ν–₯을 덜 λ°›μŒ

Performance Table by making Position Embedding method Performance Table by making Position Embedding method

μœ„ μ‹€ν—˜ κ²°κ³ΌλŠ” Position Embedding 인코딩 방식에 λ”°λ₯Έ ViT λͺ¨λΈμ˜ μ„±λŠ₯ λ³€ν™” 좔이λ₯Ό λ‚˜νƒ€λ‚Έ μžλ£Œλ‹€. 인코딩 ν˜•νƒœμ™€ 상관없이 μœ„μΉ˜ μž„λ² λ”©μ˜ μœ λ¬΄κ°€ μ„±λŠ₯에 큰 영ν–₯을 λ―ΈμΉœλ‹€λŠ” 사싀을 μ•Œλ €μ£Όκ³  μžˆλ‹€. ν•œνŽΈ, 인코딩 ν˜•νƒœ 변화에 λ”°λ₯Έ μœ μ˜λ―Έν•œ μ„±λŠ₯ λ³€ν™”λŠ” μ—†μ—ˆλ‹€. ν•˜μ§€λ§Œ Absolute 1D-Position Embedding의 컨셉이 κ°€μž₯ 직관적이며 κ΅¬ν˜„ν•˜κΈ° νŽΈν•˜κ³  μ—°μ‚°λŸ‰μ΄ λ‹€λ₯Έ 인코딩보닀 μ λ‹€λŠ” 것을 κ°μ•ˆν•˜λ©΄ ViT에 κ°€μž₯ 효율적인 μœ„μΉ˜ μž„λ² λ”© 방식이라고 νŒλ‹¨ν•  수 μžˆλ‹€.

논문은 결과에 λŒ€ν•΄ ViTκ°€ μ‚¬μš©ν•˜λŠ” Patch-Level Embedding이 Pixel-Level보닀 μƒλŒ€μ μœΌλ‘œ 짧은 μ‹œν€€μŠ€ 길이λ₯Ό κ°–κΈ° λ•Œλ¬Έμ΄λΌκ³  μ„€λͺ…ν•œλ‹€. 예λ₯Ό λ“€μ–΄ 224x224 μ‚¬μ΄μ¦ˆμ˜ 이미지λ₯Ό 16x16 μ‚¬μ΄μ¦ˆμ˜ 패치 μ—¬λŸ¬μž₯으둜 λ§Œλ“ λ‹€κ³  μƒκ°ν•΄λ³΄μž. μž„λ² λ”© 차원에 λ“€μ–΄κ°€λŠ” $N$ 은 $(224/16)^2$ , 즉 196이 λœλ‹€. ν•œνŽΈ 이것을 Pixel-Level둜 μž„λ² λ”© ν•˜κ²Œ 되면 $224^2$, 즉 50176 개의 μ‹œν€€μŠ€κ°€ 생긴닀. λ”°λΌμ„œ Pixel-Level 에 λΉ„ν•˜λ©΄ 훨씬 짧은 μ‹œν€€μŠ€ 길이λ₯Ό κ°–κΈ° λ•Œλ¬Έμ— Absolute 1D-Position Embedding λ§ŒμœΌλ‘œλ„ μΆ©λΆ„νžˆ Spatial Relation을 ν•™μŠ΅ν•  수 μžˆλŠ” 것이닀.

Absolute 1D-Position Embedding Absolute 1D-Position Embedding

ν•˜μ§€λ§Œ, ν•„μžλŠ” μžμ—°μ–΄ 처리의 Transformer-XL, XLNet, DeBERTa 같은 λͺ¨λΈλ“€μ΄ Relative Position Embedding 방식을 μ μš©ν•΄ 큰 성곡을 κ±°λ‘” λ°”κ°€ μžˆλ‹€λŠ” 점을 μƒκ°ν•˜λ©΄ 이런 κ²°κ³Όκ°€ 납득이 κ°€λ©΄μ„œλ„ μ˜μ•„ν–ˆλ‹€.

μ €μžλŠ” μ‹€ν—˜μ— μ‚¬μš©ν•œ λͺ¨λ“  데이터 μ„ΈνŠΈλ₯Ό 224x224둜 resize ν–ˆλ‹€κ³  밝히고 μžˆλŠ”λ°, λ§Œμ•½ 이미지 μ‚¬μ΄μ¦ˆκ°€ 512x512μ •λ„λ§Œ λ˜λ”λΌλ„ $N$ 값이 1024 μ΄λΌμ„œ μœ„ 결과와 μƒλ‹Ήνžˆ λ‹€λ₯Έ 양상이 λ‚˜νƒ€λ‚˜μ§€ μ•Šμ„κΉŒ ν•˜λŠ” 생각이 λ“ λ‹€. 좔후에 μ‹œκ°„μ΄ λœλ‹€λ©΄ 이 뢀뢄도 κΌ­ μ‹€ν—˜ν•΄λ΄μ•Όκ² λ‹€. 예츑컨데 이미자 μ‚¬μ΄μ¦ˆκ°€ 컀질수둝 2D Position Embedding ν˜Ήμ€ Relative Position Embedding이 더 효율적일 것이라 μ˜ˆμƒν•œλ‹€.

πŸ§‘β€βš–οΈΒ Conclusion

μ΄λ ‡κ²Œ ViT λͺ¨λΈμ„ μ œμ•ˆν•œ <An Image Is Worth 16x16 Words: Transformers For Image Recognition At Scale>에 μ‹€λ¦° λ‚΄μš©μ„ λͺ¨λ‘ μ‚΄νŽ΄λ³΄μ•˜λ‹€. Conv 에 λŒ€ν•œ μ˜μ‘΄μ„ νƒˆν”Ό ν–ˆλ‹€λŠ” μ μ—μ„œ 맀우 μ˜λ―Έκ°€ μžˆλŠ” μ‹œλ„μ˜€μœΌλ©°, Self-Attention & Transformer ꡬ쑰 μ±„νƒλ§ŒμœΌλ‘œλ„ 컴퓨터 λΉ„μ „ μ˜μ—­μ— μ–΄λŠ 정도 scalability λ₯Ό μ΄μ‹ν•˜λŠ”λ° μ„±κ³΅ν–ˆλ‹€λŠ” μ μ—μ„œ ν›„λŒ€ 연ꡬ에 μ€‘μš”ν•œ μ‹œμ‚¬μ μ„ 남겼닀. μƒλŒ€μ μœΌλ‘œ 정체(??)λ˜μ–΄ 있던 λΉ„μ „ μ˜μ—­μ΄ μ„±λŠ₯의 ν•œκ³„λ₯Ό ν•œλ‹¨κ³„ λ›°μ–΄λ„˜μ„ 수 μžˆλŠ” μ΄ˆμ„μ„ λ§ˆλ ¨ν•΄μ€€ μ…ˆμ΄λ‹€.

ν•˜μ§€λ§Œ, ViT의 Pretrain Stage에 μ ν•©ν•œ Self-Supervised Learning 방법을 찾지 λͺ»ν•΄ μ—¬μ „νžˆ Supervised Learning 방식을 μ±„νƒν•œ 점은 맀우 아쉬웠닀. μ΄λŠ” κ²°κ΅­ 데이터 Scale ν™•μž₯에 ν•œκ³„λ₯Ό μ˜λ―Έν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. μ˜€λŠ˜λ‚  BERT와 GPT의 성곡 μ‹ ν™”λŠ” 비단 Self-Attention와 Transformer의 ꡬ쑰적 탁월성에 μ˜ν•΄μ„œλ§Œ νƒ„μƒν•œκ²Œ μ•„λ‹ˆλ‹€. 이에 λͺ»μ§€ μ•Šκ²Œ(개인적으둜 제일 μ€‘μš”ν•˜λ‹€ 생각) μ£Όμš”ν–ˆλ˜ 것이 λ°”λ‘œ 데이터 Scale ν™•μž₯이닀. MLM, AR λ“±μ˜ Self-Supervised Learning 덕뢄에 데이터 Scale을 효율적으둜 μŠ€μΌ€μΌ μ—… μ‹œν‚¬ 수 μžˆμ—ˆκ³ , 사전 ν›ˆλ ¨ λ°μ΄ν„°μ˜ μ¦κ°€λŠ” λͺ¨λΈ 깊이, λ„ˆλΉ„, μ°¨μ›κΉŒμ§€ λ”μš± 크케 ν‚€μš°λŠ”λ° κΈ°μ—¬ν–ˆλ‹€.

λ˜ν•œ ViTλŠ” μ„ μ²œμ μœΌλ‘œ Patch-Level Embedding을 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— λ‹€μ–‘ν•œ 이미지 ν…ŒμŠ€ν¬μ— μ μš©ν•˜λŠ” 것이 νž˜λ“€λ‹€. Segmentation, Object Detection 같은 TaskλŠ” ν”½μ…€ λ‹¨μœ„λ‘œ μ˜ˆμΈ‘μ„ μˆ˜ν–‰ν•΄ 객체λ₯Ό νƒμ§€ν•˜κ±°λ‚˜ λΆ„ν• ν•΄μ•Ό ν•œλ‹€. ν•˜μ§€λ§Œ Patch λ‹¨μœ„λ‘œ ν›ˆλ ¨μ„ μˆ˜ν–‰ν–ˆλ˜ ViTλŠ” Pixel λ‹¨μœ„μ˜ μ˜ˆμΈ‘μ„ μˆ˜ν–‰ν•˜λŠ”λ° 어렀움을 κ²ͺλŠ”λ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ Self-Attention 자체의 Computational Overheadκ°€ λ„ˆλ¬΄ 심해 κ³ ν•΄μƒλ„μ˜ 이미지λ₯Ό 적절히 닀루기 νž˜λ“€λ‹€. μœ„μ—μ„œλ„ μ–ΈκΈ‰ν–ˆμ§€λ§Œ μ΄λ―Έμ§€μ˜ μ‚¬μ΄μ¦ˆκ°€ 512x512만 λ˜μ–΄λ„ 이미 패치의 κ°œμˆ˜κ°€ 1024κ°€ λœλ‹€. μ‚¬μ΄μ¦ˆκ°€ 컀질수둝 μ‹œν€€μŠ€ 길이 μ—­μ‹œ κΈ°ν•˜κΈ‰μˆ˜μ μœΌλ‘œ μ»€μ§€λŠ”λ°λ‹€κ°€ Self-Attention λŠ” 쿼리와 ν‚€ 행렬을 내적 (자기 μžμ‹ κ³Ό 곱이라 λ³Ό 수 있음) ν•˜κΈ° λ•Œλ¬Έμ— Computational Overheadκ°€ $N^2$이 λœλ‹€.

ν•„μžλŠ” ViTλ₯Ό 절반의 성곡이라고 ν‰ν•˜κ³  μ‹Άλ‹€. 본래 ViT의 섀계 λͺ©μ μ€ λΉ„μ „ λΆ„μ•Όμ˜ Conv에 λŒ€ν•œ μ˜μ‘΄μ„ νƒˆν”Όν•˜λ©΄μ„œ, ν“¨μ–΄ν•œ Self-Attention을 λ„μž…ν•΄ Scalabilty λ₯Ό μ΄μ‹ν•˜λŠ” κ²ƒμ΄μ—ˆλ‹€. Self-Attention을 λ„μž…ν•˜λŠ”λ°λŠ” μ„±κ³΅ν–ˆμ§€λ§Œ, μ—¬μ „νžˆ λ‹€λ£° 수 μžˆλŠ” 이미지 μ‚¬μ΄μ¦ˆλ‚˜ Taskμ—λŠ” ν•œκ³„κ°€ λΆ„λͺ…ν•˜λ©° κ²°μ •μ μœΌλ‘œ Self-Supervised Learning 방식을 λ„μž…ν•˜μ§€ λͺ»ν–ˆλ‹€. Scalabilty λΌλŠ” λ‹¨μ–΄μ˜ 의미λ₯Ό μƒκ°ν•˜λ©΄, 방금 λ§ν•œ λΆ€λΆ„μ—μ„œκΉŒμ§€ ν™•μž₯성이 μžˆμ–΄μ•Ό 섀계 μ˜λ„μ— λΆ€ν•©ν•˜λŠ” 결과라고 μƒκ°ν•œλ‹€.

Leave a comment