EasyNLP發佈融合語言學和事實知識的中文預訓練模型CKBERT

簡介: 本⽂簡要介紹CKBERT的技術解讀,以及如何在EasyNLP框架、HuggingFace Models和阿里雲機器學習平臺PAI上使⽤CKBERT模型。

導讀

預訓練語言模型在NLP的各個應用中都有及其廣泛的應用;然而,經典的預訓練語言模型(例如BERT)缺乏對知識的理解,例如知識圖譜中的關係三元組。知識增強預訓練模型使用外部知識(知識圖譜,字典和文本等)或者句子內部的語言學知識進行增強。我們發現,知識注入的過程都伴隨着很大規模的知識參數,下游任務fine-tune的時候仍然需要外部數據的支撐才能達到比較好的效果,從而無法在雲環境中很好的提供給用戶進行使用。CKBERT(Chinese Knowledge-enhanced BERT)是EasyNLP團隊自研的中文預訓練模型,結合了兩種知識類型(外部知識圖譜,內部語言學知識)對模型進行知識注入,同時使得知識注入的方式方便模型可擴展。我們的實驗驗證也表明CKBERT的模型精度超越了多種經典中文模型。在本次的框架升級中,我們將多種規模的CKBERT模型貢獻給開源社區,並且這些CKBERT模型與HuggingFace Models完全兼容。此外,用戶也可以在阿里雲機器學習平臺PAI上方便地利用雲資源使用CKBERT模型。

 

EasyNLP(https://github.com/alibaba/EasyNLP)是阿⾥雲機器學習PAI 團隊基於 PyTorch 開發的易⽤且豐富的中⽂NLP算法框架,⽀持常⽤的中⽂預訓練模型和⼤模型落地技術,並且提供了從訓練到部署的⼀站式 NLP 開發體驗。EasyNLP 提供了簡潔的接⼝供⽤戶開發 NLP 模型,包括NLP應⽤ AppZoo 和預訓練 ModelZoo,同時提供技術幫助⽤戶⾼效的落地超⼤預訓練模型到業務。由於跨模態理解需求的不斷增加,EasyNLP也⽀持各種跨模態模型,特別是中⽂領域的跨模態模型,推向開源社區,希望能夠服務更多的 NLP 和多模態算法開發者和研 究者,也希望和社區⼀起推動 NLP /多模態技術的發展和模型落地。

 

本⽂簡要介紹CKBERT的技術解讀,以及如何在EasyNLP框架、HuggingFace Models和阿里雲機器學習平臺PAI上使⽤CKBERT模型。

中文預訓練語言模型概覽

在這一節中,我們首先簡要回顧經典的中文預訓練語言模型。目前中文預訓練語言模型主要包括了兩種類型:

  • 通用領域的預訓練語言模型,主要包括了BERT、MacBERT和PERT等模型;
  • 知識增強的中文預訓練模型,主要包括了ERNIE-baidu,Lattice-BERT,K-BERT和ERNIE-THU等模型。

通用領域的預訓練語言模型

BERT直接使用Google發佈的基於中文維基文本語料進行訓練的模型。MacBERT是BERT的改進版本,引入了糾錯型掩碼語言模型(MLM as correction,Mac)預訓練任務,緩解了“預訓練-下游任務”不一致的問題。在掩碼語言模型(MLM)中,引入了[MASK]標記進行掩碼,但[MASK]標記並不會出現在下游任務中。在MacBERT中,使用相似詞來取代[MASK]標記。相似詞通過Synonyms toolkit 工具獲取,算法基於word2vec相似度計算。同時,MacBERT也引入了Whole Word Masking和N-gram Masking技術。當要對N-gram進行掩碼時,會對N-gram裏的每個詞分別查找相似詞;當沒有相似詞可替換時,將使用隨機詞進行替換。由於一定程度的亂序文本不影響語義理解,PBERT從亂序文本中學習語義知識。它對原始輸入文本進行一定的詞序調換,從而形成亂序文本(因此不會引入額外的[MASK]標記),其學習目標是預測原Token所在的位置。

知識增強的中文預訓練模型

BERT在預訓練過程中使用的數據僅是對單個字符進行屏蔽,例如下圖所示,訓練BERT時通過“哈”與“濱”的局部共現判斷出“爾”字,但是模型其實並沒有學習到與“哈爾濱”相關的知識,即只是學習到“哈爾濱”這個詞,但是並不知道“哈爾濱”所代表的含義。ERNIE-Baidu在預訓練時使用的數據是對整個詞進行屏蔽,從而學習詞與實體的表達,例如屏蔽“哈爾濱”與“冰雪”這樣的詞,使模型能夠建模出“哈爾濱”與“黑龍江”的關係,學到“哈爾濱”是“黑龍江”的省會以及“哈爾濱”是個冰雪城市這樣的含義。

與ERNIE-Baidu類似,Lattice-BERT利用Word-Lattice結構整合詞級別信息。具體來說,Lattice-BERT設計了一個Lattice位置注意機制,來表達詞級別的信息,同時提出了Masked Segment Prediction的預測任務,以推動模型學習來自豐富但冗餘的內在Lattice信息。

除了語言學知識,更多的工作利用知識圖譜中的事實性知識豐富中文預訓練模型的表徵。其中,K-BERT提出了面向知識圖譜的知識增強語言模型,將三元組作爲領域知識注入到句子中。然而,過多的知識融入會導致知識噪音,使句子偏離其正確的含義。爲了克服知識噪音, K-BERT引入了Soft-position和Visibel Matrix來限制知識的影響。由於K-BERT能夠從預訓練的BERT中加載模型參數,因此通過配備KG,可以很容易地將領域知識注入到模型中,而不需要對模型進行預訓練。EasyNLP框架也集成了K-BERT的模型和功能(看這裏)。

ERNIE-THU是一種融入知識Embedding的預訓練模型。它首先使用TAGME提取文本中的實體,並將這些實體鏈指到KG中的對應實體對象,然後獲得這些實體對象對應的Embedding。實體對象的Embedding由知識表示方法(例如TransE)訓練得到。此外,ERNIE-THU在BERT模型的基礎上進行改進,除了MLM、NSP任務外,重新添加了一個和KG相關的預訓練目標:Mask掉Token和Entity (實體) 的對齊關係,並要求模型從圖譜的實體中選擇合適的Entity完成對齊。

自研CKBERT模型技術詳解

由於當前的知識增強預訓練模型大都使用外部知識(知識圖譜,字典和文本等)或者句子內部的語言學知識進行增強,同時知識注入的過程都伴隨着很大規模的知識參數,下游任務fine-tune的時候仍然需要外部數據的支撐才能達到比較好的效果,從而無法在雲環境中很好的提供給用戶進行使用。CKBERT(Chinese Knowledge-enhanced BERT)是EasyNLP團隊自研的中文預訓練模型,結合了兩種知識類型(外部知識圖譜,內部語言學知識)對模型進行知識注入,同時使得知識注入的方式方便模型可擴展。針對實際的業務需求,我們提供了三種不同規模參數量的模型,詳細配置如下所示:

模型配置

alibaba-pai/pai-ckbert-base-zh

alibaba-pai/pai-ckbert-large-zh

alibaba-pai/pai-ckbert-huge-zh

參數量(Parameters)

151M

428M

1.3B

層數(Number of Layers)

12

24

24

注意力頭數(Attention Heads)

12

16

8

隱向量維度(Hidden Size)

768

1024

2048

文本長度(Text Length)

128

128

128

FFN 層維度

3072

4096

8192

 

CKBERT的模型架構如下圖所示:

爲了方便模型進行擴展參數,模型只在數據輸入層面和預訓練任務層面進行了改動,沒有對模型架構進行改動。因此,CKBERT的模型結構與社區版的BERT模型對齊。在數據輸入層,一共要處理兩部分的知識,外部圖譜三元組和句子級內部的語言學知識。針對語言學知識,我們使用了哈工大LTP平臺進行句子數據的處理,進行語義角色標註和依存句法分析等,然後根據規則,將識別結果中重要的成分進行標註。針對外部三元組知識是根據句子中出現的實體構造實體的正負三元組樣本,正樣本是根據圖譜中1-hop 實體進行的採樣,負樣本是根據圖譜中multi-hop進行的採樣,但負樣本的採樣過程只能在規定的多跳範圍內,而不能在圖譜中距離太遠。

 

CKBERT採用兩種預訓練任務進行模型的預訓練,語言學感知的掩碼語言模型和多跳知識對比學習:

  • 語言學感知的掩碼語言模型(Linguistic-aware MLM):在語義依存關係中的主體角色(施事者AGT和當事者EXP )部分用[MASK]進行遮掩,同時在詞的前後都加上[SDP][/SDP],附加上詞彙的邊界信息。在依存句法關係中,將主謂冰關係,定中關係,並列關係等按照上述mask機制進行處理爲[DEP][/DEP]。整體進行預訓練的token數量是整句話的15%,其中40%進行隨機MASK,30%和30%分配到語義依存關係和依存句法關係詞匯上來。損失函數如下:

  • 多跳知識對比學習:將上述構造的正負樣本數據針對該注入的實體進行處理,每一個句中實體構造1個正樣本,4個負樣本,通過標準的infoNCE損失任務進行外部知識的學習。損失函數如下:

其中,是預訓練模型產生的上下文實體表示,表示正樣本的三元組表示結果,表示負樣本的三元組表示結果。

CKBERT模型的實現

在EasyNLP框架中,我們的模型實現分爲三個部分:數據預處理,模型結構微調和損失函數的設計。首先,在數據預處理環節,主要由以下兩個步驟組成:1.NER實體及語義關係的提取;2.知識圖譜的信息注入。關於NER實體及語義信息的提取,主要採用LTP(Language Technology Platform)對原始句子進行分詞和句法分析,該部分的核心代碼如下所示:

def ltp_process(ltp: LTP, 
                data: List[Dict[str, Union[str, List[Union[int, str]]]]]):
    """use ltp to process the data
    Args:
        Dict ([str, str]): data
        example:
            {'text':['我叫湯姆去拿傘。'],...}
    Returns:
        Dict[str, str]: result
    """
    new_data = list(map(lambda x:x['text'][0].replace(" ", ""), data))
    seg, hiddens = ltp.seg(new_data)
    result = {}
    result['seg'] = seg
    result['ner'] = ltp.ner(hiddens)
    result['dep'] = ltp.dep(hiddens)
    result['sdp'] = ltp.sdp(hiddens)
    for index in range(len(data)):
        data[index]['text'][0] = data[index]['text'][0].replace(" ", "")
        data[index]['seg'] = result['seg'][index]
        data[index]['ner'] = result['ner'][index]
        data[index]['dep'] = result['dep'][index]
        data[index]['sdp'] = result['sdp'][index]

該部分完成之後需要基於原始句子中的語義依存關係對相應的詞進行整體的mask,該部分的mask策略參考BERT的mask策略的設計,給不同類型的關係分配特定的概率,並基於該概率對不同類型關係進行mask,該部分的核心代碼如下:

def dep_sdp_mask(left_numbers: List[int], 
                     data_new: List[List[Union[int, str]]], 
                     markers_: List[List[int]], 
                     selected_numbers_: set, 
                     number_: int,
                     marker_attrs: Dict[str, List[int]]) -> int:
        """ mask the `mask_labels` for sdp and dep and record the maskers for each mask item
        Args:
            left_numbers (List[int]): the options that have not been used
            data_new (List[List[Union[int, str]]]): preprocessed data for original dep and sdp
            markers_ (List[List[int]]): a list that is uesd to save the maskers for each mask item
            selected_numbers_ (set): a set that is used to save the selected options
            number_ (int): the number of mask labels
            marker_attrs Dict[str, List[int]]: marker attributes
        Returns:
            int: 0 mean no mask, the others mean the number of masked ids
        """
        np.random.shuffle(left_numbers)
        for item_ in left_numbers:
            target_item = data_new[item_]
            seg_ids = np.array(target_item[:2]) - 1
            delete_ids = np.where(seg_ids < 1)[0]
            seg_ids = np.delete(seg_ids, delete_ids)
            temp_ids = seg2id(seg_ids)
            ids = []
            for item in temp_ids:
                ids += item.copy()
            if check_ids(ids):
                length_ = len(ids)
                if number_ > length_:
                    for id_ in ids:
                        mask_labels[id_] = 1
                    if target_item[2] in marker_attrs:
                        detail_info.append([
                            target_item,
                            [seg_data[target_item[0] - 1],seg_data[target_item[1] - 1]],
                        ])
                        if len(temp_ids) == 1:
                            markers_.append([temp_ids[0][0], temp_ids[0][-1]])
                        elif len(temp_ids) == 2:
                            for i in marker_attrs[target_item[2]]:
                                markers_.append([temp_ids[i][0], temp_ids[i][-1]])
                    selected_numbers_.add(item_)
                    return length_
                else:
                    return 0
        return 0

在完成對原始句子的預處理之後,在模型的dataloader裏需要對數據進行知識注入,由於模型中引入了對比學習,因此該部分需要在數據轉換階段同時生成positive和negative的樣本數據。實現這一過程的核心代碼如下:

def get_positive_and_negative_examples(
    self,
    ner_data: str,
    negative_level: int = 3) -> Union[bool, Dict[str, List[str]]]:
    """get the positive examples and negative examples for the ner data
    Args:
        ner_data (str): the ner entity
        negative_level (int, optional): the deepth of the relationship. Defaults to 3.
    Returns:
        Union[bool, Dict[str, List[str]]]: if the `ner_data` not in `konwledge`, return False, otherwise, return the positive and negative examples
    """
    knowledge: Dict[str, Dict[str, str]] = self.Knowledge_G
    common_used = set()
    def get_data(key: str, 
                data: Dict[str, str], 
                results: List[str], 
                deep: int, 
                insert_flag: bool = False):
        """get the negative examples recursively
        Args:
            key (str): the ner
            data (Dict[str, str]): the related data about `key`
            results (List[str]): a list used to save the negative examples
            deep (int): the recursive number
            insert_flag (bool, optional): whether insert data to `results`. Defaults to False.
        """
        nonlocal knowledge
        common_used.add(key)
        if deep == 0:
            return
        else:
            for key_item in data:
                if data[key_item] not in common_used and insert_flag == True:
                    results.append(data[key_item])
                if data[key_item] in knowledge and data[key_item] not in common_used:
                    get_data(data[key_item], knowledge[data[key_item]], results, deep - 1, True)
    
    all_examples = {
        'ner': ner_data,
        'positive_examples': [],
        'negative_examples': []
    }
    if ner_data in knowledge:
        tp_data = knowledge[ner_data]
        negative_examples = []
        if '描述' in tp_data:
            positive_example = tp_data['描述']
        else:
            keys = list(tp_data.keys())
            choice = np.random.choice([_ for _ in range(len(keys))], 1)[0]
            positive_example = tp_data[keys[choice]]
        # # the description usually contains the ner entity, if not, concate the `ner_data` and the positive example
        if ner_data in positive_example:
            all_examples['positive_examples'].append(positive_example)
        else:
            all_examples['positive_examples'].append(ner_data + positive_example)
        get_data(ner_data, tp_data, negative_examples, negative_level)
        # concate the ner entity and each negative example
        negative_examples = list(map(lambda x: ner_data + x if ner_data not in x else x, negative_examples))
        all_examples['negative_examples'] = negative_examples
        return all_examples
    return False

在完成知識注入之後,模型的數據預處理環節就實現了。緊接着,由於知識注入需要額外添加特殊的Token,因此,在模型的Embedding層需要重新調整大小,該部分的實現代碼如下:

model.backbone.resize_token_embeddings(len(train_dataset.tokenizer))
model.config.vocab_size = len(train_dataset.tokenizer)

在對模型結構進行微調之後,最後就是修改原始的loss函數,由於引入了對比學習,這裏需要在原來loss的基礎之上新加一個對比學習的loss(CKBert採用SimCLS作爲對比學習的loss函數),該部分的核心代碼實現如下:

def compute_simcse(self, original_outputs: torch.Tensor, 
                   forward_outputs: torch.Tensor) -> float:
        original_hidden_states = original_outputs['hidden_states'].unsqueeze(-2)
        loss = nn.CrossEntropyLoss()
        forward_outputs = torch.mean(forward_outputs, dim=-2)
        cos_result = self.CosSim(original_hidden_states, forward_outputs)
        cos_result_size = cos_result.size()
        cos_result = cos_result.view(-1, cos_result_size[-1])
        labels = torch.zeros(cos_result.size(0), device=original_outputs['hidden_states'].device).long()
        loss_ = loss(cos_result, labels)
        return loss_

CKBERT加速預訓練

由於CKBERT的預訓練需要耗費大量時間和計算資源,我們有必須對CKBERT的預訓練進行加速。由於CKBERT採用PyTorch框架實現,與Tensorflow 1.x Graph Execution方式相比,PyTorch採用Eager Execution的方式運行,具有很好的易用性、容易開發調試等特點。但是,Pytorch缺少模型的Graph IR(Intermediate Representation)表達,因此無法進行更深度的優化。受到LazyTensor 和Pytorch/XLA(https://github.com/pytorch/xla)的啓發,PAI團隊在PyTorch框架中開發了TorchAccelerator,旨在解決PyTorch上的訓練優化問題,在保證用戶易用性和可調試行的基礎上,提升用戶訓練速度。

 

由於LazyTensor在Eager Execution到Graph Execution轉化過程中還存在很多缺陷。通過將Custom Operation封裝進XLA CustomCall、對Python代碼進行AST解析等手段,TorchAccelerator提升了Eager Execution到Graph Execution的完備性和轉化性能,通過多Stream優化、Tensor異步傳輸等手段提升編譯優化效果。


從實驗結果來看,將TorchAccelerator和AMP(Automatic Mixed Precision,混合精度訓練)結合起來使用,訓練速度將會有40%以上的提升,說明在AMP和TorchAccelerator進行相互作用下有比較好的加速效果。

CKBERT實驗效果評測

爲了驗證CKBERT模型在各種任務上的精度,我們在多個公開數據集上驗證了句子分類和NER任務的效果,如下所示:

CLUE數據集實驗效果

模型

Text Classification

Question Answering

Total Score

AFQMC

TNEWS

IFLYTEK

OCNLI

WSC

CSL

CMRC

CHID

C3

BERT

72.73

55.22

59.54

66.53

72.49

81.77

73.40

79.19

57.91

69.72

MacBERT

69.90

57.93

60.35

67.43

74.71

82.13

73.55

79.51

58.89

70.28

PERT

73.61

54.50

57.42

66.70

76.07

82.77

73.80

80.19

58.03

70.18

ERNIE-Baidu

73.08

56.22

60.11

67.48

75.79

82.14

72.86

80.03

57.63

69.83

Lattice-BERT

72.96

56.14

58.97

67.54

76.10

81.99

73.47

80.24

57.80

70.29

K-BERT

73.15

55.91

60.19

67.83

76.21

82.24

72.74

80.29

57.48

70.35

ERNIE-THU

72.88

56.59

59.33

67.95

75.82

82.35

72.96

80.22

56.30

69.98

CKBERT-base

73.17

56.44

60.65

68.53

76.38

82.63

73.55

81.69

57.91

71.36

CKBERT-large

74.75

55.86

60.62

70.57

78.89

82.30

73.45

82.34

58.12

72.23

CKBERT-huge

75.03

59.72

60.96

78.26

85.16

89.47

77.25

97.73

86.59

78.91

CKBERT-huge

(ensemble)

77.05

61.16

61.19

82.80

87.14

94.23

80.40

97.91

87.26

81.02

 

 

NER數據集實驗效果

模型

MSRA

Weibo

Onto.

Resu.

BERT

95.20

54.65

81.61

94.86

MacBERT

95.07

54.93

81.96

95.22

PERT

94.99

53.74

81.44

95.10

ERNIE-Baidu

95.39

55.14

81.17

95.13

Lattice-BERT

95.28

54.99

82.01

95.31

K-BERT

94.97

55.21

81.98

94.92

ERNIE-THU

95.25

53.85

82.03

94.89

CKBERT-base

95.35

55.97

82.19

95.68

CKBERT-large

95.58

57.09

82.43

96.08

CKBERT-huge

96.79

58.66

83.87

97.19

 

上述結果說明,首先在CLUE數據集上:(1)知識增強預訓練模型的性能相較於BERT均有較大提升,在一定程度說明了知識的注入能幫助模型進行更好的語義推理;(2)跟先前的較好的baseline模型相比,CKBERT的性能進一步得到了提升,這也說明了異構知識的注入有利於模型性能的提升;(3)模型參數量越大,異構知識的的注入所帶來的提升越明顯,這在我們的huge模型和base模型之間的對比上可以看出。其次,在NER數據集上:(1)知識增強預訓練模型的性能相較於BERT也有一定的提升;(2)CKBERT模型相較於其他baseline模型的提升較大,這進一步說明了異構知識的注入對於模型性能的提升是有幫助的。

CKBERT模型使⽤教程

以下我們簡要介紹如何在EasyNLP框架使⽤CKBERT模型。

安裝EasyNLP

⽤戶可以直接參考GitHubhttps://github.com/alibaba/EasyNLP)上的說明安裝EasyNLP算法框架。

模型預訓練

以下介紹CKBERT模型的預訓練調用過程,如果用戶沒有自行預訓練的需求可以跳過此部分。

數據準備

CKBERT是一個知識嵌入的預訓練模型,需要用戶自己準備相應的原始訓練數據(xxx.json)和知識圖譜(xxx.spo),其中數據分隔均使用\t分隔符。訓練數據的格式爲{'text':['xxx'], 'title':'xxx'},樣例如下:

{'text': ['我想,如果我沒有去做大學生村官,恐怕我這個在昆明長大的孩子永遠都不能切身感受到雲南這次60年一遇的特大旱情的嚴重性,恐怕我只是每天看着新聞上那些缺水的鏡頭,嘴上說要節水,但事實行動保持不了三天。 我任職的地方在昆明市祿勸縣的一個村委會,說實話這裏距離祿勸縣城不遠,自然環境不算很差。目前,只有一個自然村保證不了飲用水。一個自然村基本能保證有飲用水到5月。這裏所說的飲用水,是指從山肚子裏出來的水,積在小水壩或是水塘裏又通過管道輸送到村子裏的水,和我們城市裏真正意義上消過毒的、能安全飲用的飲用水不同。在整個輸送的過程中,可能已經產生了有害物質。我覺得是。 沒有飲用水的那個自然村叫大海子村,50戶,近200多人。地處山頭,交通很不便利,走路大概要1個半小時到兩個小時,而且坡度比較大,是一個苗族村寨。地理條件限制,基本沒有什麼經濟作物,算是靠天喫飯的那種。今年遇到60年一遇的乾旱,村裏的兩個水窖都基本幹了,之前幾天,他們村長來反映,幾個老人已經是擡個小板凳坐到窖底用碗舀水了。 面對這麼嚴峻的旱情,村委會的領導和各小組長都在想辦法。但是上山的路路面情況差,大車重車上不去;周邊水源地少。最可行的辦法就是從武定那邊繞路上去。但每天運水上去也不是辦法,長遠來看還是要修建一個小水壩。村委會的領導主動捐款,村民也自行籌資,開始自救。 最近每個週末都回家,添置防曬品,因爲基本每天都上山下村去了解情況,必須掌握轄區內13個村小組水資源的情況。我每次回家見到朋友們,第一句就是,要節約用水啊~~ 朋友們,你們現在看到的只是簡單理解的"缺水"。你們所不知道的是,沒水小春作物面臨絕收、4月份插秧沒有水泡秧田、5月份種烤煙也沒有水。。。那麼對農民就意味着今年一年就沒有了收入。我們現在能努力做好的,只是保證人的飲用水。 上週就在想能不能通過什麼渠道幫村民們做點事。叔叔叫我弄個抗旱的基金,他發動周圍的朋友來捐贈,希望能口口相傳帶動多一點朋友。我正在籌備階段,看怎樣才能做到最大的公開透明,讓捐贈的人完全放心。 週一接到一個朋友的電話,說他們公司想爲旱災獻點愛心,想買點水送去我們那兒。昨天見了負責人,很謙和的一個姐姐,她說大家都想做點什麼,覺得捐錢沒什麼意義,想親自送水到最需要的地方。 其實人家只是傢俬營的小公司,但我真的很感謝他們。姐姐還特別交代我,我們只需要找拖拉機下來幫忙把水運上山去,其他的什麼都不用管,他們會安排好的。這個週末,將有 400件礦泉水會送到村民家裏。我想,應該可以暫時緩解旱情。再次代村民感謝他們! 下半年,旱情給農民的生產、生活帶來的問題還很多。但是我個人的力量很有限,希望能夠看到這些帖子的朋友們,如果有能力,有這份心意的話,請給予旱災地區的農民更多的幫助。 我想大家都知道,昆明80%以上的用水都來自祿勸的雲龍水庫,雲龍的同事們也在"抗旱",他們的工作任務是要保證嚴格的節約用水,要尋求其他水源用水,從而保證昆明的用水。所以,請每一個昆明人都節水吧,祿勸的很多地方都在缺水,我們那裏不算嚴重的,請珍惜你們現在在用的每一滴水~ 也許,要經歷過這樣一次觸目驚心的大旱才真正知道水的珍貴。希望我們都行動起來,不要再讓這樣的旱災侵襲我們的家鄉。'], 'title': '旱情記要-----昆明人,請珍惜你們現在在用的每一滴水~'}

知識圖譜數據格式爲三列數據,從左到右分別是實體關係的描述,樣例如下:

紅色食品  標籤  生活

數據預處理

可以使用提供的數據預處理腳本(preprocess/run_local_preprocess.sh)來對原始數據進行一鍵處理,在經過LTP處理之後,數據樣例如下:

{"text": ["我想,如果我沒有去做大學生村官,恐怕我這個在昆明長大的孩子永遠都不能切身感受到雲南這次60年一遇的特大旱情的嚴重性,恐怕我只是每天看着新聞上那些缺水的鏡頭,嘴上說要節水,但事實行動保持不了三天。我任職的地方在昆明市祿勸縣的一個村委會,說實話這裏距離祿勸縣城不遠,自然環境不算很差。目前,只有一個自然村保證不了飲用水。一個自然村基本能保證有飲用水到5月。這裏所說的飲用水,是指從山肚子裏出來的水,積在小水壩或是水塘裏又通過管道輸送到村子裏的水,和我們城市裏真正意義上消過毒的、能安全飲用的飲用水不同。在整個輸送的過程中,可能已經產生了有害物質。我覺得是。沒有飲用水的那個自然村叫大海子村,50戶,近200多人。地處山頭,交通很不便利,走路大概要1個半小時到兩個小時,而且坡度比較大,是一個苗族村寨。地理條件限制,基本沒有什麼經濟作物,算是靠天喫飯的那種。今年遇到60年一遇的乾旱,村裏的兩個水窖都基本幹了,之前幾天,他們村長來反映,幾個老人已經是擡個小板凳坐到窖底用碗舀水了。面對這麼嚴峻的旱情,村委會的領導和各小組長都在想辦法。但是上山的路路面情況差,大車重車上不去;周邊水源地少。最可行的辦法就是從武定那邊繞路上去。但每天運水上去也不是辦法,長遠來看還是要修建一個小水壩。村委會的領導主動捐款,村民也自行籌資,開始自救。最近每個週末都回家,添置防曬品,因爲基本每天都上山下村去了解情況,必須掌握轄區內13個村小組水資源的情況。我每次回家見到朋友們,第一句就是,要節約用水啊~~朋友們,你們現在看到的只是簡單理解的\"缺水\"。你們所不知道的是,沒水小春作物面臨絕收、4月份插秧沒有水泡秧田、5月份種烤煙也沒有水。。。那麼對農民就意味着今年一年就沒有了收入。我們現在能努力做好的,只是保證人的飲用水。上週就在想能不能通過什麼渠道幫村民們做點事。叔叔叫我弄個抗旱的基金,他發動周圍的朋友來捐贈,希望能口口相傳帶動多一點朋友。我正在籌備階段,看怎樣才能做到最大的公開透明,讓捐贈的人完全放心。週一接到一個朋友的電話,說他們公司想爲旱災獻點愛心,想買點水送去我們那兒。昨天見了負責人,很謙和的一個姐姐,她說大家都想做點什麼,覺得捐錢沒什麼意義,想親自送水到最需要的地方。其實人家只是傢俬營的小公司,但我真的很感謝他們。姐姐還特別交代我,我們只需要找拖拉機下來幫忙把水運上山去,其他的什麼都不用管,他們會安排好的。這個週末,將有400件礦泉水會送到村民家裏。我想,應該可以暫時緩解旱情。再次代村民感謝他們!下半年,旱情給農民的生產、生活帶來的問題還很多。但是我個人的力量很有限,希望能夠看到這些帖子的朋友們,如果有能力,有這份心意的話,請給予旱災地區的農民更多的幫助。我想大家都知道,昆明80%以上的用水都來自祿勸的雲龍水庫,雲龍的同事們也在\"抗旱\",他們的工作任務是要保證嚴格的節約用水,要尋求其他水源用水,從而保證昆明的用水。所以,請每一個昆明人都節水吧,祿勸的很多地方都在缺水,我們那裏不算嚴重的,請珍惜你們現在在用的每一滴水~也許,要經歷過這樣一次觸目驚心的大旱才真正知道水的珍貴。希望我們都行動起來,不要再讓這樣的旱災侵襲我們的家鄉。"], "title": "旱情記要-----昆明人,請珍惜你們現在在用的每一滴水~", "seg": ["我", "想", ",", "如果", "我", "沒有", "去", "做", "大學生村官", ",", "恐怕", "我", "這個", "在", "昆明長大", "的", "孩子", "永遠", "都", "不能切身感受到", "雲南", "這次", "60年", "一遇的", "特大旱情", "的", "嚴重性", ",", "恐怕", "我", "只是", "每天", "看", "着", "新聞上", "那些", "缺水", "的", "鏡頭", ",", "嘴上說要節水", ",", "但事實行動", "保持不了", "三天", "。", "我", "任職", "的", "地方", "在", "昆明市祿勸縣", "的", "一個", "村委會", ",", "說實話", "這裏", "距離祿", "勸縣城不遠", ",", "自然環境", "不算", "很差", "。", "目前", ",", "只有", "一個", "自然村", "保證不了", "飲用水", "。", "一個", "自然村", "基本", "能", "保證", "有", "飲用水", "到", "5月", "。", "這裏所說", "的", "飲用水", ",", "是指", "從", "山肚子裏", "出來", "的", "水", ",積在", "小水壩", "或是", "水塘裏", "又", "通過", "管道", "輸送到", "村子裏", "的水", ",", "和", "我們", "城市裏", "真正意義上", "消過毒的", "、能安全", "飲用", "的", "飲用水不同", "。", "在", "整個", "輸送", "的", "過程", "中", ",", "可能", "已經", "產生", "了", "有害物質", "。", "我", "覺得", "是", "。", "沒有", "飲用水", "的", "那", "個", "自然村叫大海子村", ",", "50戶", ",近", "200多人", "。地處山頭", ",", "交通", "很不便利", ",", "走路", "大概要", "1個半小時到", "兩個", "小時", ",", "而且坡度", "比較大", ",", "是", "一個", "苗族村寨", "。地理條件", "限制", ",", "基本", "沒有什麼經濟作物", ",", "算是", "靠天", "喫飯", "的", "那種", "。", "今年", "遇到", "60年一遇", "的", "乾旱", ",村裏", "的", "兩個水窖", "都", "基本", "幹", "了", ",之前幾天", ",", "他們", "村長來反映", ",", "幾個老人", "已經", "是", "擡個小板凳坐到窖底用碗舀水", "了", "。面對", "這麼", "嚴峻的", "旱情", ",", "村委會", "的領導", "和", "各小組長", "都", "在", "想", "辦法", "。", "但是上山的", "路路面情況", "差", ",", "大車重車上不去", ";", "周邊水源地少", "。", "最", "可行", "的", "辦法", "就是", "從武定", "那邊", "繞路上去", "。", "但", "每天運水上"], "ner": [["Ns", 14, 14], ["Ns", 20, 20], ["Ns", 51, 51]], "dep": [[1, 2, "SBV"], [2, 0, "HED"], [3, 2, "WP"], [4, 6, "ADV"], [5, 6, "SBV"], [6, 2, "VOB"], [7, 6, "COO"], [8, 7, "COO"], [9, 8, "VOB"], [10, 8, "WP"], [11, 7, "COO"], [12, 172, "SBV"], [13, 172, "ADV"], [14, 172, "ADV"], [15, 14, "POB"], [16, 172, "RAD"], [17, 172, "SBV"], [18, 172, "ADV"], [19, 172, "ADV"], [20, 172, "ADV"], [21, 172, "SBV"], [22, 172, "ADV"], [23, 172, "ADV"], [24, 172, "ADV"], [25, 172, "ADV"], [26, 172, "RAD"], [27, 172, "VOB"], [28, 156, "WP"], [29, 33, "ADV"], [30, 33, "SBV"], [31, 33, "ADV"], [32, 33, "ADV"], [33, 156, "COO"], [34, 33, "RAD"], [35, 39, "ATT"], [36, 39, "ATT"], [37, 39, "ATT"], [38, 37, "RAD"], [39, 33, "VOB"], [40, 33, "WP"], [41, 44, "ADV"], [42, 44, "WP"], [43, 44, "ADV"], [44, 33, "COO"], [45, 44, "CMP"], [46, 44, "WP"], [47, 48, "SBV"], [48, 55, "ATT"], [49, 48, "RAD"], [50, 51, "POB"], [51, 48, "ADV"], [52, 51, "POB"], [53, 48, "RAD"], [54, 55, "ATT"], [55, 44, "SBV"], [56, 44, "WP"], [57, 44, "ADV"], [58, 59, "SBV"], [59, 44, "ADV"], [60, 44, "COO"], [61, 44, "WP"], [62, 63, "SBV"], [63, 71, "CMP"], [64, 71, "CMP"], [65, 71, "WP"], [66, 71, "ADV"], [67, 71, "WP"], [68, 71, "ADV"], [69, 70, "ATT"], [70, 71, "SBV"], [71, 44, "COO"], [72, 71, "COO"], [73, 71, "WP"], [74, 75, "ATT"], [75, 71, "SBV"], [76, 78, "ADV"], [77, 78, "ADV"], [78, 44, "COO"], [79, 78, "VOB"], [80, 78, "VOB"], [81, 80, "CMP"], [82, 81, "POB"], [83, 78, "WP"], [84, 86, "ATT"], [85, 84, "RAD"], [86, 78, "COO"], [87, 78, "WP"], [88, 44, "COO"], [89, 91, "ADV"], [90, 89, "POB"], [91, 93, "ATT"], [92, 91, "RAD"], [93, 101, "VOB"], [94, 101, "WP"], [95, 101, "CMP"], [96, 97, "LAD"], [97, 101, "VOB"], [98, 101, "ADV"], [99, 101, "ADV"], [100, 99, "POB"], [101, 156, "COO"], [102, 101, "SBV"], [103, 101, "RAD"], [104, 101, "WP"], [105, 109, "ADV"], [106, 107, "ATT"], [107, 105, "POB"], [108, 109, "ADV"], [109, 156, "COO"], [110, 111, "WP"], [111, 109, "COO"], [112, 109, "RAD"], [113, 109, "COO"], [114, 129, "WP"], [115, 129, "ADV"], [116, 119, "ATT"], [117, 119, "ATT"], [118, 117, "RAD"], [119, 120, "ATT"], [120, 115, "POB"], [121, 129, "WP"], [122, 124, "ADV"], [123, 124, "ADV"], [124, 129, "COO"], [125, 124, "RAD"], [126, 129, "COO"], [127, 129, "WP"], [128, 129, "SBV"], [129, 109, "COO"], [130, 129, "VOB"], [131, 129, "WP"], [132, 133, "COO"], [133, 109, "COO"], [134, 109, "RAD"], [135, 109, "ADV"], [136, 137, "ATT"], [137, 109, "SBV"], [138, 109, "WP"], [139, 109, "ADV"], [140, 109, "WP"], [141, 109, "ADV"], [142, 109, "WP"], [143, 109, "WP"], [144, 109, "COO"], [145, 109, "ADV"], [146, 156, "WP"], [147, 156, "SBV"], [148, 156, "ADV"], [149, 151, "ATT"], [150, 151, "ATT"], [151, 156, "VOB"], [152, 156, "WP"], [153, 156, "ADV"], [154, 156, "ADV"], [155, 156, "WP"], [156, 167, "COO"], [157, 158, "ATT"], [158, 167, "VOB"], [159, 160, "WP"], [160, 167, "COO"], [161, 160, "WP"], [162, 163, "ADV"], [163, 167, "COO"], [164, 165, "WP"], [165, 163, "COO"], [166, 163, "ADV"], [167, 27, "ATT"], [168, 167, "RAD"], [169, 172, "ADV"], [170, 172, "WP"], [171, 172, "ADV"], [172, 7, "COO"], [173, 175, "ATT"], [174, 175, "RAD"], [175, 172, "VOB"], [176, 175, "WP"], [177, 175, "RAD"], [178, 175, "ATT"], [179, 181, "ADV"], [180, 181, "ADV"], [181, 6, "COO"], [182, 181, "RAD"], [183, 181, "WP"], [184, 181, "WP"], [185, 190, "SBV"], [186, 190, "SBV"], [187, 190, "WP"], [188, 190, "SBV"], [189, 190, "ADV"], [190, 181, "COO"], [191, 190, "VOB"], [192, 191, "RAD"], [193, 191, "WP"], [194, 195, "ADV"], [195, 204, "CMP"], [196, 204, "VOB"], [197, 204, "WP"], [198, 204, "SBV"], [199, 198, "RAD"], [200, 204, "LAD"], [201, 204, "SBV"], [202, 204, "ADV"], [203, 204, "ADV"], [204, 191, "COO"], [205, 204, "VOB"], [206, 204, "WP"], [207, 204, "ADV"], [208, 209, "SBV"], [209, 191, "ADV"], [210, 209, "WP"], [211, 209, "SBV"], [212, 209, "WP"], [213, 209, "SBV"], [214, 209, "WP"], [215, 216, "ADV"], [216, 218, "ATT"], [217, 216, "RAD"], [218, 209, "SBV"], [219, 209, "ADV"], [220, 191, "ADV"], [221, 191, "ADV"], [222, 181, "COO"], [223, 181, "WP"], [224, 181, "ADV"], [225, 181, "ADV"]], "sdp": [[1, 2, "AGT"], [1, 129, "AGT"], [2, 0, "Root"], [3, 2, "mPUNC"], [4, 7, "mRELA"], [5, 7, "AGT"], [5, 8, "AGT"], [6, 7, "mNEG"], [6, 8, "mNEG"], [7, 2, "dCONT"], [8, 7, "eSUCC"], [9, 8, "LINK"], [10, 8, "mPUNC"], [11, 8, "eSUCC"], [12, 172, "EXP"], [13, 172, "SCO"], [14, 15, "mRELA"], [15, 167, "LOC"], [15, 172, "LOC"], [16, 172, "mDEPD"], [17, 172, "EXP"], [18, 172, "mDEPD"], [19, 172, "mDEPD"], [20, 172, "mNEG"], [21, 172, "AGT"], [22, 172, "SCO"], [23, 172, "EXP"], [24, 172, "EXP"], [25, 172, "MANN"], [26, 172, "mDEPD"], [27, 172, "CONT"], [28, 172, "mPUNC"], [29, 33, "mDEPD"], [30, 33, "AGT"], [31, 33, "mDEPD"], [32, 33, "mDEPD"], [33, 172, "eSUCC"], [34, 33, "mDEPD"], [35, 39, "FEAT"], [36, 39, "SCO"], [37, 39, "rEXP"], [38, 37, "mDEPD"], [39, 33, "CONT"], [40, 33, "mPUNC"], [41, 44, "LOC"], [42, 44, "mPUNC"], [43, 44, "mRELA"], [44, 33, "eSUCC"], [45, 44, "TIME"], [46, 44, "mPUNC"], [47, 48, "AGT"], [47, 60, "PAT"], [47, 204, "AGT"], [48, 55, "rDATV"], [49, 48, "mDEPD"], [50, 48, "LOC"], [51, 50, "mRELA"], [52, 50, "FEAT"], [53, 48, "mDEPD"], [54, 55, "MEAS"], [55, 44, "EXP"], [56, 44, "mPUNC"], [57, 44, "eCOO"], [58, 59, "EXP"], [59, 44, "eSUCC"], [60, 44, "eSUCC"], [61, 60, "mPUNC"], [62, 60, "PAT"], [63, 60, "eSUCC"], [64, 63, "mDEPD"], [65, 71, "mPUNC"], [66, 71, "TIME"], [67, 66, "mPUNC"], [68, 71, "mDEPD"], [69, 70, "MEAS"], [70, 71, "AGT"], [71, 60, "eCOO"], [72, 71, "dCONT"], [73, 72, "mPUNC"], [74, 75, "MEAS"], [75, 72, "AGT"], [76, 78, "mDEPD"], [77, 78, "mDEPD"], [78, 44, "eSUCC"], [79, 78, "dCONT"], [80, 79, "LINK"], [81, 79, "eCOO"], [82, 81, "TIME"], [83, 91, "mPUNC"], [84, 91, "LOC"], [85, 91, "mDEPD"], [86, 88, "EXP"], [87, 88, "mPUNC"], [88, 91, "mDEPD"], [89, 90, "mRELA"], [90, 91, "LOC"], [91, 79, "eSUCC"], [92, 91, "mDEPD"], [93, 79, "EXP"], [94, 93, "mPUNC"], [95, 93, "FEAT"], [96, 97, "mRELA"], [97, 93, "eCOO"], [98, 78, "mDEPD"], [99, 100, "mRELA"], [100, 101, "MANN"], [101, 78, "dCONT"], [102, 107, "FEAT"], [102, 109, "SCO"], [103, 109, "mDEPD"], [104, 109, "mPUNC"], [105, 107, "mRELA"], [106, 107, "FEAT"], [107, 109, "SCO"], [108, 109, "mDEPD"], [109, 101, "ePREC"], [110, 109, "mPUNC"], [111, 109, "eSUCC"], [112, 109, "mDEPD"], [113, 109, "eSUCC"], [114, 129, "mPUNC"], [115, 119, "mRELA"], [116, 119, "SCO"], [117, 119, "FEAT"], [118, 117, "mDEPD"], [119, 124, "STAT"], [120, 119, "mDEPD"], [121, 119, "mPUNC"], [122, 124, "mDEPD"], [123, 124, "mDEPD"], [124, 129, "dCONT"], [125, 124, "mDEPD"], [126, 129, "dCONT"], [127, 129, "mPUNC"], [128, 129, "AGT"], [129, 109, "eSUCC"], [130, 129, "dCONT"], [131, 129, "mPUNC"], [132, 109, "ePREC"], [133, 109, "eSUCC"], [134, 109, "mDEPD"], [135, 109, "SCO"], [136, 137, "MEAS"], [137, 109, "FEAT"], [138, 109, "mPUNC"], [139, 109, "FEAT"], [140, 109, "mPUNC"], [141, 109, "FEAT"], [142, 109, "mPUNC"], [143, 8, "mPUNC"], [143, 109, "mPUNC"], [144, 109, "eSUCC"], [145, 160, "mDEPD"], [146, 160, "mPUNC"], [147, 160, "eSUCC"], [148, 147, "mDEPD"], [149, 147, "MEAS"], [150, 151, "MEAS"], [151, 147, "TIME"], [152, 147, "mPUNC"], [153, 156, "mRELA"], [154, 156, "mRELA"], [155, 156, "mPUNC"], [156, 160, "mDEPD"], [157, 158, "MEAS"], [158, 156, "LINK"], [159, 156, "mPUNC"], [160, 109, "eSUCC"], [161, 160, "mPUNC"], [162, 163, "mDEPD"], [163, 160, "dEXP"], [164, 165, "mPUNC"], [165, 160, "eCOO"], [166, 167, "mRELA"], [167, 165, "dEXP"], [168, 167, "mDEPD"], [169, 167, "SCO"], [170, 160, "mPUNC"], [171, 172, "TIME"], [172, 11, "dCONT"], [173, 8, "MEAS"], [174, 175, "mDEPD"], [175, 8, "eSUCC"], [176, 175, "mPUNC"], [177, 181, "mDEPD"], [178, 181, "EXP"], [179, 181, "mDEPD"], [180, 181, "mDEPD"], [181, 2, "dCONT"], [182, 44, "mDEPD"], [182, 209, "mDEPD"], [183, 209, "mPUNC"], [184, 209, "mPUNC"], [185, 44, "AGT"], [185, 209, "EXP"], [186, 185, "eCOO"], [187, 209, "mPUNC"], [188, 191, "MEAS"], [189, 191, "mDEPD"], [190, 191, "eSUCC"], [191, 209, "dEXP"], [192, 204, "mDEPD"], [193, 204, "mPUNC"], [194, 195, "SCO"], [195, 204, "FEAT"], [196, 204, "CONT"], [197, 204, "mPUNC"], [198, 204, "AGT"], [199, 48, "mDEPD"], [199, 198, "mDEPD"], [200, 204, "mRELA"], [201, 204, "AGT"], [202, 204, "mDEPD"], [203, 204, "eCOO"], [204, 209, "ePREC"], [205, 204, "CONT"], [206, 204, "mPUNC"], [207, 204, "mDEPD"], [208, 204, "LOC"], [209, 181, "eSUCC"], [210, 209, "mPUNC"], [211, 209, "EXP"], [212, 209, "mPUNC"], [213, 209, "EXP"], [214, 209, "mPUNC"], [215, 216, "mDEPD"], [216, 218, "FEAT"], [217, 37, "mDEPD"], [217, 216, "mDEPD"], [218, 209, "EXP"], [219, 209, "mDEPD"], [220, 221, "mRELA"], [221, 209, "LOC"], [222, 181, "eSUCC"], [223, 181, "mPUNC"], [224, 181, "mRELA"], [225, 181, "SCO"]]}

緊接着,調用相應的mask策略對數據進行處理,處理後的數據樣例如下:

[['[CLS]', '我', '想', ',', '如', '果', '我', '沒', '有', '去', '做', '大', '學', '生', '村', '官', ',', '恐', '怕', '我', '這', '個', '在', '昆', '明', '長', '大', '的', '孩', '子', '永', '遠', '都', '不', '能', '切', '身', '感', '受', '到', '雲', '南', '這', '次', '6', '0', '年', '一', '遇', '的', '特', '大', '旱', '情', '的', '嚴', '重', '性', ',', '恐', '怕', '[sdp]', '我', '[sdp]', '只', '是', '每', '天', '[sdp]', '看', '[sdp]', '着', '新', '聞', '上', '那', '些', '缺', '水', '的', '鏡', '頭', ',', '嘴', '上', '說', '要', '節', '水', ',', '但', '事', '實', '行', '動', '保', '持', '不', '了', '三', '天', '。', '我', '任', '職', '的', '地', '方', '在', '昆', '明', '市', '祿', '勸', '縣', '的', '一', '個', '村', '委', '會', ',', '說', '實', '話', '這', '裏', '[SEP]'], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ['昆明長大', '雲南', '昆明市祿勸縣']]

預訓練腳本

數據處理完畢之後,就可以調用預訓練腳本進行模型的預訓練,腳本如下:

gpu_number=1
negative_e_number=4
negative_e_length=16

base_dir=$PWD
checkpoint_dir=$base_dir/checkpoints
resources=$base_dir/resources
local_kg=$resources/ownthink_triples_small.txt
local_train_file=$resources/train_small.txt
remote_kg=https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/ckbert/ownthink_triples_small.txt
remote_train_file=https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/ckbert/train_small.txt

if [ ! -d $checkpoint_dir ];then
mkdir $checkpoint_dir
fi

if [ ! -d $resources ];then
mkdir $resources
fi

if [ ! -f $local_kg ];then
wget -P $resources $remote_kg
fi

if [ ! -f $local_train_file ];then
wget -P $resources $remote_train_file
fi

python -m torch.distributed.launch --nproc_per_node=$gpu_number \
--master_port=52349 \
$base_dir/main.py \
--mode=train \
--worker_gpu=$gpu_number \
--tables=$local_train_file, \
--learning_rate=5e-5  \
--epoch_num=5  \
--logging_steps=10 \
--save_checkpoint_steps=2150 \
--sequence_length=256 \
--train_batch_size=20 \
--checkpoint_dir=$checkpoint_dir \
--app_name=language_modeling \
--use_amp \
--save_all_checkpoints \
--user_defined_parameters="pretrain_model_name_or_path=hfl/macbert-base-zh external_mask_flag=True contrast_learning_flag=True negative_e_number=${negative_e_number} negative_e_length=${negative_e_length} kg_path=${local_kg}"

模型Finetune

CKBERT模型與BERT是同樣的架構,只需要使用通用的EasyNLP框架命令就可以進行調用。以下命令分別爲Train和Predict狀態的例子,使用的模型爲ckbert-base。

當前在EasyNLP框架中也可以調用large和huge模型進行測試,只需要替換命令中的參數即可

  • pretrain_model_name_or_path=alibaba-pai/pai-ckbert-large-zh
  • pretrain_model_name_or_path=alibaba-pai/pai-ckbert-huge-zh
$ easynlp \
   --mode=train \
   --worker_gpu=1 \
   --tables=train.tsv,dev.tsv \
   --input_schema=label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1 \
   --first_sequence=sent1 \
   --label_name=label \
   --label_enumerate_values=0,1 \
   --checkpoint_dir=./classification_model \
   --epoch_num=1  \
   --sequence_length=128 \
   --app_name=text_classify \
   --user_defined_parameters='pretrain_model_name_or_path=alibaba-pai/pai-ckbert-base-zh'
$ easynlp \
  --mode=predict \
  --tables=dev.tsv \
  --outputs=dev.pred.tsv \
  --input_schema=label:str:1,sid1:str:1,sid2:str:1,sent1:str:1,sent2:str:1 \
  --output_schema=predictions,probabilities,logits,output \
  --append_cols=label \
  --first_sequence=sent1 \
  --checkpoint_path=./classification_model \
  --app_name=text_classify

在HuggingFace上使用CKBERT模型

爲了方便開源用戶使用CKBERT,我們也將三個CKBERT模型在HuggingFace Models上架,其Model Card如下所示:

用戶也可以直接使用HuggingFace提供的pipeline進行模型推理,樣例如下:

from transformers import AutoTokenizer, AutoModelForMaskedLM, FillMaskPipeline

tokenizer = AutoTokenizer.from_pretrained("alibaba-pai/pai-ckbert-base-zh", use_auth_token=True)
model = AutoModelForMaskedLM.from_pretrained("alibaba-pai/pai-ckbert-base-zh", use_auth_token=True)
unmasker = FillMaskPipeline(model, tokenizer)   
unmasker("巴黎是[MASK]國的首都。",top_k=5)

[
    {'score': 0.8580496311187744, 
     'token': 3791, 
     'token_str': '法', 
     'sequence': '巴 黎 是 法 國 的 首 都 。'}, 
    {'score': 0.08550138026475906, 
     'token': 2548, 
     'token_str': '德', 
     'sequence': '巴 黎 是 德 國 的 首 都 。'}, 
    {'score': 0.023137662559747696, 
     'token': 5401, 
     'token_str': '美', 
     'sequence': '巴 黎 是 美 國 的 首 都 。'}, 
    {'score': 0.012281022034585476, 
     'token': 5739, 'token_str': '英', 
     'sequence': '巴 黎 是 英 國 的 首 都 。'}, 
    {'score': 0.005729076452553272, 
     'token': 704, 'token_str': '中', 
     'sequence': '巴 黎 是 中 國 的 首 都 。'}
]

或者也可以使用Pytorch加載模型,樣例如下:

from transformers import AutoTokenizer, AutoModelForMaskedLM

tokenizer = AutoTokenizer.from_pretrained("alibaba-pai/pai-ckbert-base-zh", use_auth_token=True)
model = AutoModelForMaskedLM.from_pretrained("alibaba-pai/pai-ckbert-base-zh", use_auth_token=True)
text = "巴黎是[MASK]國的首都。"
encoded_input = tokenizer(text, return_tensors='pt')
output = model(**encoded_input)

在阿里雲機器學習平臺PAI上使用CKBERT模型

PAI-DSW(Data Science Workshop)是阿里雲機器學習平臺PAI開發的雲上IDE,面向不同水平的開發者,提供了交互式的編程環境(文檔)。在DSW Gallery中,提供了各種Notebook示例,方便用戶輕鬆上手DSW,搭建各種機器學習應用。我們也在DSW Gallery中上架了使用CKBERT進行中文命名實體識別的Sample Notebook(見下圖),歡迎大家體驗!

未來展望

在未來,我們計劃在EasyNLP框架中集成更多中⽂知識模型,覆蓋各個常⻅中⽂領域,敬請期待。我們也將在EasyNLP框架中集成更多SOTA模型(特別是中⽂模型),來⽀持各種NLP和多模態任務。此外, 阿⾥雲機器學習PAI團隊也在持續推進中⽂多模態模型的⾃研⼯作,歡迎⽤戶持續關注我們,也歡迎加⼊ 我們的開源社區,共建中⽂NLP和多模態算法庫!

Github地址:https://github.com/alibaba/EasyNLP

Reference

  1. Chengyu Wang, Minghui Qiu, Taolin Zhang, Tingting Liu, Lei Li, Jianing Wang, Ming Wang, Jun Huang, Wei Lin. EasyNLP: A Comprehensive and Easy-to-use Toolkit for Natural Language Processing. EMNLP 2022
  2. Taolin Zhang, Junwei Dong, Jianing Wang, Chengyu Wang, Ang Wang, Yinghui Liu, Jun Huang, Yong Li, Xiaofeng He. Revisiting and Advancing Chinese Natural Language Understanding with Accelerated Heterogeneous Knowledge Pre-training. EMNLP 2022
  3. Yiming Cui, Wanxiang Che, Ting Liu, Bing Qin, Shijin Wang, Guoping Hu. Revisiting Pre-Trained Models for Chinese Natural Language Processing. EMNLP (Findings) 2020
  4. Yiming Cui, Ziqing Yang, Ting Liu. PERT: Pre-training BERT with Permuted Language Model. arXiv
  5. Yu Sun, Shuohuan Wang, Yukun Li, Shikun Feng, Xuyi Chen, Han Zhang, Xin Tian, Danxiang Zhu, Hao Tian, Hua Wu. ERNIE: Enhanced Representation through Knowledge Integration. arXiv
  6. Yuxuan Lai, Yijia Liu, Yansong Feng, Songfang Huang, and Dongyan Zhao. Lattice-BERT: Leveraging Multi-Granularity Representations in Chinese Pre-trained Language Models. NAACL 2021
  7. Weijie Liu, Peng Zhou, Zhe Zhao, Zhiruo Wang, Qi Ju, Haotang Deng, Ping Wang. K-BERT: Enabling Language Representation with Knowledge Graph. AAAI 2020
  8. Zhengyan Zhang, Xu Han, Zhiyuan Liu, Xin Jiang, Maosong Sun, Qun Liu. ERNIE: Enhanced Language Representation with Informative Entities. ACL 2019

阿里靈傑回顧

原文鏈接:https://click.aliyun.com/m/1000362245/

本文爲阿里雲原創內容,未經允許不得轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章