CoType模型源码测试

github原项目地址

论文:《CoType: Joint Extraction of Typed Entities and Relations with Knowledge Bases》

原本是想跑一遍cotype,但是准备好数据集以后发现项目里面的cotype是用c写的,目前的能力无法debug和后续优化模型,网上也没有找到python版的项目代码。。。无可奈何放弃了。

发在这里是希望有大神看到,能提供一下cotype的python版本实现。

1. 资源下载

1.1. 项目代码下载

git clone https://github.com/INK-USC/shifted-label-distribution.git

1.2. 数据下载

1.2.1. KBP(科学获取)

googledrive下载地址

1.2.2. NYT(科学获取)

googledrive下载地址

1.2.3. TACRED(收费)

下载地址

需要注册帐号下载,找同学要的数据

2. 环境准备

Python = 3.6.12

Pytorch = 1.7.0

jdk = 1.8.0_92

2.1. Pytorch安装

pip install http://download.pytorch.org/whl/cpu/torch-0.3.1-cp36-cp36m-linux_x86_64.whl
pip install torchvision --no-deps
# 按装torchvision时忽略依赖,不然会安装最新的torch

Pytorch其他版本参考地址

注意:

from torch.nn.utils.rnn import pad_packed_sequence, pack_padded_sequence, pack_sequence, PackedSequence
中,使用0.3.1版本的torch会报错ImportError: cannot import name 'pack_sequence

猜测本项目的实际pytorch版本为1.7.0

3. 项目模型

项目里面包含了很多模型代码,本文只针对CoType模型进行数据准备。

3.1. 基于特征

  • ReHession
  • CoType
  • Logistic Regression

3.2. 基于神经网络

  • Bi-GRU
  • Bi-LSTM
  • PCNN
  • CNN
  • PositionAware LSTM
  • Bi-GRU+ATT
  • PCNN+ATT

4. 数据预处理

4.1. TACRED

4.1.1. 生成json数据文件
python DataProcessor/gen_tacred.py

得到train_split.jsontest.jsondev.json三个文件。

4.1.2. 运行数据聚类脚本
sh ./brown_clustering.sh TACRED

本数据集处理时,./brown_clustering.sh文件中的python2 DataProcessor/dev_set_partition.py --dataset $Data --ratio 0.1可以注释掉不运行,这一步是将训练数据按照9:1分为训练集和验证集,在上一步骤中已经产生了的dev.json文件。后面是将json数据生成brown文件,将原始txt文件聚类到300个类。

虚拟机耗时:15m52.688s

4.1.3. 安装配置corenlp_server

VERSION=4.2.0

  1. 安装stanford coreNLP

下载stanford-corenlp-latest.zip

下载stanford-corenlp-4.2.0-models-english.jar

解压stanford-corenlp-latest.zip文件,并将jar文件放入解压后的文件夹(如:/home/appendDisk/Downloads/stanford-corenlp-4.2.0)中。

  1. 配置环境变量
sudo vim /etc/profile
# 添加下面内容,并保存退出
export CORENLP_HOME=/home/appendDisk/Downloads/stanford-corenlp-4.2.0

#应用新环境变量
source /etc/profile
4.1.4. 统一python脚本到python3

项目代码中混合了py2的代码,花了点儿时间转到py3。

  1. DataProcessor/feature_generation.py

将文件中python2的print XXX语法都改成print(XXX)

  1. DataProcessor/ner_feature.py

将文件中python2的print XXX语法都改成print(XXX);

将文件中的下面两句注释掉。

reload(sys)
sys.setdefaultencoding('utf8')

将文件中python2的print(e.message, e.arg) 修改为:print(e.arg)

将文件中sorted(,cpm=)换成如下形式:(共3个)

# sorted_map = sorted(mentionCountByNumOfLabels.items(),cmp=lambda x,y:x[0]-y[0])
from functools import cmp_to_key # 在开头引用
sorted_map = sorted(mentionCountByNumOfLabels.items(), key=cmp_to_key(lambda x, y: x[0] - y[0]))
  1. DataProcessor/pruning_heuristics.py

将文件中python2的print XXX语法都改成print(XXX);

将文件中的下面两句注释掉。

reload(sys)
sys.setdefaultencoding('utf8')
  1. DataProcessor/statistic.py

将文件中的下面两句注释掉。

reload(sys)
sys.setdefaultencoding('utf8')
  1. 项目代码中的xrange全部替换为range

  2. DataProcessor/mention_reader.py

替换_decode函数中的下面语句:

    @staticmethod
    def _decode(mention_json):
    ...
        # if mention_json == '':
        if mention_json == '' or mention_json == b'':
            return None
    ...
4.1.5. DataProcessor/Feature/other_features.py

修改文件代码注释

class EMTypeFeature(AbstractFeature):
    def apply(self, sentence, mention, features):
        for em in sentence.entityMentions:
            if em.start == mention.em1Start and em.end == mention.em1End:
                # features.append('EM1_TYPE_%s' % sentence.ner[em.start]) # comment this line
                features.append('EM1_TYPE_%s' % em.labels) # uncomment this line
            if em.start == mention.em2Start and em.end == mention.em2End:
                # features.append('EM2_TYPE_%s' % sentence.ner[em.start]) # comment this line
                features.append('EM2_TYPE_%s' % em.labels) # uncomment this line
4.1.6. DataProcessor/nlp_parse.py

from stanza.nlp.corenlp import CoreNLPClient修改为:from stanza.server import CoreNLPClient;

将文件中python2的print('parse error: ', e.message, e.arg) 修改为:print('parse error: ', e.args);

将NLPParser的初始化部分改为如下:

class NLPParser(object):
    """
    NLP parse, including Part-Of-Speech tagging.
    Attributes
    ==========
    parser: StanfordCoreNLP
        the Staford Core NLP parser
    """
    def __init__(self, portnum):
        self.parser = CoreNLPClient(default_annotators=['ssplit', 'tokenize', 'pos', 'ner'], memory='4G', endpoint="http://localhost:{}".format(portnum))
  • 添加CoreNLPClient参数memory;将参数server改为endpoint
  • 添加NLPParser初始化参数portnum(可以支持多线程开启多个server进行语料标注)

同步修改本文件中parse函数代码,添加参数portnum

def parse(sentences, g, lock, procNum, isTrain, nOfNones, portNum, parsePOSBeforehand=False):
    rmCount = 0
    discardRmCount = 0
    parser = NLPParser(portNum)
4.1.7. DataProcessor/feature_generation.py

修改multi_process_parse函数部分,添加参数portnum

# def multi_process_parse(fin, fout, isTrain, nOfNones):
def multi_process_parse(fin, fout, isTrain, nOfNones, portNum):
    file = open(fin, 'r')
    sentences = file.readlines()
    sentsPerProc = int(math.floor(len(sentences)*1.0/numOfProcesses))
    lock = Lock()
    processes = []
    # out_file = open(fout, 'w', 0)
    out_file = open(fout, 'w')
    for i in range(numOfProcesses):
        if i == numOfProcesses - 1:
            # p = Process(target=parse, args=(sentences[i*sentsPerProc:], out_file, lock, i, isTrain, nOfNones))
            p = Process(target=parse, args=(sentences[i*sentsPerProc:], out_file, lock, i, isTrain, nOfNones, portNum+i))

        else:
            # p = Process(target=parse, args=(sentences[i*sentsPerProc:(i+1)*sentsPerProc], out_file, lock, i, isTrain, nOfNones))
            p = Process(target=parse, args=(sentences[i*sentsPerProc:(i+1)*sentsPerProc], out_file, lock, i, isTrain, nOfNones, portNum+i))
        p.start()
        processes.append(p)
    for proc in processes:
        proc.join()
    out_file.close()

修改if __name__ == "__main__"中的multi_process_parse传参部分,添加参数portnum

    print('Start nlp parsing')
    # multi_process_parse(raw_train_json, train_json, True, numOfNones)
    multi_process_parse(raw_train_json, train_json, True, numOfNones, 9001)
    print('Train set parsing done')
    # multi_process_parse(raw_dev_json, dev_json, False, 1)
    multi_process_parse(raw_dev_json, dev_json, False, 1, 9010)
    print('Dev set parsing done')
    # multi_process_parse(raw_test_json, test_json, False, 1)
    multi_process_parse(raw_test_json, test_json, False, 1, 9020)
    print('Test set parsing done')

这里的端口号可以自选,确认不会被占用即可

4.1.8. feature_extraction.sh
#python2 -m pip install tqdm stanza ujson unidecode requests nltk --user
python -m pip install tqdm stanza ujson unidecode requests nltk --no-deps -i https://pypi.doubanio.com/simple
#python2 DataProcessor/feature_generation.py $Data 5 0 1.0 1
python DataProcessor/feature_generation.py $Data 3 0 1.0 1
  • --no-deps表示不安装依赖
  • 修改DataProcessor/feature_generation.py的第二个入参numOfProcesses为3,目前自用的虚拟机状态最多可以支持正常启动3个server,多了java会报OOM,无法分配内存等性能错误,故改为3。
4.1.9. Featuremodule的引用

运行时可能会发生引用不到Feature里面的东西,只需要在DataProcessor/Feature/__init__.py里面添加:

import sys
import os
sys.path.append(os.path.join(os.getcwd(), "DataProcessor/Feature"))
4.1.10. 运行抽取文件
sh ./feature_extraction.sh TACRED

团队服务器开5个server耗时约1.5h

运行时server也可能会突然死掉,应该和机器性能有关。如果不是所有server都死了,那就请耐心等待。

4.1.11. 生成数据文件
python DataProcessor/gen_bag_level_data.py --in_dir ./data/neural/TACRED --out_dir ./data/neural_att/TACRED

5. 训练cotype模型

5.1. 准备CPP运行环境

5.1.1. 安装GSL-2.5

下载地址

cd /home/dannie/Downloads
tar -xzvf gsl-2.5.tar.gz
su - root
cd /home/dannie/Downloads/gsl-2.5
./configure && make && make install

编译需要几分钟,成功后,默认安装在了/usr/local下。

添加到环境变量:

cd /usr/local/bin
ln /usr/local/lib/libgsl.so /usr/local/lib/libgsl.so.0
vim /etc/profile
# 最下面加入:
export LD_LIBRARY_PATH=/usr/local/lib: $LD_LIBRARY_PATH
# 退出
source /etc/profile
sudo ldconfig
5.1.2. 安装eigen库
sudo apt-get install libeigen3-dev
sudo cp -r /usr/local/include/eigen3/Eigen /usr/local/include
# 查看版本信息
head -20 /usr/include/eigen3/Eigen/src/Core/util/Macros.h

5.2. 训练TACRED

CoType/retype-rm -data TACRED -mode m -size 50 -negative 3 -threads 3 -alpha 0.0001 -samples 1 -iters 1000 -lr 0.01

到这里运行c脚本文件出错,暂时无法排查原因。
只能等以后学C或者靠大神来带带了。

太悲伤了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值