MoonDream2微调指南【最小VLM】

在本指南中,我们将探讨如何使用计算机视觉数据集对完全开源的小型视觉语言模型 Moondream2 进行微调,以计数项目(这是 GPT-4V 一直表现不一致的任务),并以一种可以依赖输出用于生产应用程序的方式进行微调。

视觉语言模型 (VLM),有时也称为多模态模型,越来越受欢迎。随着 CLIP、GPT-4 with Vision 等技术的出现以及其他进步,从视觉输入中查询问题的能力变得比以往任何时候都更容易获得。

VLM 是机器学习的新前沿,随着新突破的出现,其性能也在不断提高。正如我们在 GPT-4 with Vision 和最近的 GPT-4o 中发现的那样,有些任务(例如计数)是 VLM 难以完成的。虽然可以理解,但由于训练成本和推理速度的限制,在每一项任务上都表现出色很困难,缺乏专家能力使得很难在生产用例中使用和依赖 VLM。

虽然有些多模态模型比其他模型更好,但许多模型在输出一致、可解析的格式方面存在问题。这给将 VLM 整合到应用程序和系统中带来了挑战。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 

1、什么是 Moondream2

Moondream2 是一个开源小型视觉语言模型,源代码位于 GitHub 上,vikhyatk制作。虽然它不是最先进的模型,但它能够以合理的速度和准确性在设备上本地运行,这使它成为 VLM 的一个引人注目的选择,值得尝试进行微调,看看它是否适合您的用例。与其他 VLM 相比,它的得分相对较高。它甚至在 VQAv2 上击败了最近发布的 GPT-4o,考虑到 Moondream2 的本地、开源和小得多的模型,这令人印象深刻。

Benchmark

Moondream2 (5/8/2024)

GPT-4o

Gemini 1.5 Pro

PaliGemma

VQAv2

79.0%

77.2%

73.2%

85.6%*

TextVQA

53.1%

78.0%

73.5%

73.15%*

与谷歌最近发布的另一款多模态开放 VLM PaliGemma 相比,该模型的规模要小得多,只有 18.6 亿,而 PaliGemma 的规模则为 80 亿。GPT-4o 和 Gemini 1.5 Pro 被怀疑比这两个模型大得多,但它们的具体规模尚不清楚。

  • Moondream2 开源许可

与一些因限制性条款而受到审查的“开放”模型(包括 PaliGemma)不同,Moondream2 是根据 Apache 2.0 许可开源的,也允许商业使用。

2、微调 Moondream2

对于本指南,我们将修改创建者提供的微调笔记本版本,并提高 Moondream2 在计数不同类型的美国货币时的性能。

首先,安装我们在整个过程中需要的软件包。

!pip install torch transformers timm einops datasets bitsandbytes accelerate roboflow supervision -q

3、收集用于微调 Moondream2 的数据

创建任何类型的机器学习模型都面临的挑战之一是获取高质量的训练数据。

由于我们想要微调 Moondream2 来计数硬币和钞票,因此我们将使用来自 Roboflow Universe 的这个数据集。你也可以构建和使用自己的 Roboflow 项目来执行此操作。

虽然这是一个对象检测数据集,但我们将展示如何使用它来微调 VLM。

首先,从 Universe 下载数据集:

from roboflow import Roboflow
from google.colab import userdata

rf = Roboflow(api_key=userdata.get('ROBOFLOW_API_KEY'))
project = rf.workspace("alex-hyams-cosqx").project("cash-counter")
version = project.version(8)
dataset = version.download("coco")

然后,我们创建一个辅助类,供微调时使用。我们使用 Supervision 从我们下载的 COCO 格式导入数据集。

from torch.utils.data import Dataset
import json
from PIL import Image
import supervision as sv

class RoboflowDataset(Dataset):
    def __init__(self, dataset_path, split='train'):
        self.split = split

        sv_dataset = sv.DetectionDataset.from_coco(
            f"{dataset_path}/{split}/",
            f"{dataset_path}/{split}/_annotations.coco.json"
        )

        self.dataset = sv_dataset

    def __len__(self):
        return len(self.dataset)

    # ... other methods listed below (full code in Colab notebook)

然后,我们进入定义数据集的重要步骤。在此微调实现中,数据集是从对象读取的,其中 image 是数据集图像,数组 qa 包含一个带有问题和答案的对象,它将定义我们想要微调的提示/响应对。

    def __getitem__(self, idx):
        CLASSES = ["dime", "nickel", "penny", "quarter", "fifty", "five", "hundred", "one", "ten", "twenty"]

        # Retrieve the image/annotation info from the Supervision DetectionDataset 
        image_name, annotations = list(self.dataset.annotations.items())[idx]
        image = self.dataset.images[image_name]

        # Finds the amount of each type of currency there is from the number of annotations there are
        money = {}
        for class_idx, money_type in enumerate(CLASSES):
          count = len(annotations[annotations.class_id == (class_idx+1)]) # Counts the number of annotations with that class
          if count == 0: continue; 

          money[money_type] = count

        # Define the prompt/answer
        prompt = f"How many of each type of the currency ({', '.join(CLASSES)}) are there? Respond in JSON format with the currency type as the key and a integer count as the value."
        answer = json.dumps(money, indent=2) # Formats the JSON and makes it the answer

        # Return as the proper format
        return {
            "image": Image.fromarray(image),
            "qa": [
                {
                    "question": prompt,
                    "answer": answer,
                }
            ]
        }

以下代码检索数据并为我们数据的每个分割创建数据集类。

datasets = {
    "train": RoboflowDataset(dataset.location,"train"),
    "val": RoboflowDataset(dataset.location,"valid"),
    "test": RoboflowDataset(dataset.location,"test"),
}

4、Moondream2 的初步测试

现在我们有了数据集,我们可以开始测试它在没有微调的情况下的表现。我们可以通过运行以下命令来初始化 Moondream2:

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

DEVICE = "cuda"
FLASHATTENTION = "flash_attention_2" # "flash_attention_2" if A100, RTX 3090, RTX 4090, H100, None if CPU
DTYPE = torch.float32 if DEVICE == "cpu" else torch.float16 # CPU doesn't support float16
MD_REVISION = "2024-04-02"

tokenizer = AutoTokenizer.from_pretrained("vikhyatk/moondream2", revision=MD_REVISION)
moondream = AutoModelForCausalLM.from_pretrained(
    "vikhyatk/moondream2", revision=MD_REVISION, trust_remote_code=True,
    attn_implementation=FLASHATTENTION,
    torch_dtype=DTYPE, device_map={"": DEVICE}
)

然后,我们传入一张美元钞票的图片,提示每种货币(一角硬币、五分硬币、一分硬币、四分之一美元硬币、五十美元硬币、五美元硬币、一百美元硬币、一美元硬币、十美元硬币、二十美元硬币)有多少种?以 JSON 格式响应,以货币类型为键,整数计数为值。:

sample = datasets['test'][0]

md_answer = moondream.answer_question(
    moondream.encode_image(sample['image']),
    sample['qa'][0]['question'],
    tokenizer=tokenizer,
)

sv.plot_image(sample['image'], (3,3))
print('Question:', sample['qa'][0]['question'])
print('Ground Truth:', sample['qa'][0]['answer'])
print('Moondream:', md_answer)

它返回了一个毫无帮助、支离破碎且不正确的答复:

来自数据集中其他图像的其他示例响应也不是特别有帮助、正确或一致:

  • [0.39, 0.28, 0.67, 0.52]
  • There is one silver coin in the image, which is a silver dollar coin. The coin is silver in color and features a profile of a man on it. The coin is worth one dollar.
  • 0
  • 1 dime, 1 nickel, 1 penny, 1 quarter, 1 fifty, 1 five, 1 hundred, 1 ten, 1 twenty, 1 dollar bill...

在评估了整个数据集的测试分割后,它达到了大约 0%,没有一个响应符合预期的地面实况输出。

5、微调 Moondream2 以计数对象

接下来,我们通过配置超参数来微调 Moondream2。在这里,我们将 epoch 数设置为 2,因为我们自己的测试证实,任何更少/更多的 epoch 都会导致欠拟合/过拟合。

修改了批处理大小以利用碰巧可用的更强大的 GPU。对于你可能在 Google Colab 中使用的 T4,我们建议使用 6。

其余参数保留为创建者的实现的默认值。

# Number of times to repeat the training dataset. Increasing this may cause the model to overfit or
# lose generalization due to catastrophic forgetting. Decreasing it may cause the model to underfit.
EPOCHS = 1

# Number of samples to process in each batch. Set this to the highest value that doesn't cause an
# out-of-memory error. Decrease it if you're running out of memory. Batch size 8 currently uses around
# 15 GB of GPU memory during fine-tuning.
BATCH_SIZE = 24

# Number of batches to process before updating the model. You can use this to simulate a higher batch
# size than your GPU can handle. Set this to 1 to disable gradient accumulation.
GRAD_ACCUM_STEPS = 1

# Learning rate for the Adam optimizer. Needs to be tuned on a case-by-case basis. As a general rule
# of thumb, increase it by 1.4 times each time you double the effective batch size.
#
# Source: https://www.cs.princeton.edu/~smalladi/blog/2024/01/22/SDEs-ScalingRules/
#
# Note that we linearly warm the learning rate up from 0.1 * LR to LR over the first 10% of the
# training run, and then decay it back to 0.1 * LR over the last 90% of the training run using a
# cosine schedule.
LR = 3e-5

# Whether to use Weights and Biases for logging training metrics.
USE_WANDB = False

一旦我们开始训练,训练时间将高度依赖于可用的系统,主要是 GPU。

6、评估微调的 Moondream2 结果

现在我们已经完成了训练过程,我们可以使用不属于微调数据的相同测试数据来评估微调模型的性能。

moondream.eval()

correct = 0
for i, sample in enumerate(datasets['test']):
    md_answer = moondream.answer_question(
        moondream.encode_image(sample['image']),
        sample['qa'][0]['question'],
        tokenizer=tokenizer,
    )

    if md_answer == sample['qa'][0]['answer']:
        correct += 1

    if i < 21:
        sv.plot_image(sample['image'], (3,3))
        print('Ground Truth:', sample['qa'][0]['answer'])
        print('Moondream:', md_answer)

print(f"\n\nAccuracy: {correct / len(datasets['test']) * 100:.2f}%")

查看样本,我们看到更加一致、可预测和准确的输出答案和输出格式。

经过微调的 Moondream2 对我们的第一张测试图像给出了更准确的答复:

不过,经过微调的 Moondream 版本仍然会存在计数错误的情况。

总体而言,在相同的测试数据集分割中,我们获得了 85.50% 的准确率。

7、结束语

通过本指南,我们能够利用计算机视觉数据集来微调视觉语言模型,以更一致、更准确的格式生成结果,使其易于解析以用于生产应用程序。这使 VLM 从一个有趣的实验级别变成了更大的计算机视觉系统中更有用的组件。


原文链接:MoonDream2微调指南 - BimAnt

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值