前言:
deepdive是基于python2的,如果写脚本时使用python3,就会出现一系列问题,例如最开始可能遇到的报错就是:即找不到dd文件等等
22:38:04 [Helpers$(akka://deepdive)] INFO Traceback (most recent call last):
22:38:04 [Helpers$(akka://deepdive)] INFO File "/opt/elementary-memex-ddlog/escort-review/udf/extract_test.py", line 12, in <module>
22:38:04 [Helpers$(akka://deepdive)] INFO import ddlib
22:38:04 [Helpers$(akka://deepdive)] INFO File "/home/eve/local/lib/python/ddlib/__init__.py", line 1, in <module>
22:38:04 [Helpers$(akka://deepdive)] INFO from dd import *
22:38:04 [Helpers$(akka://deepdive)] INFO ImportError: No module named 'dd'
本篇目的就是修改相关源码,使我们可以使用python3
最后会具体给出两个实践,第一个还是官方的基本demo,第二个是综合了多种关系抽取,且加了性能评价部分
关于deepdive更多使用细节:中文翻译版
https://github.com/theDoctor2013/DeepDive-tutorial/blob/master/Deepdive_new.md
本篇两个实践代码:
建议从如下第一篇博客看起,如果比较熟悉可以直接跳到实践二部分
Deepdive关系抽取:特征源码分析及优化加快信息提取_爱吃火锅的博客-CSDN博客_deepdive关系抽取
调试:
:在进行修改源码时,首先要知道哪里错了,即调试,可以使用如下两种方法:
一 deepdive 自带的调试API:
deepdive env python udf/my.py
对应到py3便是:
deepdive env python3 udf/my.py
二:print大法
除了上述方法外,我们知道在python 中经常可以使用print大法来看某些输出进而可以定位错误,但是DeepDive的UDF的所有标准输出都被转换为TSJ
或者TSV
格式并存到数据库里,所以像Python中的print
这样的语句是不可以作为屏幕信息输出的,这样会破坏我们的数据。所以正确的用法是把屏幕信息使用标准错误流standard error
中进行输出(其他语言一样):
#!/usr/bin/env python
from deepdive import *
import sys
@tsj_extractor
@returns( ... )
def extract( ... ):
...
print >>sys.stderr, 'This prints some_object to logs :', some_object
...
当然了,上述对应的是python2的写法,在python3中是:
#!/usr/bin/env python
from deepdive import *
import sys
@tsj_extractor
@returns( ... )
def extract( ... ):
...
print('This prints some_object to logs :', some_object, file=sys.stderr)
...
修改:
涉及到的源码主要是在$HOME/local/lib/python/ddlib下的四个文件
__init__.py
dd.py
gen_feats.py
util.py
一个一个来看
__init__.py
需要将路径修改为当前路径,负责会找不到相关py文件:
gen_feats.py
首先也是要改一下为当前路径
还有就是修改一下运行环境
util.py
这里需要改成对应的list,不然python3中zip 是没有len()的,后续代码中会用到len()
还有就是这里改为字符串标示
其次就是一些print需要加括号,对应的改一下就好啦
上面就是主要的修改成分,其他的一些都修改都很简单这里就不说啦,笔者这里已经修改好,直接复制这4个文件覆盖掉源码中的四个文件即可.
这样我们就可以使用python3脚本了,即udf下的脚本都可以换成python3,如果还是想在python3下用原demo中的部分脚本,一个是要将脚本开头指定为python3环境,另一个是要注意原demo中有几个脚本需要改下
比如原demo中给的trasform.py中要将print加括号等等。
map_company_mention.py中
xrange替换为range,因为python3中是没有xrange的,且在python3中unicode这种写法是不对的,直接改为str即可
实践一:
由于使用使用deepdive 原始的斯坦福的nlp包进行文本信息提取时间过长,故换用ltp处理,本例子还是实现交易记录的预测,只不过nlp处理部分替换了
即主要写了一个nlp_markup.py替换原来的nlp_markup.sh,注意这里为了演示统一将udf下的所有python脚本指定为了python3环境
首先为了使用ltp要将app.ddlog中要调用nlp_markup.sh换为调用nlp_markup.py脚本
运行流程的命令没有变:
即先是导入文章
deepdive compile && deepdive do articles
提取文本信息,基本需要几秒就可以结束该过程,而之前需要数小时
deepdive compile && deepdive do sentences
看一下结果
生成候选实体
deepdive compile && deepdive do company_mention
生成候选实体对
deepdive compile && deepdive do transaction_candidate
提取特征
deepdive compile && deepdive do transaction_feature
打标
deepdive do transaction_label_resolved
变量表定义:
deepdive compile && deepdive do has_transaction
预测:
deepdive compile && deepdive do probabilities
看一下结果:
deepdive sql "SELECT p1_id, p2_id, expectation FROM has_transaction_label_inference
ORDER BY expectation desc"
实践二:
该部分实现担保和股权质押两种关系抽取,
如果临时是想多加一种关系也按如下流程走便可,假设当前增加的关系为A,那么就是在app.ddlog中参照zhiya或danbao在如下每一部分中相应的增加A的定义即可
导入所有原始数据
原始数据:两种关系的文章以及两种关系的部分少量 label
在app.ddlog中定义了相关的存储结构:
运行导入:
deepdive compile && deepdive do zhiya_articles
deepdive compile && deepdive do zhiya_record
deepdive compile && deepdive do danbao_articles
deepdive compile && deepdive do danbao_record
用pyltp模块进行文本处理
在app.ddlog中定义相关的存储结构和处理的python脚本:
运行
deepdive compile && deepdive do zhiya_sentences
deepdive compile && deepdive do danbao_sentences
实体抽取
抽取公司
在app.ddlog中定义相关的存储结构和处理的python脚本:
运行:
deepdive compile && deepdive do zhiya_company_mention
deepdive compile && deepdive do danbao_company_mention
生成候选实体对
将每一句话中出现的所有公司名两两组合生成候选实体对
在app.ddlog中定义相关的存储结构和处理的python脚本:
运行
deepdive compile && deepdive do zhiya_candidate
deepdive compile && deepdive do danbao_candidate
特征提取
提取候选实体对的一些窗口特征
在app.ddlog中定义相关的存储结构和处理的python脚本:
运行:
deepdive compile && deepdive do zhiya_feature
deepdive compile && deepdive do danbao_feature
打标以及划分训练集和测试集
首先定义label的存储结构:
初始化标签权重(所有候选实体对权重是0),然后导入label(将相关候选实体对的权重赋值为3)
调用相应的脚本(人为定义的一些规则)进行预打标:
对多种权重进行加和:
通过调用generate_train_test_flag.py脚本随机生成训练集和测试集的flag(1~10内的一个数字)
运行
deepdive compile && deepdive do zhiya_label_test_train
deepdive compile && deepdive do danbao_label_test_train
----------------------------以下是模型构建部分-----------------------------------------
变量表定义
首先定义存储结构和生成正负样本规则(很简单看权重是正数还是负数)
这里需要注意的是,划分了训练集和测试集,如下是划分出来20%作为了测试集,假如需要划分40%,那么对应位置改为4,以此类推。
运行:
deepdive compile && deepdive do has_zhiya
deepdive compile && deepdive do has_danbao
因子图构建
这里定义了一条依赖关系,即如果A将股权质押过给B,那么一般来说认为B不会质押给A
运行形成两种关系的概率模型:
deepdive compile && deepdive do probabilities
----------------------------以下是性能评价部分-----------------------------------------
运行Performance_evaluation.py脚本生成相关的性能评价结果
python3 Performance_evaluation.py transaction zhiya danbao 2
API 参数说明
python3 Performance_evaluation.py database relation_1 relation_2 test_size
database:数据库名称,如上述例子是transaction
relation : 是要看的哪些关系的结果,上述例子是查看了所有关系即zhiya,danbao
test_size:测试集大小,记得和打标部分设置的测试集大小保持一致
运行完上述结果后,会在当前路径下生产一个Performance_evaluation文件夹,里面包括如下:
一:每一种关系的性能图
二:所有结果的csv文件
上述例子结果:
另外deepdive 自带了评价性能的API即运行
deepdive do model/calibration-plots
其在下面的位置生成了tsv
文件,相关图片保存在run/model/calibration-plots/
目录中,具体含义为:
上述图片来源于开头给的中文翻译版链接
----------------------------以下是结束语----------------------------------------
到这里就结束了,最后再总体归纳以下:
一:抽取一种新的实体关系时,需要做的改动就是app.ddlog,在其中定义相应的存储结构和处理流程(主要就是调用脚本如python),其他的不用变,如果有特殊需求,需要做的就是编写相应的python脚本即可,如上述的Performance_evaluation.py等等
二:deepdive的好坏,主要就是打标部分规则的定义以及因子图部分的依赖关系规则的定义,其中前者尤为主要,但是这也是目前关系抽取面临的通病,那就是数据集构建的困难,如果人工构建耗时耗力,所以deeepdive采用的是使用规则去部分打标,目前使用比较多的就是“远程监督”
三:上述多种关系的抽取其实可以看成是一种多标签分类(多个二分类模型),如果多种关系之间存在互斥比如目前待抽取的关系是母子和姐妹即不会有同时满足两种关系的样本,那么其实还可以当前一个多分类来做,deepdive中提供了多分类做法,对应到上述类子就是
has_zhiya?(p1_id text, p2_id text).
改为
tag?(word_id bigint) Categorical(13).
相当于定于就定义了tag
就是一个有13种类型的类别变量关系
四:其中打标过程需要定义规则,比较耗时耗力,这也是一大缺点,为此这里写了一个简单的脚本,用以统计一些文本信息,定义规则的时候可以参考这些统计信息,具体使用很简单(更多该方面的探索:远程监督和规则打标结合_爱吃火锅的博客-CSDN博客):
一 模型下载
过程中主要使用了pyltp包,下载其预训练好的一些模型和停用词放到一个目录如ltp_data_v3.4.0/目录下
其中stopwords.txt就是停用词,下载地址https://github.com/goto456/stopwords
二 数据准备
将要统计的两个csv表格放到当前目录,如danbao_articles.csv,danbao_record.csv
三 运行
python text_statistics.py -input_articles danbao_articles.csv -input_record danbao_record.csv
最后输出的是一个rule_reference.txt,以下是部分截图:
看到很多小伙伴私信和关注,为了不迷路,欢迎大家关注笔者的微信公众号,会定期发一些关于NLP的干活总结和实践心得,当然别的方向也会发,一起学习: