拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Argilla 基础技术实战:团队标注分配、预训练模型微调与 spaCy NER 探索

Argilla 基础技术实战团队标注分配、预训练模型微调与 spaCy NER 探索【免费下载链接】argillaArgilla is a collaboration tool for AI engineers and domain experts to build high-quality datasets项目地址: https://gitcode.com/GitHub_Trending/ar/argilla本篇文章围绕 Argilla 官方教程体系中的「Basics基础技术」三件套展开如何为标注团队分配记录、如何用 Hugging Face 预训练模型先预测、后标注、再微调地构建领域分类器以及如何把 spaCy NER 管道的预测灌入 Argilla 进行探索与对比。读完你可以掌握三条可立即复用的数据标注与模型迭代工作流并理解其底层客户端 APIrg.log、rg.load、rg.init的实际调用方式。本文对应的入口文档为 1_basics.md三份可直接运行的 Jupyter Notebook 均位于 docs/_source/tutorials/notebooks/ 目录下其中用到的 Argilla v1 客户端实现可在 argilla-v1/src/argilla_v1/client 中查阅源码。这三门基础课解决什么问题在 Argilla 的教程体系中「Basics」被定位为帮助用户迈出第一步的入门技术。入口页通过三张卡片详见各教程目录下的modal.md概括了它们各自覆盖的 MLOps 环节、NLP 任务与技术栈教程MLOps 环节NLP 任务依赖库核心技巧给标注团队分配记录Labelling标注TextClassification / TokenClassification / Text2TextArgilla团队协作与任务分配用 Hugging Face 微调情感分类器Labelling Training标注与训练TextClassificationsentimenttransformers预测-标注-微调闭环探索与分析 spaCy NER 管道Labelling标注TokenClassificationNERspaCy模型预测的探索与对比三个教程的卡片文件分别位于 docs/_source/_static/tutorials/labelling-tokenclassification-basics/modal.md、docs/_source/_static/tutorials/training-textclassification-transformers-pretrained/modal.md 与 docs/_source/_static/tutorials/labelling-tokenclassification-spacy-pretrained/modal.md。环境准备先跑起一个 Argilla 服务三个教程都假定你本地已经有一个可用的 Argilla 服务官方提供两种主流的部署方式部署到 Hugging Face Spaces如果你希望在 Google Colab 等外部 Notebook 环境中运行教程且有 Hugging Face 账号可以在 Spaces 上一键部署适合外部 Notebook 场景。使用 Argilla 官方 quickstart Docker 镜像如果你希望本地运行教程推荐这种方式。注意它只支持在本地机器上运行无法配合外部 Notebook 服务使用。镜像与部署配置可在 argilla-server/docker/ 目录下找到更完整的部署选项参见 distribution.md。三份 Notebook 都可以通过页面上方的 Open in Colab 按钮直接运行或下载.ipynb文件在本地 Jupyter 环境中执行涉及模型训练与推理的环节建议切换 GPU 运行时。安装依赖并初始化客户端以分配记录教程为例先安装 Argilla 客户端及必要的第三方库%pip install argilla datasets2.10.1 httpx0.23.3 -qqq随后导入并初始化客户端。若使用 Docker quickstart 镜像或 Hugging Face Spaces需要通过URL和API_KEY完成初始化import argilla as rg # 使用 Spaces 时把 api_url 替换为你的 HF Spaces 地址 # 若配置了自定义 API key同步替换 api_key rg.init( api_urlhttp://localhost:6900, api_keyadmin.apikey )如果是私有的 Hugging Face Space还需要先设置HF_TOKEN环境变量并在初始化时携带额外的鉴权头import os os.environ[HF_TOKEN] your-hf-token rg.init( api_urlhttps://[your-owner-name]-[your_space_name].hf.space, api_keyadmin.apikey, extra_headers{Authorization: fBearer {os.environ[HF_TOKEN]}}, )「微调分类器」与「spaCy NER」两个教程的初始化参数略有不同它们使用owner.apikey作为默认密钥并显式指定默认工作区例如rg.init(api_urlhttp://localhost:6900, api_keyowner.apikey, workspaceadmin)。可选的遥测开关教程还提供一段可选的匿名遥测代码自 Argilla 1.20.0 起引入用于帮助官方了解教程的使用情况你完全可以选择跳过try: from argilla.utils.telemetry import tutorial_running tutorial_running() except ImportError: print(Telemetry is introduced in Argilla 1.20.0 and not found in the current installation. Skipping telemetry.)遥测的完整机制参见 telemetry.md服务端遥测实现位于 argilla-server/src/argilla_server/telemetry/。技巧一把记录分配给标注团队实际项目中标注通常由多人分担工作量。为了避免标注重叠或反过来为了刻意控制重叠以评估标注一致性Argillav1.6.0 起提供了两种策略单一数据集 元数据分配所有成员共享同一个数据集但每人被指派其中的一部分记录多数据集 个人工作区把记录拆分到不同数据集分别写入各标注者的个人工作区。选择策略 1 的典型场景是希望团队所有人都能看到完整数据集做探索但在标注时聚焦于自己被分配的那部分——例如标注者还会基于全团队的标注结果编写弱标签规则。策略 2 更适合希望成员独立工作、互不可见他人记录的场景例如事后需要计算标注者一致性annotator agreement。注意该教程仅适用于 Text2Text、Token Classification 与 Text Classification 三类数据集Feedback 数据集的记录分配请参考 assign_records.md。加载数据集可以加载 Argilla 中已有的数据集并通过查询过滤出指定状态例如只取尚未标注、状态为Default的记录# 从数据集加载 status 为 Default 的记录 ds rg.load(gutenberg_spacy-ner, querystatus:Default)也可以从头创建新数据集——下面用datasets库从 Hugging Face Hub 拉取同一份数据再包装成 Argilla 的 Token Classification 数据集对象from datasets import load_dataset ds rg.DatasetForTokenClassification.from_datasets( datasetload_dataset(argilla/gutenberg_spacy-ner, splittrain) )数据集创建与加载的更多细节参见 create_dataset.md。随机分配记录首先获取将参与标注的用户列表。自 Argilla 1.11.0 起可直接使用rg.User.list()并可按角色过滤出annotator# 获取数据集所在或即将所在的工作区 ws rg.Workspace.from_name(my_workspace) # 获取有权限访问该工作区的用户 # 注意所有参与标注的用户都必须有该工作区的访问权限 # 可选只保留 annotator 角色的用户 users [u for u in rg.User.list() if u.role annotator]如果版本早于 1.11.0则需要直接调用 API 获取用户列表此时返回的是字典而非对象取值方式相应变为users[username]import httpx rg_client rg.active_client().client auth_headers {X-Argilla-API-Key: rg_client.token} http httpx.Client(base_urlrg_client.base_url, headersauth_headers) # 使用 Argilla Client 发起请求 users http.get(/api/users).json() # 可选只保留 annotator 角色的用户 users [u for u in users if u[role] annotator]接下来可选打乱数据集以保证分配随机然后把记录按标注者数量切成等长块轮转分发给每位用户存进一个username - records的字典import random from collections import defaultdict # 不需要打乱时跳过本行 random.shuffle(ds) # 构建 username - 记录列表 的分配字典 assignments defaultdict(list) # 按用户数切成等长块依次分配给每位用户 n len(users) chunked_records [ds[i:i n] for i in range(0, len(ds), n)] for chunk in chunked_records: for idx, record in enumerate(chunk): assignments[users[idx].username].append(record)方式一把分配结果写入记录元数据如果采用单一数据集策略需要把分配结果保存为记录的元数据字段再统一写入一个所有参与者都有权限的工作区assigned_records [] for user, records in assignments.items(): for record in records: record.metadata[user] user assigned_records.append(record) # 将记录写入 Argilla rg.log( recordsassigned_records, workspacerecognai, namegutenberg_spacy-ner, tags{with assignments: True} )rg.log是 v1 客户端最核心的写入入口其实现位于 argilla-v1/src/argilla_v1/client 下的 API 封装中负责把记录批量提交到服务端。方式二按用户拆分到个人工作区如果采用多数据集策略则为每位用户在其个人工作区中单独写入一份数据集for user, records in assignments.items(): rg.log( recordsrecords, workspaceuser, namegutenberg_spacy-ner )这种方式下标注者应使用annotator角色无法访问彼此的工作区项目负责人则使用admin角色以便管理项目下所有数据集。用户角色与权限管理参见 user.md 以及 users.md。技巧如果计划让多个用户标注同一条记录建议在拆分数据集之前为每条记录加上唯一 ID。这样后处理阶段可以通过 ID 关联同一记录的多份标注。在 UI 中按分配结果标注方式一的使用体验标注者打开数据集后在Metadata标签页选择自己的用户名并点击Filter按钮即可自动过滤出分配给自己的记录方式二则更简单标注者直接打开自己工作区中的数据集开始标注即可。元数据过滤的更多用法参见 filter_dataset.md。技巧二用预训练模型引导微调——零标注数据起步的情感分类器第二个基础教程演示了完整的predict → log → label → fine-tune闭环从一个开箱即用的预训练情感分类器出发先让模型预标注再由人工修正最后用标注结果微调出面向自身领域的分类器。为什么需要面向领域的微调大多数微调教程都假设你已经拥有一份训练集例如 IMDB 情感分析。但在实际项目中你真正想要的是针对自己用例的模型——NLP 模型在域外数据上性能通常会明显下降在电影评论IMDB上预训练的情感分类器处理银行用户请求时的表现并不理想。因此本教程以银行业务场景为例数据来自 Banking 77 数据集银行在线客服查询及其意图标注起点模型则是 Hugging Face Hub 上非常流行的distilbert-base-uncased-finetuned-sst-2-english基于 SST-2 情感基准微调的 DistilBERT。整个工作流如下图所示流程共两轮迭代第一轮用预训练模型预测并标注出首批训练集 → 微调出领域模型第二轮用微调后的模型继续预测剩余数据人工修正后再扩充训练集、再次微调。加载数据与模型并定义标注策略先把 Banking 77 数据集一分为二一半用于首轮标注另一半留到后续迭代from datasets import load_dataset, load_metric, concatenate_datasets import numpy as np banking_ds load_dataset(PolyAI/banking77) to_label1, to_label2 ( banking_ds[train].train_test_split(test_size0.5, seed42).values() )再加载预训练情感分类器并在一条例子上做一次试运行from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification from transformers import TrainingArguments, Trainer sentiment_classifier pipeline( modeldistilbert-base-uncased-finetuned-sst-2-english, tasksentiment-analysis, top_kNone, ) to_label1[3][text], sentiment_classifier(to_label1[3][text])教程中该模型把示例I have contacted the seller for a refund...判为NEGATIVE得分约 0.993但按照教程定义的标注策略这类一般性咨询问题应标为POSITIVE——这正是后续要教会模型的差异。教程还特别强调了两点标注设计原则标签体系要与任务对齐情感分析是 NLP 中最主观的任务之一可建模为连续值或 2 个以上离散标签含不同程度。本教程沿用预训练模型的原始方案仅使用POSITIVE/NEGATIVE两个标签也可加入NEUTRAL。必须事先定义标注指南annotation guidelines明确什么样本该标什么标签例如一般性咨询问题标 POSITIVE表达问题/投诉的标 NEGATIVE这是保证标注质量的前提。第 1 步跑模型、写日志predict log用datasets库的map对整份原始数据做批量预测想快速试验可先加.select(range(10))只取 10 条def predict(examples): return {predictions: sentiment_classifier(examples[text], truncationTrue)} # 小样本快速测试可改为to_label1.select(range(10)).map(...) to_label1 to_label1.map(predict, batchedTrue, batch_size4)如果不想自己跑预测也可以直接从 Hub 加载已带预测结果的记录load_dataset(argilla/sentiment-banking, splittrain)。接着把每条样本包装成TextClassificationRecord——文本、意图元数据、模型预测及prediction_agent记录预测来源便于后续在 UI 中按模型筛选——并写入 Argillarecords [] for example in to_label1.shuffle(): record rg.TextClassificationRecord( textexample[text], metadata{ category: example[label] }, # 记录意图类别便于按意图探索 prediction[(pred[label], pred[score]) for pred in example[predictions]], prediction_agentdistilbert-base-uncased-finetuned-sst-2-english, ) records.append(record) rg.log(namelabeling_with_pretrained, recordsrecords)第 2 步探索与标注label打开 Argilla 标注 UI先评估预训练模型在本数据上的表现。教程中的观察是预训练分类器把 5001 条记录中的 4835 条判为NEGATIVE明显失衡用Predictions / Predicted as:过滤器筛出被预测为POSITIVE的样本会发现不少与标注策略相悖的例子。Argilla 提供搜索驱动的标注 UI支持全文检索、搜索过滤器以及Elasticsearch 查询 DSL做高级查询特别适合稀疏数据集、多标签任务或类别不均衡场景。官方推荐的标注节奏是先顺序标注不使用搜索功能从头到尾逐条标注这样首批样本的分布与数据集整体一致再定向标注对数据有了感觉后用过滤器和搜索针对特定标签补齐样本——例如先修正所有被判为POSITIVE的记录再挑若干NEGATIVE样本。按此流程标注约 5% 的数据200 余条即可进入第一次微调。第 3 步用 Trainer 微调用querystatus:Validated从 Argilla 拉回已标注记录Validated即已标注状态转成训练集并做 tokenizerb_dataset rg.load(namelabeling_with_pretrained, querystatus:Validated) rb_dataset.to_pandas().head(3) # 生成带数值标签的 Hugging Face 数据集 train_ds rb_dataset.prepare_for_training() tokenizer AutoTokenizer.from_pretrained( distilbert-base-uncased-finetuned-sst-2-english ) def tokenize_function(examples): return tokenizer(examples[text], paddingmax_length, truncationTrue) tokenized_train_ds train_ds.map(tokenize_function, batchedTrue) # 按 8:2 划分训练集与评估集 train_dataset, eval_dataset tokenized_train_ds.train_test_split( test_size0.2, seed42 ).values()加载模型并配置Trainer每个 epoch 评估一次每 30 步记录一次日志以 accuracy 作为指标model AutoModelForSequenceClassification.from_pretrained( distilbert-base-uncased-finetuned-sst-2-english ) training_args TrainingArguments( distilbert-base-uncased-sentiment-banking, evaluation_strategyepoch, logging_steps30, ) metric load_metric(accuracy) def compute_metrics(eval_pred): logits, labels eval_pred predictions np.argmax(logits, axis-1) return metric.compute(predictionspredictions, referenceslabels) trainer Trainer( argstraining_args, modelmodel, train_datasettrain_dataset, eval_dataseteval_dataset, compute_metricscompute_metrics, ) trainer.train()prepare_for_training是 Argilla 记录集对象提供的能力负责把 Argilla 记录规整为transformers/datasets可消费的训练格式。第 4 步对比新旧模型用微调后的模型建一条新 pipeline与预训练模型在同一条样本上对比finetuned_sentiment_classifier pipeline( modelmodel.to(cpu), tokenizertokenizer, tasksentiment-analysis, return_all_scoresTrue, ) finetuned_sentiment_classifier( I need to deposit my virtual card, how do i do that. ), sentiment_classifier(I need to deposit my virtual card, how do i do that.)可以看到微调后的模型把这类一般性问题判为POSITIVE而预训练模型仍判为NEGATIVE而对于真正的问题类样本如Why is my payment still pending?两个模型都能正确判定——说明领域微调确实修正了偏差。第 57 步第二轮迭代第二轮开始用querystatus:Default加载剩余未标注记录改用微调后的模型批量预测并写入新的数据集labeling_with_finetunedrb_dataset rg.load(namelabeling_with_pretrained, querystatus:Default) def predict(examples): texts [example[text] for example in examples[inputs]] return { prediction: finetuned_sentiment_classifier(texts), prediction_agent: [distilbert-base-uncased-banking77-sentiment] * len(texts), } ds_dataset rb_dataset.to_datasets().map(predict, batchedTrue, batch_size8) records rg.read_datasets(ds_dataset, taskTextClassification) rg.log(recordsrecords, namelabeling_with_finetuned)回到 UI 探索第二轮预测微调模型的预测已更贴合标注策略。接下来用预测分数过滤不确定性高的样本、并分别修正被预测为POSITIVE/NEGATIVE的样本补充约 80 条高信息量标注约占原始数据 2%。最后把新标注并入原训练集重新从预训练权重出发微调并保存模型rb_dataset rg.load(labeling_with_finetuned) train_ds rb_dataset.prepare_for_training() tokenized_train_ds train_ds.map(tokenize_function, batchedTrue) train_dataset concatenate_datasets([train_dataset, tokenized_train_ds]) model AutoModelForSequenceClassification.from_pretrained( distilbert-base-uncased-finetuned-sst-2-english ) trainer Trainer( argstraining_args, modelmodel, train_datasettrain_dataset, eval_dataseteval_dataset, compute_metricscompute_metrics, ) trainer.train() model.save_pretrained(distilbert-base-uncased-sentiment-banking)整个教程的核心可概括为两轮predict → log → label循环先靠预训练模型降低冷启动标注成本再用模型预测 人工修正的方式持续扩充高质量训练集。除手工标注外还可以与弱监督、主动学习等方法组合例如教程末尾提到的 ModAL 主动学习、基于 Sentence Transformers 的弱监督等均在 notebooks 目录 下可找到对应教程。技巧三探索与分析 spaCy NER 管道第三个基础教程把视角转向序列标注把 spaCy 命名实体识别NER管道的输出灌入 Argilla用于评估预训练模型、定位高频错误开发期与生产期皆可、在 Argilla 标注模式下持续改进管线以及借助 Kibana 集成监控模型预测。准备数据与模型教程使用Gutenberg Time数据集从 Project Gutenberg 全文小说中提取的显式时间引用共 52183 部小说的抽取片段流式加载前几条样本from datasets import load_dataset import pandas as pd import spacy from tqdm.auto import tqdm dataset load_dataset(gutenberg_time, splittrain, streamingTrue) # 查看 train 集合的前 5 条样本 pd.DataFrame(dataset.take(5))安装并下载两个 spaCy 模型——一个基于 transformer 的高精度模型和一个轻量模型用于后续对比%pip install argilla -qqq %pip install torch -qqq %pip install datasets spacy[transformers]~3.0 protobuf -qqq !python -m spacy download en_core_web_trf !python -m spacy download en_core_web_sm把 NER 预测灌入 Argilla对前 50 条样本运行en_core_web_trf提取 token 与实体包装成TokenClassificationRecord实体格式为(label, start_char, end_char)最后rg.log写入数据集nlp spacy.load(en_core_web_trf) # 创建空记录列表用于存放所有记录 records [] # 遍历 Gutenberg 数据集的前 50 条样本 for record in tqdm(list(dataset.take(50))): # 只需要每条样本的文本 text record[tok_context] # 创建 spaCy Doc doc nlp(text) # 实体标注 entities [(ent.label_, ent.start_char, ent.end_char) for ent in doc.ents] # 预分词的输入文本 tokens [token.text for token in doc] # Argilla TokenClassificationRecord 列表 records.append( rg.TokenClassificationRecord( texttext, tokenstokens, predictionentities, prediction_agenten_core_web_trf, ) ) rg.log(recordsrecords, namegutenberg_spacy_ner)打开 Argilla 中的gutenberg_spacy_ner数据集可以对该模型的预测做以下操作按实体类型过滤记录查看每种实体最常见的表层形式mentions——例如时长duration实体的 mention 可能是 1 month这对错误分析非常有用能快速暴露问题实体类型用全文检索定位包含特定词的记录校验、采纳或拒绝具体实体标注从而构建新训练集。想跳过 spaCy 计算阶段可以直接从 Hub 加载教程预生成的 Argilla 记录例如records rg.read_datasets(load_dataset(argilla/gutenberg_spacy_ner, splittrain), taskTokenClassification)再rg.log进 web app 继续后续步骤。用轻量模型对比并在更难的域外数据上验证用en_core_web_sm重复同一流程这次跑 10000 条样本并写入同一个数据集gutenberg_spacy_ner标注prediction_agenten_core_web_smnlp spacy.load(en_core_web_sm) records [] for record in tqdm(list(dataset.take(10000))): text record[tok_context] doc nlp(text) entities [(ent.label_, ent.start_char, ent.end_char) for ent in doc.ents] tokens [token.text for token in doc] records.append( rg.TokenClassificationRecord( texttext, tokenstokens, predictionentities, prediction_agenten_core_web_sm, ) ) rg.log(recordsrecords, namegutenberg_spacy_ner)回到 UI可以通过predicted by过滤器来源于prediction_agent参数只看某个模型的预测从而在同一数据集内直接对比两个模型的表现接下来用更域外的 IMDB 影评数据集做压力测试——它与 spaCy 预训练数据分布差异更大更容易暴露问题。教程对 IMDB test 集前 5000 条运行en_core_web_sm并写入imdb_spacy_nerimdb load_dataset(imdb, splittest) records [] for record in tqdm(imdb.select(range(5000))): text record[text] doc nlp(text) entities [(ent.label_, ent.start_char, ent.end_char) for ent in doc.ents] tokens [token.text for token in doc] records.append( rg.TokenClassificationRecord( texttext, tokenstokens, predictionentities, prediction_agenten_core_web_sm ) ) rg.log(recordsrecords, nameimdb_spacy_ner)在 IMDB 上探索发现Person 实体最常见的 mention 中出现了gore电影类型与Oscar奖项这类典型误判直观印证了针对特定领域进行微调的必要性——利用过滤器和搜索框可以逐条核查这些错误。附把数据集回推 Hub 做版本管理教程附录演示了如何把 Argilla 数据集一键推送回 Hugging Face Hub从而对数据集进行版本化records rg.load(gutenberg_spacy_ner) records.to_datasets().push_to_hub(name of the dataset on the HF Hub)这一能力对应 v1 客户端的数据集 IO 封装相关实现可参考 argilla-v1/src/argilla_v1/client 中的to_datasets/read_datasets逻辑。小结三条可复用、可组合的基础工作流回到 1_basics.md 的定位——Basics 为初学者铺开三张最小可用的地图标注管理通过metadata[user]或拆分工作区两种方式分配记录配合 UI 的元数据过滤让团队协作标注有序、可控、可度量模型引导标注用pipeline预测 rg.TextClassificationRecord(prediction..., prediction_agent...)rg.log建出带预测的训练集人工修正后prepare_for_training()直接接上 Hugging FaceTrainer并支持多轮迭代扩充预测探索与对比把 spaCy 等第三方模型的预测统一灌入 Argilla借助实体类型过滤、mentions 统计与predicted by过滤器做错误分析、模型对比与领域微调决策。三者覆盖了数据标注生命周期中最常见的三个入口分工、冷启动与评估。理解这三条工作流后再前往 techniques 目录 下的其他进阶教程弱监督、主动学习、可解释性等时就能在同一个数据底座上自由组合——因为无论使用哪种技巧数据进出的方式始终是rg.log与rg.load这对基础原语。【免费下载链接】argillaArgilla is a collaboration tool for AI engineers and domain experts to build high-quality datasets项目地址: https://gitcode.com/GitHub_Trending/ar/argilla创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门