鹤啸九天 自律更自由,平凡不平庸 Less is More

数据标注专题笔记

2024-02-06
阅读量

Notes(温馨提示):

  1. ★ 首次阅读建议浏览:导航指南
  2. 右上角工具条搜索文章,右下角二维码关注微信公众号(鹤啸九天),底栏分享、赞赏、评论
  3. ★ 转载请注明文章来源,知识点积累起来不容易,水滴石穿,绳锯木断,谢谢理解
  4. ★ 如有疑问,邮件讨论,欢迎贡献优质资料


数据标注

标注意义

【2024-3-5】大模型+数据标注=?

“garbage in garbage out” 垃圾进,垃圾出

OpenAI 翁丽莲

什么是好的大模型训练数据 分析了翁丽莲(Lilian Weng)博客 “Thinking about High-Quality Human Data

  • LLM依旧是机器学习模型, 也依旧符合ML基础原理: Garbage-in-Garbage-out.
  • 人工智能里面, 数据处理依然是: 有多少人工就有多少智能

然而,大家的倾向

  • Everyone wants to do the model work, not the data work
  • Everyone wants to train the model, no one wants to do feature engineering

机器学习项目中,数据处理的投资回报往往大于模型优化

什么是高质量数据?

  • “高质量人类”生成的高质量数据

如何生产

  • 让人类标注员生产数据, 并做好质量控制
  • 模型找到错误标注数据, 并且进行修正

如何提升标注质量

  • 人类标注员的挑选, 培训, 激励, 到标注任务的设计, 质量检验的每个环节都很有讲究

怎么去做 Rater agreement 标注对齐

  • majority voting, Cohen’s Kappa和MACE (Multi-Annotator Competence Estimation)

如何找到问题数据?几类方法:

  • Influence Functions: 评估一个特定sample对Loss影响 —— 计算量大(因为计算Hessian,二阶导)
  • Prediction changes during training: 追踪预测值在训练过程的变化, 通过预测值的变化找到错标的数据
  • Noisy Cross-Validation: 把数据集分成两半, 各自训练一个模型来预测另外一半的label, 如果预测值和真实值是一致的, 那就看作是clean label

数据标注介绍

什么是数据标注

  • 对文本、图像、音频、视频等数据进行高质量、高精度的处理打标签,满足机器训练学习的需求。

参考:

数据类型

数据主要分为图像数据、语音数据、文本数据等

  • 文本标注:数据标注员对语句分词的标注、语义判断的标注、情感标注、多音字标注等,为人工智能机器学习提供高准确率的文本语料。
  • 图像数据:主要有点标框标区域标注2D/3D融合标注等标注方法。
    • 目前,人脸识别技术落地应用的比较成熟,无论是刷脸进火车站地铁站还是购物人脸支付,日常场景中随处可见。
  • 语音交互也是重要分支。基于语音识别、声纹识别、语音合成等建模测试中,需要对语音数据进行任务角色标注、环境场景的标注、多语种标注、情感标注等。

标注任务

常见的数据标注任务包括 分类标注、标框标注、区域标注、描点标注和其他标注

分类标注 Classification annotation

分类标注是从给定标签集中选择合适的标签分配给被标注的对象.

  • 一张图可以有很多分类/标签, 如:运动、读书、购物、旅行等.
  • 对于文字, 又可以标注出主语、谓语、宾语, 名词和动词等.

此项任务适用于文本、图像、语音、视频等不同的标注对象.

以图像分类标注为例:一张公园的风景图, 标注者需要对树木、猴子、围栏等不同对象加以区分和识别.

标框标注 Frame annotation

标框标注是从图像中选出要检测的对象, 此方法仅适用于图像标注.

标框标注细分为多边形拉框四边形拉框两种形式.

  • 多边形拉框(Polygonal frame): 是将被标注元素的轮廓以多边型的方式勾勒出来, 不同的被标注元素有不同的轮廓, 除了同样需要添加单级或多级标签以外, 多边型标注还有可能会涉及到物体遮挡的逻辑关系, 从而实现细线条的种类识别.
  • 四边形拉框(Quadrilateral frame): 主要用特定软件对图像中需要处理的元素(比如人、车、动物等)进行一个拉框处理, 同时, 用1个或多个独立的标签来代表 1个或多个需要处理的元素.

例如, 对人物的帽子进行了多边形拉框标注, 则对天鹅进行了四边形拉框标注.

区域标注 Region annotation

与标框标注相比, 区域标注(Region annotation)要求更加精确, 而且边缘可以是柔性的, 并仅限于图像标注

  • 主要应用场景包括自动驾驶中的道路识别和地图识别等.

区域标注任务是在地图上用曲线将城市中不同行政区域的轮廓形式勾勒出来, 并用不同的颜色(浅蓝、浅棕、紫色和粉色)加以区分

描点标注 Point annotation

描点标注将需要标注的元素(比如人脸、肢体)按照需求位置进行点位标识, 从而实现特定部位关键点的识别.

例如, 采用描点标注的方法对图示人物的骨骼关节进行了描点标识.

  • 人脸识别、骨骼识别等技术中的标注方法与人物骨骼关节点的标注方法相同
  • Point annotation

其它标注

数据标注的任务除了上述4种以外, 还有很多个性化的标注任务.

  • 自动摘要是从新闻事件或者文章中提取出最关键的信息, 然后用更加精炼的语言写成摘要.

自动摘要与分类标注类似, 但两者存在一定差异.

  • 分类标注有比较明确的界定, 比如在对给定图片中的人物、风景和物体进行分类标注时, 标注者一般不会产生歧义;
  • 而自动摘要需要先对文章的主要观点进行标注, 相对于分类标注来说, 在标注的客观性和准确性上都没有那么严格, 所以自动摘要不属于分类标注.

数据标注角色

传统手工数据标注中的用户角色可以分为3类

  • 1) 标注员: 标注数据, 由经过专业培训的人员来担任.在一些特定场合或者对标注质量要求极高的行业(例如医疗), 也可以直接由模型训练人员(程序员)或者领域专家来担任.
  • 2) 审核员: 审核已标注数据, 完成数据校对和数据统计, 适时修改错误并补充遗漏的标注. 这个角色往往由经验丰富的标注人员或权威专家来担任.
  • 3) 管理员: 管理相关人员, 发放和回收标注任务.

数据标注过程中的各个角色之间相互制约,各司其职, 每个角色都是数据标注工作中不可或缺的一部分.

此外, 已标注数据往往用于机器学习和人工智能中的算法, 这就需要模型训练人员利用人工标注好的数据训练出算法模型.而产品评估人员则需要反复验证模型的标注效果, 并对模型是否满足上线目标进行评估.

数据标注流程

数据标注基本流程

【2022-9-5】人工智能数据标注怎么做?流程是什么?

LLM 标注范式

【2023-10-22】

LLM 时代的NLP如何发展?

  • LLM覆盖所有“传统”NLP能做的事,如:分类、信息抽取、摘要、翻译等,而且效果相当不错,优秀的Zero-Shot、Few-Shot能力大大拓宽了NLP的应用场景;
  • 但LLM推理成本高,在低延时、高QPS的场景下难以直接应用,而在能应用的场景上,投入/产出比不如小模型

传统”NLP如何从LLM中获益?

  • 最轻量级的方法:用LLM来标注数据

标注本质以及LLM作用

  • 标注 = 常识 + 标注规则
  • 常识对应先验知识。有了常识能力,仅提供类别名称、而未提供标注规则就能进行标注。零样本NLP模型(如Siamese-uniNLU、paddleNLP)的核心。
  • 标注规则帮助标注员明确任务、区分边界。工作包括:任务定义、类别定义、边界处理逻辑等。

将LLM引入标注, 意味着有了标注员

  • 具备相当常识。不提供细则,也能有良好的效果(范式1);
  • 听懂人话高效。标注规则通过自然语言表达,也通过自然语言修改,成本低、速度快、且人类可以理解(范式2、范式3)。

为什么用LLM

  • 标注难
    • 如金融情感分类任务标注要求同时具有金融 + 社交媒体知识,对标注员的专业性要求高
    • 人类也只能达到70%的标注一致性,仅通过人类难以获得大量的高质量标注样本;
  • LLM标注效果好
    • LLM + In-Context Learning 来标注,在进行了promp工程之后发现效果不错,在Reddit上ACC达到72%,考虑到任务的难点,LLM标注效果符合预期,于是采用LLM来标注。

范式总结

使用LLM标注的3种范式:调参式、工具式、智能式。

  • (1) 调参式
  • (2) 工具式(局部使用)
  • (3) 智能式(智能体迭代)

各范式间的关系

  • 智能式调参式都用全局性LLM来完成标注任务;而工具式里LLM局部作用;
  • 智能式工具式核心是迭代标注规则;而调参式核心是迭代与业务无关的变量(参数、prompt技术等);
  • 调参式可以结合在智能式工具式当中,以进一步提升效果;

范式 说明 适用场景 优点 缺点 图解
调参式 prompt优化(非标注规则) 冷启动 高度自动化 bad case迭代不便
工具式 LLM作为局部子标注器 通用 可控,对LLM依赖较低,支持case迭代 框架复杂,人工重
智能式 所有工作都由prompt承担 只需修改标注规则 通用 对LLM要求高,具备复杂指令理解能力

调参式

  • 重心是调整prompt中的非标注规则部分,调参数、应用prompt技术(如Self-Consistency、Chain-of-Thought、Bias Calibration、Few-Shot Prompting等);
  • 目标:最大化dev set上的任务指标。
  • 本质是炼丹,和传统的ML过程是一样的:在dev set上,通过调整超参、应用prompt技术,以得到能带来最佳效果的prompt。
  • 优点:整个过程可以高度自动化
  • 缺点:难以针对badcase迭代;
  • 适用场景:Cold-Start 冷启动。在没有业务经验的时候,可以快速得到第一版标注结果。

工具式

  • Snorkel论文:Language Models in the Loop: Incorporating Prompting into Weak Supervision
  • 特点:把LLM当作局部子标注器,例如判断文本段落是否有联系方式;
  • 人类负责把标注任务拆解为多个LLM子标注器的组合。拆解和组合方式,取决于数据分析和业务理解。
  • 本质:Programmatic Weak Supervision 思路的扩展。
  • 优点:
  • 人类掌控全局,因此更可控;
  • 对LLM的依赖性和要求较低,可以用较弱的LLM;
  • 支持迭代,迭代的思路是新增LLM标注器、或者修改原有的LLM标注器;
  • 缺点:框架相对复杂,人类使用者需要学习如何分析数据、设计子标注器;
  • 适用场景:通用

智能式

  • 代表: OpenAI使用GPT-4来标注(内容审核)的Blog: Using GPT-4 for content moderation
  • 所有标注要求都通过prompt来表达,包括标签定义、标注边界情况的划分(例:如果XXXX,则标注XXX);
  • 支持迭代,迭代Loop是 LLM标注 -> 找到标注错误 -> 让LLM解释标注原因 -> 迭代标注规则</span>,迭代目标是让让标注规则越来越精准。
  • 本质: LLM当作智能体,人类则聚焦到标注的核心:让标注规则更清晰、准确。
  • 优点:迭代只需修改标注规则,无需代码,且对比范式2,标注规则更加具体、完整、可理解、可复用(范式2是将标注规则抽象为 子标注器+逻辑关系);
  • 缺点:对LLM要求高,尤其是对复杂指令的理解能力,因为标注规则会包含划分边界的if-else逻辑、对标签的详细定义等;
  • 适用场景:通用。

LLM 标注方案

LLM 分类方法

总结

  • (1)Prompt系列,除了直接PE,In-Context Learning 3种改进技术如下:
    • Noisy Channel Model:2022年5月,华盛顿大学和Meta出品,根据贝叶斯概率公式,反其道而行之,将 Prompt 反着写,即将分类任务转化为生成任务
    • Contextual Calibration(简称CC):2021年,消除ICL导致高方差的3类bias
    • Domain-context Calibration(简称DC):2023年7月,瑞士苏黎世联邦,改进CC,消除llm、prompt和domain里的bias
  • (2)蒸馏法:2023年,基于分类的蒸馏(CLS)、基于回归的蒸馏(REG),最后选择P-R曲线更平滑的REG,
    • 最佳prompt组合技:manual few-shot COT + self-consistency

基础方法:通用分类+判别分类

LLM用于分类任务的方法:

  • 通用分类 Generative Classifier:直接将LLM output(即token)作为分类结果,有Greedy DecodeSample两种
    • 优点:推理成本低,一次推理只需调用1次LLM
    • 缺点:覆盖率 <= 100%,因为LLM的输出格式可能不规范(幻觉)
  • 判别分类 Discriminal Classifier:对每个类别y,计算P(y|x)
    • 优点:覆盖率 = 100%,由于可以拿到y的概率分布,扩展性强(可用于蒸馏、卡阈值等)
    • 缺点:推理成本高,一次推理最多需要调用 |Y|次LLM,其中|Y| = 标签数量
LLM分类方法 说明 优点 缺点
Generative Classifier 直接使用LLM输出结果,分贪心解码和采样两种 推理成本低,调用1次即可 覆盖率 <= 100%(幻觉)
Discriminal Classifier 对每个类别y,计算P(y|x) 覆盖率 = 100%
易扩展(蒸馏/卡阈值)
推理成本高,多次调用

LLM计算P(y|x)原理示意图

两种基本方法计算P(y|x)

  • Probability概率连乘方式计算,即P(y|x) = P(y1|x) * P(y2|x,y1)
    • P(正面|“物美价廉”) = 0.8 * 0.99 = 0.792
    • P(负面|“物美价廉”)= 0.1 * 0.99 = 0.099
  • Average Log-Likelihood(简称Avg)。logP(y|x) = (logP(y1|x) + logP(y2|x,y1))/2
    • P(正面|“物美价廉") = 0.8899
    • P(负面|“物美价廉”) = 0.3146

前人论文指出Avg的方法效果好,因此采取Avg的方法来计算P(y|x)

改进方法

In-Context Learning 3种技术如下:

  • Noisy Channel Model
  • Contextual Calibration(下文简称CC)
  • Domain-context Calibration(下文简称DC)

2022.5 Noisy Channel Model:反其道而行之

【2022-5-】华盛顿大学和Meta出品

分类模型通过P(y|x)来进行分类,但是Noisy Channel Model却使用P(x|y)

理论依据:

  • 贝叶斯概率 P(Y|X) = ( P(X|Y) * P(Y) )/P(X)
  • 推理: P(Y|X) \propto P(X|Y) * P(Y), 因为 P(X) 与 P(Y|X) 无关
  • 推理: P(Y|X) \propto P(X|Y), 假设 $P(Y)$ 均匀分布

要计算P(x|y),只需将 Prompt 反着写,即将分类任务转化为生成任务:

# 原Prompt:
文本{input._text},标签
# 现Prompt:
标签{label_name},文本

Noisy Channel Model在分类时需逐字考虑,因此比较鲁棒

2021 Contextual Calibration(CC):消除3类bias

In-Context Learning 具有高variance问题

  • Task Instruction的写法、Few-Shot Examples的选择和呈现顺序等,都对最终的效果有影响。

CC 作者发现了3类bias可能是variance问题的元凶:

  • majority label bias,指倾向于预测prompt中高频的label
  • recency bias,指倾向于预测prompt中靠后的label
  • common token bias,指倾向于预测在预训练数据中高频的label

作者提出校准方法—CC。其公式抽象如下:

  • P_CC(y|x) = P(y|x) / P(y|NULL)

其中, NULL表示content-free input(如’‘、空、N/A),实现方法比较简单,直接用content-free input替换原本的待推理样本,从而得到P(y|NULL)

实验结果表明

  • Zero-Shot、Few-Shot设定下,CC都可显著提升效果,并可减少variance。

2023.7.9 Domain-context Calibration(DC):再消除domain bias

【2023-7-9】瑞士苏黎世联邦

CC基础上,DC作者再次对bias进行了分类:

  • vanilla label bias,与LLM本身参数有关,对应CC中的common token bias
  • context label bias,与prompt有关,对应CC中的majority label bias与recency bias
  • domain label bias,与input_text的分布有关,未被CC考虑

作者举例解释何谓 domain lable bias

在Tweet hate数据集上,随机从domain中抽取词语,LLM极大程度地预测其为hate,而随机英文单词的预测结果相对均衡,因此Tweet hate的domain label bias比较大;相比之下,SST-2就几乎没有domain label bias。

DC的公式如下:

  • P_DC(y|x) = P(y|x) / P(y|domain_random_words)

从方法来看,DC与CC的主要不同

  • 用于校准的input不再是content-free input,而是domain_random_words
  • 其组成方式是:从domain corpus中随机选L个word,其中L为domain data的平均长度。

在实践中常常重复这一步m步,再取m个结果的平均。

结果

  • 引入更多domain信息的DC,效果比CC要好,尤其在那些本身的domain label bias比较大的数据集上。

蒸馏法

2023 WWW论文: What do LLMs Know about Financial Markets? A Case Study on Reddit Market Sentiment Analysis

  • 蒸馏法: 基于分类的蒸馏(CLS)、基于回归的蒸馏(REG),最后选择了P-R曲线更平滑的REG
    • 最佳prompt组合技:manual few-shot COT + self-consistency

任务

  • 社交媒体中的金融市场情感分析,判断帖子表达出的、针对某公司的financial sentiment
  • 候选标签集合为:positive、negative和neutral

步骤

  • 第一步:利用LLM来标注unlabel data,通过 样本 -> LLM -> hard/soft label,得到 弱标签数据 weakly labeled data;
  • 第二步:更小的任务模型(T5/BERT等)直接从 weakly labeled data 中进行监督学习。

仅保留了用于 self-consistency 的8次sample中,一致次数>=5次的样本

  • 即丢弃了置信度低的样本,这些样本通常准确率也较低

2种方式来进行蒸馏:

  • CLS:每个样本得到 hard label(即最频繁出现的label),直接通过正常的分类loss(cross entropy)来学习;
  • REG:每个样本得到 soft label(把sample 8次结果的agreement ratio,转换为label分布),通过regression loss(MSE)来学习。

CLS 和 REG 最佳效果接近(80.5 + 68.0 vs 84.2 + 65.5),但两种方法有不同特性:

  • CLS 要更准确数据。随着 agreement减小,尽管数据多了,但 precision会下降,当agreement=8(即8次预测完全一样)时,效果最佳,但此时仅使用了31%的数据(用作蒸馏的数据共20000);
  • REG 包容性更强。可用更多的、更难的(LLM预测更不一致)数据,在agreement=5时,效果最佳,可以使用85%的数据。

最终作者选择了REG。

  • 一方面,REG用了更多的、更难的数据;
  • 另一方面,REG的P-R曲线更平滑一些(部署时,需要根据预期presion来选择threshold,更平滑的话选点的效果更好)

用 self-consistency 来产生 soft label,进而蒸馏 —— 这种方法具有启发性,soft label比hard label更好

2022.5.4 Snorkel

作为标注员的LLM(二):在弱监督学习的视角下, 方法二:多角度标注+弱监督学习法

Snorkel 是一个弱监督标注框架,专注于在标注层减少noisy label(而非学习层、模型层),去噪后的label直接供任务模型训练。

Snorkel使用步骤:

  • 定义多种多样的Label Function(将sample映射到label的函数,简称LF),每个样本因此可得到多个weak label;
    • LF可以是一段正则表达式、基于词库的匹配、或对模型预测结果的组合
    • LF的输出为任务label集合中的某一个,或abstain(置信度不足时,放弃标注)
  • 使用 Label Model,对weak labels进行去噪,得到 estimated label;
  • 使用estimated label,以监督学习的方式训练任务模型。

如何将LLM融入Snorkel

  • 不用再使用规则实现LF,用自然言语实现模糊概念

LLM作为一种全新范式labeler,只需编写自然语言prompt,即可实现LF功能。

  1. 领域专家编写多个prompt,实现多种prompted LF(每种LF对应一种角度);
  2. 在Label Map阶段,将LLM输出映射到任务label集合上;
  3. 使用Label Model去噪,得到estimated label;
  4. 将estimated label用于任务模型的监督式学习中。

prompted LF 标注的泛化性上明显强于rule-based LF,基于LLM标注结果训练的任务模型效果至少与rule-based LF相当

多角度prompt比单prompt要好

  • Prompted WS在几乎所有数据集、所有LLM上,都显著优于zero-shot的效果。

ChatGPT 超过人工标注

【2023-3-29】ChatGPT超过人工标注

  • ChatGPT Outperforms Crowd-Workers for Text-Annotation Tasks
  • Many NLP applications require manual data annotations for a variety of tasks, notably to train classifiers or evaluate the performance of unsupervised models. Depending on the size and degree of complexity, the tasks may be conducted by crowd-workers on platforms such as MTurk as well as trained annotators, such as research assistants. Using a sample of 2,382 tweets, we demonstrate that ChatGPT outperforms crowd-workers for several annotation tasks, including relevance, stance, topics, and frames detection. Specifically, the zero-shot accuracy of ChatGPT exceeds that of crowd-workers for four out of five tasks, while ChatGPT’s intercoder agreement exceeds that of both crowd-workers and trained annotators for all tasks. Moreover, the per-annotation cost of ChatGPT is less than $0.003 – about twenty times cheaper than MTurk. These results show the potential of large language models to drastically increase the efficiency of text classification.

苏黎世大学:

ChatGPT标注数据比人类便宜20倍80%任务上占优势

在ChatGPT面前,无论成本还是效率,人类可以说是毫无优势:

  • 成本上,ChatGPT平均每个标注成本低于0.003美元,比众包平台便宜20倍;何况AI还能24*7无休。
  • 效率上,在相关性、立场、主题等任务中,ChatGPT也是以4:1的优势“碾压”人类。

MTurk 是专门进行数据标注的一个众包平台。

  • 在MTurk这类众包平台内部,还会有更加精细的分工,比如说会有经过专业训练的数据标注者以及众包工作者。
  • 前者在产出高质量数据上具有优势,但自然成本也更高,而后者虽然更便宜但质量也会随任务难度波动。

于是, 研究大语言模型(LLM)在这方面的潜力,并且对比了没有额外训练(zero-shot)的ChatGPT(基于GPT-3.5)和MTurk在数据标注上的性能。这项对比基于研究团队此前收集到的2382条推文样本。

ChatGPT和MTurk分别将推文以“相关性、立场、主题、政策、实用性”这五种任务进行标注。

“生成训练数据需要人工”的说法已经成为过去式

ChatGPT NER Demo

ChatGPT 用于 人工标注的 Web系统:Weak Labeling Tool using ChatGPT, 代码

git clone https://github.com/ainbr/chatgpt-weak-labeler-webui.git
pip install -r requirements.txt
gradio app.py

填入OpenAI Key即可启动NER任务

【2023-6-18】无需人力标注!悉尼大学华人团队提出”GPT自监督标注范式

业界和学界面临数据标注任务:成本较高、存在偏见、难以评估,以及标注难度等问题。

悉尼大学研究团队提出了一种通过大语言模型自监督生成标注的框架。首次利用基于生成-还原循环标注的GPT自监督方法,解决了上述问题

  • davinci,text-curie-001,text-davinci-003,gpt-3.5-turbo在不同评估标准下标注数据质量的得分
  • 论文链接

核心思想: 利用大语言模型作为一个黑盒优化优器,构造了一个循环:

  • 模版质量越高,生成的数据-标注对质量越高;
  • 生成的数据标注对质量越高,用当前质量更高的数据对替换上一轮的模版。
  • 以此往复迭代,滚雪球式循环提升标注质量。

标注方法包含了one-shot阶段生成阶段

  • one-shot阶段的目标:迭代寻找最优的 {数据-标注}数据对 作为模板。

迭代过程:

  • 初始化一个简单数据对作为初始模版,利用GPT生成标注,生成的标注和原始数据形成一个新的数据对。
  • 然后,通过比较从标注中还原出来的数据和原始数据,评估这个新数据对作为模板的潜力。
  • 如果还原数据与原数据的相似度得分有所提高,就用当前新数据对直接作为新的模板进行一轮数据生成。

因此,这种自我对齐机制会迭代调整one-shot模板,为下一轮生成做好准备。one-shot阶段搜索到的最优模板随后用于对数据集进行标注。

通过调整不同的预训练奖励模型来评估标注的质量,并引入不同的评价指标来间接评估摘要的还原能力。

Autolabel

【2023-6-19】GPT-4终结人工标注!AI标注比人类标注效率高100倍,成本仅1/7

数据标注需要找到一个新方法,避免大量使用人工标注带来的包括道德风险在内的其他潜在麻烦。所以,包括谷歌/Anthropic在内的AI巨头和大型独角兽,都在进行数据标注自动化的探索。

初创公司refuel,也上线了一个AI标注数据的开源处理工具:Autolabel。用AI标注数据,效率最高提升100倍. introducing-autolabel

  • 按照使用成本最高的GPT-4来算,采用Autolabel标注的成本只有使用人工标注的1/7,而如果使用其他更便宜的模型,成本还能进一步降低

要点

  • 1、开源工具Autolabel能用LLM代替人工高效标注数据,效率提升100倍,成本仅1/7。
  • 2、Autolabel支持主流LLM,可快速标注NLP数据集,准确率高达88.4%,超过人工标注。
  • 3、Autolabel可估计标注置信度,不同LLM可平衡成本与质量,大幅降低标注门槛。

Autolabel安装

# 安装所有必要的库
pip install 'refuel-autolabel[openai]'
from autolabel import get_data
get_data('civil_comments')

自动标签贴标分为三个步骤:

  • 首先,指定一个标签配置(参见下面的config对象)并创建一个LabelingAgent。
  • 接下来,通过运行agent.plan,使用config中指定的LLM对的数据集进行一次标注
  • 最后,使用agent.run运行标签

LabelFast

【2023-11-3】LabelFast:基于LLM的NLP任务自动标注开源工具,Demo发布「AI小作坊」

  • LabelFast 用LLM技术,识别并快速标注简单文本数据的开源工具
  • demo
  • 标注员只需关注那些少量而关键的难样本,达到降本增效

特点如下:

  • 开箱即用。无需微调和Prompt工程,提供 标注任务 + 样本,马上开始标注;
  • 诚实可信。在提供标注结果的同时,还提供Confidence信息,以表示模型对标注结果的信心程度,便于使用者确定何时信任模型结果;
  • 完全开源。LabelFast源于开源的模型和技术,因此也将回馈开源社区。

LabelFast的核心理念是:

  • 用最快的速度,完成简单样本的标注,让人类聚焦于关键的难样本。

常见使用场景

  • 单条样本标注: 将单条样本填入文本框 -> 执行标注 -> 得到标注结果;
  • 批量样本标注: 将多条样本,按格式做成xlsx/csv文件 -> 上传文件 -> 执行标注 -> 得到批量标注结果;
  • 批量样本标注 + 选择confidence threshold: 将多条样本 + 真实标签,按格式做成xlsx/csv文件 -> 上传文件 -> 执行标注 -> 得到批量标注结果 + 各confidence threshold下的任务表现(output2) -> 根据任务表现,确定confidence threshold,高于此值的自动标注结果可直接使用,低于此值的通过其他方式标注

图片标注

【2024-1-8】告别逐一标注,一个提示实现批量图片分割,高效又准确

Segment Anything Model (SAM) 在图像分割领域引起了巨大的关注,其卓越的泛化性能引发了广泛的兴趣。然而,尽管如此,SAM 仍然面临一个无法回避的问题:

  • 为了使 SAM 能够准确地分割出目标物体的位置,每张图片都需要手动提供一个独特的视觉提示

目前的一些方法,如 SEEM 和 AV-SAM,通过提供更多模态的输入信息来引导模型更好地理解要分割的物体是什么。然而,尽管输入信息变得更加具体和多样化,但在实际场景中,每个无标注样本仍然需要一个独特的提示来作为指导,这是一种不切实际的需求。

伦敦大学玛丽女王学院的研究者们提出了一种无需训练的分割方法 GenSAM ,能够在只提供一个任务通用的文本提示的条件下,将任务下的所有无标注样本进行有效地分割。

Generalizable SAM(GenSAM)模型旨在摆脱像 SAM 这类提示分割方法对样本特定提示的依赖。

作者提出了一个跨模态思维链(Cross-modal Chains of Thought Prompting,CCTP)的概念,将一个任务通用的文本提示映射到该任务下的所有图片上,生成个性化的感兴趣物体和其背景的共识热力图,从而获得可靠的视觉提示来引导分割。此外,为了实现测试时自适应,作者进一步提出了一个渐进掩膜生成(Progressive Mask Generation,PMG)框架,通过迭代地将生成的热力图重新加权到原图上,引导模型对可能的目标区域进行从粗到细的聚焦。值得注意的是,GenSAM 无需训练,所有的优化都是在实时推理时实现的。

图见原文

LLM 标注实测

开源模型实测

基础方法

TNEWS新闻标题分类数据上

  • ChatGLM2-6BQwen-7B-Chat标注效果还不够理想,不如零样本分类模型
  • 要想学习到泛化性好的任务模型也需要干净的验证集,并未摆脱验证集依赖
  • 同类型标注员的一致性要明显大于不同类标注员
  • 简单的ensemble策略(如Majority Vote),可明显提升效果,但无法超越人类。

实验的 In-Context Learning技巧为:Self-Consistency、Few-Shot Prompting。

Prompt构造结构

  • label_name_list 为分类标签的中文名称
  • example 为 few-shot examples
  • input_text 为待预测样本。
label_name_list = ['积极','中性','消极']
example = "[1] .... \n[2] ...."
input_text = "测试"

prompt = f'''
给定一段文本,输出一个分类标签。
分类标签集合:[{','.join(label_name_list)}]
请直接输出结果,不要附带其他内容。
{example}
文本:'{input_text}'
这段文本所属标签:
'''

Few-Shot 和 Self-Consistency 效果不总是正向,覆盖率或准确率反而可能下降。主要原因是模型参数量太小,不足以涌现出Few-Shot、Self-Consistency能力

综合考虑覆盖率和准确率

  • ChatGLM2-6B选择Prompt策略为:Zero-Shot Prompt+ Self-Consistency * 3;
  • Qwen-7B-Chat选择的策略为:Zero-Shot Prompt。
  • 实验数据见原文

Cohen’s Kappa Score 来衡量标注员的一致性

  • 首先,所有标注员之间的Kappa得分都在0.4以上,属于中等一致性;
  • 其次,同类标注员间的一致性明显更大,这与相近的模型结构、相近的训练方式、相近的训练数据有关。

ensemble方法:

  • Majority Vote。取多个标注中最频繁的结果,隐含假设是每个标注员是独立且重要性一致
  • Label Model(来自Snorkel)。可建模标注员间的关系,可自动学习标注员的权重

两个方法各有优劣。

  • Majority Vote 准确率很高,但是牺牲了覆盖率(当4个标注员无法进行Majority Vote时,则放弃此次标注);
  • Label Model 效果更加均衡,可覆盖所有样本,但是准确率相对更低一些。

但是,两个方法都要比单独标注员效果要好, 明显的效果提升,Acc可以提升2% 绝对值, 即便覆盖率降低,但准确率大幅提升

改进方法

实验高级方法

优化版

  • 在TNEWS(新闻标题分类)和NLPCC2014-Task2(微博情感二分类)数据上
  • In-Context Learning试验的3种技术:
    • Noisy Channel Model
    • Contextual Calibration(简称CC)
    • Domain-context Calibration(简称DC)
  • DC可明显提升Qwen-7B-Chat的Zero-Shot效果(+3%),是值得应用的技术;
  • 在Few-Shot下,DC和CC提升了鲁棒性,但均未提升Few-Shot效果,Few-Shot还需再觅良方。

zero-shot实验结论

  • Channel Model的效果非常差。该方法的类别区分度太低,因此效果不好
  • CC和DC均可提升Zero-Shot效果,效果最好的是DC,Acc可提升3%(绝对值),已经可以超过Siamese,与paddleNLP也可一战
  • domain_random_words的改变,对DC的效果影响不大

few-shot实验结论

  • 即使用了CC和DC,Few-Shot效果还是不尽如人意,效果可能不如Zero-Shot,但增加 #shot 对效果有帮助
  • GD有潜力,但variance问题仍然明显,在TNEWS数据上 Best Acc - Worst Acc >10%
  • CC和DC均可提升Avg的鲁棒性,体现在Best与Worst的差距在减小

以Qwen-7B-Chat为基础模型时,在TNEWS和NLPCC2014-Task2数据集上:

  • Bias Calibration(CC、DC)可明显提升Zero-Shot的效果,表现最好的是DC(可以提升3%的绝对值),因此,在Zero-Shot设定下推荐使用DC技术
  • Bias Calibration(CC、DC)在Few-Shot设定下,体现了鲁棒性,可减少Best表现与Worst表现的差距,但Few-Shot的效果不明显,有时效果不如Zero-Shot,因此,在Few-Shot方面,还需要探索其他的优化技术

GPT标注实测

任务设计

自动标注任务设计

  • 基本流程: 任务开始 → 分发给标注员 → 质检员质检 → 回收
  • 标注员: 4个
  • 质检员: 1个
  • 质检方式: 统计集成+LLM检测

自动标注流程

实现方法

Coze 实现

自动标注效果

运行代码, 两种模型各跑两次,结果相同,说明非随机结果

# 执行多代理自动标注
python auto_labler.py

model: gpt-3.5-turbo-0613

样例 标注结果(,分割) 平均标注耗时(s) 质检结果 最终标签 置信度
太阳出来了吗 积极,积极,积极,积极 0.57 Yes 积极 100.00
怎么这么慢 消极,消极,消极,消极 0.46 Yes 消极 100.00
你客气了 中性,积极,积极,积极 0.45 Sure 积极 100.00
嗯嗯 中性,中性,中性,中性 0.42 Yes 中性 100.00
不想说话 中性,消极,消极,消极 0.44 Sure 消极 75.00

model: gpt-4-0613

样例 标注结果(,分割) 平均标注耗时(s) 质检结果 最终标签 置信度
太阳出来了吗 中性,中性,中性,中性 1.30 Yes 中性 100.00
怎么这么慢 消极,消极,消极,消极 0.92 Yes 消极 100.00
你客气了 中性,中性,中性,中性 1.02 Yes 中性 100.00
嗯嗯 中性,中性,中性,中性 1.26 Yes 中性 100.00
不想说话 消极,消极,消极,消极 1.01 Yes 消极 100.00

gpt-3.5 vs gpt-4

  • gpt-3.5 速度快(平均0.45s),但准确率不高(60%),不够稳定(60%)
  • gpt-4 速度慢(平均1.1s), 准确率高(100%),且稳定(100%)

实现方法

Coze平台

新建多智能体、workflow等

代码

auto_labeler.py 内容

  • 使用多线程(theading)实现多个标注人员一起标注
# -*- coding:utf8 -*-

# **************************************************************************
# * Copyright (c) 2024 wqw547243068@163.com, All Rights Reserved
# **************************************************************************
# * 多Agent自动标注, openai > 0.28
# **************************************************************************

import os
import sys

#print(os.path.dirname(os.path.abspath(__file__)))
sys.path.append('..')
from start_gpt_new import internalChat

from collections import Counter
#import asyncio
import threading
from queue import Queue

lock = threading.Lock() #创建锁
# lock.acquire(True) #锁定
# lock.release()#释放
que = Queue()

# --------------- prompt设计 ---------------
label_set = ['积极', '消极', '中性']
task_desc = f"给出以下句子的情绪等级: {','.join(label_set)}\n注意: 输出结果不能超出标签范围"

# annotator 标注员
system_prompt_a = f"""你是一个标注员,请完成文本分类标注任务. 
任务描述: {task_desc}
待标注数据: [query]
标注结果: 
"""
# inspector 质检员
system_prompt_i = f"""你是一个质检员,你判断标注结果是否合格
- 如果标注员识别结果(逗号分隔)都一样, 返回: Yes,标注结果
- 如果标注员识别结果(逗号分隔)不同, 返回: No,矫正后标注结果

任务描述: {task_desc}
待标数据: [query]
标注结果: [result]
质检结果: 
"""

# --------------- 标注任务 ---------------

model = "gpt-3.5-turbo-0613"
# model = "gpt-4-0613"
print(f"model: {model}")

task_list = ['太阳出来了吗', '怎么这么慢', '你客气了', '嗯嗯', '不想说话']

label_info = {"annotator": ['小王', '小明', '小张', '小赵'], "pass_rate":0.75, "inspector": ['小李']}
anno_num = len(label_info['annotator'])

def getLLM(model, query='', system_prompt=''):
    """
        异步调度LLM. 子线程函数不能返回值, 只能通过队列来传递结果
    """
    # lock.acquire(True) #锁定
    # lock.release()#释放
    if not query:
        res = [0, '空值']
    if system_prompt:
        res = internalChat(model, query, system_prompt)
    else:
        res = internalChat(model, query)
    que.put(res)
    # return res

# --------------- 标注流程 ---------------
# task: start -> annotator -> inspector -> end
for task in task_list:
    #task_result = []
    task_thread_list = []
    # 标注人员开始标注
    for name in label_info['annotator']:
        # 发布任务
        query = system_prompt_a.replace('[query]', task)
        #res = getLLM(model, query)
        t = threading.Thread(target = getLLM, name='send_labeler', 
            kwargs={'model':model, 'query':task, 'query':query})
        task_thread_list.append(t)
        t.start() # 启动线程
    for t in task_thread_list:
        t.join() # 启动阻塞
    # 提取标注结果
    task_result = [que.get() for _ in range(anno_num)]
    # 质检员开始质检: 一致率高于 75%(3/4) 时, 不需要LLM质检
    task_label_list = [r[1] for r in task_result]
    anno_list = [r[1] for r in task_result if r[1] in label_set]
    avg_time = sum([r[0] for r in task_result]) / anno_num
    annotations = ','.join(task_label_list)
    is_check = False # 是否需要LLM质检
    # 统计标注结果分布
    anno_tag = Counter(anno_list)
    #print(task, anno_tag, anno_list, task_result)
    if anno_tag:
        anno_tag_1 = anno_tag.most_common(1)[0] # ('消极', 3)
    else: # 全部幻觉
        anno_tag_1 = ['-', 0]
    if anno_num >= 3 and anno_tag_1[1] >= anno_num * label_info['pass_rate']: 
        # ① 标注结果一致且无幻觉(100%)
        # ② 标注结果不一致或个别幻觉, 但标注结果一致率高于阈值(75%),且标注人员超过3个
        if anno_tag_1[1] == anno_num: # ① 标注结果一致且无幻觉(100%)
            res_i = [avg_time, f'Yes,{anno_tag_1[0]}']
        else: # ② 标注结果不一致或个别幻觉, 但标注结果一致率高于阈值(75%),且标注人员超过3个
            res_i = [avg_time, f'Sure,{anno_tag_1[0]}'] 
    else: # 有幻觉或一致率偏低
        is_check = True
    if is_check:
        # 质检人员开始矫正
        res_i = getLLM(model, system_prompt_i.replace('[result]', annotations).replace('[query]', task))
    final_res = [f.strip() for f in res_i[1].split(',')]
    if len(final_res) == 1:
        final_res.append('幻觉')
    # 计算置信度
    final_percent = task_label_list.count(final_res[1]) / anno_num * 100
    print(f'{task}\t{annotations}\t{res_i[0]:.2f}\t{final_res[0]}\t{final_res[1]}\t{final_percent:.2f}')

视觉标注

yolo 目标检测

【2024-3-30】自动标注不再是幻想

用YOLOv8将目标检测任务自动化

YOLO V8中有五个模型

  • YOLOv8n, YOLOv8s, YOLOv8m, YOLOv8l, YOLOv8x

准备

# YOLO V8
pip install ultralytics --upgrade

标注代码

from ultralytics import YOLO
from ultralytics.utils.plotting import Annotator, colors
import os

# 查看 yolo 支持的类目
names = model.model.names
print(names)
# {0: 'person', 1: 'bicycle', 2: 'car', 3: 'motorcycle', 4: 'airplane', 
# 5: 'bus', 6: 'train', 7: 'truck', 8: 'boat', 9: 'traffic light', 
# 10: 'fire hydrant', 11: 'stop sign', 12: 'parking meter', 13: 'bench', 
# 14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 
# 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe', 24: 'backpack', 
# 25: 'umbrella', 26: 'handbag', 27: 'tie', 28: 'suitcase', 29: 'frisbee', 
# 30: 'skis', 31: 'snowboard', 32: 'sports ball', 33: 'kite', 
# 34: 'baseball bat', 35: 'baseball glove', 36: 'skateboard', 37: 'surfboard', 
# 38: 'tennis racket', 39: 'bottle', 40: 'wine glass', 41: 'cup', 42: 'fork', 
# 43: 'knife', 44: 'spoon', 45: 'bowl', 46: 'banana', 47: 'apple', 
# 48: 'sandwich', 49: 'orange', 50: 'broccoli', 51: 'carrot', 52: 'hot dog', 
# 53: 'pizza', 54: 'donut', 55: 'cake', 56: 'chair', 57: 'couch', 
# 58: 'potted plant', 59: 'bed', 60: 'dining table', 61: 'toilet', 62: 'tv', 
# 63: 'laptop', 64: 'mouse', 65: 'remote', 66: 'keyboard', 67: 'cell phone', 
# 68: 'microwave', 69: 'oven', 70: 'toaster', 71: 'sink', 72: 'refrigerator', 
# 73: 'book', 74: 'clock', 75: 'vase', 76: 'scissors', 77: 'teddy bear', 
# 78: 'hair drier', 79: 'toothbrush'}

完整代码

import cv2
from ultralytics import YOLO
from ultralytics.utils.plotting import Annotator, colors
import os

# 加载预训练模型
model = YOLO("yolov8n-seg.pt")
model.to('cuda')
names = model.model.names

# 打开视频文件
cap = cv2.VideoCapture("cars.mp4")

# 输出文件夹
output_folder = "output_instances"
os.makedirs(output_folder, exist_ok=True)

# 输出视频设置
# out = cv2.VideoWriter('instance-segmentation.avi',
#                       cv2.VideoWriter_fourcc(*'MJPG'),
#                       30, (int(cap.get(3)), int(cap.get(4))))

# 输出宽度和高度
output_width = 1080
output_height = 600

# 感兴趣的对象列表
objects_of_interest = ['car']

# 对象计数
object_counts = {obj: 0 for obj in objects_of_interest}

while True:
    ret, frame = cap.read()
    if not ret:
        print("视频帧为空或视频处理已成功完成。")
        break

    # 调整帧大小
    frame = cv2.resize(frame, (output_width, output_height))
        
    # 使用模型进行预测
    results = model.predict(frame, device='0', conf=0.25)
    if results[0].masks is not None:
        clss = results[0].boxes.cls.cpu().tolist()
        masks = results[0].masks.xy

        annotator = Annotator(frame, line_width=2)

        for idx, (mask, cls) in enumerate(zip(masks, clss)):
            det_label = names[int(cls)]
            if det_label in objects_of_interest:
                annotator.seg_bbox(mask=mask,
                                   mask_color=colors(int(cls), True),
                                   det_label=det_label)

                object_counts[det_label] += 1

            # 保存每个实例分割的对象
            # instance_folder = os.path.join(output_folder, det_label)
            # os.makedirs(instance_folder, exist_ok=True)
            # instance_path = os.path.join(instance_folder, f"{det_label}_{idx}.png")
            # cv2.imwrite(instance_path, frame)

            text_y = 30
        for obj, count in object_counts.items():
            cv2.putText(frame, f"{obj.capitalize()} Count: {count}", (10, text_y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
            text_y += 40

    # out.write(frame)
    cv2.imshow("实例分割", frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# out.release()
cap.release()
cv2.destroyAllWindows()

标注效果

结束


支付宝打赏 微信打赏

~ 海内存知已,天涯若比邻 ~

Share

Similar Posts

Related Posts

标题:大模型时代开发模式 Development Mode of LLM

摘要:大模型时代的开发模式,如何用LLM模式重构已有应用?

标题:DeepSpeed 学习笔记

摘要:DeepSpeed 知识点、训练技巧总结

Comments

--disqus--

    My Moment ( 微信公众号 )
    欢迎关注鹤啸九天