3种高效「自动标注」实现方法,看到就是赚到

本文带你从数据、算力和模型的「暗自较量」中,看清AI的发展趋势。同时,在大模型火热的当下,通过分享多种基于LS工具的自动标注方法,为大家提供高效标注实现思路。文中没有任何数学公式,小白也可放心食用。

01 AI三要素:数据、算力和模型

AI的早期阶段,由于受到计算机的限制,科学家们致力于发展更加高效的算法。这些算法大多基于统计学,不需要太多的数据和算力,就可以得到不错的结果。

典型的例子是上世纪六七十年代,美国阿波罗飞船导航系统使用的卡尔曼滤波。这个算法运行在速度约1MHz/s 的处理器上,而可用内存只有32KB左右。

这里有一个冷知识,大家所熟知的神经网络早在1943年就诞生了。1958年,计算机科学家罗森布拉特提出由两层神经元构建的网络(又名感知机),是现代神经网络的雏形。

但是帮美国人登陆月球的,的确是卡尔曼滤波,而非神经网络。想必大家也知道原因:英伟达还未出现(bushi)。玩笑归玩笑,但算力的限制,确实是神经网络发展道路上的一大障碍,这个局面直到2006年才被打破。

这一年,Hinton等人利用限制玻尔兹曼机对神经网络的连续层进行建模,使用逐层预训练的方法,抽取出模型数据中的高维特征。简单来说,就是深度学习正式登上历史舞台,人们也因此认识到算力的重要性。

2012年,由Alex Krizhevsky、Ilya Sutskever、Geoffrey Hinton组成的团队,提交了一个名为「AlexNet」的深度卷积神经网络模型,并在ImageNet挑战赛上大获成功。而这个AlexNet,正是在两块英伟达的GTX 580 GPU上训练的。

有了算力的支持,AI的黄金时代终于来临。各种眼花缭乱的深度神经网络模型被发明出来,大家也看到了它们的神奇效果——人脸识别、各种翻译软件、自动驾驶等技术迅速在工业界落地,甚至有人把深度学习和AI画上了等号。

很快,AI就遇到了发展瓶颈。尝试了各种各样的模型,效果却没有显著提升,挤牙膏的AI时代来了。这段时间,AI领域也逐渐形成了两个流派:模型驱动派和大数据算力派

就在前者还在为了刷榜时几个百分点的性能提升而挤破脑袋时,以OpenAI为代表的大数据算力派正在下一盘大棋。

他们信奉数据才是王道,大力才能出奇迹。于是在2015-2022这8年间,OpenAI只做了一件事:用更更更多的数据,把模型做大!后来的事情大家都知道了,ChatGPT诞生,整个AI界都为之沸腾。

故事讲完,我们不难发现,AI的发展历程完全围绕模型、算力和数据而展开。不同的历史节点,它们地位也各不相同。

早期阶段是模型主导,优秀的算法和模型往往是成败的关键;后来算力的重要性,在深度神经网络上得以体现;而现在,数据引领着AI的发展方向,优质的数据来源变得尤为重要。

02 Label Studio

Label Studio (简称LS)是一个开源的数据标注工具。它提供直观的用户界面,可以轻松创建和组织标注任务,便于团队协作。这里我们主要介绍LS的一项高级特性:集成机器学习模型(ML backend)。

在了解ML之前,我们先认识一下LS的数据结构——每个标注任务都是一个project,一个project包含了许多tasks,tasks中则记录了标注的信息和结果。

下面是一个tasks的json文件实例,详细内容可以参考:https://labelstud.io/guide/task_format.html

{
    "id": 1,
    "project":83,
    "data": {
        "image": "https://example.com/opensource/label-studio/1.jpg"
    },
    "annotations": [
        {
            "id": "1001",
            "result": [
                {
                    "from_name": "tag",
                    "id": "Dx_aB91ISN",
                    "source": "$image",
                    "to_name": "img",
                    "type": "rectanglelabels",
                    "value": {
                        "height": 10.458911419423693,
                        "rectanglelabels": [
                            "Moonwalker"
                        ],
                        "rotation": 0,
                        "width": 12.4,
                        "x": 50.8,
                        "y": 5.869797225186766
                    }
                }
            ],
        }
    ],
}

要想使用ML backend,首先,我们需要安装label_studio_ml库(安装教程:https://labelstud.io/guide/ml.html),编写你自己的model类并继承LabelStudioMLBase,然后重写predict函数即可。

这里我们进行一个简单示例:通过predict函数定义一个推理调用,每次进行一个task标注时,会自动调用predict函数,该函数的返回值会自动merge到tasks中。还可以在predict函数中实现一些自定义的操作,来对tasks进行修改。

# model.py
from label_studio_ml.model import LabelStudioMLBase

class MyModel(LabelStudioMLBase):
    def __init__(self, **kwargs):
        super(MyModel, self).__init__(**kwargs)
        self.model = self.load_my_model()# 这里导入你自己的模型
    
    # 需要重写 predict 函数
    def predict(self, tasks, **kwargs):
        predictions = []
        from_name, schema = list(self.parsed_label_config.items())[0]
        to_name = schema['to_name'][0]
        for task in tasks:
            image = get_image_from_tasks(task)# 需自己实现
            value_from_model = self.model(image)
            results.append({
                'result': [{
                    'from_name': from_name,
                    'to_name': to_name,
                    'type': 'rectanglelabels',
                    'value': value_from_model,
                }],
            })
        return predictions

假设以上model.py存在于my_backend文件夹中,运行以下命令,LS会自动创建所有ML backend运行所需要的配置文件并启动backend。详细内容可参考:https://labelstud.io/tutorials/dummy_model.html

label-studio start my_project --init --ml-backends http://localhost:9090

最后使用Label Studio,导出你需要的标注格式便大功告成。

03 X + SAM的玩法

通用分割模型Segment Anything (SAM)的出现,标志着视觉领域也正式进入了大模型时代。SAM模型接收一个prompt,可以是point prompts,也可以是box prompt,然后输出一个mask。

它其实也是个规规矩矩的transformer架构,亮眼之处在于训练思想——

通过高质量、人为标注的数据开始训练,然后将模型应用到未标注的数据上得到标注结果,接着进行人为干预修正这些结果,进而继续输入模型进行训练。

这样,模型的性能和数据量都在逐步提升,且提升速度越来越快。

使用SAM进行半自动标注

标注任务中,最令人头疼的莫过于mask的标注。如果我们将SAM模型集成到ML中,那么在标注检测框的同时,也能自动进行mask的标注。

原理想必你也发现了:就是利用我们手动选择的检测框作为prompt输入SAM模型,将SAM的结果包装成task格式,通过predict函数发送出去。

openmmlab提供了一个非常有意思的项目https://github.com/open-mmlab/playground/tree/main/label_anything,截取关键代码方便大家解析:

# playground/label_anything/sam/mmdetection.py
def predict(self, tasks, **kwargs):
        ...
        if prompt_type == 'rectanglelabels':
            x = kwargs['context']['result'][0]['value']['x'] * original_width / 100
            y = kwargs['context']['result'][0]['value']['y'] * original_height / 100
            w = kwargs['context']['result'][0]['value']['width'] * original_width / 100
            h = kwargs['context']['result'][0]['value']['height'] * original_height / 100
            output_label = kwargs['context']['result'][0]['value']['rectanglelabels'][0]
            # 使用SAM获得masks
            masks, scores, logits = predictor.predict(
                box=np.array([x, y, x+w, y+h]),
                point_labels=np.array([1]),
                multimask_output=False,
            )
            
        mask = masks[0].astype(np.uint8) 
        ...
        # 将mask加入task
        if self.out_mask:
            mask = mask * 255
            rle = brush.mask2rle(mask)
            results.append({
                "from_name": self.from_name_BrushLabels,
                "to_name": self.to_name_BrushLabels,
                "value": {
                    "format": "rle",
                    "rle": rle,
                    "brushlabels": [output_label],
                },
                "type": "brushlabels",
                "id": ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.ascii_lowercase + string.digits)), # creates a random ID for your label every time
                "readonly": False,
            })

        return [{'result': results}]

GroundingDINO+SAM=GroundedSAM

半自动标注还不够智能?想要全自动?可以,都可以。

在此之前再介绍一个优质的项目——GroundingDINO,详细地址:https://github.com/IDEA-Research/GroundingDINO

GroundingDINO在open-set检测任务中能获得极佳的zero-shot表现,在没有任何COCO训练数据的前提下,能达到52.5 AP的检测效果。它能够接收一个文字prompt和一个图片输入,输出一个检测结果:

得益于GroundingDINO优秀的泛化能力和支持文字caption的输入,我们可以轻松识别并检测到图像上的相关物体。所以只需将box作为prompt输入到SAM中,便可以得到SAM分割出的mask,从而得到检测和分割的双重标注信息。

实现也十分简单:将GroundingDINO的结果调整至tasks的格式要求在predict函数中返回,我们可以使用LS作为我们的可视化工具来审核这些标注。下图是一个通过GroundingDINO + SAM在COCO数据集上对雨伞的自动标注。

Yolo + SAM = ?

对于特定用户场景的一些并不常见的物体,GroundingDINO或许并不能给出很好的检测结果。这时我们可以使用LS工具进行少量的标注,然后训练一个小模型,比如yolo专门检测这些类别。

之后使用yolo在未标注的数据集上进行推理,推理结果作为预标注数据,在LS上进行人为审核和修正。这个过程不单依靠大模型的泛化性,还应用训练好的小模型检测特定类型,加快了用户domain的标注速度,大大加快数据和模型的双重迭代。

当然,如果想使用一些更加定制化的操作,我建议单纯地将LS作为一个前端可视化工具,使用其丰富的API和SDK以及当下百花齐放的大模型玩法来实现你的想法。

下面是一个使用Label Studio python SDK结合yolo、SAM的示例代码。

from label_studio_sdk import Client
from label_studio_sdk import Project

def connect(LABEL_STUDIO_URL, API_KEY, project_id):
    ls = Client(url=LABEL_STUDIO_URL, api_key=API_KEY)
    ls.check_connection()
    project = Project.get_from_id(ls, project_id) 
    return project
    
def get_tasks(project):
    tasks = project.tasks
    no_ann_tasks_idx = []
    # 可以实现一些定制化的过滤,也可使用Label Studio提供的过滤器
    for idx, task in enumerate(tasks):
        if task['annotations'] == []:
            no_ann_tasks_idx.append(idx)
    return no_ann_tasks_idx
    
project = connect(LABEL_STUDIO_URL, API_KEY, 25) 
no_ann_tasks_idx = get_tasks(project)

for idx in no_ann_tasks_idx:
    image_url = project.tasks[idx]['data']['image']
    # 需自己实现
    yolo_results = yolo_model(image_url)
    sam_resultes = sam_model(yolo_results)
    modify_project(sam_resultes)
    
    project.update_params() # update all

这样做的好处就在于,我们可以使用少量人工标注的数据,对数据引擎进行冷启动,然后利用训练的结果进行自动标注。

task数据结构,除了存储我们标注结果的annotations词条,还有一个存储预测结果的predictions词条,我们将yolo+SAM的结果填充predictions便可实现预标注。然后在LS可视化界面上进行标注的审核工作,极大地降低了人工标注成本。

以上就是几种基于大模型背景的自动标注实现方法。大家如果感兴趣,后续还可以出几篇详细的LS教程,深入介绍LS数据结构,以及API、SDK等使用。

事实上,LS也继承了边标注边训练的功能(实现fit方法),但个人感觉使用体验不是很好,不利于大型项目的集成和开发,最佳的方式还是自己开发后端推理框架,将LS作为交互界面。

参考资料:

[1] LS文档: https://labelstud.io/guide https://labelstud.io/tutorials/dummy_model.html

[2] SAM官网: https://segment-anything.com/

[3] openmmlab playground项目: https://github.com/open-mmlab/playground/tree/main/label_anything

[4] IDEA GroundingDINO项目: https://github.com/IDEA-Research/GroundingDINO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值