This tutorial demonstrates how to fine-tune a pre-trained Transformer model (specifically indobert-base-p1) for the SmSA (Sentiment Analysis) task. SmSA contains three labels: positive, negative, and neutral.
1. Load Model and Tokenizer
Use HuggingFace transformers to load the tokenizer and configure the model for sequence classification. Ensure config.num_labels matches the number of classes in your dataset.
from transformers import BertForSequenceClassification, BertConfig, BertTokenizer
from utils.data_utils import DocumentSentimentDataset
tokenizer = BertTokenizer.from_pretrained('indobenchmark/indobert-base-p1')
config = BertConfig.from_pretrained('indobenchmark/indobert-base-p1')
config.num_labels = DocumentSentimentDataset.NUM_LABELS
model = BertForSequenceClassification.from_pretrained('indobenchmark/indobert-base-p1', config=config)
2. Prepare Dataset and DataLoader
Use DocumentSentimentDataset and DocumentSentimentDataLoader from the utils.data_utils module to handle tokenization and batching.
from utils.data_utils import DocumentSentimentDataset, DocumentSentimentDataLoader
train_dataset = DocumentSentimentDataset(train_dataset_path, tokenizer, lowercase=True)
valid_dataset = DocumentSentimentDataset(valid_dataset_path, tokenizer, lowercase=True)
train_loader = DocumentSentimentDataLoader(dataset=train_dataset, max_seq_len=512, batch_size=32, num_workers=16, shuffle=True)
valid_loader = DocumentSentimentDataLoader(dataset=valid_dataset, max_seq_len=512, batch_size=32, num_workers=16, shuffle=False)
3. Training Loop
Perform fine-tuning using an optimizer (e.g., Adam) and the forward_sequence_classification utility function to compute loss and predictions.
from utils.forward_fn import forward_sequence_classification
from utils.metrics import document_sentiment_metrics_fn
import torch
from torch import optim
optimizer = optim.Adam(model.parameters(), lr=5e-6)
model = model.cuda()
# Inside training loop:
for i, batch_data in enumerate(train_pbar):
loss, batch_hyp, batch_label = forward_sequence_classification(model, batch_data[:-1], i2w=i2w, device='cuda')
optimizer.zero_grad()
loss.backward()
optimizer.step()
4. Inference on Sample Sentences
To test the model on a single string, tokenize the text, convert to a tensor, and extract the label from the logits.
text = 'Bahagia hatiku melihat pernikahan putri sulungku yang cantik jelita'
subwords = tokenizer.encode(text)
subwords = torch.LongTensor(subwords).view(1, -1).to(model.device)
logits = model(subwords)[0]
label = torch.topk(logits, k=1, dim=-1)[1].squeeze().item()
# Use i2w (index to word) mapping to get the string label
print(f'Text: {text} | Label : {i2w[label]}')