Transformers 中文內容分類範例

我們可以使用Transformers多種不同的文字分類功能,這些功能包含情感偵測、意圖判定、多標籤分類等等。這次我們會以情感偵測做為範例。可以在這邊查看可執行的範例

環境建置

!pip install torch>=1.9.0
!pip install sentence-transformers==2.1.0
!pip install jieba==0.42.1
!pip install transformers==4.19.1
!pip install datasets==2.2.1

準備資料

這邊我準備了一些小資料,這只是為了驗證流程,通常我們會準備更多。這邊的資料我以三個維度『正向』、『中性』、『負面』三個維度進行標記。

train_rows = [
 [[0, 1, 0],
  '台灣現正面臨快篩試劑「一劑難求」的窘境'],
 [[1, 0, 0],
  '松山慈惠堂因此宣布免費發放'],
 [[0, 0, 1],
  '沒想到卻遭粉專發文攻擊'],
 [[0, 0, 1],
  '時事評論員黃揚明更直言,這樣的攻擊行為「真的是太低估老百姓的智慧!」'],
 [[0, 0, 1],
  '台灣疫情嚴重,快篩試劑等醫療資源欠缺'],
 [[0, 0, 1],
  '若政治粉專都只會檢討、攻擊一般民眾,黃揚明直言這樣的政治人物「在政壇真的會混不久」'],
 [[0, 1, 0],
  '自己也有去慈惠堂現場看排隊,他坦言隊伍「真的很長」'],
 [[0, 1, 0],
  '有些排隊民眾本輪實快篩名制購買額度可能已用完'],
 [[0, 0, 1],
  '只要是質疑的人都是來造反、搞亂的,這樣的邏輯「會讓老百姓心裡更不舒服」。'],
 [[0, 0, 1],
  '讓國民黨台北市議員徐巧芯氣炸了,砲轟「綠營側翼就是噁心!」'],
]

資料前處理

我們將資料切成訓練集和測試集。

# Importing stock ml libraries
# Importing stock ml libraries
from sklearn import metrics
from sklearn.model_selection import train_test_split
from torch.utils.data import Dataset, DataLoader, RandomSampler, SequentialSampler
from transformers import BertTokenizer, BertModel, BertConfig, BertTokenizerFast
import numpy as np
import pandas as pd


numpy_data = np.array(train_rows)
numpy_data = pd.DataFrame(data=numpy_data)
trainset, testset = train_test_split(numpy_data, test_size=0.2, random_state = 2022)
trainset, testset = trainset.reset_index(), testset.reset_index()

將資料轉成資料集格式。



class CustomDataset(Dataset):

    def __init__(self, dataframe, tokenizer, max_len):
        self.tokenizer = tokenizer
        self.data = dataframe
        self.title = dataframe[1]
        self.targets = dataframe[0]
        self.max_len = max_len

    def __len__(self):
        return len(self.title)

    def __getitem__(self, index):
        title = str(self.title[index])
        title = " ".join(title.split())

        inputs = self.tokenizer.encode_plus(
            title,
            None,
            add_special_tokens=True,
            max_length=self.max_len,
            padding='max_length',
            return_token_type_ids=True,
            truncation=True
        )
        ids = inputs['input_ids']
        mask = inputs['attention_mask']
        token_type_ids = inputs["token_type_ids"]


        return {
            'input_ids': torch.tensor(ids, dtype=torch.long),
            'attention_mask': torch.tensor(mask, dtype=torch.long),
            'token_type_ids': torch.tensor(token_type_ids, dtype=torch.long),
            'labels': torch.tensor(self.targets[index], dtype=torch.float)
        }
    
    def samples(self):
      return [(title[:self.max_len], target) for target,title in zip(self.targets, self.title)]



#
max_seq_length = 75
tokenizer = BertTokenizerFast.from_pretrained('bert-base-chinese',max_length=max_seq_length,padding='max_length', truncation=True)
training_set = CustomDataset(trainset, tokenizer, max_seq_length)
validation_set = CustomDataset(testset, tokenizer, max_seq_length)

模型選擇

這邊我們使用ckiplab/bert-base-chinese。這個專案是CKIP Lab 中文詞知識庫小組提供的繁體中文的 transformers 模型(包含 ALBERT、BERT、GPT2)及自然語言處理工具(包含斷詞、詞性標記、實體辨識)。

加上一些標示,讓我們更好辨識結果。

from transformers import DataCollatorWithPadding, AutoModelForSequenceClassification, TrainingArguments, Trainer
import torch

# Define model
def model_init():
  return AutoModelForSequenceClassification.from_pretrained(
      "ckiplab/bert-base-chinese", 
      num_labels=3,
      output_attentions = False, # Whether the model returns attentions weights.
      output_hidden_states = False,
      return_dict=True,
      id2label={0: '正面', 1: '中性', 2: '負面'   }
  )
  

模型訓練

這邊我們可以添加更多的訓練細節,接下來開始訓練。

data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
training_args = TrainingArguments(
    output_dir="./results",
    learning_rate=2e-5,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=16,
    num_train_epochs=15,
    weight_decay=0.01,
    logging_steps=10,
    save_steps=5,
    seed=2022,
    data_seed=2022,
    evaluation_strategy="steps",
    eval_steps=5

)

trainer = Trainer(
    model_init=model_init,
    args=training_args,
    train_dataset=training_set,
    eval_dataset=validation_set,
    tokenizer=tokenizer,
    data_collator=data_collator

)

trainer.train()

模型運行

我們的結果存在./results/checkpoint-15/,這邊的15主要是看訓練時我們經過了幾次steps,根據結果可以選擇不同的版本。

from transformers import TextClassificationPipeline
from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
new_model = AutoModelForSequenceClassification.from_pretrained("./results/checkpoint-15/",output_attentions=True)

PipelineInterface = TextClassificationPipeline(model=new_model, tokenizer=tokenizer, return_all_scores=True)
PipelineInterface("你的行為真讓我感到噁心") 

運行結果

[[{'label': '正面', 'score': 0.19379371404647827},
  {'label': '中性', 'score': 0.225276917219162},
  {'label': '負面', 'score': 0.6541542410850525}]]
One Comment

Add a Comment

發佈留言必須填寫的電子郵件地址不會公開。