먼저 필요한 라이브러리를 설치하고 환경을 준비합니다.
bash
pip install torch transformers datasets accelerate bitsandbytes peft qwen-vl-utils
파인튜닝은 GPU에서 실행하는 것이 이상적이므로, CUDA가 사용 가능한지 확인하세요:
python
import torch print(torch.cuda.is_available()) # True가 출력되어야 함
Qwen2-VL-2B-Instruct 모델과 전용 프로세서를 로드합니다. 메모리 효율성을 위해 4비트 양자화를 적용합니다.
python
from transformers import Qwen2VLForConditionalGeneration, AutoProcessor from transformers import BitsAndBytesConfig # 4비트 양자화 설정 bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ) # 모델 로드 model_id = "Qwen/Qwen2-VL-2B-Instruct" model = Qwen2VLForConditionalGeneration.from_pretrained( model_id, quantization_config=bnb_config, device_map="auto", torch_dtype=torch.bfloat16 ) # 프로세서 로드 (텍스트와 이미지 전처리용) processor = AutoProcessor.from_pretrained(model_id)
모델 전체를 파인튜닝하는 대신 LoRA를 사용해 일부 파라미터만 학습하도록 설정합니다. 이를 통해 메모리 사용량을 줄이고 학습 속도를 높일 수 있습니다.
python
from peft import LoraConfig, get_peft_model # LoRA 설정 lora_config = LoraConfig( r=16, # LoRA 랭크 lora_alpha=32, # 스케일링 파라미터 target_modules=["q_proj", "v_proj"], # 타겟 모듈 (Qwen2-VL의 어텐션 레이어) lora_dropout=0.05, bias="none", task_type="CAUSAL_LM" ) # LoRA 적용 model = get_peft_model(model, lora_config) model.print_trainable_parameters() # 학습 가능한 파라미터 수 확인
Qwen2-VL은 텍스트와 이미지를 함께 처리하므로, 데이터셋은 대화 형식(예: 질문-답변 쌍)으로 구성되어야 합니다. 예를 들어, 이미지와 관련된 질문과 답변을 포함한 데이터셋을 준비합니다.
python
dataset = [ { "messages": [ {"role": "user", "content": [{"type": "image"}, {"type": "text", "text": "이 이미지에 대해 설명해줘"}]}, {"role": "assistant", "content": "이 이미지는 푸른 하늘 아래 해변이 있는 풍경입니다."} ] }, # 추가 데이터... ]
Hugging Face datasets 라이브러리를 사용해 데이터셋을 로드하고, 프로세서를 통해 입력을 준비합니다:
python
from datasets import Dataset from qwen_vl_utils import process_vision_info # 데이터셋 생성 dataset = Dataset.from_list(dataset) def preprocess_function(examples): texts = [processor.apply_chat_template(example["messages"], tokenize=False, add_generation_prompt=True) for example in examples] image_inputs = [process_vision_info(example["messages"])[0] for example in examples] inputs = processor(text=texts, images=image_inputs, padding=True, return_tensors="pt") return inputs # 데이터셋 전처리 processed_dataset = dataset.map(preprocess_function, batched=True)
Hugging Face의 Trainer를 사용해 파인튜닝을 설정합니다.
python
from transformers import TrainingArguments, Trainer training_args = TrainingArguments( output_dir="./qwen2-vl-2b-finetuned", per_device_train_batch_size=2, gradient_accumulation_steps=4, num_train_epochs=3, learning_rate=5e-5, warmup_ratio=0.1, logging_steps=10, save_steps=500, save_total_limit=2, fp16=True, # Mixed precision 학습 remove_unused_columns=False, ) trainer = Trainer( model=model, args=training_args, train_dataset=processed_dataset, )
학습을 시작합니다:
python
trainer.train()
학습이 완료되면 모델은 output_dir에 저장됩니다. LoRA 어댑터만 저장되므로, 추론 시 원본 모델과 병합해야 합니다.
LoRA 어댡터를 원본 모델과 병합해 완전한 모델로 저장합니다.
python
# 학습된 LoRA 모델 저장 model.save_pretrained("./qwen2-vl-2b-finetuned-lora") # 원본 모델과 병합 from peft import PeftModel base_model = Qwen2VLForConditionalGeneration.from_pretrained(model_id, device_map="auto") finetuned_model = PeftModel.from_pretrained(base_model, "./qwen2-vl-2b-finetuned-lora") finetuned_model = finetuned_model.merge_and_unload() # 병합된 모델 저장 finetuned_model.save_pretrained("./qwen2-vl-2b-finetuned-merged") processor.save_pretrained("./qwen2-vl-2b-finetuned-merged")
파인튜닝된 모델을 사용해 추론을 테스트합니다.
python
# 병합된 모델 로드 model = Qwen2VLForConditionalGeneration.from_pretrained("./qwen2-vl-2b-finetuned-merged", device_map="auto") processor = AutoProcessor.from_pretrained("./qwen2-vl-2b-finetuned-merged") # 테스트 입력 conversation = [ {"role": "user", "content": [{"type": "image", "image": "path/to/image.jpg"}, {"type": "text", "text": "이 이미지에 대해 설명해줘"}]} ] text = processor.apply_chat_template(conversation, tokenize=False, add_generation_prompt=True) image_inputs, _ = process_vision_info(conversation) inputs = processor(text=[text], images=image_inputs, return_tensors="pt").to("cuda") # 생성 output_ids = model.generate(**inputs, max_new_tokens=128) output_text = processor.batch_decode(output_ids, skip_special_tokens=True)[0] print(output_text)
from huggingface_hub import notebook_login notebook_login() finetuned_model.push_to_hub("your-username/qwen2-vl-2b-finetuned") processor.push_to_hub("your-username/qwen2-vl-2b-finetuned")