情感分析¶
在本笔记本中,我们展示了如何从Hugging Face下载预训练模型和数据集,以及如何通过微调部分参数来校准模型,以完成情感分析任务。
以下单元格进行了几项配置选择。默认情况下,我们使用Bert模型和imdb数据集。我们对数据的分割方式、批量大小和优化方法做出了选择。
[ ]:
pretrained_model_name_or_path = "bert-base-cased"
dataset_name = "imdb"
text_columns = ("text",)
target_column = "label"
train_split = "train[:2%]+train[-2%:]"
val_split = "test[:1%]+test[-1%:]"
test_split = "test[:1%]+test[-1%:]"
num_labels = 2
max_sequence_length = 512
per_device_train_batch_size = 16
per_device_eval_batch_size = 16
seed = 0
weight_decay = 0.01
num_train_epochs = 2
num_warmup_steps = 0
learning_rate = 2e-5
max_grad_norm = 1.0
early_stopping_patience = 1
准备数据¶
首先,我们从Hugging Face实例化一个用于预训练模型的tokenizer。
[ ]:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path)
然后,我们下载一些校准、验证和测试数据集。
[ ]:
from datasets import DatasetDict, load_dataset
datasets = DatasetDict(
{
"calibration": load_dataset(dataset_name, split=train_split),
"validation": load_dataset(dataset_name, split=val_split),
"test": load_dataset(dataset_name, split=test_split),
}
)
是时候让Fortuna发挥作用了。首先,我们调用一个序列分类数据集对象,然后我们对数据集进行标记化,最后我们构建校准、验证和测试数据加载器。
[ ]:
from fortuna.data.dataset.huggingface_datasets import (
HuggingFaceSequenceClassificationDataset,
)
import jax
hf_dataset = HuggingFaceSequenceClassificationDataset(
tokenizer=tokenizer,
padding="max_length",
max_length=max_sequence_length,
num_unique_labels=num_labels,
)
datasets = hf_dataset.get_tokenized_datasets(
datasets, text_columns=text_columns, target_column=target_column
)
rng = jax.random.PRNGKey(seed)
calib_data_loader = hf_dataset.get_data_loader(
datasets["calibration"],
per_device_batch_size=per_device_train_batch_size,
shuffle=True,
drop_last=True,
rng=rng,
)
val_data_loader = hf_dataset.get_data_loader(
datasets["validation"],
per_device_batch_size=per_device_eval_batch_size,
shuffle=False,
drop_last=False,
rng=rng,
)
test_data_loader = hf_dataset.get_data_loader(
datasets["test"],
per_device_batch_size=per_device_eval_batch_size,
shuffle=False,
drop_last=False,
rng=rng,
verbose=True,
)
定义变压器模型¶
从 Hugging Face 的 transformers 库中,我们实例化了感兴趣的预训练 transformer。
[ ]:
from transformers import FlaxAutoModelForSequenceClassification
model = FlaxAutoModelForSequenceClassification.from_pretrained(
pretrained_model_name_or_path=pretrained_model_name_or_path, num_labels=num_labels
)
我们现在将模型传递给CalibClassifier,并实例化一个校准模型。开箱即用,您将能够在自定义损失函数和模型参数的任意子集上微调您的模型。
[ ]:
from fortuna.calib_model import CalibClassifier
calib_model = CalibClassifier(model=model)
校准!¶
我们首先构建一个优化器。我们使用Fortuna的功能来为AdamW定义一个学习率调度器。
[ ]:
from fortuna.utils.optimizer import (
linear_scheduler_with_warmup,
decay_mask_without_layer_norm_fn,
)
import optax
optimizer = optax.adamw(
learning_rate=linear_scheduler_with_warmup(
learning_rate=learning_rate,
num_inputs_train=len(datasets["calibration"]),
train_total_batch_size=per_device_train_batch_size * jax.local_device_count(),
num_train_epochs=num_train_epochs,
num_warmup_steps=num_warmup_steps,
),
weight_decay=weight_decay,
mask=decay_mask_without_layer_norm_fn,
)
然后我们配置校准过程,特别是超参数、要监控的指标、早停、优化器以及我们想要校准的参数。在这里,我们选择仅校准路径中包含“classifier”的参数,即仅最后一层的参数。
[ ]:
from fortuna.calib_model import Config, Optimizer, Monitor, Hyperparameters
from fortuna.metric.classification import accuracy, brier_score
def acc(preds, uncertainties, targets):
return accuracy(preds, targets)
def brier(preds, uncertainties, targets):
return brier_score(uncertainties, targets)
config = Config(
hyperparameters=Hyperparameters(
max_grad_norm=max_grad_norm,
),
monitor=Monitor(
metrics=(acc, brier),
early_stopping_patience=1,
),
optimizer=Optimizer(
method=optimizer,
n_epochs=num_train_epochs,
freeze_fun=lambda path, v: "trainable" if "classifier" in path else "frozen",
),
)
最后,我们进行校准!默认情况下,该方法使用focal loss,但请随意使用您最喜欢的损失函数!
[ ]:
status = calib_model.calibrate(
calib_data_loader=calib_data_loader, val_data_loader=val_data_loader, config=config
)
计算指标¶
我们现在计算一些准确性和预期校准误差 (ECE) 来评估该方法在一些测试数据上的表现。
[ ]:
from fortuna.metric.classification import expected_calibration_error
test_inputs_loader = test_data_loader.to_inputs_loader()
means = calib_model.predictive.mean(
inputs_loader=test_inputs_loader,
)
modes = calib_model.predictive.mode(
inputs_loader=test_inputs_loader,
)
test_targets = test_data_loader.to_array_targets()
acc = accuracy(preds=modes, targets=test_targets)
ece = expected_calibration_error(
preds=modes,
probs=means,
targets=test_targets,
)
[ ]:
print(f"Accuracy on test set: {acc}.")
print(f"ECE on test set: {ece}.")