Traffine I/O

Bahasa Indonesia

2023-03-05

Bagaimana Menggabungkan Data Tabular dengan BERT

Pendahuluan

BERT adalah model bahasa terlatih populer yang telah menunjukkan kesuksesan besar dalam tugas pemrosesan bahasa alami (NLP) seperti analisis sentimen, klasifikasi teks, dan menjawab pertanyaan. Namun, BERT hanya menerima teks sebagai input dan tidak dapat menggabungkan jenis data lain seperti data numerik dan kategorikal.

Keterbatasan ini dapat diatasi dengan menggabungkan data tabular ke dalam model BERT. Dengan cara ini, kita dapat menggunakan kemampuan pemrosesan bahasa yang kuat dari BERT bersama dengan data tabular untuk membuat model yang lebih kuat dan akurat.

Artikel ini akan menunjukkan bagaimana menggabungkan data tabular ke dalam model BERT dan melatihnya menggunakan Hugging Face Trainer.

Menggabungkan Data Tabular dengan Model BERT

Berikut adalah kode PyTorch langkah demi langkah untuk membuat model BERT kustom yang dapat menggabungkan data tabular (data numerik dan kategorikal) dan melatihnya menggunakan Hugging Face Trainer.

Langkah 1: Menyiapkan Data

Langkah pertama adalah menyiapkan data. Kita dapat menggunakan pandas untuk memuat data dari file CSV dan membaginya menjadi set pelatihan dan validasi. Kita akan menggunakan contoh file CSV sederhana yang berisi data numerik dan kategorikal:

python
import pandas as pd
from sklearn.model_selection import train_test_split

df = pd.read_csv('data.csv')
train_df, val_df = train_test_split(df, test_size=0.2, random_state=42)

Setelah kita memiliki data training dan validasi, kita perlu mengonversinya menjadi dataset PyTorch menggunakan kelas Dataset. Kita akan membuat dataset kustom yang mewarisi kelas Dataset dan mengimplementasikan metode __len__ dan __getitem__:

python
import torch
from torch.utils.data import Dataset

class CustomDataset(Dataset):
    def __init__(self, data, tokenizer, max_length):
        self.data = data
        self.tokenizer = tokenizer
        self.max_length = max_length

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

    def __getitem__(self, index):
        row = self.data.iloc[index]

        text = row['text']
        label = row['label']
        numerical_data = torch.tensor(row[['num1', 'num2']].values, dtype=torch.float)
        categorical_data = torch.tensor(row['cat'].values, dtype=torch.long)

        encoding = self.tokenizer(text, padding='max_length', truncation=True, max_length=self.max_length, return_tensors='pt')

        return {
            'input_ids': encoding['input_ids'][0],
            'attention_mask': encoding['attention_mask'][0],
            'token_type_ids': encoding['token_type_ids'][0],
            'numerical_data': numerical_data,
            'categorical_data': categorical_data,
            'label': torch.tensor(label, dtype=torch.long)
        }

Dalam contoh ini, kita memuat setiap baris dari frame data dan mengekstrak teks, label, data numerik (num1 dan num2), dan data kategori (cat). Kemudian kita menggunakan tokenizer untuk mengodekan teks dan mengembalikan kamus yang berisi input ID, attention mask, token type ID, data numerik, data kategori, dan label.

Langkah 2: Tentukan Model

Langkah selanjutnya adalah menentukan model. Kita akan menggunakan model Hugging Face BertForSequenceClassification sebagai dasar dan menambahkan dua layer input tambahan untuk data numerik dan kategori:

python
from transformers import BertForSequenceClassification, BertConfig
import torch.nn as nn

class CustomModel(nn.Module):
    def __init__(self, num_numerical_features, num_categorical_features, num_labels):
        super().__init__()

        config = BertConfig.from_pretrained('bert-base-uncased')
        self.bert = BertForSequenceClassification(config)

        self.numerical_layer = nn.Linear(num_numerical_features, 64)
        self.categorical_layer = nn.Embedding(num_categorical_features, 16)

        self.classifier = nn.Linear(768+64+16, num_labels)

    def forward(self, input_ids, attention_mask, token_type_ids, numerical_data, categorical_data):
        bert_output = self.bert(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids).last_hidden_state[:, 0]

        numerical_output = self.numerical_layer(numerical_data)
        categorical_output = self.categorical_layer(categorical_data).mean(dim=1)

        x = torch.cat((bert_output, numerical_output, categorical_output), dim=1)
        logits = self.classifier(x)

        return logits

Pada contoh ini, kita mendefinisikan model kustom yang mewarisi dari kelas PyTorch nn.Module. Model ini memiliki tiga layer: layer BERT, layer numerik yang menerima data numerik dan mengeluarkan vektor 64-dimensi, dan layer kategorikal yang menerima data kategorikal dan mengeluarkan vektor 16-dimensi. Kemudian, kita menggabungkan keluaran dari layer-layer ini dengan keluaran BERT dan melewatinya melalui sebuah layer linear untuk mendapatkan logits.

Langkah 3: Melatih Model

Langkah terakhir adalah melatih model menggunakan Hugging Face Trainer. Kita akan menggunakan optimizer AdamW dan fungsi kerugian cross-entropy. Kita juga akan mendefinisikan metrik kustom yang menghitung akurasi:

python
from transformers import BertTokenizer
from sklearn.metrics import accuracy_score
from transformers import AdamW
from transformers import get_scheduler

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

train_dataset = CustomDataset(train_df, tokenizer, max_length=128)
val_dataset = CustomDataset(val_df, tokenizer, max_length=128)

device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')

model = CustomModel(num_numerical_features=2, num_categorical_features=4, num_labels=2).to(device)

optimizer = AdamW(model.parameters(), lr=5e-5)
scheduler = get_scheduler("linear", optimizer, num_warmup_steps=0, num_training_steps=len(train_dataset)*5)

def compute_accuracy(pred):
    labels = pred.label_ids
    preds = pred.predictions.argmax(-1)
    return accuracy_score(labels, preds)

from transformers import Trainer, TrainingArguments

training_args = TrainingArguments(
    output_dir='./results',
    num_train_epochs=5,
    per_device_train_batch_size=16,
    per_device_eval_batch_size=64,
    warmup_steps=500,
    weight_decay=0.01,
    logging_dir='./logs',
    logging_steps=10,
    evaluation_strategy='epoch',
    save_strategy='epoch',
    learning_rate=5e-5,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=val_dataset,
    compute_metrics=compute_accuracy,
    optimizer=optimizer,
    scheduler=scheduler,
)

trainer.train()

Pada contoh ini, pertama-tama kita membuat tokenizer dan dataset, dan memindahkan model ke GPU jika tersedia. Kemudian kita membuat optimizer, scheduler, dan metrik kustom. Akhirnya, kita membuat objek Trainer dan memanggil metode train.

Referensi

https://medium.com/georgian-impact-blog/how-to-incorporate-tabular-data-with-huggingface-transformers-b70ac45fcfb4
https://towardsdatascience.com/how-to-combine-textual-and-numerical-features-for-machine-learning-in-python-dc1526ca94d9

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!