はじめに
BERT は、感情分析、テキスト分類、質問応答などの自然言語処理(NLP)タスクにおいて、優れた成功を収めている人気のある事前学習言語モデルです。ただし、BERTはテキストのみを入力として受け取り、数値データやカテゴリカルデータなどの他の種類のデータを組み込むことができません。
この制限は、表形式のデータをBERTモデルに組み込むことによって解決できます。この方法により、BERTの強力な言語処理機能と表形式のデータを組み合わせて、より堅牢で正確なモデルを作成することができます。
この記事では、表形式のデータをBERTモデルに組み込み、Hugging Face Trainerを使用して学習する方法を紹介します。
BERT モデルに表データを組み込む
以下は、表形式のデータ(数値データやカテゴリカルデータ)を組み込むカスタムBERTモデルを作成し、Hugging Face Trainerを使用して学習するための、ステップバイステップのPyTorchコードです。
ステップ 1:データの準備
最初のステップは、データの準備です。pandasを使用してCSVファイルからデータを読み込み、トレーニングセットとバリデーションセットに分割します。ここでは、数値データとカテゴリカルデータの両方を含む単純なCSVファイルを使用します。
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)
トレーニングセットとバリデーションセットのデータフレームを作成した後、Datasetクラスを使用してPyTorchデータセットに変換します。Datasetクラスを継承し、__len__
メソッドと__getitem__
メソッドを実装するカスタムデータセットを作成します。
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)
}
この例では、データフレームから各行を読み込み、テキスト、ラベル、数値データ(num1とnum2)、およびカテゴリデータ(cat)の列を抽出します。次に、トークナイザーを使用してテキストをエンコードし、入力ID、アテンションマスク、トークンタイプID、数値データ、カテゴリデータ、ラベルを含む辞書を返します。
ステップ 2:モデルの定義
次のステップは、モデルの定義です。ハグイングフェイスのBertForSequenceClassification
モデルをベースにして、数値データとカテゴリデータの2つの追加の入力層を追加します。
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
この例では、PyTorch nn.Module
クラスから継承されたカスタムモデルを定義します。モデルには3つのレイヤーがあります。BERTレイヤー、数値データを入力し、64次元のベクトルを出力する数値レイヤー、およびカテゴリデータを入力し、16次元のベクトルを出力するカテゴリレイヤーがあります。これらのレイヤーからの出力をBERTの出力と連結し、線形レイヤーを通過させてロジットを取得します。
ステップ 3:モデルのトレーニング
最後のステップは、Hugging Face Trainerを使用してモデルをトレーニングすることです。AdamWオプティマイザーと交差エントロピー損失関数を使用します。また、正確度を計算するカスタムメトリックを定義します。
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()
この例では、まずトークナイザーとデータセットを作成し、モデルをGPUに移動させます。次に、オプティマイザー、スケジューラー、カスタムメトリックを作成します。最後に、Trainer
オブジェクトを作成し、train
メソッドを呼び出します。
参考