关系抽取
找到一个人关系的demo
感觉人人之间的关系其实推广就是一般的实体之间的关系了?
unknown 0
父母 1
夫妻 2
师生 3
兄弟姐妹 4
合作 5
情侣 6
祖孙 7
好友 8
亲戚 9
同门 10
上下级 11
使用BiLSTM+Attention模型
这个模型里和之前不同的就是他似乎把位置向量计入了模型运行
也就是不仅仅计算词向量,还有位置向量,初步看是直接拼接
#coding:utf8
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(1)
class BiLSTM_ATT(nn.Module):
def __init__(self,config,embedding_pre):
super(BiLSTM_ATT,self).__init__()
self.batch = config['BATCH']
self.embedding_size = config['EMBEDDING_SIZE']
self.embedding_dim = config['EMBEDDING_DIM']
self.hidden_dim = config['HIDDEN_DIM']
self.tag_size = config['TAG_SIZE']
self.pos_size = config['POS_SIZE']
self.pos_dim = config['POS_DIM']
self.pretrained = config['pretrained']
if self.pretrained:
#self.word_embeds.weight.data.copy_(torch.from_numpy(embedding_pre))
self.word_embeds = nn.Embedding.from_pretrained(torch.FloatTensor(embedding_pre),freeze=False)
else:
self.word_embeds = nn.Embedding(self.embedding_size,self.embedding_dim)
self.pos1_embeds = nn.Embedding(self.pos_size,self.pos_dim)
self.pos2_embeds = nn.Embedding(self.pos_size,self.pos_dim)
self.relation_embeds = nn.Embedding(self.tag_size,self.hidden_dim)
self.lstm = nn.LSTM(input_size=self.embedding_dim+self.pos_dim*2,hidden_size=self.hidden_dim//2,num_layers=1, bidirectional=True)
self.hidden2tag = nn.Linear(self.hidden_dim,self.tag_size)
self.dropout_emb=nn.Dropout(p=0.5)
self.dropout_lstm=nn.Dropout(p=0.5)
self.dropout_att=nn.Dropout(p=0.5)
self.hidden = self.init_hidden()
self.att_weight = nn.Parameter(torch.randn(self.batch,1,self.hidden_dim))
self.relation_bias = nn.Parameter(torch.randn(self.batch,self.tag_size,1))
def init_hidden(self):
return torch.randn(2, self.batch, self.hidden_dim // 2)
def init_hidden_lstm(self):
return (torch.randn(2, self.batch, self.hidden_dim // 2).cuda(),
torch.randn(2, self.batch, self.hidden_dim // 2).cuda())
def attention(self,H):
M = F.tanh(H)
a = F.softmax(torch.bmm(self.att_weight,M),2)
a = torch.transpose(a,1,2)
return torch.bmm(H,a)
def forward(self,sentence,pos1,pos2):
self.hidden = self.init_hidden_lstm()
embeds = torch.cat((self.word_embeds(sentence),self.pos1_embeds(pos1),self.pos2_embeds(pos2)),2)
embeds = torch.transpose(embeds,0,1)
lstm_out, self.hidden = self.lstm(embeds, self.hidden)
lstm_out = torch.transpose(lstm_out,0,1)
lstm_out = torch.transpose(lstm_out,1,2)
lstm_out = self.dropout_lstm(lstm_out)
att_out = F.tanh(self.attention(lstm_out))
#att_out = self.dropout_att(att_out)
relation = torch.tensor([i for i in range(self.tag_size)],dtype = torch.long).repeat(self.batch, 1).cuda()
relation = self.relation_embeds(relation)
res = torch.add(torch.bmm(relation,att_out),self.relation_bias)
res = F.softmax(res,1)
return res.view(self.batch,-1)
结果
并没有复现出原文的结果
下面的是没有使用他提供的预训练词向量
加上了预训练词向量后
踩坑
问题1
RuntimeError: DataLoader worker (pid(s) 7836, 11392) exited unexpectedly
在Window里试图使用多线程加载导致
解决办法:num_workers=2, # subprocesses for loading data
注释子进程即可# num_workers=2
问题2
codecs不可用
可能是python3里没有这个?安装不成功。
原先的是codecs.open,直接替换为open即可(参数遵循open的规则)
问题3
RuntimeError: Expected object of backend CUDA but got backend CPU for argument .。。。
这个问题是部分的数据没有完全拷贝上cuda导致的
这里一直卡住是因为有一部分的数据是在forward的时候才创建的并参与计算
我猜想model.cuda的拷贝只是把init的时候创建的数据拷贝
所以在所有能加上cuda的地方全部加上即可
问题4
AttributeError: ‘dict’ object has no attribute ‘has_key’
对于这个只要换成 word in dict即可
下一步
- 看看有没有更好的demo可用
- 重新阅读一下之前ner的框架,完全看懂怎么用bert做提取文本的特征的工作
数据
Kaggle数据
https://www.kaggle.com/freeappfans/entityrelationextraction?
模型
https://zhpmatrix.github.io/2019/06/30/neural-relation-extraction/
前面的好理解,最后一层的Sigmiod到HeadRelation并没有看懂。。。
那么,看了上述三篇文章需要预先给定entity,实际上我们更希望直接从句子中抽取关系而非预先给定entity,同时也是个人更加喜欢的一个思路。这里的一个代表是《Joint entity recognition and relation extraction as a multi-head selection problem》,看下图: