当前位置: 首页 > news >正文

BLIP2 工业实战(一):从零实现 LAVIS 跌倒检测 (微调与“踩坑”指南)

BLIP2 工业实战(一):从零实现 LAVIS 跌倒检测 (微调与“踩坑”指南)

在这里插入图片描述

在学习完 BLIP/BLIP2 模型原理后,如何将其应用于工业开发至关重要。本文将作为“跌倒检测”实战项目的第一篇,详细记录如何从零到一,使用 Salesforce 的 LAVIS 框架实现一个完整的工业化流程:模型部署 -> 数据构建 -> 微调 -> 验证。

本文最大的特色是**“踩坑”与“避坑”。我们将首先复现一个“失败”的预训练模型推理,然后重点展示如何自定义数据集 (Dataset)** 和 Builder,以及如何配置 yaml 文件来微调 BLIP2。我们将详细分析每一个关键步骤中(特别是 JSON 构建和 Windows 训练)我曾犯过的错误,帮助读者节省宝贵的调试时间。希望本文项目对您有所帮助。


文章目录

  • BLIP2 工业实战(一):从零实现 LAVIS 跌倒检测 (微调与“踩坑”指南)
    • 一、引言:项目目标与环境配置
      • 1.1 项目背景与“踩坑”忠告
      • 1.2 环境配置
    • 二、步骤一:“翻车”的基线推理
      • 2.1 基于 LAVIS 加载模型
      • 2.2 第一次推理:意料之中的失败
    • 三、步骤二:构建 VQA 微调数据集
      • 3.1 目录结构
      • 3.2 JSON 文件构建与踩坑
    • 四、步骤三:自定义 LAVIS 的 Dataset 与 Builder
      • 4.1 为什么要自定义?
      • 4.2 🧱 构建 Dataset
      • 4.3 🧱 构建 Builder
      • 4.4 注册 Builder
    • 五、步骤四:配置 YAML 与执行微调
      • 5.1 训练 YAML 配置文件
      • 5.2 执行微调与结果验证
    • 六、总结与下一步

一、引言:项目目标与环境配置

我们的目标是实现一个工业级的“跌倒检测”项目,完整流程规划为:部署 -> 数据构建 -> 微调 -> 量化 -> 部署。本篇(一)将重点覆盖前三个环节。

1.1 项目背景与“踩坑”忠告

本文将以“编者”(即作者我)的亲身经历,记录从零开始的整个微调过程。

编者忠告:

我认为自己已经把整个微调过程能犯的错误都犯过了。因此,跟着我的思路进行数据集构建和配置,可以帮助你避开绝大多数的 Bug。

1.2 环境配置

不同库版本间有很强的依赖性。如果条件允许,请尽量使用我的这套环境,可以避免在配置上花费不必要的时间。

表格 1:关键环境依赖

库 (Library)版本 (Version)
python3.10
torch2.7.1
torchvision0.22.1
transformer4.31.0
huggingface-hub0.25.2
LAVISmain branch

二、步骤一:“翻车”的基线推理

我们首先尝试直接使用 LAVIS 加载预训练的 BLIP2 模型,看看它在“跌倒检测”这个特定任务上的“零样本” (Zero-shot) 表现。

2.1 基于 LAVIS 加载模型

我们选择 blip2_t5 模型和 pretrain_flant5xl 类型。

# 代码块 1: 加载预训练 BLIP-2 模型
from lavis.models import load_model_and_preprocess
import torch
from PIL import Image
import requests# 1. 加载 BLIP-2 模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")# 注意:LAVIS 目前支持 flant5xl, flant5xxl, opt2.7b, opt6.7b 等
model, vis_processors, _ = load_model_and_preprocess(name="blip2_t5",model_type="pretrain_flant5xl",is_eval=True,device=device,
)

2.2 第一次推理:意料之中的失败

我们加载一张本地的跌倒图像,并向模型提问。

# 代码块 2: 执行零样本推理
# 2. 加载本地图像
url = "../dataset/falldown/images/1.jpg" # 换成你自己的图像路径
raw_image = Image.open(url).convert("RGB")# 3. 构造问题 (VQA)
question = "Is someone falling in this image? please answer yes or no:"# 4. 预处理
image = vis_processors["eval"](raw_image).unsqueeze(0).to(device)
sample = {"image": image,"text_input": question
}# 5. 生成答案
output = model.generate(sample)
print(f"提问: {question}")
print(f"回答: {output[0]}")# 预期(错误)回答: a man is being helped by another man on the ground

🔴 失败分析 (The Problem)

我们想要的回答"yes" 或者 "no"

模型的实际回答"a man is being helped by another man on the ground"

可以发现,这个回答和我们想要的答案相差甚远。模型没有在“回答问题”,而是在“描述图像”。无论我们怎么修改提示词 (Prompt),模型都只会返回对图像的完整阐述。

结论 🟢:预训练模型无法理解我们的特定任务(VQA 式的跌倒判断)。为此,构建一份新的数据集来微调模型至关重要

三、步骤二:构建 VQA 微调数据集

这是整个项目中最关键、也是“坑”最多的一步。

3.1 目录结构

我们采用 LAVIS VQA 任务的标准格式:images 文件夹 + json 标注文件。

/dataset/falldown/
├── images/
│   ├── 1.jpg
│   ├── 2.jpg
│   └── ... (编者用了10张图)
└── train.json

在这里插入图片描述
在这里插入图片描述

3.2 JSON 文件构建与踩坑

JSON 文件记录了图像、问题和答案。以下是最终的正确格式

# 代码块 3: train.json (正确格式)
[{"instance_id": 1,"image": "1.jpg","text_input": "Is anyone falling","answer": ["yes"]},{"instance_id": 2,"image": "2.jpg","text_input": "Is anyone falling in this image?","answer": ["yes"]}
]

⚠️ 踩坑警告:LAVIS 数据集构建的核心 Bug

在创建 JSON 文件时,我犯了两个致命错误,浪费了大量时间:

  1. 键名错误 (Key Names):LAVIS 默认的 Builder (如 COCOVQADataset) 对 JSON 中的 key 有严格要求。如果你使用的键名(如 "question")和 Builder 期望的(如 "text_input")不符,它根本读不到数据。
    • 解决方案:要么修改 JSON 键名,要么(像我一样)重新构建一个自己的 Builder
  2. 答案维度错误 (Dimension Error):这是最隐蔽的 Bug!
    • 错误写法"answer": "yes"
    • 正确写法"answer": ["yes"]
    • 报错RuntimeError: shape '[24, -1, 32, 64]' is invalid for input of size 655360
    • 原因:LAVIS 默认 answer 是一个列表 (List),它会遍历列表中的每个答案。如果你写了 "yes",它会把这个字符串当作列表,遍历为 "y", "e", "s" 三个独立的答案,导致后续处理(如 text_processor)时数据维度彻底崩溃。

四、步骤三:自定义 LAVIS 的 Dataset 与 Builder

由于我们的 JSON 键名和默认 Builder 不匹配,我们必须自定义 Dataset 和 Builder。

4.1 为什么要自定义?

LAVIS 在执行 train.py 时,必须通过 yaml 中指定的 Builder 来构建Dataset。当现有的 Builder 无法满足我们的任务需求(如键名不匹配、数据处理逻辑不同)时,我们必须自定义。

4.2 🧱 构建 Dataset

LAVIS/lavis/datasets/datasets/ 路径下创建你自己的 Python 文件(例如 my_vqa_dataset.py)。

# 代码块 4: my_vqa_dataset.py (自定义 Dataset)
import os
import json
import random
from PIL import Image
from lavis.datasets.datasets.vqa_datasets import VQADataset
from collections import OrderedDict# __DisplMixin 是可选的,用于美观地显示样本,这里省略以简化
# ... (省略 __DisplMixin) ...class FalldownVQADataset(VQADataset):def __init__(self, vis_processor, text_processor, vis_root, ann_paths):super().__init__(vis_processor, text_processor, vis_root, ann_paths)def __getitem__(self, index):ann = self.annotation[index]image_path = os.path.join(self.vis_root, ann["image"])image = Image.open(image_path).convert("RGB")image = self.vis_processor(image)# 对应 JSON 中的 "text_input" 键question = self.text_processor(ann["text_input"])# 对应 JSON 中的 "answer" 键 (注意它是一个列表)answer_weight = {}for answer in ann["answer"]:if answer in answer_weight.keys():answer_weight[answer] += 1 / len(ann["answer"])else:answer_weight[answer] = 1 / len(ann["answer"])answers = list(answer_weight.keys())weights = list(answer_weight.values())return {"image": image,"text_input": question,"answers": answers,"weights": weights,}# -----------------------------------------------------------------
# 关键!LAVIS 的 VQA 任务在训练时需要 "text_output" 键
# -----------------------------------------------------------------
class FalldownVQAInstructDataset(FalldownVQADataset):def __getitem__(self, index):data = super().__getitem__(index)if data is not None:# 从答案列表中随机选一个作为训练目标data['text_output'] = random.choice(data["answers"])return data# collater 貌似在新版 LAVIS 中非必须,但保留有好处# def collater(self, samples):#     data = super().collater(samples)#     if 'answer' in data:#         data['text_output'] = data['answer']#     return data

✅ 关键点

必须要有 FalldownVQAInstructDataset 这个子类!

  • FalldownVQADataset (基类) 负责从 JSON 加载数据,键为 "answers"
  • LAVIS 的 VQA 训练管道 (task) 在训练时,会去寻找一个名为 "text_output" 的键作为 T5 模型的 Decoder 输入。
  • FalldownVQAInstructDataset 的作用就是从 "answers" 列表中随机选一个,并将其赋值给 "text_output",从而桥接数据和模型

4.3 🧱 构建 Builder

LAVIS/lavis/datasets/builders/ 路径下创建 my_data_builder.py

# 代码块 5: my_data_builder.py (自定义 Builder)
from lavis.common.registry import registry
from lavis.datasets.builders.base_dataset_builder import BaseDatasetBuilder
# 关键:导入我们刚创建的 Dataset 类
from lavis.datasets.datasets.my_vqa_dataset import FalldownVQAInstructDataset# 注册一个新名字,这个名字将在 YAML 文件中用到!!!
@registry.register_builder("my_falldown_dataset")
class MyDatasetBuilder(BaseSbuilDatasetBuilder):train_dataset_cls = FalldownVQAInstructDataseteval_dataset_cls = FalldownVQAInstructDataset# 跳过 LAVIS 默认的数据集下载步骤def _download_data(self):return

4.4 注册 Builder

最后,在 LAVIS/lavis/datasets/builders/__init__.py 文件中,导入我们刚创建的 Builder。

# 代码块 6: 在 __init__.py 中注册
from lavis.datasets.builders.base_dataset_builder import load_dataset_builder
# ... (其他 builders) ...# 添加这一行,让 LAVIS 框架能找到我们的 Builder
from lavis.datasets.builders.my_data_builder import MyDatasetBuilder

五、步骤四:配置 YAML 与执行微调

数据和代码准备就绪,现在我们配置训练文件。

5.1 训练 YAML 配置文件

在你的项目目录下创建一个 my.yaml 文件。

# 代码块 7: my.yaml (训练配置文件)
model:arch: blip2_t5model_type: pretrain_flant5xlload_pretrained: True# T5 模型路径t5_model: google/flan-t5-xl# BLIP2 预训练权重路径 (你需要自己下载)pretrained: "E:/root/autodl-tmp/blip2_pretrained_flant5xl.pth"freeze_vit: True # 微调阶段,冻结 ViTdatasets:# 关键:这里的名字必须和 Builder 注册的名字一致my_falldown_dataset: data_type: imagesvis_processor:train:name: "blip_image_train"image_size: 224text_processor:train:name: "blip_instruction"build_info:images:# 图像文件夹的绝对路径storage: E:/LLM/dataset/falldown/imagesannotations:train:storage:# 标注文件的绝对路径- E:/LLM/dataset/falldown/train.jsonval:storage:- E:/LLM/dataset/falldown/train.jsontest:storage:- E:/LLM/dataset/falldown/train.jsonrun:distributed: False # Windows 下必须为 Falsetask: vqa # 关键:指定任务为 VQAlr_sched: "linear_warmup_cosine_lr"init_lr: 1e-4min_lr: 1e-5warmup_lr: 1e-6weight_decay: 0.05max_epoch: 50batch_size_train: 2 # 根据你的显存调整batch_size_eval: 2num_workers: 4warmup_steps: 2000seed: 42output_dir: "output/BLIP2/FallDown_stage1"amp: Trueresume_ckpt_path: nullevaluate: Falsetrain_splits: ["train"]device: "cuda"world_size: 1dist_url: "env://"

⚠️ 踩坑警告:YAML 配置与 Windows 训练

  1. Builder 注册名错误datasets: 下的键名 my_falldown_dataset 必须和 MyDatasetBuilder@registry.register_builder("my_falldown_dataset") 中注册的名字完全一致。否则会报错:AttributeError: 'NoneType' object has not attribute 'default_config_path'
  2. 缺少 Taskrun: 下的 task: vqa 不能省略!LAVIS 依赖这个 task 来确定使用哪个训练流程(如 RunnerVQA)。
  3. Windows 分布式错误:如果你在 Windows 下训练 (如我),run:distributed 必须设为 False
    • 报错ValueError: Default process group has not been initialized...
    • 解决方案:除了设为 False,还需要注释掉 LAVIS/lavis/runners/runner_base.py 文件中第 422 行 (或附近) 的 dist.barrier()

5.2 执行微调与结果验证

一切就绪,开始训练!

# 代码块 8: 启动训练
# 假设你在 LAVIS 的根目录
python train.py --cfg-path E:/LLM/dataset/falldown/my.yaml

(图 2:模型训练日志截图)

训练完成后,权重保存在 output_dir 中。我们加载微调后的权重(例如第 30 个 epoch 的),再试一次。

# 代码块 9: 加载微调后的模型并进行推理
from lavis.models import load_model_and_preprocess
import torch
from PIL import Imagedevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model, vis_processors, _ = load_model_and_preprocess(name="blip2_t5",model_type="pretrain_flant5xl",is_eval=True,device=device,
)# 加载我们微调后的权重
ckpt_path = "./output/BLIP2/FallDown_stage1/checkpoint_30.pth" # 换成你的权重路径
ckpt = torch.load(ckpt_path, map_location="cpu")
msg = model.load_state_dict(ckpt["model"], strict=False)
print(f"Model load status: {msg}")# --- 使用和步骤一完全相同的代码进行推理 ---
url = "../dataset/falldown/images/1.jpg"
raw_image = Image.open(url).convert("RGB")
question = "Anyone falldown?" # 换个问法image = vis_processors["eval"](raw_image).unsqueeze(0).to(device)
sample = {"image": image,"text_input": question
}output = model.generate(sample)
print(f"提问: {question}")
print(f"回答: {output[0]}")# 预期(正确)回答: yes

六、总结与下一步

⛔ 注意:过拟合警告

我们的模型现在会正确回答 yes 了。但请注意:我们只用了 10 张图进行微调。这个模型现在很可能只会输出 “yes”,无论你给它看什么(即过拟合)。

如果想真正实现一个鲁棒的跌倒检测模型,下一步必须混合通用 VQA 数据集(如 COCO-VQA)和你自己构建的“负样本”(即没有跌倒的图像,答案为 "no"),一起进行微调。

总结:在本篇(一)中,我们成功复现了 BLIP2 的“零样本”失败,并通过自定义 LAVIS 的 Dataset 和 Builder,成功微调了一个(过拟合的)跌倒检测 VQA 模型。

下一步展望:在专栏(二)中,我们将解决过拟合问题,

http://www.dtcms.com/a/540364.html

相关文章:

  • NPM下载和安装图文教程(附安装包)
  • 2025 年台湾 5 大 CDP 平台推荐比较
  • 【数据结构】栈(Stack)详解——数据结构的“后进先出”
  • Java 大视界 -- Java 大数据在智能金融理财产品风险评估与个性化配置中的应用
  • Bootstrap4 安装使用指南
  • 怎么建设购物网站免费入驻的网站设计平台
  • vue2 将接口返回数据导出为 excel 文件
  • Java 使用 Spire.XLS 库合并 Excel 文件实践
  • Vultr × Caddy 多站点反向代理 + 负载均衡网关系统实战
  • 【数据结构】(C++数据结构)查找算法与排序算法详解
  • @pytest.fixture函数怎么传变量参数
  • Excel高性能异步导出完整方案!
  • 网站正在建设 敬请期待免费的cms模板
  • 输电线路绝缘子缺陷检测图像数据集VOC+YOLO格式1578张3类别
  • 跨文化理解的困境与AI大模型作为“超级第三方“的桥梁作用
  • JDK版本管理工具JVMS
  • 【JUnit实战3_18】第十章:用 Maven 3 运行 JUnit 测试(上)
  • SQLite 核心知识点讲解
  • JAiRouter v1.1.0 发布:把“API 调没调通”从 10 分钟压缩到 10 秒
  • 自建网站如何赚钱c2c模式为消费者提供了便利和实惠
  • Lua-编译,执行和错误
  • Lua与LuaJIT的安装与使用
  • 数独生成题目lua脚本
  • 影响网站加载速度wordpress获得当前文章的相关文章
  • Hive 技术深度解析与 P7 数据分析架构师多行业全场景实战课程合集(视频教程)
  • 嘉兴高端网站建设公司网络安全等级保护
  • HOW - localstorage 超时管理方案
  • java如何判断上传文件的类型,不要用后缀名判断
  • 【Linux】系统备份与恢复:rsync 与 tar 的完整使用教程
  • ROS2系列(3):第一个C++节点