初號機暴走事件

  • 2021 年 3 月 25 日
  • AI

初號機暴走事件

2015年第三使徒登陸第三新東京市,初號機在面對第三使徒時,由於真嗣首次駕駛EVA作戰,戰況非常殘酷,初號機的頭部被第三使徒刺穿,左腕被扯斷,導致與初號機保持神經連接的真嗣失去了意識。在這樣極限的情況下,初號機開始了暴走狀態,使用再生功能修復了左腕,並且徒手撕裂了第三使徒的AT Field,虐殺了第三使徒。

EVA粉絲可以在看完文章後去B站溫習一下~

上面這段文本描述了初號機的第二次暴走事件,倘若我們想用人工智慧的技術從這段文本中抽取出「初號機暴走事件」,需要用到NLP領域的「事件抽取技術」。

接下來筆者將分別介紹事件定義、任務定義、數據標註、事件抽取模型以及模型demo。

1 事件定義

事件是指在一定時間、地點發生的涉及一個或多個參與者的具體行為,通常可以描述為一種狀態的變化[1]。有的情況下,事件的結構是預先定義好的,這類事件屬於「封閉領域」事件,比如這裡的初號機暴走事件。

  • 事件類型
    • 暴走事件
  • 事件論元
    • 暴走時間:2015年
    • 暴走地點:第三新東京市
    • 暴走原因:真嗣失去了意識
    • 暴走主角:初號機
    • 暴走後果:虐殺了第三使徒

2 事件抽取任務定義

事件抽取的目的是檢測文本中存在的事件實例,並且識別出存在的事件類型及所有的參與者和屬性。簡單的理解就是從非結構化的文本中獲取結構化表示的事件實例。

3 數據標註

事件抽取也是一種資訊抽取任務,雖然抽取的是一定結構的文本資訊,但簡單來看也只是抽取出表示事件論元的一些文本片段,以及確定某個事件類型,加上這裡僅僅涉及到單事件的抽取,不存在多個事件的論元嵌套問題,而文本片段可以看作是實體,因此可以使用簡單的命名實體識別(NER)方法來抽取出事件論元的文本片段

一段文本中存在的事件類型往往由關鍵的觸發詞隱式地表達出來,例如這段文本的「暴走狀態」,這種隱式的表達也體現在整段文本的語義表達中,因此可以結合全文的語義編碼對事件類型進行分類。總的來說,可以聯合預測文本的事件類型以及抽取出事件論元的實體

所以標註的形式基本可以確定下來,事件類型的標註看作文本分類的標註,把數據集的事件類型轉換為數字集合(0,1,2,…,k),獲得該文本的事件類型分類標籤 L ∈[0, k]。

將事件論元抽取看作NER標註,這裡對於實體類型的標註有2種方案:
  • 直接把事件論元作為實體類型,例如暴走時間、暴走地點;
  • 把事件類型和事件論元結合起來作為實體類型,例如暴走事件—暴走時間、暴走事件—暴走原因

後者能夠更好的聯合文本事件類型分類結果抽取事件實例,因此這裡選擇後者的標註方式,採用BIO標籤對文本進行序列標註(標註樣例如下)。

事件抽取模型

這裡介紹一種筆者用到的事件抽取模型。


文本輸入BERT編碼器分別獲得句向量編碼(batch, hidden_size)和序列編碼(batch, sequence_len, hidden_size)。句向量輸出用於分類器對事件類型進行分類,編碼輸出用於BIO序列標註模型抽取實體

訓練過程的誤差損失為事件類型的分類損失加上抽取事件論元的損失:

預測過程中,對抽取出的每種」事件類型—論元「實體進行平均置信度排序,篩選出每種「事件類型-論元」中置信度最高的實體,再結合文本預測的事件類型對剩餘」事件類型—論元「實體進行篩選,留下與預測的事件類型相匹配的論元實體,組合成預測的事件實例。

篩選過程如下:

模型Demo

這裡先給出簡易版模型Demo,在下一篇事件抽取文章中,將提供完整開源程式碼和數據集,歡迎持續關注!
from transformers import BertPreTrainedModel, BertModelclass BertForEventExtract(BertPreTrainedModel):    def __init__(self, config):        super(BertForEventExtract, self).__init__(config)        self.bert = BertModel(config) # 定義BERT編碼器        self.num_labels = config.num_labels #實體BIO標籤        self.event_type_outputs = nn.Linear(config.hidden_size, 5# 假設這裡一共有5種事件類型,該層用於對文本句向量進行事件類型分類        self.dropout = nn.Dropout(config.hidden_dropout_prob)        self.BIO_classifier = nn.Linear(config.hidden_size, config.num_labels) # 該層用於對每個字元進行BIO標籤分類        self.init_weights()
def forward(self, input_ids, attention_mask=None, token_type_ids=None, position_ids=None, head_mask=None, labels=None): outputs = self.bert(input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids, position_ids=position_ids, head_mask=head_mask) # 獲取BERT的輸出
        sequence_output = outputs[0#序列編碼輸出 pooled_output = outputs[1] #序列句向量輸出
        # 預測BIO實體 sequence_output = self.dropout(sequence_output) BIO_logits = self.BIO_classifier(sequence_output)
        # 預測事件類型 pooled_output = self.dropout(pooled_output) event_type_logits = self.event_type_outputs(pooled_output)
if labels is not None: BIO_labels, event_type_label = labels BIO_loss = nn.CrossEntropyLoss(ignore_index=-1)(BIO_logits.view(-1, self.num_labels), BIO_labels.view(-1)) event_type_loss = nn.CrossEntropyLoss()(event_type_logits, event_type_label.view(-1))            outputs = BIO_loss + event_type_loss else: outputs = (BIO_logits, event_type_logits)
return outputs

引用

[1]Ace (Automatic Content Extraction) English Annotation Guidelines for Events, Linguistic Data Consortium, Philadelphia, PA, USA, 2005.