SiameseUIE开发者案例:基于test.py扩展时间/机构实体类型的路径

1. 项目背景与价值

在实际的信息抽取项目中,我们经常遇到这样的需求:从一段文本中不仅要提取人物和地点,还需要识别时间信息和组织机构。比如从新闻稿件中提取事件发生的时间、涉及的公司机构,或者从历史文献中提取年代和相关的官府机构。

SiameseUIE模型部署镜像已经为我们提供了很好的基础能力,可以无缝抽取人物和地点实体。但如果我们想要扩展时间、机构等其他实体类型,该如何操作呢?这就是本文要解决的核心问题。

基于test.py脚本进行扩展有几个明显优势:首先是环境兼容性好,不需要重新配置依赖;其次是修改成本低,只需要在现有逻辑上增加新规则;最重要的是效果可控,可以根据实际需求定制抽取规则。

2. 环境准备与快速验证

2.1 基础环境确认

首先确保你已经部署了SiameseUIE模型镜像,并且能够正常运行基础测试。通过SSH登录到云实例后,执行以下命令验证环境:

# 激活torch28环境
source activate torch28

# 进入模型工作目录
cd ..
cd nlp_structbert_siamese-uie_chinese-base

# 运行原始测试脚本
python test.py

如果能看到5个测试例子的抽取结果,说明环境一切正常,可以开始进行扩展开发。

2.2 理解现有代码结构

打开test.py文件,我们可以看到核心的抽取逻辑主要在extract_pure_entities函数中。这个函数目前支持两种模式:

  1. 自定义实体模式:通过custom_entities参数指定要抽取的具体实体列表
  2. 通用规则模式:使用内置的正则规则自动匹配人物和地点

我们的扩展工作主要是在通用规则模式中添加时间和机构的识别逻辑。

3. 时间实体抽取实现

3.1 时间表达的特点分析

中文时间表达有很强的规律性,主要包括以下几种类型:

  • 绝对时间:2023年、8月15日、下午3点
  • 相对时间:昨天、下周、三个月后
  • 时间段:2020-2023年、1月至3月
  • 模糊时间:近年来、古代、改革开放初期

3.2 时间正则规则设计

基于这些特点,我们设计相应的时间识别规则:

# 在extract_pure_entities函数前添加时间正则规则
TIME_PATTERNS = [
    r'\d{4}年\d{1,2}月\d{1,2}日',  # 年月日格式
    r'\d{4}年\d{1,2}月',           # 年月格式  
    r'\d{1,2}月\d{1,2}日',         # 月日格式
    r'\d{4}年',                    # 年格式
    r'\d{1,2}时\d{1,2}分',         # 时分格式
    r'上午|下午|晚上|凌晨|清晨|傍晚', # 时间段词汇
    r'今天|昨天|明天|前天|后天',    # 相对日期
    r'上周|本周|下周|上月|本月|下月', # 相对周月
    r'\d{4}年至\d{4}年',           # 时间段
    r'古代|近代|现代|当代|年初|年末' # 模糊时间
]

3.3 时间抽取函数实现

def extract_time_entities(text):
    """
    从文本中提取时间实体
    """
    time_entities = []
    
    for pattern in TIME_PATTERNS:
        matches = re.finditer(pattern, text)
        for match in matches:
            time_entities.append(match.group())
    
    # 去重并保持原始顺序
    seen = set()
    unique_times = []
    for time in time_entities:
        if time not in seen:
            seen.add(time)
            unique_times.append(time)
    
    return unique_times

4. 机构实体抽取实现

4.1 机构表达的特点分析

组织机构名称也有明显的特征模式:

  • 后缀特征:公司、集团、银行、医院、学校、局、部、委员会
  • 前缀特征:中国、北京、上海等地域前缀
  • 中间特征:有限、责任、股份、科技等业务描述

4.2 机构正则规则设计

# 机构识别正则规则
ORG_PATTERNS = [
    r'[^\s]{2,20}(公司|集团|有限公司|有限责任公司|股份有限公司)',
    r'[^\s]{2,20}(银行|医院|学校|大学|学院|中学|小学)',
    r'[^\s]{2,20}(局|部|厅|处|科|委员会|协会|学会)',
    r'[^\s]{2,20}(厂|店|商场|超市|中心|事务所)',
    r'(中国|北京|上海|广州|深圳)[^\s]{2,10}(公司|集团|银行|医院)'
]

4.3 机构抽取函数实现

def extract_org_entities(text):
    """
    从文本中提取机构实体
    """
    org_entities = []
    
    for pattern in ORG_PATTERNS:
        matches = re.finditer(pattern, text)
        for match in matches:
            # 过滤掉明显不符合的匹配
            entity = match.group()
            if len(entity) >= 4 and len(entity) <= 30:  # 合理长度范围
                org_entities.append(entity)
    
    # 去重处理
    seen = set()
    unique_orgs = []
    for org in org_entities:
        if org not in seen:
            seen.add(org)
            unique_orgs.append(org)
    
    return unique_orgs

5. 整合到现有测试框架

5.1 修改extract_pure_entities函数

我们需要修改核心抽取函数,支持时间和机构的抽取:

def extract_pure_entities(text, schema=None, custom_entities=None):
    """
    扩展后的实体抽取函数,支持人物、地点、时间、机构
    """
    results = {}
    
    if custom_entities:
        # 自定义实体模式(原有逻辑)
        for entity_type in custom_entities:
            if entity_type in ['人物', '地点']:
                entities = []
                for entity in custom_entities[entity_type]:
                    if entity in text:
                        entities.append(entity)
                results[entity_type] = entities
    else:
        # 通用规则模式(扩展逻辑)
        results['人物'] = extract_person_entities(text)  # 原有函数
        results['地点'] = extract_location_entities(text)  # 原有函数
        results['时间'] = extract_time_entities(text)  # 新增
        results['机构'] = extract_org_entities(text)  # 新增
    
    return results

5.2 更新测试例子

修改test_examples列表,添加包含时间和机构的测试文本:

test_examples = [
    {
        "name": "例子1:历史事件多实体",
        "text": "2023年北京大学举办了一场学术会议,清华大学和上海交通大学也派代表参加。会议于8月15日上午9点开始,持续到下午5点。",
        "schema": {"人物": None, "地点": None, "时间": None, "机构": None},
        "custom_entities": None
    },
    {
        "name": "例子2:企业新闻",
        "text": "腾讯公司于2022年第一季度财报显示,阿里巴巴集团和百度公司的市场份额有所变化。今年3月15日,华为技术有限公司发布了新產品。",
        "schema": {"人物": None, "地点": None, "时间": None, "机构": None},
        "custom_entities": None
    }
    # 保留原有测试例子...
]

5.3 完善输出显示

修改结果输出部分,确保时间和机构实体也能正确显示:

# 在输出循环中添加时间和机构的显示
for example in test_examples:
    print(f"========== {example['name']} ==========")
    print(f"文本:{example['text']}")
    
    extract_results = extract_pure_entities(
        text=example["text"],
        schema=example["schema"],
        custom_entities=example.get("custom_entities")
    )
    
    print("抽取结果:")
    for entity_type, entities in extract_results.items():
        if entities:
            print(f"- {entity_type}:{', '.join(entities)}")
    
    print("-" * 40)
    print()

6. 效果验证与测试

6.1 运行扩展后的测试

保存修改后的test.py文件,然后运行测试:

python test.py

你应该能看到类似这样的输出:

========== 例子1:历史事件多实体 ==========
文本:2023年北京大学举办了一场学术会议,清华大学和上海交通大学也派代表参加。会议于8月15日上午9点开始,持续到下午5点。
抽取结果:
- 时间:2023年, 8月15日, 上午9点, 下午5点
- 机构:北京大学, 清华大学, 上海交通大学
----------------------------------------

========== 例子2:企业新闻 ==========
文本:腾讯公司于2022年第一季度财报显示,阿里巴巴集团和百度公司的市场份额有所变化。今年3月15日,华为技术有限公司发布了新產品。
抽取结果:
- 时间:2022年, 3月15日
- 机构:腾讯公司, 阿里巴巴集团, 百度公司, 华为技术有限公司
----------------------------------------

6.2 处理边界情况

在实际使用中可能会遇到一些边界情况,我们需要进行处理:

# 优化时间抽取,避免匹配数字序列
def refine_time_entities(times):
    """
    优化时间实体,过滤掉明显错误匹配
    """
    refined = []
    for time in times:
        # 过滤纯数字(可能是电话号码或其他编号)
        if re.match(r'^\d+$', time) and len(time) > 4:
            continue
        # 过滤明显不合理的时间
        if time.isdigit() and int(time) > 2100:  # 假设2100年后的年份可能是错误匹配
            continue
        refined.append(time)
    return refined

# 在extract_time_entities函数最后调用
return refine_time_entities(unique_times)

7. 进一步优化建议

7.1 性能优化

如果处理大量文本,可以考虑预编译正则表达式:

# 预编译所有正则模式
COMPILED_TIME_PATTERNS = [re.compile(pattern) for pattern in TIME_PATTERNS]
COMPILED_ORG_PATTERNS = [re.compile(pattern) for pattern in ORG_PATTERNS]

# 然后在抽取函数中使用编译后的模式
for pattern in COMPILED_TIME_PATTERNS:
    matches = pattern.finditer(text)
    # ... 其余逻辑不变

7.2 准确率提升

可以通过添加规则后处理来提高准确率:

def post_process_orgs(orgs):
    """
    后处理机构实体,提高准确率
    """
    processed = []
    for org in orgs:
        # 去除可能的前后噪音字符
        org = org.strip('.,!?;:""''()[]{}')
        if len(org) >= 2:  # 至少2个字符
            processed.append(org)
    return processed

7.3 支持更多实体类型

同样的模式可以扩展到其他实体类型:

# 添加其他实体类型的正则规则
PRODUCT_PATTERNS = [
    r'[^\s]{2,10}(手机|电脑|电视|相机|耳机)',
    r'[^\s]{2,10}(软件|系统|平台|应用|小程序)'
]

EVENT_PATTERNS = [
    r'[^\s]{2,10}(会议|比赛|展览|演唱会|庆典)',
    r'[^\s]{2,10}(战争|革命|运动|改革|事件)'
]

8. 总结

通过本文的实践,我们成功基于SiameseUIE模型的test.py脚本扩展了时间和机构实体类型的抽取能力。整个过程体现了几个重要价值:

技术层面,我们通过正则表达式规则扩展,在不改变模型结构的情况下增加了新的实体识别能力。这种方法成本低、见效快,特别适合规则相对明确的实体类型。

实践层面,我们保持了与原有环境的完全兼容,不需要安装新的依赖包,不需要修改PyTorch版本,真正做到了即改即用。

扩展性层面,我们建立的这个框架可以很容易地进一步扩展到其他实体类型,如产品名称、事件名称、专业术语等。

这种基于规则扩展的方法与深度学习模型形成了很好的互补:模型擅长处理模糊、复杂的语义理解,规则擅长处理结构明确、模式固定的信息抽取。在实际项目中,我们往往需要结合使用多种技术手段,才能达到最好的效果。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐