1018 lines
31 KiB
Markdown
1018 lines
31 KiB
Markdown
<!--
|
||
本文件由助教自动生成
|
||
课程: 人工智能数据服务 (090945)
|
||
班级: AI_251
|
||
学号: 2509165048
|
||
仓库: homework-4-3
|
||
原讲义文件: 4-3_文本标注与语音标注_学生讲义.md
|
||
-->
|
||
|
||
# 4-3 文本标注与语音标注(Label Studio)
|
||
|
||
## 学习目标
|
||
|
||
1. 掌握 Label Studio 文本标注的四种类型:分类、NER、意图、关系
|
||
2. 掌握 Label Studio 语音标注的四种类型:转写、说话人、分类
|
||
3. 学会 BIO 标注法、CoNLL 数据格式
|
||
4. 独立完成一个文本分类和一个 ASR 项目
|
||
|
||
---
|
||
|
||
## 1. 为什么用 Label Studio 做文本和语音
|
||
|
||
### 1.1 回顾:Label Studio 的多模态优势
|
||
|
||
```
|
||
一个工具,全模态覆盖:
|
||
|
||
┌──────────┐
|
||
图像 ──→│ │
|
||
文本 ──→│ Label │──→ 统一管理
|
||
语音 ──→│ Studio │──→ 统一导出
|
||
视频 ──→│ │
|
||
└──────────┘
|
||
```
|
||
|
||
### 1.2 本节内容地图
|
||
|
||
```
|
||
4-3 文本与语音标注
|
||
├── 文本部分
|
||
│ ├── 文本分类
|
||
│ ├── NER 命名实体识别
|
||
│ ├── 意图识别 + 槽位
|
||
│ └── 关系抽取
|
||
└── 语音部分
|
||
├── 语音转写 ASR
|
||
├── 说话人分离
|
||
└── 音频分类
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 文本标注基础概念
|
||
|
||
### 2.1 文本数据的特殊性
|
||
|
||
文本是最难标注的数据,因为:
|
||
- 没有"形状",靠"语义"
|
||
- 同样含义表达方式千变万化
|
||
- 上下文影响判断
|
||
- 中文分词、歧义多
|
||
|
||
```
|
||
"苹果" 这个词可以指:
|
||
├── 水果(吃的苹果)
|
||
├── 公司(苹果公司)
|
||
└── 手机(iPhone)
|
||
|
||
只有结合上下文才能判断。
|
||
```
|
||
|
||
### 2.2 文本标注的四大任务
|
||
|
||
| 任务 | 输入 | 输出 | 应用 |
|
||
|------|------|------|------|
|
||
| 文本分类 | 一段文本 | 一个或多个类别 | 情感、新闻分类 |
|
||
| NER | 一段文本 | 实体边界+类型 | 信息抽取、知识图谱 |
|
||
| 意图识别 | 用户query | 意图+槽位 | 智能客服、对话系统 |
|
||
| 关系抽取 | 文本+实体对 | 实体间关系 | 知识图谱构建 |
|
||
|
||
---
|
||
|
||
## 3. 文本分类标注
|
||
|
||
### 3.1 任务说明
|
||
|
||
**场景**:对 10 条商品评论做情感分类(正面/负面/中性)
|
||
|
||
### 3.2 创建项目
|
||
|
||
1. 启动 Label Studio
|
||
2. `+ Create Project`,命名为 `review_sentiment`
|
||
3. 进入项目 → `Settings` → `Labeling Interface` → `Code`
|
||
|
||
### 3.3 文本分类配置 XML
|
||
|
||
```xml
|
||
<View>
|
||
<Text name="text" value="$text"/>
|
||
<Choices name="sentiment" toName="text" choice="single-radio" showInline="true">
|
||
<Choice value="positive"/>
|
||
<Choice value="negative"/>
|
||
<Choice value="neutral"/>
|
||
</Choices>
|
||
</View>
|
||
```
|
||
|
||
**关键参数**:
|
||
|
||
```
|
||
<Text> ← 显示待标注文本
|
||
<Choices> ← 单选/多选
|
||
choice="single-radio" ← 单选(必选一个)
|
||
showInline="true" ← 横排显示
|
||
```
|
||
|
||
### 3.4 准备数据
|
||
|
||
`reviews.csv`:
|
||
|
||
```csv
|
||
text
|
||
这家餐厅的菜品非常美味,下次还会再来
|
||
等位等了两个小时,体验非常差
|
||
今天天气不错,适合出门散步
|
||
物流速度很快,第二天就到了
|
||
服务员态度恶劣,很不耐烦
|
||
这个电影剧情一般,但特效不错
|
||
产品质量一般,用了几天就坏了
|
||
环境优雅,装修很有格调
|
||
价格有点贵,性价比不高
|
||
操作简单,上手很快
|
||
```
|
||
|
||
**导入方式**:项目页 → `Settings` → `Data Import` → 上传 CSV
|
||
|
||
### 3.5 标注操作
|
||
|
||
1. 进入 `Label All Tasks`
|
||
2. 看到一段文本 + 三个选项
|
||
3. 选择最合适的情感
|
||
4. `Submit` 进入下一条
|
||
|
||
```
|
||
┌────────────────────────────────────────┐
|
||
│ 这家餐厅的菜品非常美味,下次还会再来 │
|
||
│ │
|
||
│ ( ) positive ( ) negative ( ) neutral│
|
||
│ │
|
||
│ [ Submit ] │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3.6 多标签分类(进阶)
|
||
|
||
如果一条文本可以同时属于多个类别:
|
||
|
||
```xml
|
||
<Choices name="topics" toName="text" choice="multiple">
|
||
<Choice value="科技"/>
|
||
<Choice value="财经"/>
|
||
<Choice value="体育"/>
|
||
<Choice value="娱乐"/>
|
||
<Choice value="教育"/>
|
||
</Choices>
|
||
```
|
||
|
||
`choice="multiple"` 表示可多选。
|
||
|
||
### 3.7 文本分类标注规范
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ 情感分析标注规范 v1.0 │
|
||
├──────────────────────────────────────────────┤
|
||
│ │
|
||
│ 【正面 positive】 │
|
||
│ 表达满意、喜欢、赞美、推荐 │
|
||
│ 关键词: 好、棒、赞、满意、推荐、完美 │
|
||
│ 示例: "东西很好用,下次还来" │
|
||
│ │
|
||
│ 【负面 negative】 │
|
||
│ 表达不满、失望、抱怨、批评 │
|
||
│ 关键词: 差、烂、垃圾、失望、后悔、投诉 │
|
||
│ 示例: "等了两小时没上菜,差评" │
|
||
│ │
|
||
│ 【中性 neutral】 │
|
||
│ 客观陈述事实,无明显情感倾向 │
|
||
│ 示例: "今天吃了火锅" │
|
||
│ │
|
||
│ ⚠️ 边界情况: │
|
||
│ - "还行" / "一般" 归为中性 │
|
||
│ - "好贵" 可能是负面(嫌贵) │
|
||
│ - 反讽要识别: "真是太好了(等了2小时)" │
|
||
│ 实际是负面 │
|
||
│ - 不确定时标 neutral │
|
||
│ │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 4. NER 命名实体识别标注
|
||
|
||
### 4.1 什么是 NER
|
||
|
||
**NER**(Named Entity Recognition):在文本中找出实体(人名、地名、机构名等),并标注它们在文本中的**起止位置**和**类型**。
|
||
|
||
```
|
||
输入: 张伟毕业于清华大学
|
||
标注: 张伟 [人名] 清华大学 [机构]
|
||
```
|
||
|
||
### 4.2 常见实体类型
|
||
|
||
| 类型 | 缩写 | 说明 | 示例 |
|
||
|------|------|------|------|
|
||
| 人名 | PER | 真实人物 | 张三、马云、周杰伦 |
|
||
| 地名 | LOC | 国家、城市、地区 | 北京、东京、华北 |
|
||
| 机构名 | ORG | 公司、学校、政府 | 华为、清华、公安部 |
|
||
| 时间 | TIME | 时间点、时期 | 1990年、昨天、三天前 |
|
||
| 数字 | NUM | 数字表达式 | 100、3.14、百分之十 |
|
||
| 货币 | MONEY | 金额 | 100元、500美元 |
|
||
|
||
### 4.3 BIO 标注法
|
||
|
||
NER 训练数据的标准格式是 **BIO**:
|
||
|
||
```
|
||
B-XXX = 实体开始(Begin)
|
||
I-XXX = 实体延续(Inside)
|
||
O = 非实体(Outside)
|
||
```
|
||
|
||
**示例**:
|
||
|
||
```
|
||
句子: 马化腾 创办 了 腾讯 公司
|
||
|
||
BIO: B-PER I-PER O B-ORG I-ORG
|
||
E-PER E-ORG (BIOES 体系)
|
||
|
||
按 BIEOS(更精细):
|
||
马: B-PER
|
||
化: I-PER
|
||
腾: E-PER
|
||
创: O
|
||
办: O
|
||
了: O
|
||
腾: B-ORG
|
||
讯: I-ORG
|
||
公: I-ORG
|
||
司: E-ORG
|
||
|
||
> 注意:上面是 BIEOS 体系(多了 E=End 单字实体、S=Single 单词实体),比 BIO 更精细。教材示例这里就以马化腾(3字)为例说明 B/I/E 三个符号。
|
||
```
|
||
|
||
### 4.4 Label Studio NER 配置
|
||
|
||
```xml
|
||
<View>
|
||
<Labels name="label" toName="text">
|
||
<Label value="人名" background="#FF0000"/>
|
||
<Label value="地名" background="#00FF00"/>
|
||
<Label value="机构" background="#0000FF"/>
|
||
<Label value="时间" background="#FFFF00"/>
|
||
</Labels>
|
||
<Text name="text" value="$text"/>
|
||
</View>
|
||
```
|
||
|
||
`<Labels>` + `<Label>` 是 NER 标注的核心:先在右侧定义标签及其颜色,标注时**用鼠标框选文字**就能打上对应标签。
|
||
|
||
### 4.5 标注操作
|
||
|
||
1. 进入标注界面
|
||
2. 看到一段文本
|
||
3. 用鼠标**拖选**要标的实体
|
||
4. 弹出标签列表,选对应类别
|
||
5. 选中的文字会变彩色背景
|
||
|
||
```
|
||
原文本:
|
||
张伟毕业于清华大学,现在在北京工作。
|
||
|
||
标注后:
|
||
[张伟]毕业于[清华大学],现在在[北京]工作。
|
||
人名 机构 地名
|
||
```
|
||
|
||
### 4.6 NER 数据准备
|
||
|
||
`ner_data.json`:
|
||
|
||
```json
|
||
[
|
||
{"text": "张伟毕业于清华大学"},
|
||
{"text": "马云创办了阿里巴巴"},
|
||
{"text": "北京是中华人民共和国的首都"},
|
||
{"text": "周杰伦在上海开了演唱会"},
|
||
{"text": "华为公司总部在深圳"}
|
||
]
|
||
```
|
||
|
||
导入即可,每条 text 是一行任务。
|
||
|
||
### 4.7 导出 CoNLL 格式
|
||
|
||
项目页 → `Export` → 选 `CoNLL`:
|
||
|
||
下载得到 `project-1-conll.txt`:
|
||
|
||
```
|
||
张 B-PER
|
||
伟 E-PER
|
||
毕 O
|
||
业 O
|
||
于 O
|
||
清 B-ORG
|
||
华 I-ORG
|
||
大 I-ORG
|
||
学 E-ORG
|
||
<空白行> ← 一句话结束
|
||
```
|
||
|
||
> 训练 NER 模型时,常用脚本把 CoNLL 格式转成 CRF / BERT 需要的格式。
|
||
|
||
### 4.8 NER 标注规范
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ NER 标注规范 v1.0 │
|
||
├──────────────────────────────────────────────┤
|
||
│ │
|
||
│ 【人名 PER】 │
|
||
│ - 完整姓名: 张三、李四 │
|
||
│ - 姓名简称: 需上下文确认("小明") │
|
||
│ - 历史人物: 鲁迅、毛泽东 │
|
||
│ │
|
||
│ 【地名 LOC】 │
|
||
│ - 国家: 中国、美国 │
|
||
│ - 城市: 北京、上海 │
|
||
│ - 区域: 华北、西部 │
|
||
│ ⚠️ "清华" 是机构不是地名 │
|
||
│ │
|
||
│ 【机构 ORG】 │
|
||
│ - 公司: 华为、阿里 │
|
||
│ - 学校: 清华、北大 │
|
||
│ - 政府: 公安部 │
|
||
│ │
|
||
│ 【歧义处理】 │
|
||
│ "苹果" → 看上下文: 水果/公司/手机 │
|
||
│ "长江" → 看上下文: 河流/公司 │
|
||
│ │
|
||
│ 【边界规则】 │
|
||
│ - 实体边界要准确,不多不少 │
|
||
│ - 含人称前缀: "马云先生" 标 "马云" │
|
||
│ - 不拆嵌套: "北京大学" 整体标 ORG │
|
||
│ │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 意图识别 + 槽位标注
|
||
|
||
### 5.1 任务说明
|
||
|
||
**场景**:智能客服。识别用户 query 的**意图**,并提取**槽位**(关键参数)。
|
||
|
||
### 5.2 概念
|
||
|
||
```
|
||
用户输入: 帮我查一下明天北京的天气
|
||
|
||
意图(intent): query_weather ← 用户想干什么
|
||
槽位(slot): city=北京, time=明天 ← 关键参数
|
||
```
|
||
|
||
### 5.3 Label Studio 配置
|
||
|
||
```xml
|
||
<View>
|
||
<Text name="text" value="$text"/>
|
||
|
||
<!-- 意图:单选 -->
|
||
<Choices name="intent" toName="text" choice="single-radio">
|
||
<Choice value="query_weather"/>
|
||
<Choice value="play_music"/>
|
||
<Choice value="set_alarm"/>
|
||
<Choice value="book_ticket"/>
|
||
<Choice value="other"/>
|
||
</Choices>
|
||
|
||
<!-- 槽位:文本中框选 -->
|
||
<Labels name="slots" toName="text">
|
||
<Label value="city" background="#FF6B6B"/>
|
||
<Label value="time" background="#4ECDC4"/>
|
||
<Label value="song" background="#FFE66D"/>
|
||
<Label value="place" background="#95E1D3"/>
|
||
</Labels>
|
||
</View>
|
||
```
|
||
|
||
### 5.4 数据示例
|
||
|
||
`intents.csv`:
|
||
|
||
```csv
|
||
text
|
||
明天北京天气怎么样
|
||
放一首周杰伦的晴天
|
||
帮我设个早上7点的闹钟
|
||
查一下从上海到北京的高铁
|
||
打开客厅的灯
|
||
```
|
||
|
||
### 5.5 标注操作
|
||
|
||
1. 先选**意图**(单选)
|
||
2. 再**框选**槽位文字(按类型上色)
|
||
3. 一次任务两个标签都打
|
||
|
||
```
|
||
文本: 明天北京天气怎么样
|
||
|
||
意图: query_weather
|
||
槽位: [明天] time, [北京] city
|
||
```
|
||
|
||
### 5.6 导出格式
|
||
|
||
```json
|
||
{
|
||
"data": {"text": "明天北京天气怎么样"},
|
||
"annotations": [{
|
||
"result": [
|
||
{
|
||
"from_name": "intent",
|
||
"value": {"choices": ["query_weather"]}
|
||
},
|
||
{
|
||
"from_name": "slots",
|
||
"value": {
|
||
"start": 0, "end": 2, "text": "明天",
|
||
"labels": ["time"]
|
||
}
|
||
},
|
||
{
|
||
"from_name": "slots",
|
||
"value": {
|
||
"start": 2, "end": 4, "text": "北京",
|
||
"labels": ["city"]
|
||
}
|
||
}
|
||
]
|
||
}]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 关系抽取标注
|
||
|
||
### 6.1 任务说明
|
||
|
||
**任务**:从文本中识别两个实体之间的关系。
|
||
|
||
```
|
||
文本: 马化腾创办了腾讯
|
||
实体: 马化腾(人), 腾讯(公司)
|
||
关系: 创办
|
||
```
|
||
|
||
### 6.2 Label Studio 配置
|
||
|
||
关系抽取在 Label Studio 里使用 `<Relations>` 控件,需要先做 NER 标注,再连接实体:
|
||
|
||
```xml
|
||
<View>
|
||
<Labels name="ner" toName="text">
|
||
<Label value="人物" background="#FF6B6B"/>
|
||
<Label value="公司" background="#4ECDC4"/>
|
||
</Labels>
|
||
<Text name="text" value="$text"/>
|
||
|
||
<Relations name="relation" toName="text">
|
||
<Relation value="创办"/>
|
||
<Relation value="任职"/>
|
||
<Relation value="持股"/>
|
||
<Relation value="合作"/>
|
||
</Relations>
|
||
</View>
|
||
```
|
||
|
||
### 6.3 标注操作
|
||
|
||
1. 先用 NER 方式标出两个实体
|
||
2. 在实体上**点击**,会弹出关系选项
|
||
3. 选择对应的关系(也可以从一个实体拖到另一个实体)
|
||
|
||
```
|
||
文本: 马化腾创办了腾讯
|
||
|
||
标注步骤:
|
||
1. 框选 "马化腾" → 标 "人物"
|
||
2. 框选 "腾讯" → 标 "公司"
|
||
3. 点击 "马化腾" → 弹出关系 → 选 "创办" → 拖到 "腾讯"
|
||
```
|
||
|
||
### 6.4 关系抽取标注规范
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ 关系抽取标注规范 v1.0 │
|
||
├──────────────────────────────────────────────┤
|
||
│ │
|
||
│ 关系类型: │
|
||
│ │
|
||
│ 【创办】 │
|
||
│ X 创办了 Y / Y 由 X 创办 │
|
||
│ 例: 马化腾创办了腾讯 │
|
||
│ │
|
||
│ 【任职】 │
|
||
│ X 任职于 Y / X 是 Y 的 CEO │
|
||
│ 例: 李彦宏是百度的 CEO │
|
||
│ │
|
||
│ 【持股】 │
|
||
│ X 持有 Y 的股份 │
|
||
│ 例: 马云持有阿里巴巴的股份 │
|
||
│ │
|
||
│ 【合作】 │
|
||
│ X 与 Y 合作 │
|
||
│ 例: 腾讯与京东合作 │
|
||
│ │
|
||
│ ⚠️ 边界情况: │
|
||
│ - 关系不明时标"无关系" │
|
||
│ - 一对多: "马云创办了阿里和蚂蚁" │
|
||
│ → 两条关系: 马云-阿里-创办, 马云-蚂蚁-创办│
|
||
│ │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 语音标注基础
|
||
|
||
### 7.1 语音数据的特点
|
||
|
||
```
|
||
文本:已处理好,直接可用
|
||
图像:矩阵,有空间结构
|
||
语音:一维波形 + 时序:
|
||
|
||
┌────────────────────────────────────┐
|
||
│ ▂▃▅▇█▇▅▃▂▃▅▇█▇▅▃▂▃▅▇▇▅▃▂▃▅▇█... │ ← 采样点
|
||
└────────────────────────────────────┘
|
||
每秒 16000 个采样点(16kHz)
|
||
- 含时序信息
|
||
- 易受噪声影响
|
||
- 说话人差异大
|
||
```
|
||
|
||
### 7.2 语音标注任务
|
||
|
||
| 任务 | 标注内容 | 应用 |
|
||
|------|---------|------|
|
||
| 语音转写 ASR | 把语音转成文字 | 字幕、会议记录 |
|
||
| 说话人分离 | 标出每段话是谁 | 多人会议、客服 |
|
||
| 音频分类 | 给整段音频打类别 | 音乐/语音/噪音分类 |
|
||
| 时间戳标注 | 标记每个字的时间 | 字幕对齐 |
|
||
|
||
---
|
||
|
||
## 8. 语音转写 ASR
|
||
|
||
### 8.1 任务说明
|
||
|
||
**任务**:把 3 段音频转写成文字,并标记时间戳。
|
||
|
||
### 8.2 Label Studio ASR 配置
|
||
|
||
```xml
|
||
<View>
|
||
<Audio name="audio" value="$audio"/>
|
||
<TextArea name="transcription" toName="audio"
|
||
placeholder="请输入听到的文字..."
|
||
maxSubmissions="1"
|
||
editable="true"/>
|
||
</View>
|
||
```
|
||
|
||
参数说明:
|
||
- `<Audio>`:加载音频(带播放控件)
|
||
- `<TextArea>`:文本输入框,标注员在这里听写
|
||
- `toName="audio"`:把文本框和音频控件**关联到同一个任务**(用 `toName` 而不是 `toName="text"`,因为这段任务的主控件是 audio)
|
||
- `placeholder`:提示文字
|
||
- `editable="true"`:允许编辑
|
||
- `maxSubmissions="1"`:每条任务只提交一次
|
||
|
||
> 💡 小提示:在 ASR 项目里 `toName="audio"` 是常见的写法;如果同时还有一段文字说明要标注,则用 `toName="text"` 关联到 `<Text>` 控件。两者本质都是"把标注结果挂到对应数据上"。
|
||
|
||
### 8.3 数据准备
|
||
|
||
`audio_tasks.json`:
|
||
|
||
```json
|
||
[
|
||
{"audio": "audio/sample_001.wav"},
|
||
{"audio": "audio/sample_002.wav"},
|
||
{"audio": "audio/sample_003.wav"}
|
||
]
|
||
```
|
||
|
||
**注意**:Label Studio 只能访问特定路径下的音频,有两种方式:
|
||
- 本地路径:`/data/audio/sample_001.wav`(需在启动时配置)
|
||
- HTTP URL:`http://example.com/audio/001.wav`
|
||
|
||
### 8.4 启动配置(本地音频)
|
||
|
||
如果是本地音频文件,启动 Label Studio 时需要指定根目录:
|
||
|
||
```bash
|
||
label-studio \
|
||
--label-config-file my_config.xml \
|
||
--root-dir /path/to/data
|
||
```
|
||
|
||
或者在 `Settings` → `Cloud Storage` → `Add Source` → `Local files` 里配置。
|
||
|
||
### 8.5 标注操作
|
||
|
||
1. 进入标注界面
|
||
2. 点音频播放按钮听
|
||
3. 在文本框输入听到的文字
|
||
4. 标完点 Submit
|
||
|
||
```
|
||
┌────────────────────────────────────────┐
|
||
│ ▶ ━━━━●─────────── 0:00 / 0:08 │
|
||
│ │
|
||
│ 文本框: │
|
||
│ ┌────────────────────────────────┐ │
|
||
│ │ 今天天气怎么样 │ │
|
||
│ └────────────────────────────────┘ │
|
||
│ │
|
||
│ [ Submit ] │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
|
||
### 8.6 时间戳分段标注
|
||
|
||
如果需要精确时间戳(每个词的时间),用更复杂的配置:
|
||
|
||
```xml
|
||
<View>
|
||
<Audio name="audio" value="$audio"/>
|
||
<Labels name="label" toName="audio">
|
||
<Label value="语音" background="#7ED321"/>
|
||
<Label value="静音" background="#9B9B9B"/>
|
||
</Labels>
|
||
<TextArea name="transcription" toName="audio"
|
||
placeholder="逐句转写,每行一句"/>
|
||
</View>
|
||
```
|
||
|
||
在音频波形上**拖动**选中一段时间,配合文字行实现"哪段时间是哪句话"。
|
||
|
||
### 8.7 语音转写规范
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ 语音转写标注规范 v1.0 │
|
||
├──────────────────────────────────────────────┤
|
||
│ │
|
||
│ 【基本规则】 │
|
||
│ - 保持原话原意,不修改内容 │
|
||
│ - 标点符号自由(保持项目一致) │
|
||
│ - 语气词(嗯、啊、这个)一般保留 │
|
||
│ │
|
||
│ 【特殊处理】 │
|
||
│ - 口吃: "我我我" 保留重复 │
|
||
│ - 笑声: 标 [笑声] 或 [laughter] │
|
||
│ - 沉默>3秒: 标 [沉默] │
|
||
│ - 环境音: 标 [噪音] / [music] │
|
||
│ - 听不清: 标 [听不清] │
|
||
│ │
|
||
│ 【时间戳】 │
|
||
│ - 格式: 秒(如 0.0、1.5) │
|
||
│ - 开始时间 < 结束时间 │
|
||
│ - 段落之间不要有重叠 │
|
||
│ │
|
||
│ 【示例】 │
|
||
│ 0.0-2.5: 今天天气怎么样 │
|
||
│ 2.5-5.0: 挺好的,适合出门 │
|
||
│ 5.0-5.5: [笑声] │
|
||
│ │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 说话人分离
|
||
|
||
### 9.1 任务说明
|
||
|
||
**任务**:在一段多人对话音频中,标出每段话分别是谁说的。
|
||
|
||
### 9.2 Label Studio 配置
|
||
|
||
```xml
|
||
<View>
|
||
<Audio name="audio" value="$audio"/>
|
||
<Labels name="speaker" toName="audio">
|
||
<Label value="Speaker A" background="#FF6B6B"/>
|
||
<Label value="Speaker B" background="#4ECDC4"/>
|
||
<Label value="Speaker C" background="#FFE66D"/>
|
||
</Labels>
|
||
<TextArea name="text" toName="audio"
|
||
placeholder="输入这段话的文字..."/>
|
||
</View>
|
||
```
|
||
|
||
### 9.3 标注操作
|
||
|
||
1. 听音频
|
||
2. 在波形上**拖选**一段对应某说话人的区域
|
||
3. 选择对应的说话人标签
|
||
4. 在文本框输入该段话的内容
|
||
5. 一段一段重复
|
||
|
||
```
|
||
音频波形 + 标注:
|
||
┌────────────────────────────────────────────┐
|
||
│ ████████░░░░████████░░██████████░░░░░░░░ │
|
||
│ │
|
||
│ [SpeA] [SpeB] [SpeA] [SpeB] │
|
||
│ │
|
||
│ 文字: │
|
||
│ 明天要开会吗? │
|
||
│ 是的,下午三点。 │
|
||
│ 好的,我知道了。 │
|
||
│ 收到。 │
|
||
└────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 9.4 导出格式
|
||
|
||
```json
|
||
{
|
||
"data": {"audio": "dialogue_001.wav"},
|
||
"annotations": [{
|
||
"result": [
|
||
{
|
||
"from_name": "speaker",
|
||
"to_name": "audio",
|
||
"type": "labels",
|
||
"value": {
|
||
"start": 0.0, "end": 2.5,
|
||
"labels": ["Speaker A"]
|
||
}
|
||
},
|
||
{
|
||
"from_name": "text",
|
||
"to_name": "audio",
|
||
"type": "textarea",
|
||
"value": {"text": ["明天要开会吗?"]}
|
||
}
|
||
]
|
||
}]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 音频分类
|
||
|
||
### 10.1 任务说明
|
||
|
||
**任务**:对 10 段音频分类(音乐、语音、噪音)
|
||
|
||
### 10.2 Label Studio 配置
|
||
|
||
```xml
|
||
<View>
|
||
<Audio name="audio" value="$audio"/>
|
||
<Choices name="category" toName="audio" choice="single-radio">
|
||
<Choice value="speech"/>
|
||
<Choice value="music"/>
|
||
<Choice value="noise"/>
|
||
<Choice value="vehicle"/>
|
||
<Choice value="alarm"/>
|
||
</Choices>
|
||
</View>
|
||
```
|
||
|
||
### 10.3 数据准备
|
||
|
||
`audio_cls.csv`:
|
||
|
||
```csv
|
||
audio
|
||
audio/clip_001.wav
|
||
audio/clip_002.wav
|
||
audio/clip_003.wav
|
||
```
|
||
|
||
### 10.4 标注操作
|
||
|
||
1. 播放音频
|
||
2. 选择对应类别
|
||
3. 提交
|
||
|
||
```
|
||
┌────────────────────────────────────────┐
|
||
│ ▶ ━━━━●─────────── 0:00 / 0:05 │
|
||
│ │
|
||
│ 这段音频属于哪一类? │
|
||
│ │
|
||
│ ( ) speech ( ) music │
|
||
│ ( ) noise ( ) vehicle │
|
||
│ ( ) alarm │
|
||
│ │
|
||
│ [ Submit ] │
|
||
└────────────────────────────────────────┘
|
||
```
|
||
|
||
### 10.5 常见音频类别
|
||
|
||
| 类别 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| speech | 人声 | 演讲、对话 |
|
||
| music | 音乐 | 流行歌曲、背景音乐 |
|
||
| noise | 噪声 | 风声、雨声 |
|
||
| vehicle | 交通工具 | 引擎声 |
|
||
| alarm | 警报 | 警笛、闹钟 |
|
||
| animal | 动物 | 猫叫、狗叫 |
|
||
|
||
---
|
||
|
||
## 11. 文本与语音标注速查
|
||
|
||
### 11.1 Label Studio 控件对照
|
||
|
||
| 标注任务 | 控件 | 关键属性 |
|
||
|---------|------|---------|
|
||
| 文本分类 | `<Choices>` | choice="single-radio" |
|
||
| NER | `<Labels>` | toName="text" |
|
||
| 意图+槽位 | `<Choices>` + `<Labels>` | 双控件 |
|
||
| 关系抽取 | `<Relations>` | 配合 NER |
|
||
| ASR 转写 | `<Audio>` + `<TextArea>` | toName="audio" |
|
||
| 说话人分离 | `<Audio>` + `<Labels>` + `<TextArea>` | 拖选时间区域 |
|
||
| 音频分类 | `<Audio>` + `<Choices>` | 单选 |
|
||
|
||
### 11.2 快捷键速查
|
||
|
||
| 快捷键 | 功能 |
|
||
|--------|------|
|
||
| `Ctrl + Enter` | 提交 |
|
||
| `H` | 显示/隐藏已标 |
|
||
| `Ctrl + Z` | 撤销 |
|
||
| `Delete` | 删除选中 |
|
||
| `Esc` | 取消选择 |
|
||
| 滚轮 | 滚音频/缩放 |
|
||
|
||
---
|
||
|
||
## 12. Python SDK 简介
|
||
|
||
### 12.1 安装
|
||
|
||
```bash
|
||
pip install label-studio-sdk
|
||
```
|
||
|
||
### 12.2 批量导入文本任务
|
||
|
||
```python
|
||
from label_studio_sdk import Client
|
||
|
||
ls = Client(url='http://localhost:8080', api_key='YOUR_API_KEY')
|
||
|
||
# 读取 CSV / JSONL
|
||
import json
|
||
tasks = []
|
||
with open('reviews.csv', 'r', encoding='utf-8') as f:
|
||
next(f) # 跳过表头
|
||
for line in f:
|
||
text = line.strip()
|
||
if text:
|
||
tasks.append({"data": {"text": text}})
|
||
|
||
# 找到项目
|
||
project = ls.get_project(title='review_sentiment')
|
||
|
||
# 批量导入
|
||
project.import_tasks(tasks)
|
||
print(f"已导入 {len(tasks)} 条任务")
|
||
```
|
||
|
||
### 12.3 批量导出 NER 结果
|
||
|
||
```python
|
||
project = ls.get_project(title='ner_demo')
|
||
|
||
# 导出为 CoNLL 格式
|
||
project.export_tasks(export_type='CONLL')
|
||
|
||
# 解析导出的 JSON
|
||
import requests
|
||
response = requests.get(
|
||
'http://localhost:8080/api/projects/1/export?exportType=JSON',
|
||
headers={'Authorization': 'Token YOUR_API_KEY'}
|
||
)
|
||
data = response.json()
|
||
print(f"共 {len(data)} 条标注数据")
|
||
```
|
||
|
||
---
|
||
|
||
## 13. 实战练习
|
||
|
||
### 13.1 任务一:情感分类(必做)
|
||
|
||
**任务**:在 Label Studio 创建项目 `product_reviews`
|
||
|
||
1. 准备 10 条商品评论
|
||
2. 配置三分类 XML(`positive/negative/neutral`)
|
||
3. 全部标完
|
||
4. 导出 JSON
|
||
|
||
### 13.2 任务二:NER 标注(必做)
|
||
|
||
**任务**:创建项目 `news_ner`
|
||
|
||
1. 准备 5 条新闻文本
|
||
2. 配置 4 个实体(人名/地名/机构/时间)
|
||
3. 全部标完
|
||
4. 导出 CoNLL 格式
|
||
|
||
### 13.3 任务三:语音转写(选做)
|
||
|
||
**任务**:创建项目 `asr_demo`
|
||
|
||
1. 准备 3 段音频
|
||
2. 配置 Audio + TextArea
|
||
3. 全部标完
|
||
4. 导出 JSON
|
||
|
||
### 13.4 自检清单
|
||
|
||
```
|
||
文本分类:
|
||
□ 类别选择是否准确
|
||
□ 边界情况(反讽、双重否定)是否正确处理
|
||
□ 导出 JSON 是否完整
|
||
|
||
NER:
|
||
□ 实体边界是否准确
|
||
□ 实体类型是否正确
|
||
□ 是否有漏标
|
||
□ CoNLL 格式是否标准
|
||
|
||
语音转写:
|
||
□ 文字内容是否完整
|
||
□ 时间戳是否准确
|
||
□ 特殊处理(沉默、笑声)是否标了
|
||
```
|
||
|
||
---
|
||
|
||
## 14. 本节知识小结
|
||
|
||
```
|
||
┌────────────────────────────────────────────────────────┐
|
||
│ 4-3 文本标注与语音标注(Label Studio) │
|
||
├────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 📌 文本标注四大任务: │
|
||
│ 分类 → <Choices> │
|
||
│ NER → <Labels> + BIO 标注法 │
|
||
│ 意图+槽位 → <Choices> + <Labels> │
|
||
│ 关系抽取 → <Relations> 配合 NER │
|
||
│ │
|
||
│ 📌 语音标注三大任务: │
|
||
│ ASR 转写 → <Audio> + <TextArea> │
|
||
│ 说话人分离 → <Audio> + <Labels> + <TextArea> │
|
||
│ 音频分类 → <Audio> + <Choices> │
|
||
│ │
|
||
│ 📌 关键格式: │
|
||
│ BIO 标注法: B-X / I-X / O │
|
||
│ CoNLL: 一行一字的标签,句子间空行 │
|
||
│ │
|
||
│ 📌 工具特性: │
|
||
│ - Python SDK 批量导入导出 │
|
||
│ - 多模态统一管理 │
|
||
│ - 可视化 XML 配置 │
|
||
│ │
|
||
└────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 课后任务
|
||
|
||
1. 创建 `product_reviews` 项目,完成 10 条情感分类
|
||
2. 创建 `news_ner` 项目,完成 5 条 NER 标注(导出 CoNLL)
|
||
3. (选做)创建 `asr_demo` 项目,完成 3 段音频转写
|
||
|
||
---
|
||
|
||
## 下节预告
|
||
|
||
下一节我们将学习 **4-4 标注质量控制与标注管理(Label Studio 协作管理)**:
|
||
- 标注一致性指标(Kappa 系数)
|
||
- Label Studio 组织/成员/角色管理
|
||
- 审核员工作流:Approve / Reject
|
||
- 冲突解决与活动日志 |