厌倦了回答基于图像的问题了吗?想象一下问一个模型“这张图片上的日期是什么?”,然后得到一个准确的答案。借助微软开发的Florence-2视觉语言模型,您就可以做到这一点。要充分发挥它的潜力,我们还需要对它进行微调!
这篇文章探索了Florence-2微调的奇妙世界,我们将探讨如何训练此强大的模型,使其能够以惊人的准确度理解与分析图像。
为什么微调?为什么要微调?
想象 Florence-2 就像一个渴望学习的好学生。没有经过微调,就像给学生一本教材却不解释其中的概念一样,它可能连基本问题都难以回答。微调才是发挥 Florence-2 真正潜力的关键。
下面说说微调是啥:
- 提供了针对性的训练:可以教导Florence-2执行特定任务,比如在图像中识别日期或在医学扫描中检测异常。
- 提高准确性:微调可以精炼模型的理解能力,从而提供更准确和可靠的答案。
- 解锁自定义应用:您可以创建符合特定需求和数据集的图像理解模型。
让我们动手操作一下,探索使用“文档视觉问答(DocVQA)”数据集来微调Florence-2的过程。该数据集提供了图像和问题与其答案的配对。我们将使用这些数据来训练Florence-2从图像中提取信息,就像视频里展示的那样!
下面给大家分解一下步骤
- 搭建环境:
- 使用带有GPU加速的平台。
- 安装必要的库,比如
datasets
,flash-attention
等(具体列表请参见视频描述)。
pip install datasets flash_attn timm einops transformers pillow huggingface_hub
- 使用您的API令牌登录Hugging Face账号。
运行 `huggingface-cli login`
export HF_TOKEN=xxxxxxxxxx
# 将你的 Hugging Face 令牌设置为 xxxxxxxxxx
2. 准备数据这一步:
- 加载DocVQA数据集。
- 创建一个名为
collate
的函数,将问题、答案和图像组合成适合处理的格式。 - 使用
DataLoader
类准备训练和验证加载器,确保数据被转换为数值嵌入,使用processor
。
3. 优化模型:让模型更符合特定任务:
- 定义一个
train_model
函数来管理训练过程。 - 设置优化器、调度器和学习率。
- 遍历每个 epoch,提供图像和问题数据给模型。
- 监控训练过程中的损失并将模型保存到名为
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 模型以检测 X 光、CT 扫描或 MRI 图像中的异常。
- 物体识别:训练模型识别图像中的特定对象,如识别不同类型车辆或动物。
- 根据文本描述生成图像:使用微调后的 Florence-2 模型生成创意图片。
微调 Florence-2 可开启图像理解的新篇章。通过用特定数据集来定制这个强大的模型,您可以创建高度准确的图像分析定制应用。
准备好探索佛罗伦萨2了吗?有任何疑问都可以随时联系,获取更多实用的AI教程。
电子邮件是: gunderichardson@gmail.com
LinkedIn:理查森·贡德
通过您的网络分享这篇博客文章,让更多人了解知识!
并分享您使用这个超赞的视觉语言模型进行调整的经验。让我们一起构建一个未来,在这个未来中,AI将帮助我们更好地理解图像!
共同学习,写下你的评论
评论加载中...
作者其他优质文章