SiameseUniNLU实战教程:用schema定义‘电影-导演-主演-票房-评分’结构化抽取模板
SiameseUniNLU实战教程用schema定义‘电影-导演-主演-票房-评分’结构化抽取模板1. 引言从混乱文本到结构化数据你是不是经常遇到这样的场景面对一段关于电影的新闻报道或影评里面混杂着导演、演员、票房、评分等各种信息你需要手动整理成表格。这个过程不仅枯燥还容易出错。比如下面这段文字“张艺谋导演的《满江红》在2023年春节档取得了超过45亿的惊人票房影片由沈腾、易烊千玺领衔主演豆瓣开分达到了8.0猫眼评分9.6成为了年度现象级作品。”如果让你手动提取你可能需要反复阅读然后分别找出电影名、导演、主演、票房、评分这些信息再填到Excel里。一部电影还好如果是成百上千条呢今天我要介绍的SiameseUniNLU就是一个能帮你自动化完成这项工作的神器。它就像一个智能的信息提取员你只需要告诉它你想找什么比如“导演是谁”、“票房多少”它就能从一大段文字里精准地把这些信息抓出来并整理成结构化的格式。这个模型最厉害的地方在于它的“通用性”。传统的NLP模型做实体识别需要一个模型做关系抽取又需要另一个模型部署和维护都很麻烦。而SiameseUniNLU通过一种巧妙的“提示Prompt文本Text”的构建思路用一个模型就能搞定命名实体识别、关系抽取、情感分类等十几种任务。你只需要改变给它的“任务说明书”也就是Schema它就能切换成不同的工作模式。在这篇教程里我会手把手带你用SiameseUniNLU搭建一个专属的“电影信息智能提取器”。我们的目标是输入任何一段包含电影信息的文本模型都能自动输出一个结构清晰的结果比如{ 电影: [《满江红》], 导演: [张艺谋], 主演: [沈腾, 易烊千玺], 票房: [45亿], 评分: [豆瓣 8.0, 猫眼 9.6] }准备好了吗我们开始吧。2. 环境准备与模型快速部署首先我们需要把SiameseUniNLU模型运行起来。别担心过程非常简单几乎是一键式的。2.1 基础环境检查确保你的环境有Python 3.7或以上版本并且安装了pip包管理工具。打开终端输入以下命令检查python3 --version pip --version如果显示出版本号说明环境没问题。2.2 一键启动模型服务根据你提供的材料模型已经预置在/root/nlp_structbert_siamese-uninlu_chinese-base/路径下了。我们进入这个目录并启动服务# 1. 进入模型目录 cd /root/nlp_structbert_siamese-uninlu_chinese-base/ # 2. 直接运行服务最简单的方式 python3 app.py运行后你会看到类似下面的输出说明服务启动成功* Serving Flask app app * Debug mode: off * Running on http://0.0.0.0:7860服务现在已经在本地7860端口运行起来了。2.3 其他启动方式按需选择如果你希望服务在后台运行或者用Docker管理这里也有对应的方法方式一后台运行推荐用于长期服务nohup python3 app.py server.log 21 这样服务就在后台运行了日志会保存在server.log文件里。你可以用tail -f server.log查看实时日志。方式二Docker方式适合容器化部署# 构建Docker镜像 docker build -t siamese-uninlu . # 运行容器 docker run -d -p 7860:7860 --name uninlu siamese-uninlu2.4 验证服务是否正常打开你的浏览器访问http://localhost:7860。如果能看到一个简单的Web界面或者通过下面的API测试能返回结果就说明一切就绪。让我们用Python快速测试一下import requests import json # 服务地址 url http://localhost:7860/api/predict # 准备测试数据 - 一个简单的实体识别任务 test_data { text: 苹果公司首席执行官蒂姆·库克宣布了新产品。, schema: {人物: null, 组织: null} } # 发送请求 response requests.post(url, jsontest_data) # 打印结果 print(状态码:, response.status_code) print(返回结果:, json.dumps(response.json(), ensure_asciiFalse, indent2))如果返回的结果中能正确识别出“蒂姆·库克”是人物“苹果公司”是组织那么恭喜你模型服务已经正常运行了3. 核心概念理解Schema与任务定义在开始我们的电影信息提取项目之前你需要先理解SiameseUniNLU的核心——Schema。你可以把Schema理解为给模型的“任务清单”或“提取模板”。3.1 Schema是什么为什么重要想象一下你要让一个助手从报告里帮你找信息。如果你只是说“帮我找点信息”他可能不知道你要什么。但如果你说“请找出所有的人物名字和公司名称”他就知道该怎么做了。Schema就是这个“清晰的指令”。它用JSON格式明确告诉模型你要提取哪些类型的实体比如“人物”、“地点”这些实体之间有什么关系比如“人物”的“工作单位”是什么3.2 Schema的基本格式SiameseUniNLU的Schema格式非常灵活主要分为两种类型类型一简单实体识别平级结构{实体类型1: null, 实体类型2: null, 实体类型3: null}这种格式用于提取独立的实体。比如{人物: null, 地点: null}就是告诉模型“从文本里找出所有的人物和地点。”类型二关系抽取嵌套结构{主体实体: {关系1: null, 关系2: null}}这种格式用于提取实体之间的关系。比如{人物: {出生于: null, 工作于: null}}的意思是“找出所有人物然后针对每个人物找出他的出生地和工作单位。”3.3 不同任务的Schema示例为了让你更清楚我整理了几个常见任务的Schema写法任务类型你要做什么Schema示例说明命名实体识别从文本中找出特定类型的词{人物: null, 地点: null, 时间: null}找出文本中所有的人物、地点、时间关系抽取找出实体之间的关系{人物: {就职于: null, 出生于: null}}找出每个人物在哪工作、出生在哪里情感分类判断文本的情感倾向{情感分类: null}需要配合特定输入格式文本分类把文本分到预定义的类别{分类: null}需要配合特定输入格式阅读理解根据文本回答问题{问题: null}直接输入文本即可3.4 设计电影信息Schema的思路回到我们的电影信息提取项目。我们需要从文本中提取五类信息电影名称比如“《满江红》”导演比如“张艺谋”主演比如“沈腾、易烊千玺”票房比如“45亿”评分比如“豆瓣8.0”、“猫眼9.6”这五类信息在文本中通常是并列存在的没有复杂的嵌套关系。所以我们应该使用简单实体识别的平级Schema结构。我们的Schema初步设计如下{电影: null, 导演: null, 主演: null, 票房: null, 评分: null}这个Schema告诉模型“请从文本中找出电影名、导演、主演、票房和评分信息。”在下一节我们将用这个Schema开始实际的提取工作。4. 实战演练构建电影信息提取模板现在我们来真正动手用SiameseUniNLU提取电影信息。我会带你走完从简单到复杂的完整流程。4.1 第一次尝试基础实体提取我们先从一个简单的例子开始看看模型的基础表现。import requests import json def extract_movie_info(text): 提取电影信息的函数 url http://localhost:7860/api/predict # 我们的电影信息Schema schema {电影: null, 导演: null, 主演: null, 票房: null, 评分: null} data { text: text, schema: schema } response requests.post(url, jsondata) return response.json() # 测试文本1简单清晰的例子 test_text_1 电影《流浪地球2》由郭帆导演吴京和刘德华主演票房突破40亿元。 result_1 extract_movie_info(test_text_1) print(测试1 - 简单文本:) print(json.dumps(result_1, ensure_asciiFalse, indent2))运行这段代码你可能会得到类似这样的结果{ 电影: [《流浪地球2》], 导演: [郭帆], 主演: [吴京, 刘德华], 票房: [40亿元], 评分: [] }看模型成功提取了电影名、导演、主演和票房不过评分是空的因为我们的测试文本里没有评分信息。4.2 处理复杂情况多部电影与模糊信息现实中的文本往往更复杂。比如一篇报道可能涉及多部电影或者信息表达比较模糊。让我们试试更复杂的文本# 测试文本2包含多部电影和更丰富的信息 test_text_2 在2023年春节档中张艺谋执导的《满江红》表现抢眼沈腾、易烊千玺的表演备受好评。 该片累计票房超过45亿豆瓣评分8.0猫眼评分9.6。 同期上映的《流浪地球2》由郭帆导演吴京、刘德华主演票房也突破了40亿豆瓣评分8.3。 result_2 extract_movie_info(test_text_2) print(\n测试2 - 复杂文本多部电影:) print(json.dumps(result_2, ensure_asciiFalse, indent2))这次的结果可能会把所有信息混在一起{ 电影: [《满江红》, 《流浪地球2》], 导演: [张艺谋, 郭帆], 主演: [沈腾, 易烊千玺, 吴京, 刘德华], 票房: [45亿, 40亿], 评分: [豆瓣评分8.0, 猫眼评分9.6, 豆瓣评分8.3] }模型提取出了所有信息但有一个问题我们不知道哪个导演对应哪部电影哪个评分属于哪部电影。所有的信息都是扁平化的列表。4.3 优化Schema建立实体关系为了解决信息对应的问题我们需要升级Schema。与其让模型提取5类独立的实体不如让它理解“电影”是一个主体其他信息都是这个主体的属性。我们可以使用关系抽取的嵌套Schema结构def extract_movie_info_with_relation(text): 使用关系抽取Schema提取电影信息 url http://localhost:7860/api/predict # 升级版Schema以电影为主体其他信息作为电影的关系 schema {电影: {导演: null, 主演: null, 票房: null, 评分: null}} data { text: text, schema: schema } response requests.post(url, jsondata) return response.json() # 用同样的复杂文本测试 result_3 extract_movie_info_with_relation(test_text_2) print(\n测试3 - 使用关系抽取Schema:) print(json.dumps(result_3, ensure_asciiFalse, indent2))这次的结果结构就清晰多了{ 电影: { 《满江红》: { 导演: [张艺谋], 主演: [沈腾, 易烊千玺], 票房: [45亿], 评分: [豆瓣评分8.0, 猫眼评分9.6] }, 《流浪地球2》: { 导演: [郭帆], 主演: [吴京, 刘德华], 票房: [40亿], 评分: [豆瓣评分8.3] } } }完美现在每部电影的信息都被正确地分组了。导演、主演、票房、评分都正确地归属到了各自的电影下面。4.4 处理边界情况与数据清洗在实际应用中我们还会遇到各种边界情况。比如文本中可能包含无关信息或者同一信息有多种表达方式。我们可以添加一些后处理逻辑def clean_and_extract_movie_info(text): 提取并清洗电影信息 返回结构化的电影数据列表 # 使用关系抽取Schema raw_result extract_movie_info_with_relation(text) movies [] # 检查是否有电影信息 if 电影 in raw_result: for movie_name, movie_info in raw_result[电影].items(): # 清洗电影名称去掉可能的多余符号 clean_name movie_name.strip(《》\) # 构建电影对象 movie { name: clean_name, director: movie_info.get(导演, []), actors: movie_info.get(主演, []), box_office: movie_info.get(票房, []), ratings: movie_info.get(评分, []) } # 进一步清洗评分信息 cleaned_ratings [] for rating in movie[ratings]: # 提取评分数字 import re numbers re.findall(r\d\.?\d*, rating) if numbers: # 判断评分平台 if 豆瓣 in rating: cleaned_ratings.append({platform: 豆瓣, score: float(numbers[0])}) elif 猫眼 in rating: cleaned_ratings.append({platform: 猫眼, score: float(numbers[0])}) elif 淘票票 in rating: cleaned_ratings.append({platform: 淘票票, score: float(numbers[0])}) movie[ratings] cleaned_ratings # 清洗票房信息提取数字 if movie[box_office]: box_office_str movie[box_office][0] # 尝试提取数字和单位 import re match re.search(r(\d\.?\d*)\s*([亿万元]), box_office_str) if match: value, unit match.groups() value float(value) # 统一转换为亿元 if 万 in unit: value value / 10000 elif 元 in unit and 亿 not in unit: value value / 100000000 movie[box_office_yuan] value movies.append(movie) return movies # 测试清洗功能 test_text_3 《热辣滚烫》是贾玲导演的第二部作品主演包括贾玲、雷佳音等票房已达34.6亿豆瓣评分7.8分。 cleaned_result clean_and_extract_movie_info(test_text_3) print(\n测试4 - 清洗后的结构化数据:) print(json.dumps(cleaned_result, ensure_asciiFalse, indent2))清洗后的输出更加规整[ { name: 热辣滚烫, director: [贾玲], actors: [贾玲, 雷佳音], box_office: [34.6亿], ratings: [ { platform: 豆瓣, score: 7.8 } ], box_office_yuan: 34.6 } ]5. 进阶技巧优化提取效果与批量处理经过前面的实践我们已经有了一个可用的电影信息提取器。现在让我们看看如何让它更强大、更实用。5.1 优化Schema设计处理模糊表述有时候文本中的表述并不规范。比如“执导”、“导演”可能混用“主演”、“领衔主演”、“参演”可能都指演员。我们可以通过优化Schema来提高识别率。def create_robust_movie_schema(): 创建更健壮的电影信息Schema 考虑同义词和多种表达方式 # 基础Schema base_schema { 电影: { 导演: None, 主演: None, 票房: None, 评分: None } } # 在实际使用中我们可以通过多次测试来调整Schema # 如果发现某些表述识别不好可以尝试调整 return json.dumps(base_schema, ensure_asciiFalse) # 测试不同表述的文本 test_cases [ 由陈思诚执导的《消失的她》票房突破35亿朱一龙和倪妮的表演备受好评。, 《封神第一部》导演乌尔善费翔、李雪健、黄渤等主演豆瓣评分7.9。, 动画电影《长安三万里》追光动画制作累计票房18.24亿元。 ] print(测试不同表述的识别效果:) for i, text in enumerate(test_cases, 1): result extract_movie_info_with_relation(text) print(f\n案例{i}: {text[:30]}...) print(json.dumps(result, ensure_asciiFalse, indent2))5.2 批量处理与性能优化在实际应用中我们往往需要处理大量文本。比如从新闻网站批量抓取电影报道进行分析。这时候批量处理和性能优化就很重要了。import concurrent.futures import time from typing import List, Dict def batch_extract_movie_info(texts: List[str], max_workers: int 4) - List[Dict]: 批量提取电影信息 使用多线程提高处理速度 results [] def process_single(text): try: return clean_and_extract_movie_info(text) except Exception as e: print(f处理文本时出错: {e}) return [] # 使用线程池并行处理 with concurrent.futures.ThreadPoolExecutor(max_workersmax_workers) as executor: future_to_text {executor.submit(process_single, text): text for text in texts} for future in concurrent.futures.as_completed(future_to_text): text future_to_text[future] try: result future.result() results.extend(result) except Exception as e: print(f处理文本{text[:50]}...时出错: {e}) return results # 模拟批量处理 def simulate_batch_processing(): 模拟批量处理电影报道 # 模拟一些电影报道文本 movie_reports [ 《八角笼中》是王宝强导演的作品主演包括王宝强、陈永胜等票房22亿。, 张艺谋新作《坚如磐石》于国庆档上映雷佳音、张国立、于和伟主演。, 动画电影《深海》由田晓鹏执导票房9.2亿豆瓣评分7.3。, 《志愿军雄兵出击》陈凯歌导演朱一龙、张子枫主演票房8.7亿。, 《莫斯科行动》邱礼涛导演张涵予、刘德华主演票房6.6亿。 ] print(开始批量处理...) start_time time.time() # 批量提取信息 all_movies batch_extract_movie_info(movie_reports) end_time time.time() print(f处理完成共处理{len(movie_reports)}条文本提取到{len(all_movies)}部电影信息) print(f总耗时: {end_time - start_time:.2f}秒) print(f平均每条文本耗时: {(end_time - start_time)/len(movie_reports):.2f}秒) # 汇总统计 total_box_office sum(movie.get(box_office_yuan, 0) for movie in all_movies) print(f\n票房统计:) print(f总票房: {total_box_office:.2f}亿元) print(f平均票房: {total_box_office/len(all_movies):.2f}亿元 if all_movies else 无数据) # 导演作品统计 director_stats {} for movie in all_movies: for director in movie.get(director, []): director_stats[director] director_stats.get(director, 0) 1 if director_stats: print(f\n导演作品数量统计:) for director, count in sorted(director_stats.items(), keylambda x: x[1], reverseTrue): print(f {director}: {count}部) return all_movies # 运行批量处理 batch_results simulate_batch_processing()5.3 构建电影信息数据库有了批量提取的能力我们可以构建一个简单的电影信息数据库import sqlite3 import pandas as pd from datetime import datetime class MovieDatabase: 电影信息数据库 def __init__(self, db_pathmovies.db): self.db_path db_path self.init_database() def init_database(self): 初始化数据库表 conn sqlite3.connect(self.db_path) cursor conn.cursor() # 创建电影表 cursor.execute( CREATE TABLE IF NOT EXISTS movies ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, director TEXT, release_date DATE, box_office REAL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ) # 创建演员表 cursor.execute( CREATE TABLE IF NOT EXISTS actors ( id INTEGER PRIMARY KEY AUTOINCREMENT, movie_id INTEGER, actor_name TEXT, FOREIGN KEY (movie_id) REFERENCES movies (id) ) ) # 创建评分表 cursor.execute( CREATE TABLE IF NOT EXISTS ratings ( id INTEGER PRIMARY KEY AUTOINCREMENT, movie_id INTEGER, platform TEXT, score REAL, FOREIGN KEY (movie_id) REFERENCES movies (id) ) ) conn.commit() conn.close() def add_movie(self, movie_data): 添加电影到数据库 conn sqlite3.connect(self.db_path) cursor conn.cursor() # 插入电影基本信息 cursor.execute( INSERT INTO movies (name, director, box_office) VALUES (?, ?, ?) , ( movie_data[name], , .join(movie_data.get(director, [])), movie_data.get(box_office_yuan, 0) )) movie_id cursor.lastrowid # 插入演员信息 for actor in movie_data.get(actors, []): cursor.execute( INSERT INTO actors (movie_id, actor_name) VALUES (?, ?) , (movie_id, actor)) # 插入评分信息 for rating in movie_data.get(ratings, []): cursor.execute( INSERT INTO ratings (movie_id, platform, score) VALUES (?, ?, ?) , (movie_id, rating[platform], rating[score])) conn.commit() conn.close() return movie_id def query_movies(self, min_box_office0): 查询电影信息 conn sqlite3.connect(self.db_path) query SELECT m.name, m.director, m.box_office, GROUP_CONCAT(DISTINCT a.actor_name) as actors, GROUP_CONCAT(DISTINCT r.platform || : || r.score) as ratings FROM movies m LEFT JOIN actors a ON m.id a.movie_id LEFT JOIN ratings r ON m.id r.movie_id WHERE m.box_office ? GROUP BY m.id ORDER BY m.box_office DESC df pd.read_sql_query(query, conn, params(min_box_office,)) conn.close() return df # 使用示例 def build_movie_database(): 构建电影数据库示例 db MovieDatabase() # 添加一些电影数据 sample_movies [ { name: 满江红, director: [张艺谋], actors: [沈腾, 易烊千玺], box_office: [45亿], ratings: [ {platform: 豆瓣, score: 8.0}, {platform: 猫眼, score: 9.6} ], box_office_yuan: 45.0 }, { name: 流浪地球2, director: [郭帆], actors: [吴京, 刘德华], box_office: [40亿], ratings: [ {platform: 豆瓣, score: 8.3} ], box_office_yuan: 40.0 } ] for movie in sample_movies: db.add_movie(movie) # 查询数据 print(电影数据库查询结果:) df db.query_movies(min_box_office30) print(df.to_string(indexFalse)) # 运行数据库示例 build_movie_database()6. 总结从信息提取到知识构建通过这篇教程我们完成了一个完整的电影信息结构化提取项目。让我们回顾一下关键步骤和收获6.1 核心收获回顾理解了SiameseUniNLU的核心机制我们学会了如何通过设计不同的Schema让同一个模型适应不同的信息提取任务。从简单的实体识别到复杂的关系抽取只需要改变Schema的定义。掌握了电影信息提取的完整流程从简单的平级Schema开始快速验证想法升级到嵌套Schema解决信息归属问题添加数据清洗逻辑处理现实中的不规范表述实现批量处理满足实际应用需求构建了实用的数据处理管道我们不仅完成了信息提取还进一步实现了数据清洗、批量处理和数据库存储形成了一个完整的数据处理流程。6.2 实际应用建议基于我们的实践这里有一些实用的建议对于Schema设计从简单开始先用平级Schema快速验证根据实际文本调整实体类型名称使其更符合文本中的表述对于有关联的信息使用嵌套Schema建立关系对于数据处理一定要添加数据清洗步骤处理提取结果中的噪声对于批量处理考虑使用多线程或异步提高效率设计合理的数据存储结构方便后续分析和使用对于模型调优如果遇到提取不准的情况可以尝试调整Schema的表述对于重要任务可以设计多个Schema进行投票或融合定期用新数据测试确保模型适应语言的变化6.3 扩展思考与应用场景我们构建的电影信息提取器只是一个起点。同样的思路可以应用到很多其他领域新闻事件提取从新闻报道中提取时间、地点、人物、事件等要素产品信息提取从电商描述中提取产品参数、价格、特性等信息学术文献分析从论文中提取作者、机构、关键词、研究方法等信息医疗报告解析从医疗记录中提取症状、诊断、治疗方案等信息SiameseUniNLU的通用性让它成为了一个强大的信息提取工具箱。你只需要设计合适的Schema就能快速构建针对特定领域的信息提取系统。6.4 下一步学习方向如果你对这个项目感兴趣想要进一步深入尝试更复杂的Schema设计比如多层嵌套的关系或者条件触发的关系抽取集成其他NLP工具结合分词、词性标注等工具提升预处理效果构建Web应用用Flask或FastAPI将整个流程包装成Web服务探索模型微调如果领域特异性很强可以考虑用领域数据微调模型信息提取是NLP中最实用、最有价值的任务之一。掌握了SiameseUniNLU这个工具你就拥有了从海量文本中挖掘结构化信息的能力。希望这篇教程能帮助你开启自己的信息提取项目获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。