1. 程式人生 > >NLP(二十六)限定領域的三元組抽取的一次嘗試

NLP(二十六)限定領域的三元組抽取的一次嘗試

  本文將會介紹筆者在2019語言與智慧技術競賽的三元組抽取比賽方面的一次嘗試。由於該比賽早已結束,筆者當時也沒有參加這個比賽,因此沒有測評成績,我們也只能拿到訓練集和驗證集。但是,這並不耽誤我們在這方面做實驗。 ### 比賽介紹   該比賽的網址為:[http://lic2019.ccf.org.cn/kg](http://lic2019.ccf.org.cn/kg) ,該比賽主要是從給定的句子中提取三元組,給定schema約束集合及句子sent,其中schema定義了關係P以及其對應的主體S和客體O的類別,例如(S_TYPE:人物,P:妻子,O_TYPE:人物)、(S_TYPE:公司,P:創始人,O_TYPE:人物)等。比如下面的例子: ``` {   "text": "九玄珠是在縱橫中文網連載的一部小說,作者是龍馬",   "spo_list": [     ["九玄珠", "連載網站", "縱橫中文網"],     ["九玄珠", "作者", "龍馬"]   ] } ``` 該比賽一共提供了20多萬標註質量很高的三元組,其中17萬訓練集,2萬驗證集和2萬測試集,實體關係(schema)50個。   在具體介紹筆者的思路和實戰前,先介紹下本次任務的處理思路: ![任務的處理思路](https://img-blog.csdnimg.cn/2020031513145448.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pjbGlhbjkx,size_16,color_FFFFFF,t_70) 首先是對拿到的資料進行資料分析,包括統計每個句子的長度及三元組數量,每種關係的數量分佈情況。接著,對資料單獨走序列標註模型和關係分析模型。最後在提取三元組的時候,用Pipeline模型,先用序列標註模型預測句子中的實體,再對實體(加上句子)走關係分類模型,預測實體的關係,最後形成有效的三元組。   接下來筆者將逐一介紹,專案結構圖如下: ![專案結構圖](https://img-blog.csdnimg.cn/20200315112107112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pjbGlhbjkx,size_16,color_FFFFFF,t_70) ### 資料分析   我們能拿到的只有訓練集和驗證集,沒有測試集。我們對訓練集做資料分析,訓練集資料檔案為train_data.json。   資料分析會統計訓練集中每個句子的長度及三元組數量,還有關係的分佈圖,程式碼如下: ```python # -*- coding: utf-8 -*- # author: Jclian91 # place: Pudong Shanghai # time: 2020-03-12 21:52 import json from pprint import pprint import pandas as pd from collections import defaultdict import matplotlib.pyplot as plt plt.figure(figsize=(18, 8), dpi=100) # 輸出圖片大小為1800*800 # Mac系統設定中文字型支援 plt.rcParams["font.family"] = 'Arial Unicode MS' # 載入資料集 def load_data(filename): D = [] with open(filename, 'r', encoding='utf-8') as f: content = f.readlines() content = [_.replace(' ', '').replace('\u3000', '').replace('\xa0', '').replace('\u2003', '') for _ in content] for l in content: l = json.loads(l) D.append({ 'text': l['text'], 'spo_list': [ (spo['subject'], spo['predicate'], spo['object']) for spo in l['spo_list'] ] }) return D filename = '../data/train_data.json' D = load_data(filename=filename) pprint(D) # 建立text, text_length, spo_num的DataFrame text_list = [_["text"] for _ in D] spo_num = [len(_["spo_list"])for _ in D] df = pd.DataFrame({"text": text_list, "spo_num": spo_num} ) df["text_length"] = df["text"].apply(lambda x: len(x)) print(df.head()) print(df.describe()) # 繪製spo_num的條形統計圖 pprint(df['spo_num'].value_counts()) label_list = list(df['spo_num'].value_counts().index) num_list = df['spo_num'].value_counts().tolist() # 利用Matplotlib模組繪製條形圖 x = range(len(num_list)) rects = plt.bar(x=x, height=num_list, width=0.6, color='blue', label="頻數") plt.ylim(0, 80000) # y軸範圍 plt.ylabel("數量") plt.xticks([index + 0.1 for index in x], label_list) plt.xlabel("三元組數量") plt.title("三元組頻數統計圖") # 條形圖的文字說明 for rect in rects: height = rect.get_height() plt.text(rect.get_x() + rect.get_width() / 2, height+1, str(height), ha="center", va="bottom") # plt.show() plt.savefig('./spo_num_bar_chart.png') plt.close() import matplotlib.pyplot as plt plt.figure(figsize=(18, 8), dpi=100) # 輸出圖片大小為1800*800 # Mac系統設定中文字型支援 plt.rcParams["font.family"] = 'Arial Unicode MS' # 關係統計圖 relation_dict = defaultdict(int) for spo_dict in D: # print(spo_dict["spo_list"]) for spo in spo_dict["spo_list"]: relation_dict[spo[1]] += 1 label_list = list(relation_dict.keys()) num_list = list(relation_dict.values()) # 利用Matplotlib模組繪製條形圖 x = range(len(num_list)) rects = plt.bar(x=x, height=num_list, width=0.6, color='blue', label="頻數") plt.ylim(0, 80000) # y軸範圍 plt.ylabel("數量") plt.xticks([index + 0.1 for index in x], label_list) plt.xticks(rotation=45) # x軸的標籤旋轉45度 plt.xlabel("三元組關係") plt.title("三元組關係頻數統計圖") # 條形圖的文字說明 for rect in rects: height = rect.get_height() plt.text(rect.get_x() + rect.get_width() / 2, height+1, str(height), ha="center", va="bottom") plt.savefig('./relation_bar_chart.png') ``` 輸出結果如下: ``` spo_num text_length count 173108.000000 173108.000000 mean 2.103993 54.057190 std 1.569331 31.498245 min 0.000000 5.000000 25% 1.000000 32.000000 50% 2.000000 45.000000 75% 2.000000 68.000000 max 25.000000 300.000000 ``` 句子的平均長度為54,最大長度為300;每句話中的三元組數量的平均值為2.1,最大值為25。   每句話中的三元組數量的分佈圖如下:![每句話中的三元組數量分佈圖](https://img-blog.csdnimg.cn/20200315112630155.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pjbGlhbjkx,size_16,color_FFFFFF,t_70)   關係數量的分佈圖如下: ![關係數量分佈圖](https://img-blog.csdnimg.cn/20200315113529945.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pjbGlhbjkx,size_16,color_FFFFFF,t_70) ### 序列標註模型   我們將句子中的主體和客體作為實體,分別標註為SUBJ和OBJ,標註體系採用BIO。一個簡單的標註例子如下: ``` 如 O 何 O 演 O 好 O 自 O 己 O 的 O 角 O 色 O , O 請 O 讀 O 《 O 演 O 員 O 自 O 我 O 修 O 養 O 》 O 《 O 喜 B-SUBJ 劇 I-SUBJ 之 I-SUBJ 王 I-SUBJ 》 O 周 B-OBJ 星 I-OBJ 馳 I-OBJ 崛 O 起 O 於 O 窮 O 困 O 潦 O 倒 O 之 O 中 O 的 O 獨 O 門 O 祕 O 笈 O ```   序列標註的模型採用ALBERT+Bi-LSTM+CRF,結構圖如下: ![序列標註模型結構圖](https://img-blog.csdnimg.cn/20200315113946554.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pjbGlhbjkx,size_16,color_FFFFFF,t_70) 模型方面的程式碼不再具體給出,有興趣的同學可以參考文章[NLP(二十五)實現ALBERT+Bi-LSTM+CRF模型](https://blog.csdn.net/jclian91/article/details/104826655),也可以參考文章最後給出的Github專案網址。   模型設定文字最大長度為128,利用ALBERT做特徵提取,在自己的電腦上用CPU訓練5個epoch,結果如下: ``` _________________________________________________________________ Train on 173109 samples, validate on 21639 samples Epoch 1/5 173109/173109 [==============================] - 3275s 19ms/step - loss: 0.1269 - crf_viterbi_accuracy: 0.9417 - val_loss: 0.0251 - val_crf_viterbi_accuracy: 0.9613 Epoch 2/5 173109/173109 [==============================] - 3252s 19ms/step - loss: -0.0192 - crf_viterbi_accuracy: 0.9623 - val_loss: -0.0612 - val_crf_viterbi_accuracy: 0.9638 Epoch 3/5 173109/173109 [==============================] - 3445s 20ms/step - loss: -0.1040 - crf_viterbi_accuracy: 0.9644 - val_loss: -0.1450 - val_crf_viterbi_accuracy: 0.9649 Epoch 4/5 173109/173109 [==============================] - 3363s 19ms/step - loss: -0.1869 - crf_viterbi_accuracy: 0.9655 - val_loss: -0.2269 - val_crf_viterbi_accuracy: 0.9652 Epoch 5/5 173109/173109 [==============================] - 3266s 19ms/step - loss: -0.2694 - crf_viterbi_accuracy: 0.9662 - val_loss: -0.3088 - val_crf_viterbi_accuracy: 0.9651 precision recall f1-score support OBJ 0.9591 0.8870 0.9216 40844 SUBJ 0.9621 0.9202 0.9407 25252 micro avg 0.9603 0.8997 0.9290 66096 macro avg 0.9602 0.8997 0.9289 66096 ``` 利用seqeval模組做評估,在驗證集上的F1值約為93%。 ### 關係分類模型   需要對關係做一下說明,因為筆者會對句子(sent)中的主體(S)和客體(O)組合起來,加上句子,形成訓練資料。舉個例子,在句子`歷史評價李氏朝鮮的創立並非太祖大王李成桂一人之功﹐其五子李芳遠功不可沒`,三元組為`[{"predicate": "父親", "object_type": "人物", "subject_type": "人物", "object": "李成桂", "subject": "李芳遠"}, {"predicate": "國籍", "object_type": "國家", "subject_type": "人物", "object": "朝鮮", "subject": "李成桂"}]}`,在這句話中主體有李成桂,李芳遠,客體有李成桂和朝鮮,關係有父親(關係型別:2)和國籍(關係型別:22)。按照筆者的思路,這句話應組成4個關係分類樣本,如下: ``` 2 李芳遠$李成桂$歷史評價李氏朝鮮的創立並非太祖大王###一人之功﹐其五子###功不可沒 0 李芳遠$朝鮮$歷史評價李氏##的創立並非太祖大王李成桂一人之功﹐其五子###功不可沒 0 李成桂$李成桂$歷史評價李氏朝鮮的創立並非太祖大王###一人之功﹐其五子李芳遠功不可沒 22 李成桂$朝鮮$歷史評價李氏##的創立並非太祖大王###一人之功﹐其五子李芳遠功不可沒 ``` 因此,就會出現關係0(表示“未知”),這樣我們在提取三元組的時候就可以略過這條關係,形成真正有用的三元組。   因此,關係一共為51個(加上未知關係:0)。關係分類模型採用ALBERT+Bi-GRU+ATT,結構圖如下: ![關係分類模型圖](https://img-blog.csdnimg.cn/20200315115506974.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pjbGlhbjkx,size_16,color_FFFFFF,t_70)   模型方面的程式碼不再具體給出,有興趣的同學可以參考文章[NLP(二十一)人物關係抽取的一次實戰](https://blog.csdn.net/jclian91/article/details/104380371),也可以參考文章最後給出的Github專案網址。   模型設定文字最大長度為128,利用ALBERT做特徵提取,在自己的電腦上用CPU訓練30個epoch(實際上,由於有early stopping機制,訓練不到30個eopch),在驗證集上的評估結果如下: ``` Epoch 23/30 396766/396766 [==============================] - 776s 2ms/step - loss: 0.1770 - accuracy: 0.9402 - val_loss: 0.2170 - val_accuracy: 0.9308 Epoch 00023: val_accuracy did not improve from 0.93292 49506/49506 [==============================] - 151s 3ms/step 在測試集上的效果: [0.21701653493155634, 0.930776059627533] precision recall f1-score support 未知 0.87 0.76 0.81 5057 祖籍 0.92 0.73 0.82 181 父親 0.79 0.88 0.83 609 總部地點 0.95 0.95 0.95 310 出生地 0.94 0.95 0.94 2330 目 1.00 1.00 1.00 1271 面積 0.90 0.92 0.91 79 簡稱 0.97 0.99 0.98 138 上映時間 0.94 0.98 0.96 463 妻子 0.91 0.83 0.87 680 所屬專輯 0.97 0.97 0.97 1282 註冊資本 1.00 1.00 1.00 63 首都 0.92 0.96 0.94 47 導演 0.92 0.94 0.93 2603 字 0.96 0.97 0.97 339 身高 0.98 0.98 0.98 393 出品公司 0.96 0.96 0.96 851 修業年限 1.00 1.00 1.00 2 出生日期 0.99 0.99 0.99 2892 製片人 0.69 0.88 0.77 127 母親 0.75 0.88 0.81 425 編劇 0.82 0.80 0.81 771 國籍 0.92 0.92 0.92 1621 海拔 1.00 1.00 1.00 43 連載網站 0.98 1.00 0.99 1658 丈夫 0.84 0.91 0.87 678 朝代 0.85 0.92 0.88 419 民族 0.98 0.99 0.99 1434 號 0.95 0.99 0.97 197 出版社 0.98 0.99 0.99 2272 主持人 0.82 0.86 0.84 200 專業程式碼 1.00 1.00 1.00 3 歌手 0.89 0.94 0.91 2857 作詞 0.85 0.81 0.83 884 主角 0.86 0.77 0.81 39 董事長 0.81 0.74 0.78 47 畢業院校 0.99 0.99 0.99 1433 佔地面積 0.89 0.89 0.89 61 官方語言 1.00 1.00 1.00 15 郵政編碼 1.00 1.00 1.00 4 人口數量 1.00 1.00 1.00 45 所在城市 0.90 0.94 0.92 77 作者 0.97 0.97 0.97 4359 成立日期 0.99 0.99 0.99 1608 作曲 0.78 0.77 0.78 849 氣候 1.00 1.00 1.00 103 嘉賓 0.76 0.72 0.74 158 主演 0.94 0.97 0.95 7383 改編自 0.95 0.82 0.88 71 創始人 0.86 0.87 0.86 75 accuracy 0.93 49506 macro avg 0.92 0.92 0.92 49506 weighted avg 0.93 0.93 0.93 49506 ``` ### 三元組提取   最後一部分,也是本次比賽的最終目標,就是三元組提取。   三元組提取採用Pipeline模式,先用序列標註模型預測句子中的實體,然後再用關係分類模型判斷實體關係的類別,過濾掉關係為未知的情形,就是我們想要提取的三元組了。   三元組提取的程式碼如下: ```python # -*- coding: utf-8 -*- # author: Jclian91 # place: Pudong Shanghai # time: 2020-03-14 20:41 import os, re, json, traceback import json import numpy as np from keras_contrib.layers import CRF from keras_contrib.losses import crf_loss from keras_contrib.metrics import crf_accuracy, crf_viterbi_accuracy from keras.models import load_model from collections import defaultdict from pprint import pprint from text_classification.att import Attention from albert_zh.extract_feature import BertVector # 讀取label2id字典 with open("../sequence_labeling/ccks2019_label2id.json", "r", encoding="utf-8") as h: label_id_dict = json.loads(h.read()) id_label_dict = {v: k for k, v in label_id_dict.items()} # 利用ALBERT提取文字特徵 bert_model = BertVector(pooling_strategy="NONE", max_seq_len=128) f = lambda text: bert_model.encode([text])["encodes"][0] # 載入NER模型 custom_objects = {'CRF': CRF, 'crf_loss': crf_loss, 'crf_viterbi_accuracy': crf_viterbi_accuracy} ner_model = load_model("../sequence_labeling/ccks2019_ner.h5", custom_objects=custom_objects) # 載入分類模型 best_model_path = '../text_classification/models/per-rel-08-0.9234.h5' classification_model = load_model(best_model_path, custom_objects={"Attention": Attention}) # 分類與id的對應關係 with open("../data/relation2id.json", "r", encoding="utf-8") as g: relation_id_dict = json.loads(g.read()) id_relation_dict = {v: k for k, v in relation_id_dict.items()} # 從預測的標籤列表中獲取實體 def get_entity(sent, tags_list): entity_dict = defaultdict(list) i = 0 for char, tag in zip(sent, tags_list): if 'B-' in tag: entity = char j = i+1 entity_type = tag.split('-')[-1] while j < min(len(sent), len(tags_list)) and 'I-%s' % entity_type in tags_list[j]: entity += sent[j] j += 1 entity_dict[entity_type].append(entity) i += 1 return dict(entity_dict) # 三元組提取類 class TripleExtract(object): def __init__(self, text): self.text = text.replace(" ", "") # 輸入句子 # 獲取輸入句子中的實體(即:主體和客體) def get_entity(self): train_x = np.array([f(self. text)]) y = np.argmax(ner_model.predict(train_x), axis=2) y = [id_label_dict[_] for _ in y[0] if _] # 輸出預測結果 return get_entity(self.text, y) # 對實體做關係判定 def relation_classify(self): entities = self.get_entity() subjects = list(set(entities.get("SUBJ", []))) objs = list(set(entities.get("OBJ", []))) spo_list = [] for subj in subjects: for obj in objs: sample = '$'.join([subj, obj, self.text.replace(subj, '#'*len(subj)).replace(obj, "#"*len(obj))]) vec = bert_model.encode([sample])["encodes"][0] x_train = np.array([vec]) # 模型預測並輸出預測結果 predicted = classification_model.predict(x_train) y = np.argmax(predicted[0]) relation = id_relation_dict[y] if relation != "未知": spo_list.append([subj, relation, obj]) return spo_list # 提取三元組 def extractor(self): return self.relation_classify() ```   執行三元組提取指令碼,程式碼如下: ``` # -*- coding: utf-8 -*- # author: Jclian91 # place: Pudong Shanghai # time: 2020-03-14 20:53 import os, re, json, traceback from pprint import pprint from triple_extract.triple_extractor import TripleExtract text = "真人版的《花木蘭》由紐西蘭導演妮基·卡羅執導,由劉亦菲、甄子丹、鄭佩佩、鞏俐、李連杰等加盟,幾乎是全亞洲陣容。" triple_extract = TripleExtract(text) print("原文: %s" % text) entities = triple_extract.get_entity() print("實體: ", end='') pprint(entities) spo_list = triple_extract.extractor() print("三元組: ", end='') pprint(spo_list) ```   我們在網上找幾條樣本進行測試,測試的結果如下: >原文: 真人版的《花木蘭》由紐西蘭導演妮基·卡羅執導,由劉亦菲、甄子丹、鄭佩佩、鞏俐、李連杰等加盟,幾乎是全亞洲陣容。 實體: {'OBJ': ['妮基·卡羅', '劉亦菲', '甄子丹', '鄭佩佩', '鞏俐', '李連杰'], 'SUBJ': ['花木蘭']} 三元組: [['花木蘭', '主演', '劉亦菲'], ['花木蘭', '導演', '妮基·卡羅'], ['花木蘭', '主演', '甄子丹'], ['花木蘭', '主演', '李連杰'], ['花木蘭', '主演', '鄭佩佩'], ['花木蘭', '主演', '鞏俐']] >原文: 《冒險小王子》作者周藝文先生,教育、文學領域的專家學者以及來自全國各地的出版業從業者參加了此次沙龍,並圍繞兒童文學創作這一話題做了精彩的分享與交流。 實體: {'OBJ': ['周藝文'], 'SUBJ': ['冒險小王子']} 三元組: [['冒險小王子', '作者', '周藝文']] >原文: 宋應星是江西奉新人,公元1587年生,經歷過明朝腐敗至滅亡的最後時期。 實體: {'OBJ': ['江西奉新', '1587年'], 'SUBJ': ['宋應星']} 三元組: [['宋應星', '出生地', '江西奉新'], ['宋應星', '出生日期', '1587年']] >原文: 韓愈,字退之,河陽(今河南孟縣)人。 實體: {'OBJ': ['退之', '河陽'], 'SUBJ': ['韓愈']} 三元組: [['韓愈', '出生地', '河陽'], ['韓愈', '字', '退之']] >原文: 公開資料顯示,李強,男,漢族,出生於1971年12月,北京市人,北京市委黨校在職研究生學歷,教育學學士學位,1996年11月入黨,1993年7月參加工作。 實體: {'OBJ': ['漢族', '1971年12月', '北京市', '北京市委黨校'], 'SUBJ': ['李強']} 三元組: [['李強', '民族', '漢族'], ['李強', '出生地', '北京市'], ['李強', '畢業院校', '北京市委黨校'], ['李強', '出生日期', '1971年12月']] >原文: 楊牧,本名王靖獻,早期筆名葉珊,1940年生於臺灣花蓮,著名詩人、作家。 實體: {'OBJ': ['1940年', '臺灣花蓮'], 'SUBJ': ['楊牧']} 三元組: [['楊牧', '出生地', '臺灣花蓮'], ['楊牧', '出生日期', '1940年']] >原文: 楊廣是隋文帝楊堅的第二個兒子。 實體: {'OBJ': ['楊堅'], 'SUBJ': ['楊廣']} 三元組: [['楊廣', '父親', '楊堅']] >原文: 此次權益變動後,何金明與妻子宋琦、其子何浩不再擁有對上市公司的控制權。 實體: {'OBJ': ['何金明'], 'SUBJ': ['宋琦', '何浩']} 三元組: [['何浩', '父親', '何金明'], ['宋琦', '丈夫', '何金明']] >原文: 線上直播發佈會中,譚維維首次演繹了新歌《章存仙》,這首歌由錢雷作曲、尹約作詞,尹約也在直播現場透過手機鏡頭跟網友互動聊天。 實體: {'OBJ': ['譚維維', '錢雷', '尹約', '尹約'], 'SUBJ': ['章存仙']} 三元組: [['章存仙', '作曲', '錢雷'], ['章存仙', '作詞', '尹約'], ['章存仙', '歌手', '譚維維']] >原文: “土木之變”後,造就了明代傑出的民族英雄于謙。 實體: {'OBJ': ['明代'], 'SUBJ': ['于謙']} 三元組: [['于謙', '朝代', '明代']] >原文: 另外,哈爾濱歷史博物館也是全國面積最小的國有博物館,該場館面積只有50平方米,可稱之“微縮博物館”。 實體: {'OBJ': ['50平方米'], 'SUBJ': ['哈爾濱歷史博物館']} 三元組: [['哈爾濱歷史博物館', '佔地面積', '50平方米']] >原文: 孫楊的媽媽叫楊明,孫楊的名字後面一個字也是來源於她的名字。 實體: {'OBJ': ['楊明', '孫楊'], 'SUBJ': ['孫楊']} 三元組: [['孫楊', '母親', '楊明']] >原文: 企查查顯示,達鑫電子成立於1998年6月,法定代表人張高圳,註冊資本772.33萬美元,股東僅新加坡達鑫控股有限公司一名。 實體: {'OBJ': ['1998年6月'], 'SUBJ': ['達鑫電子']} 三元組: [['達鑫電子', '成立日期', '1998年6月']] ### 總結   本文標題為限定領域的三元組抽取的一次嘗試,之所以取名為限定領域,是因為該任務的實體關係是確定,一共為50種關係。   當然,上述方法還存在著諸多不足,參考蘇建林的文章[基於DGCNN和概率圖的輕量級資訊抽取模型](https://spaces.ac.cn/archives/6671),我們發現不足之處如下: - 主體和客體的標註策略有問題,因為句子中有時候主體和客體會重疊在一起; - 新引入了一類關係:未知,是否有辦法避免引入; - 其他(暫時未想到)   從比賽的角度將,本文的辦法效果未知,應該會比聯合模型的效果差一些。但是,這是作為筆者自己的模型,演算法是一種嘗試,之所以採用這種方法,是因為筆者一開始是從開放領域的三元組抽取入手的,而這種方法方便擴充套件至開放領域。關於開放領域的三元組抽取,筆者稍後就會寫文章介紹,敬請期待。   本文的原始碼已經公開至Github,網址為: [https://github.com/percent4/ccks_triple_extract](https://github.com/percent4/ccks_triple_extract) 。 ### 參考網址 1. NLP(二十五)實現ALBERT+Bi-LSTM+CRF模型:https://blog.csdn.net/jclian91/article/details/104826655 2. NLP(二十一)人物關係抽取的一次實戰: https://blog.csdn.net/jclian91/article/details/104380371 3. 基於DGCNN和概率圖的輕量級資訊抽取模型:https://spaces.ac.cn/archi