NLP(十四)自制序列标注平台

背景介绍

??在平时的NLP任务中,我们经常用到命名实体识别(NER),常用的识别实体类型为人名、地名、组织机构名,但是我们往往也会有识别其它实体的需求,比如时间、品牌名等。在利用算法做实体识别的时候,我们一般采用序列标注算法,这就对标注的文本格式有一定的要求,因此,一个好的序列标注的平台必不可少,将会大大减少我们标注的工作量,有效提升算法的更新迭代速度。
??本文将介绍笔者的一个工作:自制的序列标注平台。我们以时间识别为例。比如,在下面的文章中:

按计划,2019年8月10日,荣耀智慧屏将在华为开发者大会上正式亮相,在8月6日,荣耀官微表示该产品的预约量已破十万台,8月7日下午,荣耀总裁赵明又在微博上造势率先打出差异化牌,智慧屏没有开关机广告,并表态以后也不会有,消费者体验至上,营销一波接一波,可谓来势汹汹。

我们需要从该文章中标注出三个时间:2019年8月10日8月6日8月7日下午,并形成标注序列。
??下面将详细介绍笔者的工作。

序列标注平台

??由于开发时间仓促以及笔者能力有限,因此,序列标注平台的功能还没有很完善,希望笔者的工作能抛砖引玉。
??项目的结构图如下:

templates中存放静态资源,time_index.html为平台的操作界面,time_output为平台标注完实体后的文件保存路径,time_server.py是用tornado写的服务端路径控制代码,utils.py中是获取某个路径下的txt文件的最大数值的函数。

??其中,utils.py的完整代码如下:

# -*- coding: utf-8 -*-
# time: 2019-03-14
# place: Xinbeiqiao, Beijing

import os

# 获取当前所在目录的txt文本的最大数值
def get_max_num(path):
    files = os.listdir(path)
    if files:
        numbers = list(map(lambda x: int(x.replace('.txt', '')), files))
        return max(numbers)
    else:
        return 0

??time_server.py的完整代码如下:

# -*- coding: utf-8 -*-
# time: 2019-08-08
# place: Xinbeiqiao, Beijing

import os.path
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
from utils import get_max_num

#定义端口为9005
define("port", default=9005, help="run on the given port", type=int)

# GET请求
class QueryHandler(tornado.web.RequestHandler):
    # get函数
    def get(self):
        self.render('time_index.html', data = ['', []])

# POST请求
class PostHandler(tornado.web.RequestHandler):
    # post函数
    def post(self):

        # 获取前端参数, event, time, index
        event = self.get_argument('event')
        times = self.get_arguments('time')
        indices = self.get_arguments('index')
        print(event)
        print(times)
        print(indices)

        # 前端显示序列标注信息
        tags = ['O'] * len(event)

        for time, index in zip(times, indices):
            index = int(index)
            tags[index] = 'B-TIME'
            for i in range(1, len(time)):
                tags[index+i] = 'I-TIME'

        data = [event, tags]

        self.render('time_index.html', data=data)

        # 保存为txt文件
        dir_path = './time_output'
        with open('./%s/%s.txt' % (dir_path, get_max_num(dir_path)+1), 'w', encoding='utf-8') as f:
            for char, tag in zip(event, tags):
                f.write(char+'\t'+tag+'\n')

# 主函数
def main():
    # 开启tornado服务
    tornado.options.parse_command_line()
    # 定义app
    app = tornado.web.Application(
            handlers=[(r'/query', QueryHandler),
                      (r'/result', PostHandler)
                      ], #网页路径控制
            template_path=os.path.join(os.path.dirname(__file__), "templates") # 模板路径
          )
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

main()

??time_index.html文件如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>时间抽取标注平台</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">

    <style>
        mark {
            background-color:#00ff90; font-weight:bold;
        }
        p{text-indent:2em;}
    </style>

</head>
<body>

<center>
    <br><br><br>
<form class="form-horizontal" role="form" method="post" action="/result" style="width:600px">
    <div class="form-group">
        <label for="event" class="col-sm-2 control-label">输入语料</label>
        <div class="col-sm-10">
            <textarea type="text" class="form-control" id="event" style="width:490px; height:200px" name="event"></textarea>
        </div>
    </div>
    <div class="form-inline" style="text-align:left;">
        <label for="time_0" class="col-sm-2 control-label">时间</label>
        <div class="col-sm-10" id="time_column">
            <input type="text" class="form-control" id="time_0" style="width:306px;" name="time" />
            &emsp;&emsp;&emsp;
            <select class="form-control" id="index_0" name="index" style="width:120px;" ondblclick="select_click(0)"></select>
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <br>
            <button type="button" class="btn btn-default" id="add_time">添加时间</button>
            <button type="submit" class="btn btn-success">显示标签</button>
            <a href="/query"><button type="button" class="btn btn-danger">返回</button></a>
            <button type="reset" class="btn btn-warning">重置</button>
        </div>
    </div>

</form>
    <br>
    <div style="width:600px">
        <p> 原文:{{data[0]}} </p>
        <table class="table table-striped">
        {% for char, tag in zip(data[0], data[1]) %}
            <tr>
                <td>{{char}} </td>
                <td>{{tag}} </td>
            </tr>
        {%end%}
        </table>
    </div>
</center>

</body>
</html>

平台使用

??运行上述time_server.py后,在浏览器端输入网址: http://localhost:9005/query , 则会显示如下界面:

??在输入语料框中,我们输入语料:

8月8日是“全民健身日”,推出重磅微视频《我们要赢的,是自己》。

在时间这个输入框中,可以标注语料中的时间,同时双击同一行中的下拉列表,就能显示该标注时间在语料中的起始位置,有时候同样的标注时间会在语料中出现多次,那么我们在下拉列表中选择我们需要的标注的起始位置即可。
??点击添加时间按钮,它会增加一行标注,允许我们在同一份预料中标注多个时间。我们的一个简单的标注例子如下:

??点击显示标注,则会显示我们标注完后形成的序列标注信息,同时将该序列信息保存为txt文件,该txt文件位于time_output目录下。在网页上的序列标注信息如下:

同时,我们也可以查看保存的txt文档信息,如下:

??点击返回按钮,它会允许我们进行下一次的标注。刚才展示的只是一个简单例子,稍微复杂的标注如下图:

它形成的标注序列(部分)如下:

按   O
计   O
划   O
,   O
2   B-TIME
0   I-TIME
1   I-TIME
9   I-TIME
年   I-TIME
8   I-TIME
月   I-TIME
1   I-TIME
0   I-TIME
日   I-TIME
,   O
荣   O
耀   O
智   O
慧   O
屏   O
将   O
在   O
华   O
为   O
开   O
发   O
者   O
大   O
会   O
上   O
正   O
式   O
亮   O
相   O
,   O
在   O
8   B-TIME
月   I-TIME
6   I-TIME
日   I-TIME
,   O
荣   O
耀   O
官   O
微   O
表   O
示   O
该   O
产   O
品   O
......

总结

??本平台仅作为序列标注算法的前期标注工具使用,并不涉及具体的算法。另外,后续该平台也会陆续开放出来,如果大家有好的建议,也可以留言~
??本项目已上传只Github, 网址为: https://github.com/percent4/entity_tagging_platform

注意:不妨了解下笔者的微信公众号: Python爬虫与算法(微信号为:easy_web_scrape), 欢迎大家关注~

原文地址:https://www.cnblogs.com/jclian91/p/11324681.html

时间: 2024-08-14 10:39:04

NLP(十四)自制序列标注平台的相关文章

六十四、Linux监控平台介绍、zabbix监控介绍、安装zabbix、忘记Admin密码如何做

一.Linux监控平台介绍 cacti.nagios.zabbix.smokeping.open-falcon等等 cacti.smokeping偏向于基础监控,成图非常漂亮 cacti.nagios.zabbix服务端监控中心,需要php环境支持,其中zabbix和cacti都需要mysql作为数据存储,nagios不用存储历史数据,注重服务或者监控项的状态,zabbix会获取服务或者监控项目的数据,会把数据记录到数据库里,从而可以成图. open-falcon为小米公司开发,开源后受到诸多大

使用RNN解决NLP中序列标注问题的通用优化思路

/* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/ author: 张俊林 序列标注问题应该说是自然语言处理中最常见的问题,而且很可能是最而没有之一.在深度学习没有广泛渗透到各个应用领域之前,传统的最常用的解决序列标注问题的方案是最大熵.CRF等模型,尤其是CRF,基本是最主流的方法.随着深度学习的不断探索和发展,很可能RNN模型会取代CRF的传统霸主地位,会成为解决序列标注问题的标配解决方案. 本文主要抽象出利用RNN解决序列标注问题的通用优化思路.这个RNN优化思路应该

转:使用RNN解决NLP中序列标注问题的通用优化思路

http://blog.csdn.net/malefactor/article/details/50725480 /* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/ author: 张俊林 序列标注问题应该说是自然语言处理中最常见的问题,而且很可能是最而没有之一.在深度学习没有广泛渗透到各个应用领域之前,传统的最常用的解决序列标注问题的方案是最大熵.CRF等模型,尤其是CRF,基本是最主流的方法.随着深度学习的不断探索和发展,很可能RNN模型会取代CRF的传统霸主地位,会成

Senparc.Weixin.MP SDK 微信公众平台开发教程(十四):请求消息去重

原文:Senparc.Weixin.MP SDK 微信公众平台开发教程(十四):请求消息去重 为了确保信息请求消息的到达率,微信服务器在没有及时收到响应消息(ResponseMessage)的情况下,会多次发送同一条请求消息(RequestMessage),包括MsgId等在内的所有文本内容都是一致的. 这种机制确保了在诸如网络状况不佳的情况下消息的回复成功率,但是有时候由于服务器负荷.本身请求过程就需要好几秒才能完成等情况,多次重复的消息反而成了服务器的负担,甚至对业务和数据也可能造成影响.

第三十四天 我为集成平台狂(七)-步履轻盈的JQuery(五)

7月13日,晴."别院深深夏席清,石榴开遍透帘明. 树阴满地日当午,梦觉流莺时一声." 在JQuery的法则里,风格重于一切,IT牛人们从来没有把自己束缚在一张乏味的表单上,怀着对JavaScript的理解,在不断的尝试中寻求着转化的灵感. 大多购票.旅游网站上都提供了一个城市和日期输入查询的功能.用户在输入框中只需输入城市的拼音或者简称就可以弹出相关城市的名称,选择日期时则是出现一个月的日历控件,只需点选日期即可,整个操作一目了然. 本文讲解如何使用jQuery实现城市查询和日历显示

Python基础教程(第十四章 网络编程)

本文内容全部出自<Python基础教程>第二版,在此分享自己的学习之路. ______欢迎转载:http://www.cnblogs.com/Marlowes/p/5538341.html______ Created on Marlowes 本章将会给读者展示一些例子,这些例子会使用多种Python的方法编写一个将网络(比如因特网)作为重要组成部分的程序.Python是一个很强大的网络编程工具,这么说有很多原因,首先,Python内有很多针对常见网络协议的库,在库顶部可以获得抽象层,这样就可以

【转】花开正当时,十四款120/128GB SSD横向评测

原文地址:http://www.expreview.com/19604-all.html SSD横评是最具消费指导意义的评测文章,也是各类热门SSD固态硬盘的决斗疆场.SSD评测在行业内已经有不少网站做过,超能网也从今年开始专注SSD固态硬盘重点产品的评测.随着40nm和25nm新制程的NAND颗粒的 量产,SSD固态硬盘在今年迎来了价格大幅度下降,特别是国内120GB和128GB的SSD固态硬盘价格已经达到非常合理的区间,因此需要阅读SSD评测特别是SSD横评来指导消费的用户,也在呈现爆发式增

第十四章——循环神经网络(Recurrent Neural Networks)(第二部分)

本章共两部分,这是第二部分: 第十四章--循环神经网络(Recurrent Neural Networks)(第一部分) 第十四章--循环神经网络(Recurrent Neural Networks)(第二部分) 14.4 深度RNN 堆叠多层cell是很常见的,如图14-12所示,这就是一个深度RNN. 图14-12 深度RNN(左),随时间展开(右) 在TensorFlow中实现深度RNN,需要创建多个cell并将它们堆叠到一个MultiRNNCell中.下面的代码创建了三个完全相同的cel

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序 本篇名言:"即是我们是一支蜡烛也应该 " 蜡烛成灰泪始干 " 即使我们只是一根火柴也要在关键时刻有一次闪耀即使我们死后尸骨都腐烂了解也要变成磷火在荒野中燃烧. -- 艾青" 继续来看什么是简单选择排序. 欢迎转载,转载请标明出处: 1.  简单选择排序 设所排序序列的记录个数为n.i取1,2,-,n-1,从所有n-i+1个记录(Ri,Ri+1,-,Rn)中找出排序码最小的记录,与第i个记录交换.执行n-1趟后就完