
대형 언어 모델(LLM)은 instruction tuning을 통해 zero-shot 성능을 크게 향상시켰습니다. ChatGPT와 GPT-4의 성공은 언어 영역에서 instruction-following의 강력함을 입증했습니다. 하지만 멀티모달 영역에서의 instruction tuning은 거의 탐구되지 않았습니다.
기존 컴퓨터 비전 연구들은:

LLaVA(Large Language and Vision Assistant)는 vision과 language를 통합한 end-to-end 학습 멀티모달 모델입니다.

주요 기여점:
Multimodal Instruction-Following Data
Large Multimodal Model (LMM)
평가 벤치마크
사람에게 "이 사진에서 고양이를 찾아서 빨간색으로 칠해줘"라고 말하면 대부분 쉽게 해낼 수 있습니다. 하지만 AI에게는 이미지 이해, 자연어 해석, 행동 실행이라는 세 가지 능력이 동시에 필요한 어려운 문제입니다. 연구자들은 이 문제를 크게 두 방향으로 접근해왔습니다.
첫 번째는 End-to-End 학습 모델입니다.
입력부터 출력까지 하나의 신경망이 모든 것을 처리하는 방식으로, Vision-Language Navigation(VLN), Habitat 2.0, InstructPix2Pix 등이 대표적입니다.
두 번째는 시스템 기반 접근입니다.
LLM을 지휘자(Orchestrator)로 활용하여 여러 전문 모델을 순차적으로 호출하는 방식입니다. Visual ChatGPT, MM-REACT, VisProg, ViperGPT 등이 여기에 해당합니다.
LLaVA는 이 두 접근법 사이에서 균형점을 찾습니다. End-to-End 모델의 효율성(단일 모델, 빠른 추론)을 유지하면서도, 시스템 기반 접근의 범용성(다양한 태스크 처리)을 갖추는 것이 목표입니다.
Instruction Tuning은 사전학습된 LLM을 자연어 지시문 형태의 데이터로 추가 학습시켜, 다양한 태스크를 zero-shot으로 수행할 수 있게 만드는 기법입니다.

https://medium.com/@lmpo/an-overview-instruction-tuning-for-llms-440228e7edab
LLaVA는 이 Instruction Tuning 아이디어를 비전 분야에 적용합니다. 핵심은 학습 데이터를 어떻게 확보하느냐인데, LLaVA는 GPT-4를 데이터 생성기로 활용합니다. GPT-4는 이미지를 직접 볼 수 없지만, 이미지의 캡션이나 바운딩 박스 정보를 텍스트로 제공받으면 해당 이미지에 대한 고품질 Q&A 데이터를 생성할 수 있습니다. 이는 NLP에서 검증된 Self-Instruct 방식의 변형으로, LLaVA는 이렇게 생성된 visual instruction-following 데이터로 vision-language 모델을 튜닝합니다.
LLaVA가 등장하기 전에도 이미지와 텍스트를 함께 처리하는 Large Multimodal Model들이 존재했습니다. 이 흐름의 시작점으로 많이 언급되는 것이 바로 Flamingo입니다.

Flamingo는 "멀티모달 GPT-3 순간"이라 불릴 만큼 상징적인 모델로, 대규모 이미지-텍스트 데이터로 학습하여 zero-shot task transfer와 in-context learning 능력을 보여주었습니다.
(참고) GPT-3(2020) 이전의 NLP 모델들은 새로운 태스크를 수행하려면 해당 태스크에 맞는 데이터로 fine-tuning이 필수였습니다.
- 그런데 GPT-3는 별도 fine-tuning 없이 프롬프트에 몇 개의 예시만 보여주면(few-shot) 새로운 태스크를 수행할 수 있었습니다. 이게 바로 in-context learning이고, "scaling이 곧 능력이다"라는 패러다임을 열었죠.
마치 GPT-3가 NLP 분야에서 few-shot learning의 가능성을 열었듯이, Flamingo는 비전-언어 분야에서 비슷한 패러다임 전환을 이끌었습니다.
Flamingo는 GPT-3처럼 few-shot in-context learning을 멀티모달 영역에서 처음으로 가능하게 했습니다:
- 이미지-텍스트 예시 몇 개만 프롬프트에 넣어주면
- Fine-tuning 없이 VQA, 캡셔닝, 분류 등 다양한 태스크 수행
- 심지어 일부 벤치마크에서 fine-tuned 모델들을 능가
Flamingo 이후로 다양한 image-text 쌍 기반 학습 모델들이 등장했습니다. BLIP-2는 frozen image encoder와 LLM을 Q-Former라는 경량 모듈로 연결하여 효율적인 학습을 가능하게 했고, FROMAGe는 텍스트 생성과 이미지 검색(retrieval)을 모두 수행할 수 있는 능력을 갖추었습니다. KOSMOS-1은 마이크로소프트에서 발표한 모델로 다양한 멀티모달 태스크에서 강력한 성능을 보였으며, PaLM-E는 구글에서 로봇 제어와 같은 embodied AI 태스크를 위해 설계되었습니다. 오픈소스 진영에서도 OpenFlamingo와 LLaMA-Adapter 등이 공개되면서 연구 커뮤니티의 접근성이 높아졌습니다.
NLP 분야에서 GPT-3가 InstructGPT로 발전하며 사용자 지시를 훨씬 잘 따르게 된 것처럼, 멀티모달 모델에도 이런 instruction tuning이 필요했지만 아직 체계적으로 연구되지 않은 상태였습니다.
LLaVA는 바로 이 격차를 메우기 위해 등장했습니다. 기존 모델들이 놓치고 있던 visual instruction tuning을 체계적으로 연구하고, 이를 통해 멀티모달 태스크에서의 성능을 끌어올리는 것이 LLaVA의 핵심 목표입니다.

GPT-4는 이미지를 직접 볼 수 없으니까, 텍스트로 이미지 정보를 설명해줍니다. (이미지 상단: GPT-4에게 주는 입력 (Context))
이미지를 언어 전용 GPT-4가 이해할 수 있는 형태로 인코딩:
1. Captions (이미지 설명)
A group of people standing outside of a black vehicle with various luggage.
Luggage surrounds a vehicle in an underground parking area.
People try to fit all of their luggage in an SUV.2. Bounding Boxes (객체 위치)
person: [0.681, 0.242, 0.774, 0.694]
backpack: [0.384, 0.696, 0.485, 0.914]
suitcase: [0.758, 0.413, 0.845, 0.69]이 context를 바탕으로 GPT-4가 3가지 유형의 Q&A 데이터를 생성합니다. (이미지 하단: GPT-4가 생성하는 출력 (Response))
Response type 1: Conversation (단순 대화)
Q: What type of vehicle is featured in the image?
A: The image features a black sport utility vehicle (SUV)...
Response type 2: Detailed Description (상세 설명)
Q: (암묵적으로 "이미지를 설명해줘")
A: The image is an underground parking area with a black SUV parked.
There are three people in the scene, with one person standing closer
to the left side of the vehicle...
Response type 3: Complex Reasoning (복잡한 추론)
Q: What challenges do these people face?
A: They are facing the challenge of fitting all their luggage into the
black SUV. There are multiple suitcases and backpacks to be packed,
which suggests that the group has a significant amount of belongings...

1. Vision Encoder: CLIP ViT-L/14
2. Projection Layer
3. Language Model: Vicuna

각 이미지 에 대해 multi-turn conversation 데이터 를 생성합니다. 여기서 는 총 턴 수이고, 는 질문, 는 응답입니다.
번째 턴의 instruction 는 다음과 같이 구성됩니다:


LLM의 기존 auto-regressive training objective를 사용합니다. 길이 인 시퀀스에서 target answer 의 확률을 최대화합니다:
중요한 점은 Assistant의 응답 토큰()만 loss 계산에 사용된다는 것입니다. Human의 질문이나 이미지 토큰에는 loss를 걸지 않습니다.
목적:
데이터:
학습 설정:
X_system-message <STOP>
Human: X_instruct <STOP> Assistant: X_a <STOP>
- X_instruct = [X_q, X_v] 또는 [X_v, X_q] (랜덤 선택)
- X_q: 이미지 설명 요청 질문 (랜덤 샘플링)
- X_v: 이미지 features
- X_a: 원본 캡션 (ground-truth)
파라미터:
결과: 이미지 features 가 LLM word embedding과 정렬됨
목적:
파라미터:
Multi-turn Conversation 형식:
Xsystem-message <STOP>
Human: X¹_instruct <STOP> Assistant: X¹_a <STOP>
Human: X²_instruct <STOP> Assistant: X²_a <STOP>
...
- X_instruct = [X_q, X_v] 또는 [X_v, X_q] (랜덤 선택)
- X_q: 이미지 설명 요청 질문 (랜덤 샘플링)
- X_v: 이미지 features
- X_a: 원본 캡션 (ground-truth)
구성:
Loss Computation:
결과: LLM이 visual context를 이해하면서 다양한 instruction을 따르는 Multimodal Chatbot 능력 획득
데이터: 158K language-image instruction-following samples
학습 설정:
데이터셋: ScienceQA benchmark
형식: Single-turn conversation
학습 설정:
Example: Extreme Ironing

LLaVA 응답:
The unusual aspect of this image is a man ironing clothes on the back
of a minivan or van. This is not a typical place to perform this activity,
as one would usually iron clothes in a more stationary and safe location,
such as a home, using a regular ironing board. The scene depicted in the
image is peculiar as it involves a makeshift ironing setup on a vehicle,
which can be both unsafe and unconventional...
GPT-4 응답:
The unusual thing about this image is that a man is ironing clothes on
an ironing board attached to the roof of a moving taxi.
BLIP-2 응답:
a man is sitting on the back of a yellow cab
OpenFlamingo 응답:
The man is drying his clothes on the hood of his car.
분석:
평가 방법:
1. Triplet 생성: (Image, Ground-truth description, Question)
2. 모델 응답 생성
3. Text-only GPT-4를 judge로 활용
LLaVA-Bench (COCO): 90 questions
| Training Data | Conversation | Detail | Complex | All |
|---|---|---|---|---|
| Full data | 83.1 | 75.3 | 96.5 | 85.1 |
| Detail + Complex | 81.5 (-1.6) | 73.3 (-2.0) | 90.8 (-5.7) | 81.9 (-3.2) |
| Conv + 5% Detail + 10% Complex | 81.0 (-2.1) | 68.4 (-7.1) | 91.5 (-5.0) | 80.5 (-4.4) |
| Conversation | 76.5 (-6.6) | 59.8 (-16.2) | 84.9 (-12.4) | 73.8 (-11.3) |
| No Instruction Tuning | 22.0 (-61.1) | 24.0 (-51.3) | 18.5 (-78.0) | 21.5 (-63.6) |
핵심 발견:
1. Instruction tuning으로 50점 이상 향상
2. Detailed description + complex reasoning 추가 시 7점 향상
3. Reasoning 능력이 conversation 능력도 보완
4. 세 가지 데이터 유형 모두 사용 시 최고 성능
LLaVA-Bench (In-the-Wild): 60 questions
| Model | Conversation | Detail | Complex | All |
|---|---|---|---|---|
| OpenFlamingo | 19.3 ± 0.5 | 19.0 ± 0.5 | 19.1 ± 0.7 | 19.1 ± 0.4 |
| BLIP-2 | 54.6 ± 1.4 | 29.1 ± 1.2 | 32.9 ± 0.7 | 38.1 ± 1.0 |
| LLaVA | 57.3 ± 1.9 | 52.5 ± 6.3 | 81.7 ± 1.8 | 67.3 ± 2.0 |
성과:
도전적인 예제들:
1. Ramen 예제: 레스토랑 이름 인식
흥미로운 실패 사례:
| Model | NAT | SOC | LAN | TXT | IMG | NO | G1-6 | G7-12 | Avg |
|---|---|---|---|---|---|---|---|---|---|
| Human | 90.23 | 84.97 | 87.48 | 89.60 | 87.50 | 88.10 | 91.59 | 82.42 | 88.40 |
| GPT-3.5 CoT | 75.44 | 70.87 | 78.09 | 74.68 | 67.43 | 79.93 | 78.23 | 69.68 | 75.17 |
| LLaMA-Adapter | 84.37 | 88.30 | 84.36 | 83.72 | 80.32 | 86.90 | 85.83 | 84.05 | 85.19 |
| MM-CoT_Large | 95.91 | 82.00 | 90.82 | 95.26 | 88.80 | 92.89 | 92.44 | 90.31 | 91.68 |
| LLaVA | 90.36 | 95.95 | 88.00 | 89.49 | 88.00 | 90.66 | 90.93 | 90.90 | 90.92 |
| LLaVA+GPT-4 (judge) | 91.56 | 96.74 | 91.09 | 90.62 | 88.99 | 93.52 | 92.73 | 92.16 | 92.53 |
핵심 성과:
1. LLaVA 단독으로 90.92% (SoTA MM-CoT_Large와 근접)
2. GPT-4 judge 앙상블로 92.53% (새로운 SOTA)
3. Text-only GPT-4(82.69%)가 multimodal 성능 향상에 기여
| Variant | Before Last | Last |
|---|---|---|
| Best | 90.92 | 89.96 (-0.96) |
| Predict answer first | - | 89.77 (-1.15) |
| Train from scratch | 85.81 (-5.11) | - |
| 7B model | 89.84 (-1.08) | - |
발견:
1. Visual features: Before last layer가 0.96% 더 높음
Chain-of-Thought: Reasoning-first 전략
Pre-training: 5.11% 향상 기여
Model size: 13B > 7B (1.08% 차이)
아래는 https://github.com/haotian-liu/LLaVA 코드를 분석 후 정리한 내용입니다.
LLaVA/
├── llava/ # 핵심 패키지
│ ├── model/ # 모델 아키텍처
│ │ ├── llava_arch.py # 핵심 vision-language 모델
│ │ ├── builder.py # 모델 로딩 및 인스턴스화
│ │ ├── multimodal_encoder/
│ │ │ └── clip_encoder.py # CLIP 비전 인코더
│ │ └── multimodal_projector/
│ │ └── builder.py # Vision-language bridge
│ ├── train/ # 학습 스크립트
│ │ ├── train.py # 메인 학습 파이프라인
│ │ └── llava_trainer.py # 커스텀 트레이너
│ ├── serve/ # 추론 서빙
│ │ ├── cli.py
│ │ ├── gradio_web_server.py # Web UI
│ │ └── model_worker.py
│ ├── mm_utils.py # 멀티모달 유틸리티
│ └── conversation.py # 대화 관리
├── scripts/ # 학습/평가 스크립트
│ ├── pretrain.sh
│ ├── finetune.sh
│ └── finetune_lora.sh
└── predict.py # 추론 인터페이스

# CLIP Vision Model 로딩
self.vision_tower = CLIPVisionModel.from_pretrained(vision_tower_name)
self.vision_tower.requires_grad_(False) # ⭐ 항상 Frozen
def forward(self, images):
image_features = self.vision_tower(images, output_hidden_states=True)
return image_features # [batch, num_patches, 1024]
Vision Encoder는 CLIP ViT-L/14를 사용하며, Stage 1, 2 모두 frozen 상태로 유지됩니다.
def build_vision_projector(config):
projector_type = config.mm_projector_type
if projector_type == 'linear':
# 단순 선형 변환: 1024 → 4096
return nn.Linear(config.mm_hidden_size, config.hidden_size)
if projector_type == 'mlp2x_gelu':
# 2-layer MLP: Linear → GELU → Linear
return nn.Sequential(
nn.Linear(config.mm_hidden_size, config.hidden_size),
nn.GELU(),
nn.Linear(config.hidden_size, config.hidden_size)
)
Projector는 Vision Encoder 출력(1024차원)을 LLM embedding 공간(4096차원)으로 변환합니다.
def prepare_inputs_labels_for_multimodal(self, input_ids, images, labels, ...):
# 1) 이미지 인코딩
image_features = self.encode_images(images) # [batch, 256, 4096]
# 2) IMAGE_TOKEN_INDEX 위치 찾기
image_token_indices = torch.where(input_ids == IMAGE_TOKEN_INDEX)[0]
# 3) 텍스트 embedding과 이미지 features 결합
for i, idx in enumerate(image_token_indices):
# 이미지 토큰 이전 텍스트
cur_new_input_embeds.append(embed_tokens(input_ids[:idx]))
# 이미지 features 삽입
cur_new_input_embeds.append(image_features[i])
# 이미지 토큰 이후 텍스트
cur_new_input_embeds.append(embed_tokens(input_ids[idx+1:]))
# 4) 이미지 위치에는 IGNORE_INDEX로 loss 제외
image_labels = torch.full((num_patches,), IGNORE_INDEX)
return torch.cat(cur_new_input_embeds, dim=0)
핵심 흐름:
입력: "Human: <image> 이 사진을 설명해줘"
↓
1. <image> 토큰 위치 찾기
2. 해당 위치에 image_features (256개 토큰) 삽입
3. 이미지 토큰에는 loss 계산 제외 (IGNORE_INDEX)
↓
출력: [텍스트 임베딩] + [이미지 256토큰] + [텍스트 임베딩]
# Stage 1: Projection만 학습
if model_args.tune_mm_mlp_adapter:
model.requires_grad_(False) # 전체 frozen
for p in model.get_model().mm_projector.parameters():
p.requires_grad = True # projector만 trainable
# Stage 2: Projection + LLM 학습
if training_args.freeze_mm_mlp_adapter:
for p in model.get_model().mm_projector.parameters():
p.requires_grad = False # projector frozen (선택적)
def train():
# 1) 모델 로딩
model = LlavaLlamaForCausalLM.from_pretrained(model_name_or_path)
# 2) Vision Tower 초기화 (CLIP)
model.get_model().initialize_vision_modules(model_args)
vision_tower = model.get_vision_tower()
vision_tower.to(dtype=torch.bfloat16, device=device)
# 3) 데이터셋 로딩
data_module = make_supervised_data_module(tokenizer, data_args)
# 4) 학습 실행
trainer = LLaVATrainer(model=model, tokenizer=tokenizer, **data_module)
trainer.train()
# 5) 모델 저장
trainer.save_state()
{
"image": "image_001.jpg",
"conversations": [
{"from": "human", "value": "<image>\n이 사진을 설명해줘"},
{"from": "gpt", "value": "이 사진에는 고양이가 있습니다..."}
]
}
class LazySupervisedDataset(Dataset):
def __getitem__(self, i):
# 1) 이미지 로딩 및 전처리
image = Image.open(image_path).convert('RGB')
image = processor.preprocess(image, return_tensors='pt')['pixel_values'][0]
# 2) <image> 토큰 위치 정규화
# "이 사진 <image> 설명해줘" → "<image>\n이 사진 설명해줘"
sentence['value'] = DEFAULT_IMAGE_TOKEN + '\n' + sentence['value']
# 3) Conversation → input_ids, labels 변환
data_dict = preprocess(sources, tokenizer, has_image=True)
return {
'input_ids': data_dict['input_ids'],
'labels': data_dict['labels'], # Assistant 응답만 loss 계산
'image': image
}
입력: [Human: <image> 설명해줘] [Assistant: 고양이입니다]
labels: [ IGNORE_INDEX ] [ 실제 토큰 ID ]
↑ ↑
loss 계산 안 함 loss 계산 대상
class Predictor:
def setup(self):
# 모델 로딩
self.tokenizer, self.model, self.image_processor, _ = load_pretrained_model(
model_path="liuhaotian/llava-v1.5-13b"
)
def predict(self, image, prompt, temperature=0.2, max_tokens=1024):
# 1) 이미지 전처리
image_tensor = process_images([image], self.image_processor)
image_tensor = image_tensor.to(self.model.device, dtype=torch.float16)
# 2) Conversation 구성
conv = conv_templates["vicuna_v1"].copy()
inp = DEFAULT_IMAGE_TOKEN + "\n" + prompt # "<image>\n사용자 질문"
conv.append_message(conv.roles[0], inp) # Human
conv.append_message(conv.roles[1], None) # Assistant (생성 대상)
# 3) Tokenization
input_ids = tokenizer_image_token(
conv.get_prompt(),
self.tokenizer,
IMAGE_TOKEN_INDEX,
return_tensors='pt'
).to(self.model.device)
# 4) 생성
with torch.inference_mode():
output = self.model.generate(
inputs=input_ids,
images=image_tensor,
temperature=temperature,
max_new_tokens=max_tokens
)
return self.tokenizer.decode(output[0])
[System Message] <STOP>
Human: <image>
이 사진을 설명해줘 <STOP>
Assistant:
↓
[시스템 토큰들] + [이미지 256토큰] + [질문 토큰들]
↓
LLM이 다음 토큰 생성 시작
Stage 1 (Feature Alignment):
Stage 2 (Instruction Tuning):
Out-of-distribution Generalization:
Multi-turn Conversation:
더 정교한 Connector:
고해상도 처리:
더 큰 데이터셋:
Model Scaling:
Malicious Input:
Hallucination:
Biases:
Energy Consumption:
Research Community:
Accessibility:
LLaVA는 visual instruction tuning이라는 새로운 패러다임을 제시했습니다:
핵심 기여:
1. GPT-4 기반 158K multimodal instruction data 생성
2. Simple yet effective 3-component architecture
3. ScienceQA에서 92.53% 달성 (SOTA)
4. LLaVA-Bench: 최초의 multimodal instruction-following 벤치마크
의의:
오픈소스:
LLaVA는 멀티모달 AI의 democratization을 위한 중요한 방향성을 제시한 중요한 논문입니다.
읽어주셔서 감사합니다 :)