主頁 >  其他 > 自然語言處理 Paddle NLP - 情感分析技術及應用SKEP-實踐

自然語言處理 Paddle NLP - 情感分析技術及應用SKEP-實踐

2023-06-22 07:51:11 其他

Part A. 情感分析任務

眾所周知,人類自然語言中包含了豐富的情感色彩:表達人的情緒(如悲傷、快樂)、表達人的心情(如倦怠、憂郁)、表達人的喜好(如喜歡、討厭)、表達人的個性特征和表達人的立場等等,情感分析在商品喜好、消費決策、輿情分析等場景中均有應用,利用機器自動分析這些情感傾向,不但有助于幫助企業了解消費者對其產品的感受,為產品改進提供依據;同時還有助于企業分析商業伙伴們的態度,以便更好地進行商業決策,

被人們所熟知的情感分析任務是將一段文本分類,如分為情感極性為正向負向其他的三分類問題:



情感分析任務

  • 正向: 表示正面積極的情感,如高興,幸福,驚喜,期待等,
  • 負向: 表示負面消極的情感,如難過,傷心,憤怒,驚恐等,
  • 其他: 其他型別的情感,

實際上,以上熟悉的情感分析任務是句子級情感分析任務

情感分析任務還可以進一步分為句子級情感分析目標級情感分析等任務,在下面章節將會詳細介紹兩種任務及其應用場景,

Part B. 情感分析預訓練模型SKEP

近年來,大量的研究表明基于大型語料庫的預訓練模型(Pretrained Models, PTM)可以學習通用的語言表示,有利于下游NLP任務,同時能夠避免從零開始訓練模型,隨著計算能力的發展,深度模型的出現(即 Transformer)和訓練技巧的增強使得 PTM 不斷發展,由淺變深,

情感預訓練模型SKEP(Sentiment Knowledge Enhanced Pre-training for Sentiment Analysis),SKEP利用情感知識增強預訓練模型, 在14項中英情感分析典型任務上全面超越SOTA,此作業已經被ACL 2020錄用,SKEP是百度研究團隊提出的基于情感知識增強的情感預訓練演算法,此演算法采用無監督方法自動挖掘情感知識,然后利用情感知識構建預訓練目標,從而讓機器學會理解情感語意,SKEP為各類情感分析任務提供統一且強大的情感語意表示,

論文地址:https://arxiv.org/abs/2005.05635


百度研究團隊在三個典型情感分析任務,句子級情感分類(Sentence-level Sentiment Classification),評價目標級情感分類(Aspect-level Sentiment Classification)、觀點抽取(Opinion Role Labeling),共計14個中英文資料上進一步驗證了情感預訓練模型SKEP的效果,

具體實驗效果參考:https://github.com/baidu/Senta#skep

Part C 句子級情感分析 & 目標級情感分析

Part C.1 句子級情感分析

對給定的一段文本進行情感極性分類,常用于影評分析、網路論壇輿情分析等場景,如:

選擇珠江花園的原因就是方便,有電動扶梯直接到達海邊,周圍餐館、食廊、商場、超市、攤位一應俱全,酒店裝修一般,但還算整潔, 泳池在大堂的屋頂,因此很小,不過女兒倒是喜歡, 包的早餐是西式的,還算豐富, 服務嗎,一般	1
15.4寸筆記本的鍵盤確實爽,基本跟臺式機差不多了,蠻喜歡數字小鍵盤,輸數字特方便,樣子也很美觀,做工也相當不錯	1
房間太小,其他的都一般,,,,,,,,,	0

其中1表示正向情感,0表示負向情感,




句子級情感分析任務

常用資料集

ChnSenticorp資料集是公開中文情感分析常用資料集, 其為2分類資料集,PaddleNLP已經內置該資料集,一鍵即可加載,

from paddlenlp.datasets import load_dataset

train_ds, dev_ds, test_ds = load_dataset("chnsenticorp", splits=["train", "dev", "test"])

print(train_ds[0])
print(train_ds[1])
print(train_ds[:10])
100%|██████████| 1909/1909 [00:00<00:00, 37287.30it/s]
{'text': '選擇珠江花園的原因就是方便,有電動扶梯直接到達海邊,周圍餐館、食廊、商場、超市、攤位一應俱全,酒店裝修一般,但還算整潔, 泳池在大堂的屋頂,因此很小,不過女兒倒是喜歡, 包的早餐是西式的,還算豐富, 服務嗎,一般', 'label': 1, 'qid': ''}

{'text': '15.4寸筆記本的鍵盤確實爽,基本跟臺式機差不多了,蠻喜歡數字小鍵盤,輸數字特方便,樣子也很美觀,做工也相當不錯', 'label': 1, 'qid': ''}

[{'text': '選擇珠江花園的原因就是方便,有電動扶梯直接到達海邊,周圍餐館、食廊、商場、超市、攤位一應俱全,酒店裝修一般,但還算整潔, 泳池在大堂的屋頂,因此很小,不過女兒倒是喜歡, 包的早餐是西式的,還算豐富, 服務嗎,一般', 'label': 1, 'qid': ''}, {'text': '15.4寸筆記本的鍵盤確實爽,基本跟臺式機差不多了,蠻喜歡數字小鍵盤,輸數字特方便,樣子也很美觀,做工也相當不錯', 'label': 1, 'qid': ''}, {'text': '房間太小,其他的都一般,,,,,,,,,', 'label': 0, 'qid': ''}, {'text': '1.接電源沒有幾分鐘,電源配接器熱的不行. 2.攝像頭用不起來. 3.機蓋的鋼琴漆,手不能摸,一摸一個印. 4.硬碟磁區不好辦.', 'label': 0, 'qid': ''}, {'text': '今天才知道這書還有第6卷,真有點郁悶:為什么同一套書有兩種版本呢?當當網是不是該跟出版社商量商量,單獨出個第6卷,讓我們的孩子不會有所遺憾,', 'label': 1, 'qid': ''}, {'text': '機器背面似乎被撕了張什么標簽,殘膠還在,但是又看不出是什么標簽不見了,該有的都在,怪', 'label': 0, 'qid': ''}, {'text': '呵呵,雖然表皮看上去不錯很精致,但是我還是能看得出來是盜的,但是里面的內容真的不錯,我媽愛看,我自己也學著找一些穴位,', 'label': 0, 'qid': ''}, {'text': '這本書實在是太爛了,以前聽浙大的老師說這本書怎么怎么不對,哪些地方都是誤導的還不相信,終于買了一本看一下,發現真是~~~無語,這種書都寫得出來', 'label': 0, 'qid': ''}, {'text': '地理位置佳,在市中心,酒店服務好、早餐品種豐富,我住的商務數碼房電腦寬帶速度滿意,房間還算干凈,離湖南路小吃街近,', 'label': 1, 'qid': ''}, {'text': '5.1期間在這住的,位置還可以,在市委市政府附近,要去商業區和步行街得打車,屋里有蚊子,雖然空間挺大,晚上熄燈后把窗簾拉上簡直是伸手不見五指,很適合睡覺,但是會被該死的蚊子吵醒!打死了兩只,第二天早上還是發現又沒打死的,衛生間挺大,但是設備很老舊,', 'label': 1, 'qid': ''}]

SKEP模型加載

PaddleNLP已經實作了SKEP預訓練模型,可以通過一行代碼實作SKEP加載,

句子級情感分析模型是SKEP fine-tune 文本分類常用模型SkepForSequenceClassification,其首先通過SKEP提取句子語意特征,之后將語意特征進行分類,

from paddlenlp.transformers import SkepForSequenceClassification, SkepTokenizer

# 指定模型名稱,一鍵加載模型
model = SkepForSequenceClassification.from_pretrained(pretrained_model_name_or_path="skep_ernie_1.0_large_ch", num_classes=len(train_ds.label_list))
# 同樣地,通過指定模型名稱一鍵加載對應的Tokenizer,用于處理文本資料,如切分token,轉token_id等,
tokenizer = SkepTokenizer.from_pretrained(pretrained_model_name_or_path="skep_ernie_1.0_large_ch")
[2023-06-09 11:33:08,208] [    INFO] - Downloading https://paddlenlp.bj.bcebos.com/models/transformers/skep/skep_ernie_1.0_large_ch.pdparams and saved to /home/aistudio/.paddlenlp/models/skep_ernie_1.0_large_ch
[2023-06-09 11:33:08,211] [    INFO] - Downloading skep_ernie_1.0_large_ch.pdparams from https://paddlenlp.bj.bcebos.com/models/transformers/skep/skep_ernie_1.0_large_ch.pdparams
100%|██████████| 1238309/1238309 [00:30<00:00, 40700.73it/s]
W0609 11:33:38.774677   148 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 8.0, Driver API Version: 11.2, Runtime API Version: 11.2
W0609 11:33:38.778790   148 device_context.cc:465] device: 0, cuDNN Version: 8.2.
[2023-06-09 11:33:46,676] [    INFO] - Downloading https://paddlenlp.bj.bcebos.com/models/transformers/skep/skep_ernie_1.0_large_ch.vocab.txt and saved to /home/aistudio/.paddlenlp/models/skep_ernie_1.0_large_ch
[2023-06-09 11:33:46,679] [    INFO] - Downloading skep_ernie_1.0_large_ch.vocab.txt from https://paddlenlp.bj.bcebos.com/models/transformers/skep/skep_ernie_1.0_large_ch.vocab.txt
100%|██████████| 55/55 [00:00<00:00, 5570.66it/s]

SkepForSequenceClassification可用于句子級情感分析和目標級情感分析任務,其通過預訓練模型SKEP獲取輸入文本的表示,之后將文本表示進行分類,

  • pretrained_model_name_or_path:模型名稱,支持"skep_ernie_1.0_large_ch","skep_ernie_2.0_large_en",

    • "skep_ernie_1.0_large_ch":是SKEP模型在預訓練ernie_1.0_large_ch基礎之上在海量中文資料上繼續預訓練得到的中文預訓練模型;
    • "skep_ernie_2.0_large_en":是SKEP模型在預訓練ernie_2.0_large_en基礎之上在海量英文資料上繼續預訓練得到的英文預訓練模型;
  • num_classes: 資料集分類類別數,

關于SKEP模型實作詳細資訊參考:https://github.com/PaddlePaddle/PaddleNLP/tree/develop/paddlenlp/transformers/skep

資料處理

同樣地,我們需要將原始ChnSentiCorp資料處理成模型可以讀入的資料格式,

SKEP模型對中文文本處理按照字粒度進行處理,我們可以使用PaddleNLP內置的SkepTokenizer完成一鍵式處理,

import os
from functools import partial


import numpy as np
import paddle
import paddle.nn.functional as F
from paddlenlp.data import Stack, Tuple, Pad

from utils import create_dataloader

def convert_example(example,
                    tokenizer,
                    max_seq_length=512,
                    is_test=False):
    """
    Builds model inputs from a sequence or a pair of sequence for sequence classification tasks
    by concatenating and adding special tokens. And creates a mask from the two sequences passed 
    to be used in a sequence-pair classification task.
        
    A skep_ernie_1.0_large_ch/skep_ernie_2.0_large_en sequence has the following format:
    ::
        - single sequence: ``[CLS] X [SEP]``
        - pair of sequences: ``[CLS] A [SEP] B [SEP]``

    A skep_ernie_1.0_large_ch/skep_ernie_2.0_large_en sequence pair mask has the following format:
    ::

        0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
        | first sequence    | second sequence |

    If `token_ids_1` is `None`, this method only returns the first portion of the mask (0s).


    Args:
        example(obj:`list[str]`): List of input data, containing text and label if it have label.
        tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer` 
            which contains most of the methods. Users should refer to the superclass for more information regarding methods.
        max_seq_len(obj:`int`): The maximum total input sequence length after tokenization. 
            Sequences longer than this will be truncated, sequences shorter will be padded.
        is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.

    Returns:
        input_ids(obj:`list[int]`): The list of token ids.
        token_type_ids(obj: `list[int]`): List of sequence pair mask.
        label(obj:`int`, optional): The input label if not is_test.
    """
    # 將原資料處理成model可讀入的格式,enocded_inputs是一個dict,包含input_ids、token_type_ids等欄位
    encoded_inputs = tokenizer(
        text=example["text"], max_seq_len=max_seq_length)

    # input_ids:對文本切分token后,在詞匯表中對應的token id
    input_ids = encoded_inputs["input_ids"]
    # token_type_ids:當前token屬于句子1還是句子2,即上述圖中表達的segment ids
    token_type_ids = encoded_inputs["token_type_ids"]

    if not is_test:
        # label:情感極性類別
        label = np.array([example["label"]], dtype="int64")
        return input_ids, token_type_ids, label
    else:
        # qid:每條資料的編號
        qid = np.array([example["qid"]], dtype="int64")
        return input_ids, token_type_ids, qid
# 批量資料大小
batch_size = 32
# 文本序列最大長度
max_seq_length = 256

# 將資料處理成模型可讀入的資料格式
trans_func = partial(
    convert_example,
    tokenizer=tokenizer,
    max_seq_length=max_seq_length)

# 將資料組成批量式資料,如
# 將不同長度的文本序列padding到批量式資料中最大長度
# 將每條資料label堆疊在一起
batchify_fn = lambda samples, fn=Tuple(
    Pad(axis=0, pad_val=tokenizer.pad_token_id),  # input_ids
    Pad(axis=0, pad_val=tokenizer.pad_token_type_id),  # token_type_ids
    Stack()  # labels
): [data for data in fn(samples)]
train_data_loader = create_dataloader(
    train_ds,
    mode='train',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)
dev_data_loader = create_dataloader(
    dev_ds,
    mode='dev',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)

模型訓練和評估

定義損失函式、優化器以及評價指標后,即可開始訓練,

推薦超參設定:

  • max_seq_length=256
  • batch_size=48
  • learning_rate=2e-5
  • epochs=10

實際運行時可以根據顯存大小調整batch_size和max_seq_length大小,

import time

from utils import evaluate

# 訓練輪次
epochs = 1
# 訓練程序中保存模型引數的檔案夾
ckpt_dir = "skep_ckpt"
# len(train_data_loader)一輪訓練所需要的step數
num_training_steps = len(train_data_loader) * epochs

# Adam優化器
optimizer = paddle.optimizer.AdamW(
    learning_rate=2e-5,
    parameters=model.parameters())
# 交叉熵損失函式
criterion = paddle.nn.loss.CrossEntropyLoss()
# accuracy評價指標
metric = paddle.metric.Accuracy()
# 開啟訓練
global_step = 0
tic_train = time.time()
for epoch in range(1, epochs + 1):
    for step, batch in enumerate(train_data_loader, start=1):
        input_ids, token_type_ids, labels = batch
        # 喂資料給model
        logits = model(input_ids, token_type_ids)
        # 計算損失函式值
        loss = criterion(logits, labels)
        # 預測分類概率值
        probs = F.softmax(logits, axis=1)
        # 計算acc
        correct = metric.compute(probs, labels)
        metric.update(correct)
        acc = metric.accumulate()

        global_step += 1
        if global_step % 10 == 0:
            print(
                "global step %d, epoch: %d, batch: %d, loss: %.5f, accu: %.5f, speed: %.2f step/s"
                % (global_step, epoch, step, loss, acc,
                    10 / (time.time() - tic_train)))
            tic_train = time.time()
        
        # 反向梯度回傳,更新引數
        loss.backward()
        optimizer.step()
        optimizer.clear_grad()

        if global_step % 100 == 0:
            save_dir = os.path.join(ckpt_dir, "model_%d" % global_step)
            if not os.path.exists(save_dir):
                os.makedirs(save_dir)
            # 評估當前訓練的模型
            evaluate(model, criterion, metric, dev_data_loader)
            # 保存當前模型引數等
            model.save_pretrained(save_dir)
            # 保存tokenizer的詞表等
            tokenizer.save_pretrained(save_dir)
global step 10, epoch: 1, batch: 10, loss: 0.68203, accu: 0.56875, speed: 2.49 step/s
global step 20, epoch: 1, batch: 20, loss: 0.67362, accu: 0.60313, speed: 3.92 step/s
global step 30, epoch: 1, batch: 30, loss: 0.32944, accu: 0.67812, speed: 3.74 step/s
global step 40, epoch: 1, batch: 40, loss: 0.23817, accu: 0.73203, speed: 3.60 step/s
global step 50, epoch: 1, batch: 50, loss: 0.22706, accu: 0.76812, speed: 3.69 step/s
global step 60, epoch: 1, batch: 60, loss: 0.32217, accu: 0.79010, speed: 3.65 step/s
global step 70, epoch: 1, batch: 70, loss: 0.38290, accu: 0.80848, speed: 3.99 step/s
global step 80, epoch: 1, batch: 80, loss: 0.32560, accu: 0.81914, speed: 3.81 step/s
global step 90, epoch: 1, batch: 90, loss: 0.28812, accu: 0.83090, speed: 3.69 step/s
global step 100, epoch: 1, batch: 100, loss: 0.08818, accu: 0.83906, speed: 3.68 step/s
eval loss: 0.22184, accu: 0.91250
global step 110, epoch: 1, batch: 110, loss: 0.19725, accu: 0.90312, speed: 1.06 step/s
global step 120, epoch: 1, batch: 120, loss: 0.13100, accu: 0.90781, speed: 3.58 step/s
global step 130, epoch: 1, batch: 130, loss: 0.19981, accu: 0.90833, speed: 3.68 step/s
global step 140, epoch: 1, batch: 140, loss: 0.15833, accu: 0.90938, speed: 3.77 step/s
global step 150, epoch: 1, batch: 150, loss: 0.11410, accu: 0.91563, speed: 3.76 step/s
global step 160, epoch: 1, batch: 160, loss: 0.22827, accu: 0.91771, speed: 3.78 step/s
global step 170, epoch: 1, batch: 170, loss: 0.13842, accu: 0.91652, speed: 3.62 step/s
global step 180, epoch: 1, batch: 180, loss: 0.03657, accu: 0.91992, speed: 3.88 step/s
global step 190, epoch: 1, batch: 190, loss: 0.20643, accu: 0.91840, speed: 3.65 step/s
global step 200, epoch: 1, batch: 200, loss: 0.40149, accu: 0.91750, speed: 3.84 step/s
eval loss: 0.19440, accu: 0.93083

預測提交結果

使用訓練得到的模型還可以對文本進行情感預測,

import numpy as np
import paddle

# 處理測驗集資料
trans_func = partial(
    convert_example,
    tokenizer=tokenizer,
    max_seq_length=max_seq_length,
    is_test=True)
batchify_fn = lambda samples, fn=Tuple(
    Pad(axis=0, pad_val=tokenizer.pad_token_id),  # input
    Pad(axis=0, pad_val=tokenizer.pad_token_type_id),  # segment
    Stack() # qid
): [data for data in fn(samples)]
test_data_loader = create_dataloader(
    test_ds,
    mode='test',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)
# 根據實際運行情況,更換加載的引數路徑
params_path = 'skep_ckp/model_500/model_state.pdparams'
if params_path and os.path.isfile(params_path):
    # 加載模型引數
    state_dict = paddle.load(params_path)
    model.set_dict(state_dict)
    print("Loaded parameters from %s" % params_path)
label_map = {0: '0', 1: '1'}
results = []
# 切換model模型為評估模式,關閉dropout等隨機因素
model.eval()
for batch in test_data_loader:
    input_ids, token_type_ids, qids = batch
    # 喂資料給模型
    logits = model(input_ids, token_type_ids)
    # 預測分類
    probs = F.softmax(logits, axis=-1)
    idx = paddle.argmax(probs, axis=1).numpy()
    idx = idx.tolist()
    labels = [label_map[i] for i in idx]
    qids = qids.numpy().tolist()
    results.extend(zip(qids, labels))
res_dir = "./results"
if not os.path.exists(res_dir):
    os.makedirs(res_dir)
# 寫入預測結果
with open(os.path.join(res_dir, "ChnSentiCorp.tsv"), 'w', encoding="utf8") as f:
    f.write("index\tprediction\n")
    for qid, label in results:
        f.write(str(qid[0])+"\t"+label+"\n")

Part C.2 目標級情感分析

在電商產品分析場景下,除了分析整體商品的情感極性外,還細化到以商品具體的“方面”為分析主體進行情感分析(aspect-level),如下、:

  • 這個薯片口味有點咸,太辣了,不過口感很脆,

關于薯片的口味方面是一個負向評價(咸,太辣),然而對于口感方面卻是一個正向評價(很脆),

  • 我很喜歡夏威夷,就是這邊的海鮮太貴了,

關于夏威夷是一個正向評價(喜歡),然而對于夏威夷的海鮮卻是一個負向評價(價格太貴),




目標級情感分析任務

#### 常用資料集

千言資料集已提供了許多任務常用資料集,
其中情感分析資料集下載鏈接:https://aistudio.baidu.com/aistudio/competition/detail/50/?isFromLUGE=TRUE

SE-ABSA16_PHNS資料集是關于手機的目標級情感分析資料集,PaddleNLP已經內置了該資料集,加載方式,如下:

train_ds, test_ds = load_dataset("seabsa16", "phns", splits=["train", "test"])

print(train_ds[0])
print(train_ds[1])
print(train_ds[2])

SKEP模型加載

目標級情感分析模型同樣使用SkepForSequenceClassification模型,但目標級情感分析模型的輸入不單單是一個句子,而是句對,一個句子描述“評價物件方面(aspect)”,另一個句子描述"對該方面的評論",如下圖所示,

# 指定模型名稱一鍵加載模型
model = SkepForSequenceClassification.from_pretrained(
    'skep_ernie_1.0_large_ch', num_classes=len(train_ds.label_list))
# 指定模型名稱一鍵加載tokenizer
tokenizer = SkepTokenizer.from_pretrained('skep_ernie_1.0_large_ch')

資料處理

同樣地,我們需要將原始SE_ABSA16_PHNS資料處理成模型可以讀入的資料格式,

SKEP模型對中文文本處理按照字粒度進行處理,我們可以使用PaddleNLP內置的SkepTokenizer完成一鍵式處理,

from functools import partial
import os
import time

import numpy as np
import paddle
import paddle.nn.functional as F
from paddlenlp.data import Stack, Tuple, Pad


def convert_example(example,
                    tokenizer,
                    max_seq_length=512,
                    is_test=False,
                    dataset_name="chnsenticorp"):
    """
    Builds model inputs from a sequence or a pair of sequence for sequence classification tasks
    by concatenating and adding special tokens. And creates a mask from the two sequences passed 
    to be used in a sequence-pair classification task.
        
    A skep_ernie_1.0_large_ch/skep_ernie_2.0_large_en sequence has the following format:
    ::
        - single sequence: ``[CLS] X [SEP]``
        - pair of sequences: ``[CLS] A [SEP] B [SEP]``

    A skep_ernie_1.0_large_ch/skep_ernie_2.0_large_en sequence pair mask has the following format:
    ::

        0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
        | first sequence    | second sequence |

    If `token_ids_1` is `None`, this method only returns the first portion of the mask (0s).
    
    note: There is no need token type ids for skep_roberta_large_ch model.


    Args:
        example(obj:`list[str]`): List of input data, containing text and label if it have label.
        tokenizer(obj:`PretrainedTokenizer`): This tokenizer inherits from :class:`~paddlenlp.transformers.PretrainedTokenizer` 
            which contains most of the methods. Users should refer to the superclass for more information regarding methods.
        max_seq_len(obj:`int`): The maximum total input sequence length after tokenization. 
            Sequences longer than this will be truncated, sequences shorter will be padded.
        is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
        dataset_name((obj:`str`, defaults to "chnsenticorp"): The dataset name, "chnsenticorp" or "sst-2".

    Returns:
        input_ids(obj:`list[int]`): The list of token ids.
        token_type_ids(obj: `list[int]`): List of sequence pair mask.
        label(obj:`numpy.array`, data type of int64, optional): The input label if not is_test.
    """
    encoded_inputs = tokenizer(
        text=example["text"],
        text_pair=example["text_pair"],
        max_seq_len=max_seq_length)

    input_ids = encoded_inputs["input_ids"]
    token_type_ids = encoded_inputs["token_type_ids"]

    if not is_test:
        label = np.array([example["label"]], dtype="int64")
        return input_ids, token_type_ids, label
    else:
        return input_ids, token_type_ids
# 處理的最大文本序列長度
max_seq_length=256
# 批量資料大小
batch_size=16

# 將資料處理成model可讀入的資料格式
trans_func = partial(
    convert_example,
    tokenizer=tokenizer,
    max_seq_length=max_seq_length)
# 將資料組成批量式資料,如
# 將不同長度的文本序列padding到批量式資料中最大長度
# 將每條資料label堆疊在一起
batchify_fn = lambda samples, fn=Tuple(
    Pad(axis=0, pad_val=tokenizer.pad_token_id),  # input_ids
    Pad(axis=0, pad_val=tokenizer.pad_token_type_id),  # token_type_ids
    Stack(dtype="int64")  # labels
): [data for data in fn(samples)]
train_data_loader = create_dataloader(
    train_ds,
    mode='train',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)

模型訓練

定義損失函式、優化器以及評價指標后,即可開始訓練,

# 訓練輪次
epochs = 3
# 總共需要訓練的step數
num_training_steps = len(train_data_loader) * epochs
# 優化器
optimizer = paddle.optimizer.AdamW(
    learning_rate=5e-5,
    parameters=model.parameters())
# 交叉熵損失
criterion = paddle.nn.loss.CrossEntropyLoss()
# Accuracy評價指標
metric = paddle.metric.Accuracy()
# 開啟訓練
ckpt_dir = "skep_aspect"
global_step = 0
tic_train = time.time()
for epoch in range(1, epochs + 1):
    for step, batch in enumerate(train_data_loader, start=1):
        input_ids, token_type_ids, labels = batch
        # 喂資料給model
        logits = model(input_ids, token_type_ids)
        # 計算損失函式值
        loss = criterion(logits, labels)
        # 預測分類概率
        probs = F.softmax(logits, axis=1)
        # 計算acc
        correct = metric.compute(probs, labels)
        metric.update(correct)
        acc = metric.accumulate()

        global_step += 1
        if global_step % 10 == 0:
            print(
                "global step %d, epoch: %d, batch: %d, loss: %.5f, acc: %.5f, speed: %.2f step/s"
                % (global_step, epoch, step, loss, acc,
                    10 / (time.time() - tic_train)))
            tic_train = time.time()
        
        # 反向梯度回傳,更新引數
        loss.backward()
        optimizer.step()
        optimizer.clear_grad()

        if global_step % 100 == 0:
            
            save_dir = os.path.join(ckpt_dir, "model_%d" % global_step)
            if not os.path.exists(save_dir):
                os.makedirs(save_dir)
            # 保存模型引數
            model.save_pretrained(save_dir)
            # 保存tokenizer的詞表等
            tokenizer.save_pretrained(save_dir)

預測提交結果

使用訓練得到的模型還可以對評價物件進行情感預測,

@paddle.no_grad()
def predict(model, data_loader, label_map):
    """
    Given a prediction dataset, it gives the prediction results.

    Args:
        model(obj:`paddle.nn.Layer`): A model to classify texts.
        data_loader(obj:`paddle.io.DataLoader`): The dataset loader which generates batches.
        label_map(obj:`dict`): The label id (key) to label str (value) map.
    """
    model.eval()
    results = []
    for batch in data_loader:
        input_ids, token_type_ids = batch
        logits = model(input_ids, token_type_ids)
        probs = F.softmax(logits, axis=1)
        idx = paddle.argmax(probs, axis=1).numpy()
        idx = idx.tolist()
        labels = [label_map[i] for i in idx]
        results.extend(labels)
    return results
# 處理測驗集資料
label_map = {0: '0', 1: '1'}
trans_func = partial(
    convert_example,
    tokenizer=tokenizer,
    max_seq_length=max_seq_length,
    is_test=True)
batchify_fn = lambda samples, fn=Tuple(
    Pad(axis=0, pad_val=tokenizer.pad_token_id),  # input_ids
    Pad(axis=0, pad_val=tokenizer.pad_token_type_id),  # token_type_ids
): [data for data in fn(samples)]
test_data_loader = create_dataloader(
    test_ds,
    mode='test',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)
# 根據實際運行情況,更換加載的引數路徑
params_path = 'skep_ckpt/model_900/model_state.pdparams'
if params_path and os.path.isfile(params_path):
    # 加載模型引數
    state_dict = paddle.load(params_path)
    model.set_dict(state_dict)
    print("Loaded parameters from %s" % params_path)

results = predict(model, test_data_loader, label_map)
# 寫入預測結果
with open(os.path.join("results", "SE-ABSA16_PHNS.tsv"), 'w', encoding="utf8") as f:
    f.write("index\tprediction\n")
    for idx, label in enumerate(results):
        f.write(str(idx)+"\t"+label+"\n")

視頻:https://aistudio.baidu.com/aistudio/course/introduce/24177?sharedLesson=1470935&sharedType=2&sharedUserId=2631487&ts=1686280983462

實踐:https://aistudio.baidu.com/aistudio/projectdetail/6357403?forkThirdPart=1&sUid=2631487&shared=1&ts=1686280956584

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/555771.html

標籤:其他

上一篇:詳解深度學習中推薦系統的經典模型

下一篇:返回列表

標籤雲
其他(161459) Python(38244) JavaScript(25512) Java(18251) C(15238) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7260) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1970) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 自然語言處理 Paddle NLP - 情感分析技術及應用SKEP-實踐

    ## Part A. 情感分析任務 眾所周知,人類自然語言中包含了豐富的情感色彩:表達人的情緒(如悲傷、快樂)、表達人的心情(如倦怠、憂郁)、表達人的喜好(如喜歡、討厭)、表達人的個性特征和表達人的立場等等。情感分析在商品喜好、消費決策、輿情分析等場景中均有應用。利用機器自動分析這些情感傾向,不但有 ......

    uj5u.com 2023-06-22 07:51:11 more
  • 詳解深度學習中推薦系統的經典模型

    摘要:DSSM 用字向量作為輸入既可以減少切詞的依賴,又可以提高模型的泛化能力,因為每個漢字所能表達的語意是可以復用的。 本文分享自華為云社區《深度學習應用篇-推薦系統[12]:經典模型-DeepFM模型、DSSM模型召回排序策略以及和其他模型對比》,作者:汀丶。 1.DeepFM模型 1.1模型簡 ......

    uj5u.com 2023-06-22 07:49:11 more
  • 自然語言處理 Paddle NLP - 情感分析技術及應用-理論

    對帶有感情色彩的主觀性文本進行 分析、處理、歸納和推理的程序,輸入文本 => (描述物體/entity,屬性/aspect,情感/opinion ,觀點持有者/holder,時間/time) ......

    uj5u.com 2023-06-22 07:48:18 more
  • Kubernetes Ingress 之 Nginx Ingress

    一. 引言 k8s 提供了一下四種方式來暴露埠,分別是: ClusterIP, 僅供集群內部訪問 NodePort,埠映射,給node隨機分配埠,然后由service進行代理 LoadBalancer, 負載均衡模式,一般由云服務商提供負載均衡策略 Ingress,網關模式,使用自定義的htt ......

    uj5u.com 2023-06-22 07:47:39 more
  • 建設數字工廠:華為云數字工廠平臺接入第三方網關設備資料

    摘要:本期介紹工業自動化產線設備由第三方數采網關(軟體)采集資料后,如何快速接入到華為云數字工廠平臺,實作生產自動化控制層與數字工廠應用層的資料集成和實時互動。 本文分享自華為云社區《數字工廠深入淺出系列(五):接入第三方網關設備資料》,作者: 云起MAE。 華為云數字工廠平臺內置工業IoT資料引擎 ......

    uj5u.com 2023-06-22 07:46:59 more
  • Codeforces Round 881 (Div. 3)

    ## [A - Sasha and Array Coloring (CF1843 A)](https://codeforces.com/contest/1843/problem/A) ### 題目大意 給定一個陣列,給每個元素涂色。求最大的代價。 代價為每個顏色的代價和。 每個顏色的代價為涂了該顏色 ......

    uj5u.com 2023-06-22 07:45:56 more
  • 【技識訓累】資料結構中的基本概念【一】

    博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ......

    uj5u.com 2023-06-22 07:45:51 more
  • ZEGO 即構音樂場景降噪技術決議

    隨著線上泛娛樂的興起,語聊房、在線 KTV 以及直播等場景在人們的日常生活中占據越來越重要的地位,用戶對于音質的要求也越來越高,因此超越傳統語音降噪演算法的 AI 降噪演算法應運而生,所以目前各大 RTC 廠商普遍使用 AI 技術進行降噪處理,使用 AI 降噪技術消除除人聲外的一切聲音。 但對于一些特殊 ......

    uj5u.com 2023-06-22 07:45:16 more
  • 即視角|出海正當時:歐美、東南亞、中東、拉美市場觀察

    共享即構新洞察,共建行業新動能——ZEGO即構科技基于音視頻技術領域的多年深耕,綜合面向各行業的服務經驗,推出【即視角】欄目,發布即構對行業的洞察。歡迎大家探討論道,共驅前行。 ......

    uj5u.com 2023-06-22 07:44:46 more
  • 視頻直播原始碼技術知識分享:連麥功能(一)

    我們開發視頻直播平臺就要去了解視頻直播開發相關功能知識,這對我們開發平臺有著重要的作用,連麥技術就是視頻直播原始碼重要的技術功能之一,每一個功能技術都有自己的用武之地 ......

    uj5u.com 2023-06-22 07:43:25 more