厌倦了回答基于图像的问题了吗?想象一下问一个模型“这张图片上的日期是什么?”,然后得到一个准确的答案。借助微软开发的Florence-2视觉语言模型,您就可以做到这一点。要充分发挥它的潜力,我们还需要对它进行微调!
这篇文章探索了Florence-2微调的奇妙世界,我们将探讨如何训练此强大的模型,使其能够以惊人的准确度理解与分析图像。
为什么要微调?
想象 Florence-2 就像一个渴望学习的好学生。没有经过微调,就像给学生一本教材却不解释其中的概念一样,它可能连基本问题都难以回答。微调才是发挥 Florence-2 真正潜力的关键。
下面说说微调是啥:
让我们动手操作一下,探索使用“文档视觉问答(DocVQA)”数据集来微调Florence-2的过程。该数据集提供了图像和问题与其答案的配对。我们将使用这些数据来训练Florence-2从图像中提取信息,就像视频里展示的那样!
下面给大家分解一下步骤
datasets
,flash-attention
等(具体列表请参见视频描述)。pip install datasets flash_attn timm einops transformers pillow huggingface_hub
运行 `huggingface-cli login` export HF_TOKEN=xxxxxxxxxx # 将你的 Hugging Face 令牌设置为 xxxxxxxxxx
2. 准备数据这一步:
collate
的函数,将问题、答案和图像组合成适合处理的格式。DataLoader
类准备训练和验证加载器,确保数据被转换为数值嵌入,使用processor
。3. 优化模型:让模型更符合特定任务:
train_model
函数来管理训练过程。Model_Checkpoints
的目录中。4. 上传到Hugging Face 。
model.push_to_hub
和 processor.push_to_hub
将您的训练好的模型和处理器上传到Hugging Face,让其他人也能使用。从datasets导入load_dataset() 从transformers导入AutoModelForCausalLM, AutoProcessor 导入torch 导入os 从torch.utils.data导入DataLoader 从tqdm导入tqdm 从transformers导入AdamW, AutoProcessor, get_scheduler 从torch.utils.data导入Dataset # 1. 配置 data = load_dataset("HuggingFaceM4/DocumentVQA") device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = AutoModelForCausalLM.from_pretrained("microsoft/Florence-2-base-ft", trust_remote_code=True, revision='refs/pr/6').to(device) processor = AutoProcessor.from_pretrained("microsoft/Florence-2-base-ft", trust_remote_code=True, revision='refs/pr/6') torch.cuda.empty_cache() # 2. 在训练模型之前 def run_example(task_prompt, text_input, image): prompt = task_prompt + text_input # 确保图片为RGB模式 if image.mode != "RGB": image = image.convert("RGB") inputs = processor(text=prompt, images=image, return_tensors="pt").to(device) generated_ids = model.generate( input_ids=inputs["input_ids"], pixel_values=inputs["pixel_values"], max_new_tokens=1024, num_beams=3 ) generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0] parsed_answer = processor.post_process_generation(generated_text, task=task_prompt, image_size=(image.width, image.height)) return parsed_answer for idx in range(3): print(run_example("DocVQA", 'What do you see in this image?', data['train'][idx]['image'])) # 3. 数据集准备 """我们需要构建数据集。请注意我们在构建提示时如何在问题前添加了一个新任务前缀 `<DocVQA>`。""" class DocVQADataset(Dataset): def __init__(self, data): self.data = data def __len__(self): return len(self.data) def __getitem__(self, idx): example = self.data[idx] question = "<DocVQA>" + example['question'] first_answer = example['answers'][0] image = example['image'] if image.mode != "RGB": image = image.convert("RGB") return question, first_answer, image train_dataset = DocVQADataset(data['train'].select(range(1000))) val_dataset = DocVQADataset(data['validation'].select(range(100))) # 转换为Embeddings def collate_fn(batch): questions, answers, images = zip(*batch) inputs = processor(text=list(questions), images=list(images), return_tensors="pt", padding=True).to(device) return inputs, answers batch_size = 1 num_workers = 0 train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, collate_fn=collate_fn, num_workers=num_workers) val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, collate_fn=collate_fn, num_workers=num_workers) # 4. 训练模型 def train_model(train_loader, val_loader, model, processor, epochs=10, lr=1e-6): optimizer = AdamW(model.parameters(), lr=lr) num_training_steps = epochs * len(train_loader) lr_scheduler = get_scheduler( name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps, ) for epoch in range(epochs): model.train() train_loss = 0 i = -1 for batch in tqdm(train_loader, desc=f"Training Epoch {epoch + 1}/{epochs}"): i += 1 inputs, answers = batch input_ids = inputs["input_ids"] pixel_values = inputs["pixel_values"] labels = processor.tokenizer(text=answers, return_tensors="pt", padding=True, return_token_type_ids=False).input_ids.to(device) outputs = model(input_ids=input_ids, pixel_values=pixel_values, labels=labels) loss = outputs.loss loss.backward() optimizer.step() lr_scheduler.step() optimizer.zero_grad() train_loss += loss.item() avg_train_loss = train_loss / len(train_loader) print(f"Average Training Loss: {avg_train_loss}") # 验证阶段 model.eval() val_loss = 0 with torch.no_grad(): for batch in tqdm(val_loader, desc=f"Validation Epoch {epoch + 1}/{epochs}"): inputs, answers = batch input_ids = inputs["input_ids"] pixel_values = inputs["pixel_values"] labels = processor.tokenizer(text=answers, return_tensors="pt", padding=True, return_token_type_ids=False).input_ids.to(device) outputs = model(input_ids=input_ids, pixel_values=pixel_values, labels=labels) loss = outputs.loss val_loss += loss.item() avg_val_loss = val_loss / len(val_loader) print(f"Average Validation Loss: {avg_val_loss}") # 保存模型检查点 output_dir = f"./model_checkpoints/epoch_{epoch+1}" os.makedirs(output_dir, exist_ok=True) model.save_pretrained(output_dir) processor.save_pretrained(output_dir) # 注意:我们将冻结图像编码器以完成本教程。作者报告在解冻图像编码器时有所改进,但请注意这将导致更多资源消耗。 for param in model.vision_tower.parameters(): param.requires_grad = False train_model(train_loader, val_loader, model, processor, epochs=1) # 5. 保存到HuggingFace Hub model.push_to_hub("USERNAME/Florence-2-FT-DocVQA") processor.push_to_hub("USERNAME/Florence-2-FT-DocVQA")
经过微调后,您会看到模型理解图片和正确回答问题的能力会有显著提高。
这个示例主要关注DocVQA,不过你可以将这些原则应用于其他各种任务,包括:
微调 Florence-2 可开启图像理解的新篇章。通过用特定数据集来定制这个强大的模型,您可以创建高度准确的图像分析定制应用。
准备好探索佛罗伦萨2了吗?有任何疑问都可以随时联系,获取更多实用的AI教程。
电子邮件是: gunderichardson@gmail.com
LinkedIn:理查森·贡德
通过您的网络分享这篇博客文章,让更多人了解知识!
并分享您使用这个超赞的视觉语言模型进行调整的经验。让我们一起构建一个未来,在这个未来中,AI将帮助我们更好地理解图像!