-
[2023 Winter Multimodal Seminar 4.Transference 2) Transfer] Multimodal Few-Shot Learning with Frozen Language Models 논문 리뷰 (NeurIPS, 2021)AI/Multimodal 2023. 2. 20. 13:51728x90
[2023 Winter Multimodal Seminar 4.Transference 2) Transfer]
Multimodal Few-Shot Learning with Frozen Language Models 논문 리뷰 (NeurIPS, 2021)본 포스팅은 딥마인드에서 발표한 Frozen Method에 대해서 알아본다
딥마인드, 많이 들어보셨죠 ?
데미스 허사비스(Demis Hassabis), 셰인 레그(Shane Legg), 무스타파 술레이만(Mustafa Suleyman)의 세 명이 2010년 딥마인드 테크놀로지(DeepMind Technologies)라는 이름으로 처음 공동 창업하였다. 현재와 같이 이름이 바뀌게 된 것은 2014년 구글에 인수되면서부터이다. 구글 X 소속이었으나 2015년 구글의 모기업인 알파벳이 설립되며 알파벳의 자회사가 되었다.
주요 목표는 기계학습(machine learning)과 신경과학(neuroscience)를 기반으로 인간 지능을 분석, 구현하는 것이다. 인공물에 인공 지능을 탑재하는 것 뿐만 아니라 인간 지능의 궁극적인 이해를 목표로 두고 있다고 한다.
흔히 아는 성과로는 DQN, 알파고, 알파스타 등이 있다.목차
- 들어가기 전에 ... Transference
- Introduction
- Related Works
- The Frozen Method
- Experiments: A Multi-Modal Few-Shot Learner
- Discussion
- Code Review
0. 들어가기 전에 ... Transference
벌써 멀티모달의 6가지 core challenges 중 5가지를 살펴보았다
간략하게 이전에 발표하신 논문들을 정리해보자면,
같은 시간에 발표하신 은님의 논문(Learning Factorized Multimodal Representations)은 generation task에 속하며,
어떤 한 모달이 input으로 들어왔을 때 유사한 의미를 담은 다른 모달리티를 새롭게 생성하게 된다!오늘 발표할 논문과 효림님의 논문(Scaling Up Visual and Vision-Language Representation Learning With Noisy Text Supervision)은 Transference task에 속한다.
Transference란 주로 부족하거나 noisy한 데이터들을 더 잘 학습하기 위한 목적으로,
다른 풍부한 modalities의 knowledge을 전달(주입, 공유)해서 더 좋은 성능의 멀티모달 모델을 만드는 방법이다.(a.k.a noisy data 보완 목적인 효림님 발표 논문)
특히, 이 논문은 cross modal transfer라는 transference의 sub challenge에 속한다.
cross modal transfer는
대량의 데이터로 학습된 pretrained model이나 supervised model들로부터 얻은 풍부한 knowledge를
다른 모달리티 데이터로 전달하는 방식이며,본 논문은,
Pretrained Language Model을 통해 (가중치를 업데이트를 하지 않고==Frozen) image encoder들을 학습하는 방식을 제안하여,
그 결과 거대 LM의 빠른 학습 능력을 멀티 모달 세팅(image+language)에 확장할 수 있도록 한다
1. Introduction
Background
- 기존 연구
- 최근의 Language Model들 (Auto-regressive transformers)은 few shot learners 다 ! (gpt-3 논문 제목 : Language models are few-shot learners)
- prompting을 통해, gradient update없이도 몇 가지 예시를 통해 새로운 task에 대해 학습하는 것이 가능함
- rapid task adaptation : 격식체에서 비격식체로 바꾸는 것
- retrieving encyclopedic/general knowledge : '프랑스 혁명이 언제 시작되었는가'과 같은 질문에 대한 대답
- fast concept binding : 새로운 단어들이 무엇을 의미하는지 배운 직후에 적절하게 사용하는 것
- prompting을 통해, gradient update없이도 몇 가지 예시를 통해 새로운 task에 대해 학습하는 것이 가능함
- 최근의 Language Model들 (Auto-regressive transformers)은 few shot learners 다 ! (gpt-3 논문 제목 : Language models are few-shot learners)
- 한계
- 이런 놀라운 기능들이 text에만 국한되어 있다 ➔ visual tasks, questions을 다루지 못하는데 어떻게 인간 지능을 모방할 수 있겠어?
Our Approachs
- Technical methods
- 가중치를 변경하지 않고 PLM이 시각적 정보에 접근할 수 있도록 하는 방법인 Frozen을 제시
- LM이 해당 이미지에 대한 캡션을 생성하도록 하기 위해, PLM의 단어 임베딩 공간으로 이미지를 인코딩하도록 훈련된 신경망으로 구성
- LM의 가중치는 frozen된 상태로 유지되지만, gradient는 이미지 인코더를 처음부터 훈련시키기 위해 이 LM을 통해 역전파된다
- Frozen은 단일 이미지-텍스트 쌍에 대해 훈련하지만, 훈련 후에는 여러 이미지와 단어의 align된 set에 효과적으로 대응할 수 있다
- 이를 통해, 새로운 멀티모달 태스크의 몇 가지 예를 prompt하거나, 새로운 visual category의 이름을 묻기 직전에 가르치고 바로 적절하게 대답할 수 있도록 한다 (fast concept binding).
- 가중치를 변경하지 않고 PLM이 시각적 정보에 접근할 수 있도록 하는 방법인 Frozen을 제시
Contributions
- 우리가 제시한 Frozen method는 PLM의 기능을 그대로 유지하면서도, 이미지와 텍스트 input을 모두 처리할 수 있는 효과적인 방법이다
- 그리고 우리는 이 모델이 1) rapid task adaptation, 2) encyclopedic knowledge, 3) fast concept binding을 위해 모델의 capacity를 transfer할 수 있으며,
시각적 정보와 언어 정보를 모두 사용하여 prompting하는 것이 언어 정보만으로 하는 것보다 더 효과적일 수 있음을 확인함 - 우리는 기존 벤치마크 + 새로운 벤치마크를 통해 앞서 말한 기능들을 정량화해서 보여줄거야 ~
2. Related Works
- transformer language models
- 이전 연구 : transformer 기반 LM에 인코딩된 Knowledge들이 image classification과 같은 태스크에서도 효과적이라는 것을 알 수 있었음 ➔ 텍스트로부터 얻은 knowledge를 image에도 적용할 수 있다 !
- 개선점 : 하지만 이 연구에서는 여러 downstream task에 맞춰서 fine-tuning을 했어야 했음
- 본 논문 : Frozen method는 weight update 필요 없다 ~
- prefix tuning or prompt tuning
- 이전 연구
- prompt tuning : 태스크의 입력에 작업 지침 과 몇 가지 예를 추가하여 언어모델에서 출력을 생성하는 것을 의미
- prefix tuning : prompting 방법의 일종으로, 설명을 나타내는 가상토큰으로 prefix라고 하는 하는 연속적 태스크 특화 벡터를 추가하여 해당 prefix와 관련된 파라미터만 튜닝하는 방법
- 텍스트 프롬프트의 continuous embedding과 동일한 역할을 하는 task-specific bias term을 학습하기 위해 경사하강법을 수행
- prefix는 텍스트 프롬프트를 숫자로 변환한 거랑 같은 역할 / prefixes == continuous prompts == task-specific bias term
- 본 논문 : 이 논문에서는 prefix(==continuous prompt)는 bias가 아닌, external neural network을 통해 생성해낸 image-conditional activation다
- (뒤에서도 이 문장에 대한 설명이 제대로 안 나오는데, 단순히 고정된 임베딩 값이 아니라 nn을 통해서 동적으로 변화할 수 있어서 의미를 잘 담도록 된 것? 이라는 맥락인 듯함 )
- 이전 연구
- text-specific/multimodal representation-learning approaches
- 이전 연구 : BERT와 같이 텍스트 특화된 모델이나 multimodal representation-learning들을 visual question answering (VQA) and captioning에 적용
- 개선점 : 이미지와 텍스트 align된 상태에서 훈련 시킨 뒤, 각 task에 맞게 fine-tuning 하는 방식 사용 ➔ 좋은 성능 ! 이지만 ...
- 본 논문 : 각 task마다 fine-tuning 하지 않아도 되며, few shot으로도 새로운 task를 잘 학습한다
- task-general multimodal models
- 이전 연구 : (그렇다고 우리가 최초는 아니다)
- 개선점
- 이전 연구들은 pretrained LM 쓰면 더 좋은 캡션 달 수 있음에도 pretrained LM 사용하지 않은 모델도 있으며,
- 사용한 모델들은 few shot이나 zero shot 고려하지 않았다
- 본 논문 : 우리는 이들과 달리 pretrained LM 쓰고, zero-shot/few-shot 한다
- Multimodal pre-training
- 이전 연구
- (discriminative setting) zero-shot : 최근의 multimodal pre-training은 contrastive learning을 통해 zero-shot generalization을 가능하게 되었다 ! (효림님 논문 5.2 Zero-shot Visual Classification 부분)
- (discriminative setting) few-shot : [43] has observed signs of emergent few-shot-learning from large-scale training.
- 본 논문 : Frozen method는 generative text output을 만들어내는 generative setting에서 zero shot/ few shot generalization 모두 잘한다
- 한 마디로 정리하자면, 분류와 같은 discriminative setting에서 제로샷/퓨샷하는 모델들은 있었는데,
생성 분야와 같은 generative setting에서는 우리가 제로샷/퓨샷 처음이다
- 한 마디로 정리하자면, 분류와 같은 discriminative setting에서 제로샷/퓨샷하는 모델들은 있었는데,
- 이전 연구
Prefix tuning 이란 ?
각 응용 태스크에 대해 연속형의 prefixes를 최적화 하는 방법으로 언어모델을 효율적으로 조정하기 위해 사용되어 자연어 생성에서 저용량의 파라미터만 조정하고 저장하면서도 기존의 Fine-tuning 방법과 유사한 성능을 유지함을 보였다.
자연어 생성에서 인코더와 인코더 모두에 대한 Prefix를 추가하여 z = [prefix; x; prefix'; y]로 입력을 준다.
목적함수에서 fine-tuning과 달리 훈련 가능한 매개변수 세트가 변경되어 언어 모델 파라미터 ϕ는 고정되어
prefix 파라미터 𝑃𝜃만이 오직 훈련 가능한 매개변수로 활용된다.3. The Frozen Method
- Frozen method는 prefix tuning의 연장선 !
- 기존의 prefix tuning : task-specific continuous bias term를 학습한다 (prefix == test set에 대한 static하고, constant한 text prompt에 대한 embedding처럼 작동하도록 )
- task마다 고정된 bias 값처럼 작용한다
- Frozen method : prefix가 constant bias가 아니라, dynamic한 input conditional activation으로 작용할 수 있도록
- 고정된 값이 아니라, nn을 통해 생성해서 동적으로 변화할 수 있는 값
- 기존의 prefix tuning : task-specific continuous bias term를 학습한다 (prefix == test set에 대한 static하고, constant한 text prompt에 대한 embedding처럼 작동하도록 )
1) Architecture
(1) Pre-trained Autoregressive Language Models based on the Transformer architecture
- gpt 계열이라고만 나와있음 ➔ OPT 사용 ! (not official code)
- 70억 개의 parameters
- 32 layers / 각 layer 4096 unit
- input : SentencePiece tokenizer
- vocab size : 32,000
- pretrain에 사용된 dataset : C4 dataset
- embedding function :
- distribution
- in code
- huggingface OPT https://huggingface.co/docs/transformers/model_doc/opt
- The OPT model was proposed in Open Pre-trained Transformer Language Models by Meta AI. OPT is a series of open-sourced large causal language models which perform similar in performance to GPT3.
from transformers.models.opt.modeling_opt import ( OPTDecoder, OPTPreTrainedModel, OPTModel, OPT_START_DOCSTRING, OPT_INPUTS_DOCSTRING, _CHECKPOINT_FOR_DOC, _CONFIG_FOR_DOC, _EXPECTED_OUTPUT_SHAPE, _TOKENIZER_FOR_DOC, ) from transformers.models.opt.configuration_opt import OPTConfig
class CustomOPTDecoder(OPTDecoder): ... class CustomOPTModel(OPTPreTrainedModel): ... class CustomOPTCausalLM(OPTPreTrainedModel): ...
class CustomOPTCausalLM(OPTPreTrainedModel): ... def forward(~~): ... output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions output_hidden_states = ( output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states ) return_dict = return_dict if return_dict is not None else self.config.use_return_dict # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn) outputs = self.model.decoder( input_ids=input_ids, image_features=image_features, attention_mask=attention_mask, head_mask=head_mask, image_token_mask=image_token_mask, past_key_values=past_key_values, inputs_embeds=inputs_embeds, use_cache=use_cache, output_attentions=output_attentions, output_hidden_states=output_hidden_states, return_dict=return_dict, ) logits = self.lm_head(outputs[0]).contiguous() loss = None if labels is not None: # Shift so that tokens < n predict n shift_logits = logits[..., :-1, :].contiguous() shift_labels = labels[..., 1:].contiguous() # Flatten the tokens loss_fct = CrossEntropyLoss() loss = loss_fct(shift_logits.view(-1, self.config.vocab_size), shift_labels.view(-1)) if not return_dict: output = (logits,) + outputs[1:] return (loss,) + output if loss is not None else output return CausalLMOutputWithPast( loss=loss, logits=logits, past_key_values=outputs.past_key_values, hidden_states=outputs.hidden_states, attentions=outputs.attentions, )
(2) Vision Encoder
- NF-ResNet-50 모델 사용
- NF-ResNet-50은 기존의 ResNet-50보다 대략 ~15% 정도의 차이로 더 뛰어난 퍼포먼스를 보인다고 함
- in code
- Pytorch Image Models (timm) https://timm.fast.ai/
from transformers import AutoConfig, AutoModel, CLIPVisionModel, CLIPVisionConfig import timm TIMM_MODELS = { 'nf_resnet50': 2048, } def get_image_encoder(model_name): if model_name in TIMM_MODELS.keys(): model = timm.create_model(model_name, pretrained=True, num_classes=0) elif is_clip_model(model_name): config = CLIPVisionConfig.from_pretrained(model_name) model = CLIPVisionModel.from_pretrained( model_name, config=config, ) else: model = AutoModel.from_pretrained(model_name) return model
(3) Visual Prefix
- 중요한 점 ! : 트랜스포머가 이미 이해하고 있는 형태로 이미지를 표현하는 것
- token embedding t_l과 동일한 D 차원을 갖는 a sequence of continuous embeddings (unsqueeze)
- visual encoder의 output을 D X n 차원으로 mapping 후, sequence로 재구성함 ➔ prefix !
- token은 1, 2, 4개로 실험해봤는데 2개일 때가 제일 잘 되더라
def get_image_transform(model_name): if model_name in TIMM_CONFIGS.keys(): config = TIMM_CONFIGS[model_name] transform = create_transform(**config) transform.transforms.append( Lambda(lambda x: x.unsqueeze(0)), ) elif is_clip_model(model_name): transform = CLIPFeatureExtractor.from_pretrained(model_name) else: transform = AutoFeatureExtractor.from_pretrained(model_name) return transform class COCODataset(Dataset): def __init__( self, name='COCO', path=None, split='val', year=2017, image_transform=None, tokenizer=None, num_image_tokens=0, ): super().__init__() assert split in ('train', 'val') assert year in (2014, 2017) logging.warn(f'num_image_tokens = {num_image_tokens}') self.path = osp.abspath(osp.expanduser(path)) self.split = split self.year = year self.image_transform = image_transform self.tokenizer = tokenizer self.num_image_tokens = num_image_tokens if self.tokenizer is None: self.tokenizer = GPT2Tokenizer.from_pretrained("facebook/opt-2.7b") if not IMAGE_TOKEN in self.tokenizer.all_special_tokens: self.tokenizer.add_special_tokens(SPECIAL_TOKEN_DICT) self.setup_dataset() def setup_dataset(self): split, year = self.split, self.year self.split_name = f'{split}{year}' self.image_dir = osp.join(self.path, self.split_name) self.annotation_file = osp.join( self.path, 'annotations', f'captions_{self.split_name}.json') with open(self.annotation_file, 'r') as f: json_data = json.load(f) annotations = json_data['annotations'] image_dict = dict() for item in json_data['images']: image_dict[item['id']] = item self.annotations = annotations self.image_dict = image_dict @property def image_token_id(self): return self.tokenizer.convert_tokens_to_ids(IMAGE_TOKEN) def __len__(self): return len(self.annotations) def _read_image(self, index): image_id = self.annotations[index]['image_id'] file_name = self.image_dict[image_id]['file_name'] file_path = osp.join(self.image_dir, file_name) raw = Image.open(file_path) raw = raw.convert('RGB') if raw.mode != 'RGB' else raw if isinstance(self.image_transform, Compose): image = self.image_transform(raw) elif self.image_transform is not None: # HuggingFace image = self.image_transform(raw, return_tensors='pt') image = image['pixel_values'] return image_id, raw, image def _add_image_tokens(self, caption): N = self.num_image_tokens if N is not None or N > 0: tokens = ' '.join([IMAGE_TOKEN for x in range(N)]) caption = f'{tokens} {caption}' return caption def _new_add_image_tokens(self, inputs): N = self.num_image_tokens I = self.tokenizer.convert_tokens_to_ids(IMAGE_TOKEN) if N is not None or N > 0: input_ids = [I for i in range(N)] + inputs['input_ids'] attention_mask = [1 for i in range(N)] + inputs['attention_mask'] return { 'input_ids': torch.tensor(input_ids).unsqueeze(0), 'attention_mask': torch.tensor(attention_mask).unsqueeze(0), } def __getitem__(self, index): try: image_id, raw, image = self._read_image(index) except: image_id, raw, image = -1, None, None caption = self.annotations[index]['caption'] inputs = self.tokenizer(caption) inputs = self._new_add_image_tokens(inputs) image_token_mask = inputs['input_ids'] == self.image_token_id return { 'pixel_values': image, 'caption': caption, 'input_ids': inputs['input_ids'], 'attention_mask': inputs['attention_mask'], 'image_token_mask': image_token_mask.long(), 'item_id': index, 'image_id': image_id, 'caption_id': self.annotations[index]['id'], 'raw_image': raw, }
2) Training
- Conceptual Captions dataset으로 학습
- Vision encoder의 파라미터만 업데이트
- Fine-tuning 안하는 이유
- LM을 pretrain할 때 쓴 corpus의 양보다 caption dataset의 양이 더 적은데 fine-tuning 하면 generalization 능력을 해칠 수도 있기 때문이래
- 또, vision encoder의 파라미터만 업데이트하면 LM은 별다른 학습없이 바로 사용할 수 있어서 좋대
- Caption system을 예로
- y는 text
- x는 image / representation은 아래와 같이 나타낸다
- 다음의 목적함수를 최대화할 수 있는 방향으로 학습
def training_step(self, batch, batch_index): V = self.model.text_encoder.config.vocab_size N = self.num_image_tokens kwargs = { 'pixel_values': batch['pixel_values'], 'input_ids': batch['input_ids'], 'attention_mask': batch['attention_mask'], 'image_token_mask': batch['image_token_mask'], } output = self.forward(**kwargs) labels = batch['input_ids'].clone() shift_logits = output.logits[..., N:-1, :].contiguous() shift_labels = labels[..., N+1:].contiguous() loss = self.loss_fn(shift_logits.view(-1, V), shift_labels.view(-1)) return {'loss': loss}
3) Interface at Inference Time
- inference 시에 input으로는 text prompt 또는 'prefix' y1, y2, ..., yp, output으로는 LM이 텍스트 시퀀스 y_p+1, y_p+2, ...를 생성
- ex) (a)에서는 이미지와 질문이 y1 ~ yp / 답변은 y_p+1 ....
4) Few-Shot Learning Definitions
뒤에서 사용될 용어들 정리
- Task Induction
- 이미지 및 텍스트 시퀀스 앞에 오는 설명 텍스트
- 예를 들어 '질문에 답하십시오'와 같이 작업을 모델에게 자연어로 설명하기 위한 것
- Number of shots
- 평가 예제 이전에, 모델에 제시된 작업의 전체 예제 수
- 예를 들어, VQA에서의 shot은 이미지-질문-대답 쌍
Fast concept binding(ex. few shot classification)과 관련된 용어들
- Number of ways
- 분류해야 하는 class의 개수 (강아지/고양이 -> 2 way)
- Number of inner-shots
- 각 category 안에서의 각각 다른 객체의 사진들
- 예시) number of images of different dogs (in figure 6)
- Number of repeats
- 각 inner shot이 반복되는 횟수
- 모델이 category에 대한 visual information를 통합하는 방법을 탐색하기 위해 ablation study로
4. Experiments: A Multi-Modal Few-Shot Learner
Introduction에서부터 계속 강조해왔던 것처럼,
본 논문의 장점인 1) rapid task adaptation, 2) encyclopedic knowledge, 3) fast concept binding 에 대해 실험하고 설명한다
세팅은 아래와 같다
- 학습 데이터 셋 : Conceptual Caption dataset (300만 개의 image-caption 쌍)
- Batch size : 128
- Early stopping on the validation set
- Adam optimizer : β1 = 0.9 / β2 = 0.95
- Learning rate : 3e-4 (따로 적혀져 있는 세팅 없으면)
- training & test 시에 모두 224×224 image 사용 (정사각형 아니면 0으로 패딩한 후에 224로 resize함 )
1) Rapid Task Adaptation
격식체에서 비격식체로 바꾸는 것과 같은 새로운 task를 빠르게 잘 적용하는가 ?
(1) Zero-shot transfer from captioning to VQA
- captioning에서 훈련이나 in-context examples 없이도 VQA로 잘 transfer할 수 있다
- 하지만 PLM은 문제도 있는데...
- generalization 능력을 높일 수도 있지만(good), 역으로 visual input를 전혀 고려하지 않고도 잘 작동할 수도 있다(bad)
- 위 같은 문제를 방지하기 위해, 시각적 인코더에 표시된 이미지를 블랙아웃하고 convnet는 여전히 훈련할 수 있도록 설정하여 blinded baseline을 훈련시켜봤다
- VQAv2 validation set 사용해서 평가
- from captioning to visual question-answering
- from language modelling to open-domain question-answering
- tau는 VQAv2을 training data로 썼냐 안 썼냐 여부 (우리는 SOTA랑 달리 VQAv2를 training data로 안 썼어 강조 )
- 하지만 PLM은 문제도 있는데...
- 결과
- LM을 frozen state로 유지하는 것이 fine-tuning보다 VQA에 훨씬 더 낫더라
- 처음부터 훈련된 scratch 모델은 캡션에서 VQA로 전혀 transfer 안 됨
- visual input를 전혀 고려하지 않도록 이미지를 블랙아웃한 blinded 모델은 그렇지 않은 모델보다 성능 낮음 (visual input에서의 정보도 중요하게 사용한다 !)
(2) Improving performance with few-shot learning
- prompting을 통해 몇 가지 examples를 모델에 제공함으로써 VQA로의 zero-shot transfer 성능이 개선됨
- 아래의 figure에 나와 있는 inferface를 이용해서 위의 basline model 6개에 대해
- 4개의 image-질문-답변 쌍을 넣어서 훈련시켜보았다
- result
- 단 4개의 예제로도 fine-tuning한 모델과의 성능 격차가 중간 정도로 줄어들었다 !! (29.5 <-> 38.7 <-> 73.8 )
2) Encyclopedic Knowledge
'프랑스 혁명이 언제 시작되었는가'과 같은 질문에 사전적인 지식을 포함한 대답을 얼마나 잘하는가 ?
- 사용 데이터 셋 : Conceptual Captions dataset
- 고유한 이름이 사람과 같은 일반 단어로 대체됨 ( 엔티티에 대한 구체적 정보 다 삭제되었단 뜻 )
- named entities에 대한 모든 지식이 PLM에서 나오기 때문에, transfer of factual knowledge에 대해서 잘 확인할 수 있음
- 결과
- ex) 모델에게 비행기의 이미지를 보여주고, "이거 누가 만들었게 ? " 라고 물어보면
- Visual encoder는 이미지에 비행기가 포함되어 있다고 판단했고,
- PLM은 이 정보를 사용하여 비행기가 라이트 형제에 의해 발명되었다는 지식을 반영함
- ex) 모델에게 비행기의 이미지를 보여주고, "이거 누가 만들었게 ? " 라고 물어보면
예시 1)
예시 2)
예시 3)
- Quantitative analysis
- 정확한 답변을 위해서는 외부 지식이 필요하도록 설계된 VQA 데이터 셋인 OKVQA으로 성능 평가
- Table 2
- tau는 OKVQA을 training data로 썼냐 안 썼냐 여부 (우리는 SOTA랑 달리 OKVQA를 training data로 안 썼어 강조 )
- 안 쓴 이유는 우리 매번 fine-tuning 안해도 된다는 것 보여주려고 그런 거 아닐까 ?
- 성능은 PLM의 크기에 따라 달라진다는 것을 알 수 있음 (첫번째 row은 70억개 파라미터인 LM)
- generalization 관점에서, finetuning한 모델이 frozen 방식보다 성능이 떨어진다
- tau는 OKVQA을 training data로 썼냐 안 썼냐 여부 (우리는 SOTA랑 달리 OKVQA를 training data로 안 썼어 강조 )
3) Fast Concept Binding
멀티모달 세팅에서의 fast concept binding이란, N shot 안에 주어진 단어와 visual category를 잘 연결하여 학습하고,
즉시 잘 분류해내는 것을 의미한다 !(1) Open-Ended miniImageNet and Real-Name miniImageNet
- 사용 데이터셋 : minImageNet meta-learning task
- few shot classification을 잘하는지 확인하기 위한 벤치마크
- 본 논문에서는 얼마나 concept binding을 빠르게 잘 하는지 평가하기 위해 사용
- 하지만 본 논문에서 하고 싶은 건, 기존의 minImageNet meta-learning task와는 차이점이 있음 !
- 우리는 기존의 minImageNet에서는 정답으로 인정받기 위해선 올바른 카테고리 이름(+ EOS token)을 생성해야만 하는 open-ended 방식으로 Frozen를 검증함
- 우리는 miniImageNet의 test set과 동일한 image class를 사용하는데, 이 test set의 class 이름에는 말도 안되는 단어들도 포함되어 있다 (figure 4a의 blicket, dax)
- 그래서 task를 두 가지로 나눠서 정의함
- Open-Ended miniImageNet : 위의 세 가지 차이점을 반영한 task
- Real-Name miniImageNet : support set과 answer에 들어가는 이름을 원래의 카테고리 이름 그대로 유지한 것 (사자, 허스키 처럼)
- 구체적으로 어떻게 만들어졌는지는 Appendix
1. Sample two classes c1, c2 from S
2. Sample n images v c1 1 . . . v c1 n+1 from c1 and n images v c2 1 . . . vc2 n from c2
3. Interleave into a sequence of 2n support images [v c1 1 , v c2 1 . . . vc1 n , vc2 n ]
4. Assign the nonsense words (dax, blicket) to c1, c2 at random, and interleave support captions "this is a dax" or "this is a blicket" accordingly
5. Select one of c1, c2 at random, cq, and sample a further question image v cq
6. Assign the truncated caption "this is a" to vq and the appropriate nonsense word as the correct answer.- Result
- Frozen이 일련의 이미지와 새로운 이름에 대한 설명과 함께 제시될 때, 제시된 객체에 대한 새로운 이름을 학습한 다음, 이러한 새로운 이름을 즉시 사용할 수 있다는 것 (랜덤으로 찍어도 50%인데 우리는 53 ~ 66 %니까 ~ ! )
- 이러한 새로운 단어를 사용하는 능력이 해당 범주의 더 많은 예제를 통해 향상된다 (33.7 -> 66 -> 66 )
- Open-Ended miniImagenet 보다는 Real-Name miniImagenet에서 성능이 더 높은데
- Open-Ended miniImagenet는 모델이 이미 알고 있을 수 있는 범주에 새로운 단어를 할당해야 하고 바뀌기 전의 실제 이름이 캡션 데이터에서 활용된 시각적 정보를 전달할 수 있기 때문에 더 어려울 수 있다
- result
- 여기서는 frozen이 그닥 좋은 성능을 보이지 못하는 것을 알 수 있다
- 다섯 개의 새로운 이름을 다섯 개의 visual category에 연결하는 것은 현재 Frozen의 능력을 벗어난다
- 여기서는 frozen이 그닥 좋은 성능을 보이지 못하는 것을 알 수 있다
(2) Fast-VQA and Real-Fast-VQA
위에서의 task는 이름에 연결된 visual category로 transfer되어 시스템이 필요에 따라 이름을 생성할 수 있음을 보여준다
하지만, 해당 범주에 대한 질문에 대해서 설명하거나 답변할 수 있는지에 대한 의문이 들지 않니 ?
- 새로운 task인 "Fast VQA" (ImageNet + Visual Genome 활용)
- 위에서 사용했던 말도 안 되는 단어들(‘dax’ and ‘blicket’)과 그 단어에 매칭되도록 ImageNet에서 N개의 이미지를 support image로 제시
- 질문은 두 category 중 하나만 포함하게 하고, 질문 이미지는 두 category가 모두 포함되는 이미지를 visual Genome에서 가져옴
- 위와 마찬가지로 원래의 카테고리 이름 그대로 사용한 task는 Real-Fast-VQA로 명명
- 구체적으로 어떻게 만들어졌는지는 appendix
1. Sample n images v ci 1 . . . v ci n+1 from c1 and n images v cj 1 . . . v cj n from c2
2. Depending on coin toss, form either the support [v ci 1 , v cj 1 . . . vci n , v cj n ] or the support [v cj 1 , v ci 1 . . . v cj n , vci n ]
3. Assign the nonsense words (dax, blicket) to wi , wj at random, and interleave support captions "this is a dax" or "this is a blicket" accordingly
4. Transform q and a into modified questions and answers q∗ and a∗ by replacing all instances of wi and any instances of wj with the corresponding strings dax or blicket
5. Append the (VG) question (Im, q∗, a∗) to the (ImageNet) support from 2. to create the Fast-VQA sample.- Result
- 더 많은 샷을 통해 모델이 개선된다 -> 자연어를 처리하고 생성하는 능력에 새로운 단어를 통합할 수 있는 능력이 있다는 증거임
- blinded model에서도 제공되는 예시가 많아질 수록 성능이 좋아지는 것을 보면, 추가적인 언어적 단서가 성능 향상에 도움이 된다는 의미
- 이미지를 가리지 않은 경우가 성능이 더 좋은 것을 보았을 때 이미지가 모델 성능에 도움이 된다는 것은 multimodal support가 있음을 확인할 수 있다
- 더 많은 샷을 통해 모델이 개선된다 -> 자연어를 처리하고 생성하는 능력에 새로운 단어를 통합할 수 있는 능력이 있다는 증거임
5. Discussion
- Limitation & Future works
- 아직 N shot 방식으로 학습한 것은 train set 전부 다 사용한 경우보다 성능이 낮다 (그래도 우리 연구 흥미로운 시작점이야 ~)
- 더 복잡한 아키텍쳐로 visual-langauage 모델들이 더 좋은 성능을 낼 수 있을지, 그 여부에 대한 많은 기술적 질문을 아직 탐구 되지 않았다
- 우리가 발견한 insight와 우리가 제공하는 데이터셋으로 우리 모델과 비슷한 모델들이 개발되는 데 도움을 줄 거야
- 논문의 장점
- 텍스트로부터 얻은 knowledge를 image에도 적용할 수 있다는 접근이 참신하게 느껴졌다
- 최근에 NLP분야에서의 prompting 관련해서 궁금한 점이 많았던 참인데, 이 논문을 통해서 이렇게 image와 text가 결합된 형태로도 prompt를 줄 수 있구나 ! 를 알아갑니당
- 성능이 좋지 않음에도 불구하고 신선한 접근 ! 개척하려는 정신 굳
- 논문의 단점
- 성능의 문제
6. Code Review
https://fh295.github.io/frozen.html
데이터 제공은 이 곳에서
https://github.com/ilkerkesen/frozen
오피셜 코드는 못 찾겠다...
이 분, 아주 친절하게 inference하는 notebook도 올려주셨다
import os import os.path as osp import urllib from PIL import Image import torch from transformers import AutoTokenizer, AutoFeatureExtractor from frozen.experiment import Experiment from frozen.data import COCODataset, IMAGE_TOKEN, SPECIAL_TOKEN_DICT !ls ~/logs/frozen/rn50-opt-125m-coco-joint-v0/checkpoints/epoch=2-step=110955.ckpt ckpt_path = "~/best.ckpt" ckpt_path = osp.abspath(osp.expanduser(ckpt_path)) device = 'cuda:0' experiment = Experiment.load_from_checkpoint(ckpt_path).half().to(device) image_encoder = experiment.model.config['image_encoder'] text_encoder = experiment.model.config['text_encoder'] feature_extractor = AutoFeatureExtractor.from_pretrained(image_encoder) tokenizer = AutoTokenizer.from_pretrained(text_encoder) num_image_tokens = experiment.model.config['num_image_tokens'] if not IMAGE_TOKEN in tokenizer.all_special_tokens: tokenizer.add_special_tokens(SPECIAL_TOKEN_DICT) data = COCODataset( path='~/data/coco', image_transform=feature_extractor, tokenizer=tokenizer, num_image_tokens=num_image_tokens, ) item = data[240] prompt = ' '.join([IMAGE_TOKEN for i in range(num_image_tokens)]) input_ids = torch.tensor([50265, 50265, 2]).unsqueeze(0) attention_mask = torch.tensor([1, 1, 1]).unsqueeze(0) inputs = data.tokenizer(prompt, return_tensors='pt') image_token_id = data.tokenizer.convert_tokens_to_ids(IMAGE_TOKEN) image_token_mask = input_ids == image_token_id kwargs = { 'pixel_values': item['pixel_values'].half().to(device), 'input_ids': input_ids.to(device), 'attention_mask': attention_mask.to(device), 'image_token_mask': image_token_mask.long().to(device), 'num_beams': 5, } with torch.no_grad(): experiment.model.eval() output = experiment.model.generate(**kwargs) decoded = tokenizer.batch_decode( output.sequences, skip_special_tokens=True, clean_up_tokenization_spaces=False, ) display(item['raw_image']) print(decoded[0])
이런 캡션을 달았군요
Reference
# 구글 딥마인드
https://ko.wikipedia.org/wiki/%EB%94%A5%EB%A7%88%EC%9D%B8%EB%93%9C
# prefix tuning
https://medium.com/@vincentchen0110/alternative-for-fine-tuning-prefix-tuning-may-be-your-answer-a1ce05e95464
https://koreascience.kr/article/CFKO202130060705831.pdf728x90'AI > Multimodal' 카테고리의 다른 글